specrails-core 3.8.1 → 4.0.1

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.
@@ -10,11 +10,20 @@ const COMMANDS = {
10
10
  doctor: "bin/doctor.sh",
11
11
  "perf-check": "bin/perf-check.sh",
12
12
  enrich: null,
13
+ version: null,
13
14
  };
14
15
 
15
16
  const args = process.argv.slice(2);
16
17
  const subcommand = args[0];
17
18
 
19
+ // ─── Global --version / -V flag ──────────────────────────────────────────────
20
+
21
+ if (args.includes("--version") || args.includes("-V")) {
22
+ const pkg = require(resolve(ROOT, "package.json"));
23
+ console.log(`specrails-core v${pkg.version}`);
24
+ process.exit(0);
25
+ }
26
+
18
27
  if (!subcommand) {
19
28
  console.log(`specrails-core — Agent Workflow System for Claude Code
20
29
 
@@ -24,6 +33,7 @@ Usage:
24
33
  specrails-core doctor Run health checks
25
34
  specrails-core perf-check [--files <list>] Performance regression check (CI)
26
35
  specrails-core enrich [--from-config <path>] Run /specrails:enrich via Claude CLI
36
+ specrails-core version Show installed version
27
37
 
28
38
  Flags for init:
29
39
  --root-dir <path> Target repository path (default: current directory)
@@ -32,13 +42,16 @@ Flags for init:
32
42
  --no-direct Skip TUI; use the legacy interactive bash installer
33
43
  --from-config Skip TUI; use existing .specrails/install-config.yaml
34
44
 
45
+ Global flags:
46
+ --version | -V Show installed version
47
+
35
48
  More info: https://github.com/fjpulidop/specrails-core`);
36
49
  process.exit(0);
37
50
  }
38
51
 
39
52
  if (!(subcommand in COMMANDS)) {
40
53
  console.error(`Unknown command: ${subcommand}\n`);
41
- console.error("Available commands: init, update, doctor, perf-check, enrich");
54
+ console.error("Available commands: init, update, doctor, perf-check, enrich, version");
42
55
  process.exit(1);
43
56
  }
44
57
 
@@ -51,6 +64,7 @@ const ALLOWED_FLAGS = {
51
64
  doctor: [],
52
65
  "perf-check": ["--files", "--context"],
53
66
  enrich: ["--from-config", "--quick"],
67
+ version: [],
54
68
  };
55
69
 
56
70
  const subargs = args.slice(1);
@@ -63,6 +77,14 @@ for (const arg of subargs) {
63
77
  }
64
78
  }
65
79
 
80
+ // ─── version subcommand ──────────────────────────────────────────────────────
81
+
82
+ if (subcommand === "version") {
83
+ const pkg = require(resolve(ROOT, "package.json"));
84
+ console.log(`specrails-core v${pkg.version}`);
85
+ process.exit(0);
86
+ }
87
+
66
88
  // ─── enrich subcommand ───────────────────────────────────────────────────────
67
89
  // Launches `claude --command "/specrails:enrich [flags]"` so the AI-powered
68
90
  // enrichment runs inside Claude Code with full model access.
@@ -9,11 +9,26 @@
9
9
  * --yes - skip TUI, write defaults immediately
10
10
  */
11
11
 
12
- import { checkbox, select, input, Separator } from '@inquirer/prompts';
12
+ import { checkbox, select, Separator } from '@inquirer/prompts';
13
13
  import { writeFileSync, mkdirSync, existsSync } from 'node:fs';
14
14
  import { execSync } from 'node:child_process';
15
15
  import { resolve } from 'node:path';
16
16
 
17
+ // ─── Alternate screen buffer (fullscreen mode) ──────────────────────────────
18
+
19
+ function enterFullscreen() {
20
+ process.stdout.write('\x1b[?1049h'); // switch to alternate screen buffer
21
+ process.stdout.write('\x1b[H'); // move cursor to top-left
22
+ }
23
+
24
+ function exitFullscreen() {
25
+ process.stdout.write('\x1b[?1049l'); // restore original screen buffer
26
+ }
27
+
28
+ function clearScreen() {
29
+ process.stdout.write('\x1b[2J\x1b[H'); // clear screen + cursor to top
30
+ }
31
+
17
32
  // ─── Agent registry ───────────────────────────────────────────────────────────
18
33
 
19
34
  const AGENTS = [
@@ -40,10 +55,17 @@ const AGENTS = [
40
55
 
41
56
  const ALL_AGENT_IDS = AGENTS.map(a => a.id);
42
57
 
43
- const DEFAULT_SELECTED = new Set([
58
+ // Core agents are always installed and cannot be deselected.
59
+ // The implementation pipeline (implement / batch-implement) depends on them.
60
+ const CORE_AGENTS = new Set([
44
61
  'sr-architect',
45
62
  'sr-developer',
46
63
  'sr-reviewer',
64
+ 'sr-merge-resolver',
65
+ ]);
66
+
67
+ const DEFAULT_SELECTED = new Set([
68
+ ...CORE_AGENTS,
47
69
  'sr-test-writer',
48
70
  'sr-product-manager',
49
71
  ]);
@@ -97,10 +119,12 @@ function buildCheckboxChoices() {
97
119
  choices.push(new Separator(`── ${agent.category} ${'─'.repeat(Math.max(0, 46 - agent.category.length))}`));
98
120
  currentCategory = agent.category;
99
121
  }
122
+ const isCore = CORE_AGENTS.has(agent.id);
100
123
  choices.push({
101
124
  value: agent.id,
102
- name: `${agent.id.padEnd(28)} ${agent.description}`,
125
+ name: `${agent.id.padEnd(28)} ${agent.description}${isCore ? ' (core)' : ''}`,
103
126
  checked: DEFAULT_SELECTED.has(agent.id),
127
+ disabled: isCore ? 'core — always installed' : false,
104
128
  });
105
129
  }
106
130
  return choices;
@@ -127,9 +151,6 @@ function writeInstallConfig(specrailsDir, cfg) {
127
151
  ` preset: ${cfg.modelPreset}`,
128
152
  ` defaults: { model: ${cfg.modelDefaults} }`,
129
153
  ` overrides:${overridesYaml}`,
130
- `quick_context:`,
131
- ` product_description: "${cfg.productDescription.replace(/"/g, '\\"')}"`,
132
- ` target_users: "${cfg.targetUsers.replace(/"/g, '\\"')}"`,
133
154
  `agent_teams: ${cfg.agentTeams}`,
134
155
  '',
135
156
  ].join('\n');
@@ -148,8 +169,6 @@ function writeDefaultConfig(specrailsDir, provider) {
148
169
  modelPreset: 'balanced',
149
170
  modelDefaults: 'sonnet',
150
171
  modelOverrides: {},
151
- productDescription: '',
152
- targetUsers: '',
153
172
  agentTeams: false,
154
173
  });
155
174
  }
@@ -165,12 +184,7 @@ async function run() {
165
184
 
166
185
  const specrailsDir = resolve(rootDir, '.specrails');
167
186
 
168
- console.log('\n╔══════════════════════════════════════════════╗');
169
- console.log('║ specrails — Direct Install (v1) ║');
170
- console.log('║ Configure your AI agent workflow system ║');
171
- console.log('╚══════════════════════════════════════════════╝\n');
172
-
173
- // Auto-yes: write defaults and exit
187
+ // Auto-yes: write defaults and exit (no TUI needed)
174
188
  if (autoYes) {
175
189
  const { hasClaude, hasCodex } = detectProvider();
176
190
  const provider = hasCodex && !hasClaude ? 'codex' : 'claude';
@@ -180,6 +194,28 @@ async function run() {
180
194
  return;
181
195
  }
182
196
 
197
+ // ── Enter fullscreen ────────────────────────────────────────────────────────
198
+
199
+ enterFullscreen();
200
+
201
+ // Ensure we exit fullscreen on any exit path
202
+ const _exitFs = () => exitFullscreen();
203
+ process.on('exit', _exitFs);
204
+
205
+ const cols = process.stdout.columns || 80;
206
+ const banner = [
207
+ '',
208
+ '╔══════════════════════════════════════════════════════════════╗',
209
+ '║ specrails — Agent Workflow Installer ║',
210
+ '║ Configure your AI agent workflow system ║',
211
+ '╚══════════════════════════════════════════════════════════════╝',
212
+ '',
213
+ ` Target: ${rootDir}`,
214
+ ` ${'─'.repeat(Math.min(cols - 4, 60))}`,
215
+ '',
216
+ ];
217
+ console.log(banner.join('\n'));
218
+
183
219
  // ── Step 1: Provider ────────────────────────────────────────────────────────
184
220
 
185
221
  const { hasClaude, hasCodex } = detectProvider();
@@ -207,36 +243,52 @@ async function run() {
207
243
 
208
244
  // ── Step 2: Installation tier ───────────────────────────────────────────────
209
245
 
246
+ clearScreen();
247
+ console.log(` Provider: ${provider}\n`);
248
+
210
249
  const tier = await select({
211
250
  message: 'Installation tier:',
251
+ default: 'quick',
212
252
  choices: [
213
- {
214
- value: 'full',
215
- name: 'Full — AI-powered setup (recommended)',
216
- description: 'After install, run /specrails:enrich to AI-customize all agents for your codebase',
217
- },
218
253
  {
219
254
  value: 'quick',
220
- name: 'Quick — Template-only install',
255
+ name: 'Quick — Ready to use immediately (recommended)',
221
256
  description: 'Agents installed with sensible defaults. No AI step required.',
222
257
  },
258
+ {
259
+ value: 'full',
260
+ name: 'Full — AI-powered setup',
261
+ description: 'After install, run /specrails:enrich to AI-customize all agents for your codebase',
262
+ },
223
263
  ],
224
264
  });
225
265
 
226
266
  // ── Step 3: Agent selection ─────────────────────────────────────────────────
227
267
 
228
- console.log('\n Select agents to install. Space = toggle, a = all/none, Enter = confirm.\n');
268
+ clearScreen();
269
+ console.log(` Provider: ${provider} | Tier: ${tier}\n`);
270
+ console.log(' Select agents to install. Space = toggle, a = all/none, Enter = confirm.\n');
271
+
272
+ // Use most of the terminal height for agent list (reserve 6 lines for header/footer)
273
+ const termRows = process.stdout.rows || 24;
274
+ const agentPageSize = Math.max(10, termRows - 6);
229
275
 
230
- const selectedAgents = await checkbox({
276
+ const userSelected = await checkbox({
231
277
  message: 'Agents to install:',
232
278
  choices: buildCheckboxChoices(),
279
+ pageSize: agentPageSize,
233
280
  validate: (selected) => selected.length > 0 || 'Select at least one agent.',
234
281
  });
235
282
 
283
+ // Core agents are always included regardless of checkbox state
284
+ const selectedAgents = [...new Set([...CORE_AGENTS, ...userSelected])];
236
285
  const excludedAgents = ALL_AGENT_IDS.filter(id => !selectedAgents.includes(id));
237
286
 
238
287
  // ── Step 4: Model preset ────────────────────────────────────────────────────
239
288
 
289
+ clearScreen();
290
+ console.log(` Provider: ${provider} | Tier: ${tier} | Agents: ${selectedAgents.length}/${ALL_AGENT_IDS.length}\n`);
291
+
240
292
  const modelPreset = await select({
241
293
  message: 'Model configuration:',
242
294
  choices: Object.entries(MODEL_PRESETS).map(([key, val]) => ({
@@ -249,6 +301,9 @@ async function run() {
249
301
 
250
302
  // ── Step 5: Agent Teams (Claude only) ──────────────────────────────────────
251
303
 
304
+ clearScreen();
305
+ console.log(` Provider: ${provider} | Tier: ${tier} | Agents: ${selectedAgents.length} | Preset: ${modelPreset}\n`);
306
+
252
307
  let agentTeams = false;
253
308
  if (provider === 'claude') {
254
309
  agentTeams = await select({
@@ -260,21 +315,9 @@ async function run() {
260
315
  });
261
316
  }
262
317
 
263
- // ── Step 6: Quick context ───────────────────────────────────────────────────
264
-
265
- console.log('\n Quick context helps specrails personalize agents for your project.\n');
266
-
267
- const productDescription = await input({
268
- message: 'Product description (2–3 sentences):',
269
- validate: (v) => v.trim().length > 0 || 'Please enter a brief product description.',
270
- });
271
-
272
- const targetUsers = await input({
273
- message: 'Target users (who will use this product?):',
274
- validate: (v) => v.trim().length > 0 || 'Please describe your target users.',
275
- });
318
+ // ── Write config & exit fullscreen ──────────────────────────────────────────
276
319
 
277
- // ── Write config ────────────────────────────────────────────────────────────
320
+ exitFullscreen();
278
321
 
279
322
  writeInstallConfig(specrailsDir, {
280
323
  provider,
@@ -284,8 +327,6 @@ async function run() {
284
327
  modelPreset,
285
328
  modelDefaults,
286
329
  modelOverrides,
287
- productDescription: productDescription.trim(),
288
- targetUsers: targetUsers.trim(),
289
330
  agentTeams,
290
331
  });
291
332
 
@@ -299,6 +340,7 @@ async function run() {
299
340
  }
300
341
 
301
342
  run().catch(err => {
343
+ exitFullscreen();
302
344
  // Graceful Ctrl+C handling
303
345
  if (err.name === 'ExitPromptError' || (err.message && err.message.includes('User force closed'))) {
304
346
  console.error('\n Installation cancelled by user.\n');
@@ -52,8 +52,6 @@ Parse the YAML and extract:
52
52
  - `config.models.preset` — `balanced`, `budget`, or `max` (see Model Presets below)
53
53
  - `config.models.defaults.model` — default model override (overrides preset)
54
54
  - `config.models.overrides` — per-agent model overrides (highest priority)
55
- - `config.quick_context.product_description` — product description seed
56
- - `config.quick_context.target_users` — target users seed
57
55
  - `config.agent_teams` — boolean; whether to install team-review/team-debug commands
58
56
 
59
57
  Store all values in variables prefixed `FC_`.
@@ -78,21 +76,19 @@ Set `SPECRAILS_DIR` and `CLI_PROVIDER` from resolved provider.
78
76
  ### FC3: If tier is `quick` — run Quick Mode with config context
79
77
 
80
78
  If `FC_tier == "quick"`:
81
- - Set `QS_PROJECT_DESCRIPTION = FC_quick_context.product_description`
82
- - Set `QS_TARGET_USERS = FC_quick_context.target_users`
83
79
  - Set `FC_AGENTS_SELECTED` as the list of agents to generate (instead of defaults)
84
- - Execute Quick Mode (QS1–QS4) with these values injected, generating all `FC_AGENTS_SELECTED` agents (not just defaults)
80
+ - Execute Quick Mode (QS1–QS4), generating all `FC_AGENTS_SELECTED` agents (not just defaults)
85
81
  - Then stop.
86
82
 
87
83
  ### FC4: If tier is `full` — run automated full wizard
88
84
 
89
85
  **Phase 1 (Silent):** Run the full Phase 1 analysis (1.1–1.4) without any user prompts. Store all detected values internally.
90
86
 
91
- **Phase 2 (Seeded VPC Discovery):** Run VPC persona generation using `FC_quick_context` as seeds:
92
- - Treat `FC_quick_context.product_description` as the answer to "Describe your product"
93
- - Treat `FC_quick_context.target_users` as the answer to "Who are your users"
94
- - Use AI to expand these seeds into full VPC personas (3 primary, 3 secondary)
95
- - Do not ask the user any questions — infer all answers from seeds + codebase analysis
87
+ **Phase 2 (AI-Inferred VPC Discovery):** Run VPC persona generation from codebase analysis:
88
+ - Analyze the codebase (README, package.json, source code, configs) to infer what the product does and who it serves
89
+ - Generate `PROJECT_DESCRIPTION` (2–3 sentence summary) and `TARGET_USERS` from analysis
90
+ - Use these inferred values to generate full VPC personas (3 primary, 3 secondary)
91
+ - Do not ask the user any questions — infer everything from codebase analysis
96
92
 
97
93
  **Phase 3 (Silent):** Run Phase 3 normally without user prompts.
98
94
 
@@ -415,20 +411,26 @@ Update `.specrails/specrails-manifest.json` to reflect the new checksums for all
415
411
 
416
412
  When `--quick` or `--lite` is passed, run this streamlined 3-question setup. Do NOT run Phase 1–5. When QS4 is complete, stop.
417
413
 
418
- ### QS1: Ask the 3 questions
414
+ ### QS1: Infer context and ask git access
419
415
 
420
- Display the following prompt EXACTLY ONCE and then wait for the user's responses. Do NOT repeat the questions — output them a single time only.
416
+ **Step 1 AI inference (silent):** Analyze the codebase to infer:
417
+ - `QS_PROJECT_DESCRIPTION` — a 2–3 sentence summary of what this project does (from README, package.json, source code, configs)
418
+ - `QS_TARGET_USERS` — who the target users are (from docs, UI copy, API design, domain language)
421
419
 
422
- Welcome to specrails! Let's get your AI agent team set up in 3 quick questions.
420
+ **Step 2 Ask one question:**
423
421
 
424
- 1. What is this project? (one sentence)
425
- 2. Who are the target users?
426
- 3. Git access for agents read-only or read-write?
422
+ Display the following prompt EXACTLY ONCE:
423
+
424
+ Welcome to specrails! Let's get your AI agent team set up.
425
+
426
+ I've analyzed your codebase:
427
+ - **Project:** {QS_PROJECT_DESCRIPTION}
428
+ - **Target users:** {QS_TARGET_USERS}
429
+
430
+ 1. Git access for agents — read-only or read-write?
427
431
  (read-only = agents can read and suggest; read-write = agents can commit)
428
432
 
429
- Store the answers as:
430
- - `QS_PROJECT_DESCRIPTION` — answer to question 1
431
- - `QS_TARGET_USERS` — answer to question 2
433
+ Store the answer as:
432
434
  - `QS_GIT_ACCESS` — "read-only" or "read-write" (normalize if user types "ro", "rw", "readonly", etc.)
433
435
 
434
436
  ### QS2: Apply opinionated defaults
@@ -490,8 +492,6 @@ Read `.specrails/setup-templates/claude-md/CLAUDE-quickstart.md` (or fall back t
490
492
 
491
493
  Replace placeholders:
492
494
  - `{{PROJECT_NAME}}` → derive from directory name or README.md first heading
493
- - `{{PROJECT_DESCRIPTION}}` → `QS_PROJECT_DESCRIPTION`
494
- - `{{TARGET_USERS}}` → `QS_TARGET_USERS`
495
495
  - `{{GIT_ACCESS}}` → `QS_GIT_ACCESS`
496
496
 
497
497
  Write to `CLAUDE.md` in the repo root. If `CLAUDE.md` already exists, ask:
@@ -506,8 +506,6 @@ For each default agent (sr-architect, sr-developer, sr-reviewer, sr-product-mana
506
506
 
507
507
  Fill placeholders with best-effort values from the limited context available:
508
508
  - `{{PROJECT_NAME}}` → directory name or README first heading
509
- - `{{PROJECT_DESCRIPTION}}` → `QS_PROJECT_DESCRIPTION`
510
- - `{{TARGET_USERS}}` → `QS_TARGET_USERS`
511
509
  - `{{GIT_ACCESS}}` → `QS_GIT_ACCESS`
512
510
  - `{{ARCHITECTURE_DIAGRAM}}` → "(Quick Mode — run `/specrails:enrich` for full architecture analysis)"
513
511
  - `{{TECH_EXPERTISE}}` → "(Quick Mode — run `/specrails:enrich` for codebase-specific expertise)"
@@ -280,9 +280,6 @@ agents:
280
280
  models:
281
281
  preset: balanced # balanced | budget | max
282
282
  overrides: {} # per-agent overrides: { sr-architect: opus }
283
- quick_context:
284
- product_description: "" # product description seed
285
- target_users: "" # target users seed
286
283
  agent_teams: false # install team-review/team-debug commands
287
284
  ```
288
285