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/README.md +11 -11
- package/bin/specrails-core.js +106 -13
- package/bin/tui-installer.mjs +309 -0
- package/commands/enrich.md +1565 -0
- package/docs/README.md +1 -1
- package/docs/changelog.md +17 -0
- package/docs/customization.md +37 -7
- package/docs/getting-started.md +5 -5
- package/docs/installation.md +61 -15
- package/docs/migration-guide.md +3 -3
- package/docs/plugin-architecture.md +13 -11
- package/docs/user-docs/faq.md +11 -11
- package/docs/user-docs/getting-started-codex.md +6 -6
- package/docs/user-docs/installation.md +9 -7
- package/docs/user-docs/quick-start.md +5 -3
- package/install.sh +328 -63
- package/package.json +5 -3
- package/templates/commands/specrails/enrich.md +1637 -0
- package/templates/commands/specrails/reconfig.md +89 -0
- package/templates/commands/specrails/setup.md +75 -3
- package/templates/settings/integration-contract.json +88 -0
- package/update.sh +20 -14
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:
|
|
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/
|
|
166
|
-
local
|
|
167
|
-
|
|
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/
|
|
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
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
info "
|
|
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 "
|
|
230
|
-
|
|
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
|
-
|
|
273
|
-
|
|
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:
|
|
437
|
-
# If the user selects JIRA in /specrails:
|
|
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/
|
|
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:
|
|
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:
|
|
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/
|
|
521
|
-
} > "$REPO_ROOT/.agents/skills/
|
|
522
|
-
ok "Installed \$
|
|
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/
|
|
541
|
-
ok "Installed /specrails:
|
|
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
|
-
#
|
|
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 /
|
|
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/
|
|
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/
|
|
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
|
|
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
|
|
921
|
+
echo " 2. Run the enrich wizard:"
|
|
657
922
|
echo ""
|
|
658
923
|
if [[ "$CLI_PROVIDER" == "codex" ]]; then
|
|
659
|
-
echo -e " ${BOLD}\$
|
|
924
|
+
echo -e " ${BOLD}\$enrich${NC}"
|
|
660
925
|
else
|
|
661
|
-
echo -e " ${BOLD}/specrails:
|
|
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.
|
|
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
|
}
|