Skip to content

Commit fb5b011

Browse files
MrFlounderclaude
andcommitted
feat(init): add template system for project-type-aware setup
Add a template system to `crab init` that auto-detects project type and applies pre-built configurations. Includes a promptfoo-cloud template with port_spacing, install_env, admin-app/.env, and API_PORT/PORT refs. New flags: --template/-t <name>, --list-templates. The `pf` alias maps to promptfoo-cloud. Also updates Slack token config to prefer the CRAB_SLACK_BOT_TOKEN env var over config file. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 07e668f commit fb5b011

File tree

1 file changed

+208
-17
lines changed

1 file changed

+208
-17
lines changed

src/crabcode

Lines changed: 208 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
# <N> continue Resume session with --continue flag
1414
# restart Auto-detect workspace from cwd + restart
1515
# continue Auto-detect workspace from cwd + resume
16-
# init Minimal config setup (2 questions)
16+
# init Setup config (auto-detects project type)
1717
# config Show current configuration
1818
# config scan Auto-detect .env files and ports
1919
# doctor Diagnose common issues
@@ -2664,10 +2664,9 @@ tk_upload_slack() {
26642664

26652665
# Otherwise use curl with Slack API
26662666
if [ -z "$slack_token" ]; then
2667-
error "Slack not configured. Add to ~/.crabcode/config.yaml:"
2667+
error "Slack not configured. Set CRAB_SLACK_BOT_TOKEN env var:"
26682668
echo ""
2669-
echo "slack:"
2670-
echo " bot_token: xoxb-your-bot-token"
2669+
echo " export CRAB_SLACK_BOT_TOKEN=xoxb-your-bot-token"
26712670
return 1
26722671
fi
26732672

@@ -3024,9 +3023,13 @@ handle_tk_command() {
30243023
# Slack Integration
30253024
# =============================================================================
30263025

3027-
# Get Slack bot token from config
3026+
# Get Slack bot token from env var (preferred) or config
30283027
slack_get_token() {
3029-
config_get "slack.bot_token" ""
3028+
if [ -n "${CRAB_SLACK_BOT_TOKEN:-}" ]; then
3029+
echo "$CRAB_SLACK_BOT_TOKEN"
3030+
else
3031+
config_get "slack.bot_token" ""
3032+
fi
30303033
}
30313034

30323035
# Get display name for messages (git config or override)
@@ -3206,7 +3209,7 @@ slack_chat() {
32063209
local token=$(slack_get_token)
32073210

32083211
if [ -z "$token" ]; then
3209-
error "Slack not configured. Add bot_token to ~/.crabcode/config.yaml"
3212+
error "Slack not configured. Set CRAB_SLACK_BOT_TOKEN env var"
32103213
return 1
32113214
fi
32123215

@@ -3313,7 +3316,7 @@ slack_send() {
33133316
local token=$(slack_get_token)
33143317

33153318
if [ -z "$token" ]; then
3316-
error "Slack not configured. Add bot_token to ~/.crabcode/config.yaml"
3319+
error "Slack not configured. Set CRAB_SLACK_BOT_TOKEN env var"
33173320
return 1
33183321
fi
33193322

@@ -3362,7 +3365,7 @@ slack_read() {
33623365
local token=$(slack_get_token)
33633366

33643367
if [ -z "$token" ]; then
3365-
error "Slack not configured. Add bot_token to ~/.crabcode/config.yaml"
3368+
error "Slack not configured. Set CRAB_SLACK_BOT_TOKEN env var"
33663369
return 1
33673370
fi
33683371

@@ -3497,17 +3500,158 @@ show_slack_help() {
34973500
echo " crab slack read @michael"
34983501
echo " crab slack chat @michael"
34993502
echo ""
3500-
echo "Configuration (~/.crabcode/config.yaml):"
3503+
echo "Configuration:"
3504+
echo " export CRAB_SLACK_BOT_TOKEN=xoxb-your-token # add to shell profile"
3505+
echo ""
3506+
echo "Optional (~/.crabcode/config.yaml):"
35013507
echo " slack:"
3502-
echo " bot_token: xoxb-your-token"
3503-
echo " display_name: \"Your Name\" # optional, defaults to git config"
3508+
echo " display_name: \"Your Name\" # defaults to git config"
35043509
}
35053510

35063511
# =============================================================================
35073512
# Init / Config / Doctor
35083513
# =============================================================================
35093514

3515+
# -- Template System ----------------------------------------------------------
3516+
3517+
template_promptfoo_cloud() {
3518+
cat << 'TEMPLATE_EOF'
3519+
# Crabcode Configuration - Promptfoo Cloud Template
3520+
# Generated by 'crabcode init --template promptfoo-cloud'
3521+
3522+
session_name: crab
3523+
workspace_base: WORKSPACE_BASE_PLACEHOLDER
3524+
main_repo: MAIN_REPO_PLACEHOLDER
3525+
3526+
workspaces:
3527+
prefix: cloud-workspace
3528+
branch_pattern: workspace-{N}
3529+
3530+
layout:
3531+
panes:
3532+
- name: terminal
3533+
command: ""
3534+
- name: server
3535+
command: pnpm dev
3536+
- name: main
3537+
command: claude --dangerously-skip-permissions --chrome
3538+
3539+
install_command: pnpm install
3540+
install_env: PROMPTFOO_NODE_MODULES_CACHED=true
3541+
3542+
submodules:
3543+
- path: promptfoo
3544+
reset_to: origin/main
3545+
install_command: pnpm install
3546+
3547+
env_sync:
3548+
port_spacing: 10
3549+
files:
3550+
- path: server/.env
3551+
copy_from: server/.env.example
3552+
ports: [API_URL, APP_URL]
3553+
refs:
3554+
API_PORT: API_URL:port
3555+
- path: app/.env
3556+
copy_from: app/.env.example
3557+
refs:
3558+
VITE_API_BASE_URL: API_URL
3559+
PORT: APP_URL:port
3560+
- path: admin-app/.env
3561+
copy_from: admin-app/.env.example
3562+
refs:
3563+
VITE_API_BASE_URL: API_URL
3564+
- path: promptfoo/.env
3565+
refs:
3566+
PROMPTFOO_REMOTE_GENERATION_URL: API_URL
3567+
PROMPTFOO_UNALIGNED_INFERENCE_ENDPOINT: API_URL
3568+
API_HOST: API_URL
3569+
3570+
cleanup:
3571+
preserve_files: ".env"
3572+
kill_pattern: "cloud-workspace-{N}.*pnpm|cloud-workspace-{N}.*node"
3573+
3574+
shared_volume:
3575+
enabled: true
3576+
path: ~/.crabcode/shared
3577+
link_as: .local
3578+
TEMPLATE_EOF
3579+
}
3580+
3581+
detect_template() {
3582+
local repo_path="${1:-.}"
3583+
3584+
# Check for promptfoo-cloud: has .gitmodules with "promptfoo" AND server/.env.example
3585+
if [ -f "$repo_path/.gitmodules" ] && grep -q "promptfoo" "$repo_path/.gitmodules" 2>/dev/null \
3586+
&& [ -f "$repo_path/server/.env.example" ]; then
3587+
echo "promptfoo-cloud"
3588+
return
3589+
fi
3590+
3591+
# Fallback: directory name contains "promptfoo-cloud"
3592+
if [[ "$(basename "$repo_path")" == *"promptfoo-cloud"* ]]; then
3593+
echo "promptfoo-cloud"
3594+
return
3595+
fi
3596+
3597+
echo ""
3598+
}
3599+
3600+
apply_template() {
3601+
local template_name="$1"
3602+
local main_repo="$2"
3603+
local workspace_base="$3"
3604+
3605+
local template_content=""
3606+
case "$template_name" in
3607+
"promptfoo-cloud")
3608+
template_content="$(template_promptfoo_cloud)"
3609+
;;
3610+
*)
3611+
error "Unknown template: $template_name"
3612+
return 1
3613+
;;
3614+
esac
3615+
3616+
mkdir -p "$CONFIG_DIR"
3617+
echo "$template_content" \
3618+
| sed "s|MAIN_REPO_PLACEHOLDER|$main_repo|g" \
3619+
| sed "s|WORKSPACE_BASE_PLACEHOLDER|$workspace_base|g" \
3620+
> "$CONFIG_FILE"
3621+
}
3622+
3623+
show_templates() {
3624+
echo -e "${CYAN}Available Templates${NC}"
3625+
echo ""
3626+
echo -e " ${GREEN}promptfoo-cloud${NC} Full config for promptfoo-cloud repos"
3627+
echo " Includes env_sync, submodules, port_spacing, install_env"
3628+
echo ""
3629+
echo "Usage:"
3630+
echo " crab init --template promptfoo-cloud"
3631+
echo " crab init -t promptfoo-cloud"
3632+
}
3633+
3634+
# -- End Template System ------------------------------------------------------
3635+
35103636
show_init() {
3637+
# Parse arguments
3638+
local template_name=""
3639+
while [ $# -gt 0 ]; do
3640+
case "$1" in
3641+
--template|-t)
3642+
template_name="$2"
3643+
shift 2
3644+
;;
3645+
--list-templates)
3646+
show_templates
3647+
return
3648+
;;
3649+
*)
3650+
shift
3651+
;;
3652+
esac
3653+
done
3654+
35113655
echo -e "${CYAN}Crabcode Setup${NC}"
35123656
echo ""
35133657

@@ -3564,7 +3708,6 @@ show_init() {
35643708
fi
35653709

35663710
echo "Let's set up crabcode for your project."
3567-
echo "(Minimal setup - run 'crab config scan' after to detect ports)"
35683711
echo ""
35693712

35703713
# Main repo
@@ -3603,10 +3746,56 @@ show_init() {
36033746
# Expand ~
36043747
workspace_base="${workspace_base/#\~/$HOME}"
36053748

3606-
# Create config directory
3749+
# Template handling: explicit flag or auto-detection
3750+
if [ -n "$template_name" ]; then
3751+
# Validate the explicit template name
3752+
case "$template_name" in
3753+
"promptfoo-cloud"|"pf")
3754+
template_name="promptfoo-cloud"
3755+
;;
3756+
*)
3757+
error "Unknown template: $template_name"
3758+
echo "Run 'crab init --list-templates' to see available templates."
3759+
return 1
3760+
;;
3761+
esac
3762+
echo ""
3763+
echo -e "Applying ${GREEN}$template_name${NC} template..."
3764+
apply_template "$template_name" "$main_repo" "$workspace_base"
3765+
echo ""
3766+
success "Config created at $CONFIG_FILE (template: $template_name)"
3767+
echo ""
3768+
echo -e "${CYAN}Next steps:${NC}"
3769+
echo " 1. Review config: crab config"
3770+
echo " 2. Run 'crab ws 1' to create your first workspace"
3771+
return
3772+
fi
3773+
3774+
# Auto-detect template from repo contents
3775+
local detected
3776+
detected=$(detect_template "$main_repo")
3777+
if [ -n "$detected" ]; then
3778+
echo ""
3779+
echo -e "Detected ${GREEN}$detected${NC} project."
3780+
read -p "Use template? [Y/n]: " use_tpl
3781+
if [ "$use_tpl" != "n" ] && [ "$use_tpl" != "N" ]; then
3782+
echo ""
3783+
echo -e "Applying ${GREEN}$detected${NC} template..."
3784+
apply_template "$detected" "$main_repo" "$workspace_base"
3785+
echo ""
3786+
success "Config created at $CONFIG_FILE (template: $detected)"
3787+
echo ""
3788+
echo -e "${CYAN}Next steps:${NC}"
3789+
echo " 1. Review config: crab config"
3790+
echo " 2. Run 'crab ws 1' to create your first workspace"
3791+
return
3792+
fi
3793+
echo ""
3794+
fi
3795+
3796+
# No template - generate minimal config
36073797
mkdir -p "$CONFIG_DIR"
36083798

3609-
# Generate minimal config file
36103799
cat > "$CONFIG_FILE" << EOF
36113800
# Crabcode Configuration
36123801
# Generated by 'crabcode init'
@@ -5793,7 +5982,9 @@ show_help() {
57935982
echo " tk share --serve Local HTTP server"
57945983
echo ""
57955984
echo "Other Commands:"
5796-
echo " init Minimal config setup (2 questions)"
5985+
echo " init Setup config (auto-detects project type)"
5986+
echo " init -t <name> Setup with template (e.g., promptfoo-cloud)"
5987+
echo " init --list-templates Show available templates"
57975988
echo " config Show configuration"
57985989
echo " config scan Auto-detect .env files and ports"
57995990
echo " doctor Diagnose issues"
@@ -6039,7 +6230,7 @@ main() {
60396230
handle_ws_command "${@:2}"
60406231
;;
60416232
"init")
6042-
show_init
6233+
show_init "${@:2}"
60436234
;;
60446235
"config")
60456236
if [ "${2:-}" = "scan" ]; then

0 commit comments

Comments
 (0)