specrails-core 4.8.1 → 4.9.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.
Files changed (37) hide show
  1. package/bin/specrails-core.mjs +5 -1
  2. package/bin/tui-installer.mjs +87 -65
  3. package/dist/installer/cli.js +46 -6
  4. package/dist/installer/cli.js.map +1 -1
  5. package/dist/installer/commands/doctor.js +14 -5
  6. package/dist/installer/commands/doctor.js.map +1 -1
  7. package/dist/installer/commands/framework.js +134 -0
  8. package/dist/installer/commands/framework.js.map +1 -0
  9. package/dist/installer/commands/init.js +107 -32
  10. package/dist/installer/commands/init.js.map +1 -1
  11. package/dist/installer/commands/update.js +60 -34
  12. package/dist/installer/commands/update.js.map +1 -1
  13. package/dist/installer/phases/scaffold.js +592 -67
  14. package/dist/installer/phases/scaffold.js.map +1 -1
  15. package/dist/installer/util/fs.js +143 -1
  16. package/dist/installer/util/fs.js.map +1 -1
  17. package/dist/installer/util/registry.js +339 -0
  18. package/dist/installer/util/registry.js.map +1 -0
  19. package/package.json +1 -1
  20. package/pinned-versions.json +1 -1
  21. package/templates/agents/sr-architect.md +14 -10
  22. package/templates/agents/sr-backend-developer.md +4 -2
  23. package/templates/agents/sr-developer.md +20 -8
  24. package/templates/agents/sr-frontend-developer.md +4 -2
  25. package/templates/agents/sr-reviewer.md +10 -6
  26. package/templates/codex-skills/implement/SKILL.md +19 -10
  27. package/templates/codex-skills/rails/sr-architect/SKILL.md +17 -8
  28. package/templates/codex-skills/rails/sr-backend-developer/SKILL.md +4 -1
  29. package/templates/codex-skills/rails/sr-developer/SKILL.md +13 -4
  30. package/templates/codex-skills/rails/sr-doc-sync/SKILL.md +3 -2
  31. package/templates/codex-skills/rails/sr-frontend-developer/SKILL.md +4 -1
  32. package/templates/codex-skills/rails/sr-product-manager/SKILL.md +9 -7
  33. package/templates/codex-skills/rails/sr-reviewer/SKILL.md +13 -7
  34. package/templates/codex-skills/retry/SKILL.md +10 -5
  35. package/templates/commands/specrails/implement.md +41 -23
  36. package/templates/commands/specrails/retry.md +3 -1
  37. package/templates/gemini-commands/implement.toml +76 -21
@@ -50,6 +50,8 @@ const KNOWN_SUBCOMMANDS = new Set([
50
50
  'init',
51
51
  'update',
52
52
  'doctor',
53
+ 'install-framework',
54
+ 'assemble',
53
55
  'enrich',
54
56
  'version',
55
57
  'profile',
@@ -58,7 +60,9 @@ const KNOWN_SUBCOMMANDS = new Set([
58
60
 
59
61
  if (!KNOWN_SUBCOMMANDS.has(subcommand)) {
60
62
  console.error(`Unknown command: ${subcommand}\n`)
61
- console.error('Available commands: init, update, doctor, enrich, version, profile, help')
63
+ console.error(
64
+ 'Available commands: init, update, doctor, install-framework, assemble, enrich, version, profile, help',
65
+ )
62
66
  process.exit(1)
63
67
  }
64
68
 
@@ -72,7 +72,10 @@ const DEFAULT_SELECTED = new Set([
72
72
  ...CORE_AGENTS,
73
73
  ]);
74
74
 
75
- // ─── Model presets ────────────────────────────────────────────────────────────
75
+ // ─── Model presets (Claude only — see PROVIDER_DEFAULT_MODEL) ────────────────────
76
+ // Claude has real cost/quality tiers (sonnet/haiku/opus). Codex and gemini are
77
+ // single-model in the scaffold (it hardcodes the per-agent model and ignores the
78
+ // install-config preset), so these presets apply to Claude only.
76
79
 
77
80
  const MODEL_PRESETS = {
78
81
  balanced: {
@@ -92,30 +95,51 @@ const MODEL_PRESETS = {
92
95
  },
93
96
  };
94
97
 
98
+ // Per-provider default agent model. For codex/gemini the scaffold hardcodes this
99
+ // (the install-config model is advisory), so the TUI writes the provider's real
100
+ // model instead of a Claude-flavoured preset. Keep in sync with scaffold.ts
101
+ // (GEMINI_DEFAULT_MODEL / the codex config.toml model).
102
+ const PROVIDER_DEFAULT_MODEL = {
103
+ claude: 'sonnet',
104
+ codex: 'gpt-5.5-mini',
105
+ gemini: 'gemini-3.5-flash',
106
+ };
107
+
108
+ // ─── Provider registry ─────────────────────────────────────────────────────────
109
+ // Single source of truth for the AI CLIs the TUI can target. Add a provider here
110
+ // and it flows through detection, the --provider flag, and the interactive picker.
111
+ const PROVIDERS = [
112
+ { id: 'claude', label: 'Claude Code (recommended)', versionCmd: 'claude --version', installLabel: 'Claude Code', installUrl: 'https://claude.ai/download' },
113
+ { id: 'codex', label: 'Codex (OpenAI)', versionCmd: 'codex --version', installLabel: 'Codex CLI', installUrl: 'https://developers.openai.com/codex' },
114
+ { id: 'gemini', label: 'Gemini CLI (Google)', versionCmd: 'gemini --version', installLabel: 'Gemini CLI', installUrl: 'https://github.com/google-gemini/gemini-cli' },
115
+ ];
116
+ const VALID_PROVIDER_IDS = new Set(PROVIDERS.map(p => p.id));
117
+
95
118
  // ─── Helpers ──────────────────────────────────────────────────────────────────
96
119
 
97
- function detectProvider() {
98
- let hasClaude = false;
99
- let hasCodex = false;
100
- try { execSync('claude --version', { stdio: 'ignore' }); hasClaude = true; } catch { /* not installed */ }
101
- try { execSync('codex --version', { stdio: 'ignore' }); hasCodex = true; } catch { /* not installed */ }
102
- return { hasClaude, hasCodex };
120
+ // Returns the set of provider ids whose CLI responds to `<bin> --version`.
121
+ function detectInstalledProviders() {
122
+ const installed = new Set();
123
+ for (const p of PROVIDERS) {
124
+ try { execSync(p.versionCmd, { stdio: 'ignore' }); installed.add(p.id); } catch { /* not installed */ }
125
+ }
126
+ return installed;
103
127
  }
104
128
 
105
- // Parse `--provider <id>` or `--provider=<id>` from process.argv. Returns
106
- // 'claude' | 'codex' | null. Unknown values warn-then-null so the TUI
107
- // falls back to interactive selection.
129
+ // Parse `--provider <id>` or `--provider=<id>` from process.argv. Returns a valid
130
+ // provider id or null (unknown values warn-then-null so the TUI falls back to the
131
+ // interactive picker).
108
132
  function parseProviderArg() {
109
133
  const args = process.argv.slice(2);
110
134
  for (let i = 0; i < args.length; i++) {
111
135
  const a = args[i];
112
136
  if (a === '--provider' && args[i + 1]) {
113
137
  const v = args[i + 1].trim().toLowerCase();
114
- return v === 'claude' || v === 'codex' ? v : null;
138
+ return VALID_PROVIDER_IDS.has(v) ? v : null;
115
139
  }
116
140
  if (a.startsWith('--provider=')) {
117
141
  const v = a.slice('--provider='.length).trim().toLowerCase();
118
- return v === 'claude' || v === 'codex' ? v : null;
142
+ return VALID_PROVIDER_IDS.has(v) ? v : null;
119
143
  }
120
144
  }
121
145
  return null;
@@ -188,7 +212,7 @@ function writeDefaultConfig(specrailsDir, provider) {
188
212
  selectedAgents: defaultSelected,
189
213
  excludedAgents: defaultExcluded,
190
214
  modelPreset: 'balanced',
191
- modelDefaults: 'sonnet',
215
+ modelDefaults: PROVIDER_DEFAULT_MODEL[provider] ?? 'sonnet',
192
216
  modelOverrides: {},
193
217
  agentTeams: false,
194
218
  });
@@ -251,36 +275,29 @@ async function run() {
251
275
  // Honours an explicit --provider <id> argv flag when present; otherwise
252
276
  // picks claude → codex → first-detected. Errors only when none detected.
253
277
  if (autoYes) {
254
- const { hasClaude, hasCodex } = detectProvider();
278
+ const installed = detectInstalledProviders();
255
279
  const argvProvider = parseProviderArg();
256
280
  let provider;
257
281
  if (argvProvider) {
258
- if (argvProvider === 'claude' && !hasClaude) {
282
+ if (!installed.has(argvProvider)) {
283
+ const p = PROVIDERS.find(x => x.id === argvProvider);
259
284
  console.error('');
260
- console.error(' ⚠ --provider claude requested but Claude Code is not installed.');
261
- console.error(' Install: https://claude.ai/download');
285
+ console.error(` ⚠ --provider ${argvProvider} requested but ${p.installLabel} is not installed.`);
286
+ console.error(` Install: ${p.installUrl}`);
262
287
  console.error('');
263
288
  process.exit(1);
264
289
  }
265
- if (argvProvider === 'codex' && !hasCodex) {
290
+ provider = argvProvider;
291
+ } else {
292
+ // No flag: pick the first installed provider in registry order.
293
+ provider = PROVIDERS.find(p => installed.has(p.id))?.id;
294
+ if (!provider) {
266
295
  console.error('');
267
- console.error(' ⚠ --provider codex requested but Codex CLI is not installed.');
268
- console.error(' Install: https://developers.openai.com/codex');
296
+ console.error(' ⚠ No supported AI CLI detected on PATH (Claude Code, Codex, or Gemini CLI).');
297
+ for (const p of PROVIDERS) console.error(` Install ${p.installLabel}: ${p.installUrl}`);
269
298
  console.error('');
270
299
  process.exit(1);
271
300
  }
272
- provider = argvProvider;
273
- } else if (hasClaude) {
274
- provider = 'claude';
275
- } else if (hasCodex) {
276
- provider = 'codex';
277
- } else {
278
- console.error('');
279
- console.error(' ⚠ Neither Claude Code nor Codex CLI detected on PATH.');
280
- console.error(' Install Claude: https://claude.ai/download');
281
- console.error(' Install Codex: https://developers.openai.com/codex');
282
- console.error('');
283
- process.exit(1);
284
301
  }
285
302
  writeDefaultConfig(specrailsDir, provider);
286
303
  console.log(` ✓ Default config written to .specrails/install-config.yaml`);
@@ -312,40 +329,37 @@ async function run() {
312
329
 
313
330
  // ── Step 1: Provider ────────────────────────────────────────────────────────
314
331
 
315
- const { hasClaude, hasCodex } = detectProvider();
332
+ const installed = detectInstalledProviders();
316
333
  const argvProvider = parseProviderArg();
317
334
  let provider;
318
335
 
319
336
  if (argvProvider) {
320
- if (argvProvider === 'claude' && !hasClaude) {
321
- exitFullscreen();
322
- console.error('\n ⚠ --provider claude requested but Claude Code is not installed.\n Install: https://claude.ai/download\n');
323
- process.exit(1);
324
- }
325
- if (argvProvider === 'codex' && !hasCodex) {
337
+ if (!installed.has(argvProvider)) {
326
338
  exitFullscreen();
327
- console.error('\n ⚠ --provider codex requested but Codex CLI is not installed.\n Install: https://developers.openai.com/codex\n');
339
+ const p = PROVIDERS.find(x => x.id === argvProvider);
340
+ console.error(`\n ⚠ --provider ${argvProvider} requested but ${p.installLabel} is not installed.\n Install: ${p.installUrl}\n`);
328
341
  process.exit(1);
329
342
  }
330
343
  provider = argvProvider;
331
344
  console.log(` → Provider: ${provider} (from --provider flag)\n`);
332
- } else if (hasClaude && hasCodex) {
333
- provider = await select({
334
- message: 'Which AI provider will you use?',
335
- choices: [
336
- { value: 'claude', name: 'Claude Code (recommended)' },
337
- { value: 'codex', name: 'Codex (OpenAI)' },
338
- ],
339
- });
340
- } else if (hasCodex) {
341
- provider = 'codex';
342
- console.log(' → Provider: codex (auto-detected — Claude Code not found)\n');
343
- } else if (hasClaude) {
344
- provider = 'claude';
345
- console.log(' → Provider: claude (auto-detected)\n');
346
345
  } else {
347
- provider = 'claude';
348
- console.log(' → Provider: claude (default neither claude nor codex CLI found)\n');
346
+ const detected = PROVIDERS.filter(p => installed.has(p.id));
347
+ if (detected.length > 1) {
348
+ provider = await select({
349
+ message: 'Which AI provider will you use?',
350
+ choices: detected.map(p => ({ value: p.id, name: p.label })),
351
+ });
352
+ } else if (detected.length === 1) {
353
+ provider = detected[0].id;
354
+ console.log(` → Provider: ${provider} (auto-detected)\n`);
355
+ } else {
356
+ // None detected — still offer the full list (a CLI may work despite a
357
+ // failed --version probe, e.g. a PATH quirk).
358
+ provider = await select({
359
+ message: 'No AI CLI detected on PATH — which will you use?',
360
+ choices: PROVIDERS.map(p => ({ value: p.id, name: p.label })),
361
+ });
362
+ }
349
363
  }
350
364
 
351
365
  // ── Step 2: Installation tier ───────────────────────────────────────────────
@@ -397,15 +411,23 @@ async function run() {
397
411
  clearScreen();
398
412
  console.log(` Provider: ${provider} | Tier: ${tier} | Agents: ${selectedAgents.length}/${ALL_AGENT_IDS.length}\n`);
399
413
 
400
- const modelPreset = await select({
401
- message: 'Model configuration:',
402
- choices: Object.entries(MODEL_PRESETS).map(([key, val]) => ({
403
- value: key,
404
- name: `${key.padEnd(10)} ${val.label}`,
405
- })),
406
- });
407
-
408
- const { defaults: modelDefaults, overrides: modelOverrides } = MODEL_PRESETS[modelPreset];
414
+ // Claude exposes real model tiers; codex/gemini are single-model in the scaffold,
415
+ // so skip the (Claude-flavoured) preset picker for them and use the fixed model.
416
+ let modelPreset = 'balanced';
417
+ let modelDefaults = PROVIDER_DEFAULT_MODEL[provider] ?? 'sonnet';
418
+ let modelOverrides = {};
419
+ if (provider === 'claude') {
420
+ modelPreset = await select({
421
+ message: 'Model configuration:',
422
+ choices: Object.entries(MODEL_PRESETS).map(([key, val]) => ({
423
+ value: key,
424
+ name: `${key.padEnd(10)} ${val.label}`,
425
+ })),
426
+ });
427
+ ({ defaults: modelDefaults, overrides: modelOverrides } = MODEL_PRESETS[modelPreset]);
428
+ } else {
429
+ console.log(` → Model: ${modelDefaults} (${provider} uses one model for all agents)\n`);
430
+ }
409
431
 
410
432
  // ── Step 5: Agent Teams (Claude only) ──────────────────────────────────────
411
433
 
@@ -10,8 +10,9 @@
10
10
  */
11
11
  import { readFileSync } from 'node:fs';
12
12
  import path from 'node:path';
13
- import { fileURLToPath } from 'node:url';
13
+ import { fileURLToPath, pathToFileURL } from 'node:url';
14
14
  import { runDoctor } from './commands/doctor.js';
15
+ import { runAssemble, runInstallFramework, runSwapCurrent, } from './commands/framework.js';
15
16
  import { runInit } from './commands/init.js';
16
17
  import { runUpdate } from './commands/update.js';
17
18
  import { isInstallerError } from './util/errors.js';
@@ -78,11 +79,14 @@ function usageText() {
78
79
  ' specrails-core <command> [options]',
79
80
  '',
80
81
  'Commands:',
81
- ' init Install specrails into a repository',
82
- ' update Update an existing specrails installation',
83
- ' doctor Diagnose the health of an existing installation',
84
- ' help Show this help message',
85
- ' version Print the installed version',
82
+ ' init Install specrails into a repository',
83
+ ' update Update an existing specrails installation',
84
+ ' doctor Diagnose the health of an existing installation',
85
+ ' install-framework Materialize the versioned framework (offline)',
86
+ ' swap-current Point framework/current at a version (offline)',
87
+ ' assemble Symlink the framework into a workspace (offline)',
88
+ ' help Show this help message',
89
+ ' version Print the installed version',
86
90
  '',
87
91
  'Global options:',
88
92
  ' -h, --help Show this help',
@@ -126,6 +130,15 @@ async function dispatch(subcommand, flags, _positionals) {
126
130
  const result = await runDoctor(flags);
127
131
  return result.failed === 0 ? 0 : 1;
128
132
  }
133
+ case 'install-framework':
134
+ await runInstallFramework(flags);
135
+ return 0;
136
+ case 'swap-current':
137
+ await runSwapCurrent(flags);
138
+ return 0;
139
+ case 'assemble':
140
+ await runAssemble(flags);
141
+ return 0;
129
142
  case 'help':
130
143
  case '':
131
144
  process.stdout.write(usageText());
@@ -162,4 +175,31 @@ export async function main(argv = process.argv.slice(2)) {
162
175
  return 1;
163
176
  }
164
177
  }
178
+ /**
179
+ * Auto-run guard: when this module is executed DIRECTLY as a script
180
+ * (`node dist/installer/cli.js <subcommand>`), run `main()` and propagate its
181
+ * exit code. specrails-desktop's bundled-core path (server/framework-manager.ts)
182
+ * spawns `node <core>/dist/installer/cli.js install-framework|assemble …` and
183
+ * relies on this — the legacy bin dispatcher (bin/specrails-core.mjs) imports
184
+ * `main` and is unaffected (it never executes this file as argv[1]).
185
+ *
186
+ * Comparing `import.meta.url` against `process.argv[1]` keeps the guard inert on
187
+ * import (so unit tests that `import { main }` never trigger a process.exit).
188
+ */
189
+ const isDirectRun = (() => {
190
+ try {
191
+ const entry = process.argv[1];
192
+ if (!entry)
193
+ return false;
194
+ return import.meta.url === pathToFileURL(entry).href;
195
+ }
196
+ catch {
197
+ return false;
198
+ }
199
+ })();
200
+ if (isDirectRun) {
201
+ void main().then((code) => {
202
+ process.exitCode = code;
203
+ });
204
+ }
165
205
  //# sourceMappingURL=cli.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/installer/cli.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/installer/cli.ts"],"names":[],"mappings":"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"}
@@ -6,8 +6,17 @@ import { commandExists, runCommand } from '../util/exec.js';
6
6
  import { isDir, isFile, listDir, mkdirp } from '../util/fs.js';
7
7
  import { assertClaudeAuthenticated } from '../phases/provider-detect.js';
8
8
  import { derivedPaths } from '../phases/provider-detect.js';
9
+ import { resolveArtifacts } from '../util/registry.js';
9
10
  export async function runDoctor(flags = {}) {
10
11
  const projectRoot = path.resolve(typeof flags['root-dir'] === 'string' ? flags['root-dir'] : process.cwd());
12
+ // Relocate-always: Specrails artifacts (provider dir, agent files, instructions
13
+ // file) live under `artifactRoot`. Git stays in the repo (codeRoot). Readers
14
+ // pass allocate:false → falls back to the in-repo legacy layout when there is
15
+ // no registry entry (so a never-installed / legacy repo still reports cleanly).
16
+ const { artifactRoot, codeRoot } = resolveArtifacts(projectRoot, {
17
+ allocate: false,
18
+ home: process.env.SPECRAILS_REGISTRY_HOME,
19
+ });
11
20
  rawOut('\nspecrails doctor\n\n');
12
21
  const results = [];
13
22
  const addPass = (message) => {
@@ -16,7 +25,7 @@ export async function runDoctor(flags = {}) {
16
25
  const addFail = (message, fix) => {
17
26
  results.push({ kind: 'fail', message, fix });
18
27
  };
19
- const provider = resolveInstalledProvider(projectRoot);
28
+ const provider = resolveInstalledProvider(artifactRoot);
20
29
  const { providerDir, instructionsFile } = derivedPaths(provider);
21
30
  // Check 1: Claude Code CLI
22
31
  if (await commandExists('claude')) {
@@ -37,7 +46,7 @@ export async function runDoctor(flags = {}) {
37
46
  }
38
47
  }
39
48
  // Check 3: Agent files present in the active provider directory.
40
- const agentsDir = path.join(projectRoot, providerDir, 'agents');
49
+ const agentsDir = path.join(artifactRoot, providerDir, 'agents');
41
50
  if (isDir(agentsDir)) {
42
51
  const agentFiles = findInstalledAgentFiles(agentsDir, provider);
43
52
  if (agentFiles.length >= 1) {
@@ -54,7 +63,7 @@ export async function runDoctor(flags = {}) {
54
63
  addFail(`Agent files: ${providerDir}/agents directory not found`, 'Run specrails-core init to set up agents');
55
64
  }
56
65
  // Check 4: provider instructions file present
57
- if (isFile(path.join(projectRoot, instructionsFile))) {
66
+ if (isFile(path.join(artifactRoot, instructionsFile))) {
58
67
  addPass(`${instructionsFile}: present`);
59
68
  }
60
69
  else {
@@ -62,8 +71,8 @@ export async function runDoctor(flags = {}) {
62
71
  ? 'Run specrails-core init to regenerate the provider instructions.'
63
72
  : 'Run /specrails:enrich inside Claude Code to regenerate.');
64
73
  }
65
- // Check 5: Git initialized
66
- if (isDir(path.join(projectRoot, '.git'))) {
74
+ // Check 5: Git initialized (in the repo — codeRoot, not the artifact root)
75
+ if (isDir(path.join(codeRoot, '.git'))) {
67
76
  addPass('Git: initialized');
68
77
  }
69
78
  else {
@@ -1 +1 @@
1
- {"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../../src/installer/commands/doctor.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../../src/installer/commands/doctor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,134 @@
1
+ import path from 'node:path';
2
+ import { fileURLToPath } from 'node:url';
3
+ import { InstallerError } from '../util/errors.js';
4
+ import { ok, step } from '../util/logger.js';
5
+ import { pathExists, readTextFile } from '../util/fs.js';
6
+ import { derivedPaths } from '../phases/provider-detect.js';
7
+ import { assembleProjectWorkspace, ensureCurrentSymlink } from '../phases/scaffold.js';
8
+ import { ensureFramework } from './init.js';
9
+ function requireString(value, flagName) {
10
+ if (typeof value !== 'string' || value.length === 0) {
11
+ throw new InstallerError(`--${flagName} is required`, 40);
12
+ }
13
+ return value;
14
+ }
15
+ function parseProvider(value) {
16
+ const v = requireString(value, 'provider');
17
+ if (v !== 'claude' && v !== 'codex' && v !== 'gemini') {
18
+ throw new InstallerError(`--provider value must be 'claude', 'codex', or 'gemini', got: ${v}`, 40);
19
+ }
20
+ return v;
21
+ }
22
+ /**
23
+ * Resolves the specrails-core package root (where templates/ + commands/ live).
24
+ * - Published: `<pkg>/dist/installer/commands/framework.js`
25
+ * - Source: `<repo>/src/installer/commands/framework.ts`
26
+ * Both are three levels deep (commands → installer → src|dist → root). The
27
+ * SPECRAILS_CORE_SCRIPT_DIR env var overrides for tests / desktop bundling.
28
+ */
29
+ function resolveScriptDir() {
30
+ const override = process.env.SPECRAILS_CORE_SCRIPT_DIR;
31
+ if (override && override.length > 0)
32
+ return path.resolve(override);
33
+ const here = path.dirname(fileURLToPath(import.meta.url));
34
+ return path.resolve(here, '..', '..', '..');
35
+ }
36
+ /**
37
+ * `specrails-core install-framework` — materialize the provider-invariant
38
+ * framework subtree ONCE under `<framework-dir>/<version>/<providerDir>/` and
39
+ * point `<framework-dir>/current` at it. Idempotent + offline.
40
+ */
41
+ export async function runInstallFramework(flags) {
42
+ const scriptDir = resolveScriptDir();
43
+ const frameworkDir = path.resolve(requireString(flags['framework-dir'], 'framework-dir'));
44
+ const provider = parseProvider(flags.provider);
45
+ const version = requireString(flags.version, 'version');
46
+ const { providerDir } = derivedPaths(provider);
47
+ const swapCurrent = flags['no-swap'] !== true;
48
+ step(`Materializing framework ${version} (${provider}) → ${frameworkDir}`);
49
+ ensureFramework({
50
+ scriptDir,
51
+ frameworkDir,
52
+ provider,
53
+ providerDir,
54
+ version,
55
+ agentTeams: flags['agent-teams'] === true,
56
+ swapCurrent,
57
+ });
58
+ if (swapCurrent) {
59
+ ok(`Framework ${version} ready (${providerDir}) + current → ${version}`);
60
+ }
61
+ else {
62
+ ok(`Framework ${version} ready (${providerDir}) — current NOT swapped (--no-swap)`);
63
+ }
64
+ return { frameworkDir, provider, version, providerDir, swapped: swapCurrent };
65
+ }
66
+ /**
67
+ * `specrails-core swap-current` — atomically point `<framework-dir>/current` at
68
+ * `<version>`. The multi-provider "materialize-all-then-swap-once" finaliser:
69
+ * after EVERY provider was materialized with `--no-swap`, this single call makes
70
+ * the version visible. Idempotent + offline.
71
+ */
72
+ export async function runSwapCurrent(flags) {
73
+ const frameworkDir = path.resolve(requireString(flags['framework-dir'], 'framework-dir'));
74
+ const version = requireString(flags.version, 'version');
75
+ step(`Swapping framework current → ${version} (${frameworkDir})`);
76
+ ensureCurrentSymlink(frameworkDir, version);
77
+ ok(`current → ${version}`);
78
+ return { frameworkDir, version };
79
+ }
80
+ /**
81
+ * `specrails-core assemble` — SYMLINK the materialized framework subtrees into a
82
+ * project workspace and seed the per-project layer (agent-memory, manifest,
83
+ * instruction/settings files, gemini acks). NO network, NO openspec init.
84
+ */
85
+ export async function runAssemble(flags) {
86
+ const scriptDir = resolveScriptDir();
87
+ const workspace = path.resolve(requireString(flags.workspace, 'workspace'));
88
+ const frameworkDir = path.resolve(requireString(flags['framework-dir'], 'framework-dir'));
89
+ const provider = parseProvider(flags.provider);
90
+ const version = requireString(flags.version, 'version');
91
+ const codeRoot = path.resolve(requireString(flags['code-root'], 'code-root'));
92
+ const { providerDir } = derivedPaths(provider);
93
+ // Defence-in-depth: the framework must be materialized + `current` pointed at
94
+ // `<version>` BEFORE assemble can link from it. The desktop FrameworkManager
95
+ // always calls install-framework first; this guard surfaces a clear error if
96
+ // a caller skips it.
97
+ const currentProviderDir = path.join(frameworkDir, 'current', providerDir);
98
+ if (!pathExists(currentProviderDir)) {
99
+ throw new InstallerError(`framework not materialized: ${currentProviderDir} is missing — run install-framework first`, 41);
100
+ }
101
+ const selectedAgentsFlag = flags['selected-agents'];
102
+ const selectedAgents = typeof selectedAgentsFlag === 'string' && selectedAgentsFlag.length > 0
103
+ ? selectedAgentsFlag.split(',').map((s) => s.trim()).filter((s) => s.length > 0)
104
+ : undefined;
105
+ step(`Assembling workspace ${workspace} ← framework ${version} (${provider})`);
106
+ assembleProjectWorkspace({
107
+ workspace,
108
+ frameworkDir,
109
+ provider,
110
+ providerDir,
111
+ version,
112
+ codeRoot,
113
+ scriptDir,
114
+ selectedAgents,
115
+ agentTeams: flags['agent-teams'] === true,
116
+ });
117
+ ok(`Linked ${providerDir}/ from framework ${version} + seeded project layer`);
118
+ return { workspace, frameworkDir, provider, version, codeRoot, providerDir };
119
+ }
120
+ /** Read the package version (the version the desktop should materialize). */
121
+ export function readPackageVersion(scriptDir) {
122
+ const dir = scriptDir ?? resolveScriptDir();
123
+ const p = path.join(dir, 'package.json');
124
+ if (!pathExists(p))
125
+ return 'unknown';
126
+ try {
127
+ const pkg = JSON.parse(readTextFile(p));
128
+ return pkg.version?.trim() || 'unknown';
129
+ }
130
+ catch {
131
+ return 'unknown';
132
+ }
133
+ }
134
+ //# sourceMappingURL=framework.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"framework.js","sourceRoot":"","sources":["../../../src/installer/commands/framework.ts"],"names":[],"mappings":"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"}