specrails-core 3.5.3 → 3.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/install.sh CHANGED
@@ -3,7 +3,7 @@ set -euo pipefail
3
3
 
4
4
  # specrails installer
5
5
  # Installs the agent workflow system into any repository.
6
- # Step 1 of 2: Prerequisites + scaffold. Step 2: Run /specrails:setup inside Claude Code.
6
+ # Step 1 of 2: Prerequisites + scaffold. Step 2: Run /specrails:enrich inside Claude Code.
7
7
 
8
8
  # Detect pipe mode (curl | bash) vs local execution
9
9
  if [[ -z "${BASH_SOURCE[0]:-}" || "${BASH_SOURCE[0]:-}" == "bash" ]]; then
@@ -46,6 +46,13 @@ HAS_CLAUDE=false
46
46
  HAS_CODEX=false
47
47
  AGENT_TEAMS=false
48
48
 
49
+ # Direct-mode flags (set by bin/specrails-core.js after TUI completes)
50
+ FROM_CONFIG=false # read provider/agent_teams from .specrails/install-config.yaml
51
+ CONFIG_PATH="" # explicit config file path (passed after --from-config)
52
+ HAS_GUM=false # set to true if gum CLI is available (optional UI enhancement)
53
+ TIER="full" # install tier: full (default) or quick (template-only, no enrich)
54
+ HUB_JSON=false # emit JSON checkpoint lines for programmatic consumption (specrails-hub)
55
+
49
56
  while [[ $# -gt 0 ]]; do
50
57
  case "$1" in
51
58
  --root-dir)
@@ -72,9 +79,36 @@ while [[ $# -gt 0 ]]; do
72
79
  CLI_PROVIDER="$2"
73
80
  shift 2
74
81
  ;;
82
+ --from-config)
83
+ # Config was written by the TUI; skip interactive prompts and read
84
+ # provider + agent_teams from install-config.yaml.
85
+ # Optional: --from-config <path> (defaults to .specrails/install-config.yaml)
86
+ FROM_CONFIG=true
87
+ if [[ -n "${2:-}" && "${2:-}" != -* ]]; then
88
+ CONFIG_PATH="${2}"
89
+ shift 2
90
+ else
91
+ shift
92
+ fi
93
+ ;;
94
+ --agent-teams)
95
+ # Explicitly enable agent teams commands (alternative to config file).
96
+ AGENT_TEAMS=true
97
+ shift
98
+ ;;
99
+ --quick)
100
+ # Template-only install; sets tier=quick in the generated config.
101
+ TIER="quick"
102
+ shift
103
+ ;;
104
+ --hub-json)
105
+ # Emit JSON checkpoint lines for programmatic consumption by specrails-hub.
106
+ HUB_JSON=true
107
+ shift
108
+ ;;
75
109
  *)
76
110
  echo "Unknown argument: $1" >&2
77
- echo "Usage: install.sh [--root-dir <path>] [--yes|-y] [--provider <claude|codex>]" >&2
111
+ echo "Usage: install.sh [--root-dir <path>] [--yes|-y] [--provider <claude|codex>] [--from-config [<path>]] [--agent-teams] [--quick] [--hub-json]" >&2
78
112
  exit 1
79
113
  ;;
80
114
  esac
@@ -162,14 +196,14 @@ generate_manifest() {
162
196
  \"${relpath}\": \"${checksum}\""
163
197
  done < <(find "$SCRIPT_DIR/templates" -type f -not -path '*/node_modules/*' -not -name 'package-lock.json' -print0 | sort -z)
164
198
 
165
- # Include commands/setup.md
166
- local setup_checksum
167
- setup_checksum="sha256:$(shasum -a 256 "$SCRIPT_DIR/commands/setup.md" | awk '{print $1}')"
199
+ # Include commands/enrich.md
200
+ local enrich_checksum
201
+ enrich_checksum="sha256:$(shasum -a 256 "$SCRIPT_DIR/commands/enrich.md" | awk '{print $1}')"
168
202
  if [ -n "$artifacts_json" ]; then
169
203
  artifacts_json="${artifacts_json},"
170
204
  fi
171
205
  artifacts_json="${artifacts_json}
172
- \"commands/specrails/setup.md\": \"${setup_checksum}\""
206
+ \"commands/specrails/enrich.md\": \"${enrich_checksum}\""
173
207
 
174
208
  # Include commands/doctor.md
175
209
  local doctor_checksum
@@ -215,47 +249,149 @@ if command -v codex &> /dev/null; then
215
249
  HAS_CODEX=true
216
250
  fi
217
251
 
218
- if [[ -n "$CLI_PROVIDER" ]]; then
219
- # --provider flag was set explicitly — skip interactive detection
220
- ok "Provider: $CLI_PROVIDER (--provider flag)"
221
- elif [ "$HAS_CLAUDE" = true ] && [ "$HAS_CODEX" = true ]; then
222
- echo ""
223
- echo -e " ${BOLD}Both Claude Code and Codex detected.${NC}"
224
- if [ "$AUTO_YES" = true ]; then
225
- CLI_PROVIDER="claude"
226
- info "Auto-selected Claude Code (--yes flag active)"
252
+ # 1.2a Gum detection (optional UI enhancement — used in non-TUI bash paths)
253
+ if command -v gum &> /dev/null; then
254
+ HAS_GUM=true
255
+ ok "gum CLI: found (enhanced UI available)"
256
+ else
257
+ # Attempt a lightweight auto-install on supported platforms (best-effort)
258
+ _GUM_INSTALLED=false
259
+ if command -v brew &> /dev/null; then
260
+ info "Installing gum CLI via Homebrew (optional adds nicer prompts)..."
261
+ if brew install gum &>/dev/null; then
262
+ HAS_GUM=true
263
+ _GUM_INSTALLED=true
264
+ ok "gum installed via Homebrew"
265
+ fi
266
+ fi
267
+ if [[ "$_GUM_INSTALLED" == false ]]; then
268
+ info "gum CLI not found — install via 'brew install gum' for enhanced prompts (optional)"
269
+ fi
270
+ fi
271
+
272
+ if [[ "$FROM_CONFIG" == true ]]; then
273
+ # Config was written by the TUI — read provider and agent_teams from it.
274
+ # Resolve config path: explicit path > default location.
275
+ if [[ -z "$CONFIG_PATH" ]]; then
276
+ CONFIG_PATH="${REPO_ROOT}/.specrails/install-config.yaml"
277
+ fi
278
+ if [[ -f "$CONFIG_PATH" ]]; then
279
+ _cfg_version=$(grep '^version:' "$CONFIG_PATH" 2>/dev/null | awk '{print $2}' | tr -d '[:space:]' || true)
280
+ _cfg_provider=$(grep '^provider:' "$CONFIG_PATH" 2>/dev/null | awk '{print $2}' | tr -d '[:space:]' || true)
281
+ _cfg_agent_teams=$(grep '^agent_teams:' "$CONFIG_PATH" 2>/dev/null | awk '{print $2}' | tr -d '[:space:]' || true)
282
+ _cfg_tier=$(grep '^tier:' "$CONFIG_PATH" 2>/dev/null | awk '{print $2}' | tr -d '[:space:]' || true)
283
+ _cfg_preset=$(grep '^\s*preset:' "$CONFIG_PATH" 2>/dev/null | head -1 | awk '{print $2}' | tr -d '[:space:]' || true)
284
+ _cfg_has_agents=$(grep -c '^\s*selected:' "$CONFIG_PATH" 2>/dev/null || true)
285
+
286
+ _config_errors=0
287
+ if [[ -z "$_cfg_version" ]]; then
288
+ fail "Invalid config: missing required 'version' field"
289
+ _config_errors=$(( _config_errors + 1 ))
290
+ elif [[ "$_cfg_version" != "1" ]]; then
291
+ fail "Invalid config: unsupported version '$_cfg_version' (expected: 1)"
292
+ _config_errors=$(( _config_errors + 1 ))
293
+ fi
294
+ if [[ -z "$_cfg_provider" ]]; then
295
+ fail "Invalid config: missing required 'provider' field"
296
+ _config_errors=$(( _config_errors + 1 ))
297
+ elif [[ "$_cfg_provider" != "claude" && "$_cfg_provider" != "codex" ]]; then
298
+ fail "Invalid config: unsupported provider '$_cfg_provider' (expected: claude or codex)"
299
+ _config_errors=$(( _config_errors + 1 ))
300
+ fi
301
+ if [[ "$_cfg_has_agents" -eq 0 ]]; then
302
+ fail "Invalid config: missing required 'agents' section with 'selected' list"
303
+ _config_errors=$(( _config_errors + 1 ))
304
+ fi
305
+ if [[ -n "$_cfg_tier" && "$_cfg_tier" != "full" && "$_cfg_tier" != "quick" ]]; then
306
+ fail "Invalid config: unsupported tier '$_cfg_tier' (expected: full or quick)"
307
+ _config_errors=$(( _config_errors + 1 ))
308
+ fi
309
+ if [[ -n "$_cfg_preset" && "$_cfg_preset" != "balanced" && "$_cfg_preset" != "budget" && "$_cfg_preset" != "max" ]]; then
310
+ fail "Invalid config: unsupported preset '$_cfg_preset' (expected: balanced, budget, or max)"
311
+ _config_errors=$(( _config_errors + 1 ))
312
+ fi
313
+
314
+ # Warn about unknown agents in selected list
315
+ if [[ "$_cfg_has_agents" -gt 0 ]]; then
316
+ _selected_line=$(grep '^\s*selected:' "$CONFIG_PATH" 2>/dev/null | head -1 || true)
317
+ if echo "$_selected_line" | grep -q '\[' 2>/dev/null; then
318
+ _selected_agents=$(echo "$_selected_line" | sed 's/.*\[//;s/\].*//;s/,/\n/g' | tr -d ' ')
319
+ else
320
+ _selected_agents=$(grep -A100 '^\s*selected:' "$CONFIG_PATH" 2>/dev/null \
321
+ | tail -n +2 | grep '^\s*-\s*' | sed 's/^\s*-\s*//' | tr -d ' ' || true)
322
+ fi
323
+ while IFS= read -r _agent_name; do
324
+ [[ -z "$_agent_name" ]] && continue
325
+ if [[ ! -f "$SCRIPT_DIR/templates/agents/${_agent_name}.md" ]]; then
326
+ warn "Unknown agent in selected list: ${_agent_name}"
327
+ fi
328
+ done <<< "$_selected_agents"
329
+ fi
330
+
331
+ if [[ "$_config_errors" -gt 0 ]]; then
332
+ fail "Config validation failed with ${_config_errors} error(s) — aborting"
333
+ exit 1
334
+ fi
335
+
336
+ if [[ -n "$_cfg_provider" ]]; then
337
+ CLI_PROVIDER="$_cfg_provider"
338
+ ok "Provider: $CLI_PROVIDER (from install-config.yaml)"
339
+ fi
340
+ if [[ "$_cfg_agent_teams" == "true" ]]; then
341
+ AGENT_TEAMS=true
342
+ fi
343
+ if [[ -n "$_cfg_tier" ]]; then
344
+ TIER="$_cfg_tier"
345
+ fi
227
346
  else
347
+ warn "install-config.yaml not found at $CONFIG_PATH — falling back to auto-detection"
348
+ FROM_CONFIG=false
349
+ fi
350
+ fi
351
+
352
+ if [[ "$FROM_CONFIG" != true ]]; then
353
+ if [[ -n "$CLI_PROVIDER" ]]; then
354
+ # --provider flag was set explicitly — skip interactive detection
355
+ ok "Provider: $CLI_PROVIDER (--provider flag)"
356
+ elif [ "$HAS_CLAUDE" = true ] && [ "$HAS_CODEX" = true ]; then
228
357
  echo ""
229
- echo " Which provider would you like to use?"
230
- echo " 1) Claude Code (claude) → output to .claude/"
231
- echo " 2) Codex (codex) → output to .codex/"
232
- echo ""
233
- read -p " Select provider (1 or 2, default: 1): " PROVIDER_CHOICE || PROVIDER_CHOICE="1"
234
- PROVIDER_CHOICE="${PROVIDER_CHOICE:-1}"
235
- if [[ "$PROVIDER_CHOICE" == "2" ]]; then
236
- CLI_PROVIDER="codex"
237
- else
358
+ echo -e " ${BOLD}Both Claude Code and Codex detected.${NC}"
359
+ if [ "$AUTO_YES" = true ]; then
238
360
  CLI_PROVIDER="claude"
361
+ info "Auto-selected Claude Code (--yes flag active)"
362
+ else
363
+ echo ""
364
+ echo " Which provider would you like to use?"
365
+ echo " 1) Claude Code (claude) → output to .claude/"
366
+ echo " 2) Codex (codex) → output to .codex/"
367
+ echo ""
368
+ read -p " Select provider (1 or 2, default: 1): " PROVIDER_CHOICE || PROVIDER_CHOICE="1"
369
+ PROVIDER_CHOICE="${PROVIDER_CHOICE:-1}"
370
+ if [[ "$PROVIDER_CHOICE" == "2" ]]; then
371
+ CLI_PROVIDER="codex"
372
+ else
373
+ CLI_PROVIDER="claude"
374
+ fi
239
375
  fi
376
+ ok "Provider: $CLI_PROVIDER"
377
+ elif [ "$HAS_CLAUDE" = true ]; then
378
+ CLI_PROVIDER="claude"
379
+ CLAUDE_VERSION=$(claude --version 2>/dev/null || echo "unknown")
380
+ ok "Claude Code CLI: $CLAUDE_VERSION"
381
+ elif [ "$HAS_CODEX" = true ]; then
382
+ CLI_PROVIDER="codex"
383
+ CODEX_VERSION=$(codex --version 2>/dev/null || echo "unknown")
384
+ ok "Codex CLI: $CODEX_VERSION"
385
+ elif [[ "$SKIP_PREREQS" == "1" ]]; then
386
+ CLI_PROVIDER="claude"
387
+ warn "No AI CLI found (skipped — SPECRAILS_SKIP_PREREQS=1)"
388
+ else
389
+ fail "No AI CLI found (claude or codex)."
390
+ echo ""
391
+ echo " Install Claude Code: https://claude.ai/download"
392
+ echo " Install Codex: https://github.com/openai/codex"
393
+ exit 1
240
394
  fi
241
- ok "Provider: $CLI_PROVIDER"
242
- elif [ "$HAS_CLAUDE" = true ]; then
243
- CLI_PROVIDER="claude"
244
- CLAUDE_VERSION=$(claude --version 2>/dev/null || echo "unknown")
245
- ok "Claude Code CLI: $CLAUDE_VERSION"
246
- elif [ "$HAS_CODEX" = true ]; then
247
- CLI_PROVIDER="codex"
248
- CODEX_VERSION=$(codex --version 2>/dev/null || echo "unknown")
249
- ok "Codex CLI: $CODEX_VERSION"
250
- elif [[ "$SKIP_PREREQS" == "1" ]]; then
251
- CLI_PROVIDER="claude"
252
- warn "No AI CLI found (skipped — SPECRAILS_SKIP_PREREQS=1)"
253
- else
254
- fail "No AI CLI found (claude or codex)."
255
- echo ""
256
- echo " Install Claude Code: https://claude.ai/download"
257
- echo " Install Codex: https://github.com/openai/codex"
258
- exit 1
259
395
  fi
260
396
 
261
397
  # Derive output directory and instruction file from provider
@@ -269,12 +405,24 @@ fi
269
405
 
270
406
  # 1.2b Agent Teams opt-in (Claude Code only)
271
407
  if [[ "$CLI_PROVIDER" == "claude" ]]; then
272
- echo ""
273
- if [ "$AUTO_YES" = true ]; then
408
+ if [[ "$FROM_CONFIG" == true || "$AGENT_TEAMS" == true ]]; then
409
+ # Already resolved from config or --agent-teams flag
410
+ if [[ "$AGENT_TEAMS" == true ]]; then
411
+ ok "Agent Teams commands: enabled (from install-config.yaml)"
412
+ echo ""
413
+ info "Remember to set the feature flag before using these commands:"
414
+ echo ""
415
+ echo " export CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1"
416
+ echo ""
417
+ else
418
+ info "Agent Teams commands: skipped (from install-config.yaml)"
419
+ fi
420
+ elif [ "$AUTO_YES" = true ]; then
274
421
  # --yes flag: default to NOT installing (opt-in, not opt-out)
275
422
  AGENT_TEAMS=false
276
423
  info "Agent Teams commands: skipped (opt-in, use interactive mode to enable)"
277
424
  else
425
+ echo ""
278
426
  echo -e " ${BOLD}Agent Teams commands are available (experimental):${NC}"
279
427
  echo " /specrails:team-review — Multi-perspective code review with AI reviewers"
280
428
  echo " /specrails:team-debug — Collaborative debugging with competing hypotheses"
@@ -433,8 +581,8 @@ if command -v jira &> /dev/null; then
433
581
  HAS_JIRA=true
434
582
  else
435
583
  HAS_JIRA=false
436
- # Don't warn here — JIRA is only relevant if chosen during /specrails:setup.
437
- # If the user selects JIRA in /specrails:setup and it's not installed, the setup
584
+ # Don't warn here — JIRA is only relevant if chosen during /specrails:enrich.
585
+ # If the user selects JIRA in /specrails:enrich and it's not installed, the enrich
438
586
  # wizard will offer to install it (go-jira via brew/go, or Atlassian CLI).
439
587
  fi
440
588
 
@@ -488,7 +636,7 @@ step "Phase 3: Installing specrails artifacts"
488
636
  mkdir -p "$REPO_ROOT/specrails"
489
637
  if [[ "$CLI_PROVIDER" == "codex" ]]; then
490
638
  # Codex: install as Agent Skills (Codex doesn't support .codex/commands/)
491
- mkdir -p "$REPO_ROOT/.agents/skills/setup"
639
+ mkdir -p "$REPO_ROOT/.agents/skills/enrich"
492
640
  mkdir -p "$REPO_ROOT/.agents/skills/doctor"
493
641
  else
494
642
  mkdir -p "$REPO_ROOT/$SPECRAILS_DIR/commands/specrails"
@@ -503,13 +651,13 @@ mkdir -p "$REPO_ROOT/.specrails/setup-templates/settings"
503
651
  mkdir -p "$REPO_ROOT/.specrails/setup-templates/prompts"
504
652
  mkdir -p "$REPO_ROOT/$SPECRAILS_DIR/agent-memory/explanations"
505
653
 
506
- # Copy the /specrails:setup and /specrails:doctor commands (or skills for Codex)
654
+ # Copy the /specrails:enrich and /specrails:doctor commands (or skills for Codex)
507
655
  if [[ "$CLI_PROVIDER" == "codex" ]]; then
508
656
  # Codex uses Agent Skills in .agents/skills/<name>/SKILL.md
509
657
  {
510
658
  echo '---'
511
- echo 'name: setup'
512
- echo 'description: "Interactive wizard to configure the full specrails agent workflow system for this repository."'
659
+ echo 'name: enrich'
660
+ echo 'description: "Interactive wizard to configure the full specrails agent workflow system for this repository. Supports config-driven mode for direct installation from a pre-built config file."'
513
661
  echo 'license: MIT'
514
662
  echo 'compatibility: "Requires npm, git."'
515
663
  echo 'metadata:'
@@ -517,9 +665,9 @@ if [[ "$CLI_PROVIDER" == "codex" ]]; then
517
665
  echo ' version: "1.0"'
518
666
  echo '---'
519
667
  echo ''
520
- cat "$SCRIPT_DIR/commands/setup.md"
521
- } > "$REPO_ROOT/.agents/skills/setup/SKILL.md"
522
- ok "Installed \$setup skill"
668
+ cat "$SCRIPT_DIR/commands/enrich.md"
669
+ } > "$REPO_ROOT/.agents/skills/enrich/SKILL.md"
670
+ ok "Installed \$enrich skill"
523
671
 
524
672
  {
525
673
  echo '---'
@@ -537,8 +685,8 @@ if [[ "$CLI_PROVIDER" == "codex" ]]; then
537
685
  ok "Installed \$doctor skill"
538
686
  else
539
687
  # Claude Code uses commands in .claude/commands/specrails/ (namespaced as /specrails:*)
540
- cp "$SCRIPT_DIR/commands/setup.md" "$REPO_ROOT/$SPECRAILS_DIR/commands/specrails/setup.md"
541
- ok "Installed /specrails:setup command"
688
+ cp "$SCRIPT_DIR/commands/enrich.md" "$REPO_ROOT/$SPECRAILS_DIR/commands/specrails/enrich.md"
689
+ ok "Installed /specrails:enrich command"
542
690
 
543
691
  cp "$SCRIPT_DIR/commands/doctor.md" "$REPO_ROOT/$SPECRAILS_DIR/commands/specrails/doctor.md"
544
692
  ok "Installed /specrails:doctor command"
@@ -550,13 +698,130 @@ cp "$SCRIPT_DIR/bin/doctor.sh" "$REPO_ROOT/.specrails/bin/doctor.sh"
550
698
  chmod +x "$REPO_ROOT/.specrails/bin/doctor.sh"
551
699
  ok "Installed specrails doctor (bin/doctor.sh)"
552
700
 
701
+ # Write install-config.yaml: copy from --from-config source if provided,
702
+ # otherwise write defaults. Ensures a config file always exists after install
703
+ # so /specrails:enrich --from-config works regardless of how the installer was invoked.
704
+ _install_config="${REPO_ROOT}/.specrails/install-config.yaml"
705
+ if [[ "$FROM_CONFIG" == true && -n "$CONFIG_PATH" && -f "$CONFIG_PATH" && "$CONFIG_PATH" != "$_install_config" ]]; then
706
+ cp "$CONFIG_PATH" "$_install_config"
707
+ ok "Copied install-config.yaml from ${CONFIG_PATH}"
708
+ elif [[ ! -f "$_install_config" ]]; then
709
+ _ic_provider="${CLI_PROVIDER:-claude}"
710
+ _ic_tier="${TIER:-full}"
711
+ _ic_agent_teams="${AGENT_TEAMS:-false}"
712
+ cat > "$_install_config" << YAML
713
+ # specrails install config — generated during install (defaults)
714
+ # Re-run: npx specrails-core@latest init to regenerate with TUI
715
+ version: 1
716
+ provider: ${_ic_provider}
717
+ tier: ${_ic_tier}
718
+ agents:
719
+ selected: [sr-architect, sr-developer, sr-reviewer, sr-test-writer, sr-product-manager]
720
+ excluded: [sr-frontend-developer, sr-backend-developer, sr-frontend-reviewer, sr-backend-reviewer, sr-security-reviewer, sr-performance-reviewer, sr-product-analyst, sr-doc-sync, sr-merge-resolver]
721
+ models:
722
+ preset: balanced
723
+ defaults: { model: sonnet }
724
+ overrides: {}
725
+ quick_context:
726
+ product_description: ""
727
+ target_users: ""
728
+ agent_teams: ${_ic_agent_teams}
729
+ YAML
730
+ ok "Written .specrails/install-config.yaml (defaults)"
731
+ fi
732
+
553
733
  # Copy templates (includes commands, skills, agents, rules, personas, settings)
554
734
  # Use tar to exclude node_modules and package-lock.json for performance
555
735
  tar -C "$SCRIPT_DIR/templates" --exclude='node_modules' --exclude='package-lock.json' -cf - . \
556
736
  | tar -C "$REPO_ROOT/.specrails/setup-templates/" -xf -
557
737
  ok "Installed setup templates (commands + skills)"
558
738
 
559
- # Write OSS detection results for /specrails:setup
739
+ # Filter agent templates to only those listed in agents.selected (when --from-config is active).
740
+ # This allows hub or the TUI to pre-select a subset of agents before enrichment.
741
+ if [[ "$FROM_CONFIG" == true ]]; then
742
+ _cfg_to_read="${CONFIG_PATH:-${REPO_ROOT}/.specrails/install-config.yaml}"
743
+ if [[ -f "$_cfg_to_read" ]]; then
744
+ # Parse selected agents from inline YAML list: selected: [sr-architect, sr-developer, ...]
745
+ _selected_raw=$(grep '^ selected:' "$_cfg_to_read" | sed 's/.*\[//;s/\].*//;s/,/ /g' || true)
746
+ if [[ -n "$_selected_raw" ]]; then
747
+ _agents_dir="${REPO_ROOT}/.specrails/setup-templates/agents"
748
+ _removed=0
749
+ for _agent_file in "$_agents_dir/"*.md; do
750
+ [[ -f "$_agent_file" ]] || continue
751
+ _agent_name="$(basename "$_agent_file" .md)"
752
+ _in_selected=false
753
+ for _sel in $_selected_raw; do
754
+ # Strip whitespace/commas from parsed token
755
+ _sel="${_sel//,/}"
756
+ _sel="${_sel// /}"
757
+ if [[ "$_sel" == "$_agent_name" ]]; then
758
+ _in_selected=true
759
+ break
760
+ fi
761
+ done
762
+ if [[ "$_in_selected" == false ]]; then
763
+ rm -f "$_agent_file"
764
+ (( _removed++ )) || true
765
+ fi
766
+ done
767
+ if (( _removed > 0 )); then
768
+ ok "Agent templates filtered: removed ${_removed} excluded agent(s)"
769
+ fi
770
+ fi
771
+
772
+ # Apply defaults.model to all agent templates when present.
773
+ # Handles both inline "defaults: { model: haiku }" and block "defaults:\n model: haiku"
774
+ _cfg_default_model=""
775
+ _defaults_line=$(grep '^\s*defaults:' "$_cfg_to_read" 2>/dev/null | head -1 || true)
776
+ if echo "$_defaults_line" | grep -q 'model:' 2>/dev/null; then
777
+ _cfg_default_model=$(echo "$_defaults_line" | sed 's/.*model:[[:space:]]*//' | awk '{print $1}' | tr -d '}[:space:]')
778
+ else
779
+ _cfg_default_model=$(sed -n '/^\s*defaults:/,/^\s*[a-z]/{ /^\s*model:/p; }' "$_cfg_to_read" 2>/dev/null | awk '{print $2}' | tr -d '[:space:]' || true)
780
+ fi
781
+ if [[ -n "$_cfg_default_model" ]]; then
782
+ for _agent_file in "$_agents_dir/"*.md; do
783
+ [[ -f "$_agent_file" ]] || continue
784
+ sed -i.bak "s/^model: .*/model: ${_cfg_default_model}/" "$_agent_file" && rm -f "${_agent_file}.bak"
785
+ done
786
+ fi
787
+
788
+ # Apply model overrides to agent frontmatter when present.
789
+ # Overrides YAML format: " overrides:\n sr-architect: opus"
790
+ _in_overrides=false
791
+ while IFS= read -r _line; do
792
+ if [[ "$_line" =~ ^[[:space:]]*overrides: ]]; then
793
+ # Check if overrides are on same line: overrides: { sr-architect: opus }
794
+ if [[ "$_line" =~ \{.*\} ]]; then
795
+ _inline=$(echo "$_line" | sed 's/.*{//;s/}.*//;s/,/ /g')
796
+ for _pair in $_inline; do
797
+ _key="${_pair%%:*}"
798
+ _val="${_pair##*:}"
799
+ _agent_file="${REPO_ROOT}/.specrails/setup-templates/agents/${_key}.md"
800
+ if [[ -f "$_agent_file" ]]; then
801
+ sed -i.bak "s/^model: .*/model: ${_val}/" "$_agent_file" && rm -f "${_agent_file}.bak"
802
+ fi
803
+ done
804
+ _in_overrides=false
805
+ else
806
+ _in_overrides=true
807
+ fi
808
+ elif [[ "$_in_overrides" == true ]]; then
809
+ if [[ "$_line" =~ ^[[:space:]]{4}([a-z0-9_-]+):[[:space:]]*([a-z]+) ]]; then
810
+ _key="${BASH_REMATCH[1]}"
811
+ _val="${BASH_REMATCH[2]}"
812
+ _agent_file="${REPO_ROOT}/.specrails/setup-templates/agents/${_key}.md"
813
+ if [[ -f "$_agent_file" ]]; then
814
+ sed -i.bak "s/^model: .*/model: ${_val}/" "$_agent_file" && rm -f "${_agent_file}.bak"
815
+ fi
816
+ elif [[ ! "$_line" =~ ^[[:space:]]{4} ]]; then
817
+ _in_overrides=false
818
+ fi
819
+ fi
820
+ done < "$_cfg_to_read"
821
+ fi
822
+ fi
823
+
824
+ # Write OSS detection results for /specrails:enrich
560
825
  cat > "$REPO_ROOT/.specrails/setup-templates/.oss-detection.json" << EOF
561
826
  {
562
827
  "is_oss": $IS_OSS,
@@ -569,7 +834,7 @@ cat > "$REPO_ROOT/.specrails/setup-templates/.oss-detection.json" << EOF
569
834
  EOF
570
835
  ok "OSS detection results written"
571
836
 
572
- # Write provider detection results for /setup
837
+ # Write provider detection results for /specrails:enrich
573
838
  cat > "$REPO_ROOT/.specrails/setup-templates/.provider-detection.json" << EOF
574
839
  {
575
840
  "cli_provider": "$CLI_PROVIDER",
@@ -629,12 +894,12 @@ fi
629
894
  echo ""
630
895
  echo " Files installed:"
631
896
  if [[ "$CLI_PROVIDER" == "codex" ]]; then
632
- echo " .agents/skills/setup/SKILL.md ← The \$setup skill"
897
+ echo " .agents/skills/enrich/SKILL.md ← The \$enrich skill"
633
898
  echo " .agents/skills/doctor/SKILL.md ← The \$doctor skill"
634
899
  else
635
- echo " $SPECRAILS_DIR/commands/specrails/setup.md ← The /specrails:setup command"
900
+ echo " $SPECRAILS_DIR/commands/specrails/enrich.md ← The /specrails:enrich command"
636
901
  fi
637
- echo " .specrails/setup-templates/ ← Templates: commands + skills (temporary, removed after setup)"
902
+ echo " .specrails/setup-templates/ ← Templates: commands + skills (temporary, removed after enrich)"
638
903
  echo " .specrails/specrails-version ← Installed specrails version"
639
904
  echo " .specrails/specrails-manifest.json ← Artifact checksums for update detection"
640
905
  echo ""
@@ -653,12 +918,12 @@ echo " 1. Open $CLI_PROVIDER in this repo:"
653
918
  echo ""
654
919
  echo -e " ${BOLD}cd $REPO_ROOT && $CLI_PROVIDER${NC}"
655
920
  echo ""
656
- echo " 2. Run the setup wizard:"
921
+ echo " 2. Run the enrich wizard:"
657
922
  echo ""
658
923
  if [[ "$CLI_PROVIDER" == "codex" ]]; then
659
- echo -e " ${BOLD}\$setup${NC}"
924
+ echo -e " ${BOLD}\$enrich${NC}"
660
925
  else
661
- echo -e " ${BOLD}/specrails:setup${NC}"
926
+ echo -e " ${BOLD}/specrails:enrich${NC}"
662
927
  fi
663
928
  echo ""
664
929
  if [[ "$CLI_PROVIDER" == "codex" ]]; then
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "specrails-core",
3
- "version": "3.5.3",
3
+ "version": "3.7.0",
4
4
  "description": "AI agent workflow system for Claude Code — installs 12 specialized agents, orchestration commands, and persona-driven product discovery into any repository",
5
5
  "bin": {
6
6
  "specrails-core": "bin/specrails-core.js"
@@ -14,8 +14,7 @@
14
14
  ".claude/skills/",
15
15
  "commands/",
16
16
  "docs/",
17
- "VERSION",
18
- "integration-contract.json"
17
+ "VERSION"
19
18
  ],
20
19
  "engines": {
21
20
  "node": ">=18.0.0"
@@ -54,6 +53,9 @@
54
53
  "test": "bash tests/run-all.sh",
55
54
  "test:coverage": "bash tests/run-coverage.sh"
56
55
  },
56
+ "dependencies": {
57
+ "@inquirer/prompts": "^7.0.0"
58
+ },
57
59
  "license": "MIT",
58
60
  "author": "fjpulidop"
59
61
  }