specrails-core 4.11.3 → 5.0.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 +96 -89
- package/bin/specrails-core.mjs +282 -39
- package/bin/tui-installer.mjs +117 -149
- package/commands/doctor.md +1 -1
- package/dist/installer/cli.js +13 -3
- package/dist/installer/cli.js.map +1 -1
- package/dist/installer/commands/doctor.js +487 -27
- package/dist/installer/commands/doctor.js.map +1 -1
- package/dist/installer/commands/framework.js +49 -7
- package/dist/installer/commands/framework.js.map +1 -1
- package/dist/installer/commands/init.js +443 -41
- package/dist/installer/commands/init.js.map +1 -1
- package/dist/installer/commands/update.js +51 -23
- package/dist/installer/commands/update.js.map +1 -1
- package/dist/installer/commands/v5-migration.js +119 -0
- package/dist/installer/commands/v5-migration.js.map +1 -0
- package/dist/installer/phases/framework-lifecycle.js +125 -0
- package/dist/installer/phases/framework-lifecycle.js.map +1 -0
- package/dist/installer/phases/install-config.js +160 -11
- package/dist/installer/phases/install-config.js.map +1 -1
- package/dist/installer/phases/manifest.js +29 -8
- package/dist/installer/phases/manifest.js.map +1 -1
- package/dist/installer/phases/prereqs.js +57 -3
- package/dist/installer/phases/prereqs.js.map +1 -1
- package/dist/installer/phases/provider-detect.js +116 -6
- package/dist/installer/phases/provider-detect.js.map +1 -1
- package/dist/installer/phases/scaffold.js +1217 -117
- package/dist/installer/phases/scaffold.js.map +1 -1
- package/dist/installer/runtime/kimi.js +255 -0
- package/dist/installer/runtime/kimi.js.map +1 -0
- package/dist/installer/util/paths.js +12 -0
- package/dist/installer/util/paths.js.map +1 -1
- package/dist/installer/util/registry.js +234 -14
- package/dist/installer/util/registry.js.map +1 -1
- package/docs/README.md +1 -0
- package/docs/deployment.md +6 -7
- package/docs/getting-started.md +11 -7
- package/docs/installation.md +34 -16
- package/docs/plugin-architecture.md +11 -8
- package/docs/updating.md +21 -3
- package/docs/user-docs/cli-reference.md +43 -22
- package/docs/user-docs/codex-vs-claude-code.md +11 -9
- package/docs/user-docs/faq.md +1 -1
- package/docs/user-docs/getting-started-codex.md +5 -8
- package/docs/user-docs/getting-started-kimi.md +423 -0
- package/docs/user-docs/installation.md +49 -14
- package/docs/user-docs/quick-start.md +11 -8
- package/docs/windows.md +29 -4
- package/integration-contract.json +85 -13
- package/package.json +9 -5
- package/schemas/profile.v1.json +68 -6
- package/templates/agents/sr-architect.md +30 -0
- package/templates/agents/sr-developer.md +21 -8
- package/templates/agents/sr-reviewer.md +44 -31
- package/templates/codex-skills/batch-implement/SKILL.md +9 -32
- package/templates/codex-skills/implement/SKILL.md +61 -143
- package/templates/codex-skills/rails/sr-architect/SKILL.md +38 -20
- package/templates/codex-skills/rails/sr-developer/SKILL.md +29 -10
- package/templates/codex-skills/rails/sr-reviewer/SKILL.md +21 -10
- package/templates/commands/specrails/doctor.md +1 -1
- package/templates/commands/specrails/implement.md +117 -288
- package/templates/commands/specrails/memory-inspect.md +6 -4
- package/templates/commands/specrails/propose-spec.md +1 -1
- package/templates/commands/specrails/refactor-recommender.md +8 -51
- package/templates/commands/specrails/retry.md +12 -48
- package/templates/commands/specrails/telemetry.md +1 -1
- package/templates/gemini-commands/implement.toml +9 -0
- package/templates/kimi/specrails/run-skill.mjs +3005 -0
- package/templates/kimi/specrails/vendor/js-yaml/LICENSE +21 -0
- package/templates/kimi/specrails/vendor/js-yaml/NOTICE.md +16 -0
- package/templates/kimi/specrails/vendor/js-yaml/js-yaml.mjs +3856 -0
- package/templates/profiles/default.json +5 -18
- package/templates/profiles/kimi-default.json +15 -0
- package/commands/enrich.md +0 -1456
- package/templates/agents/sr-backend-developer.md +0 -91
- package/templates/agents/sr-backend-reviewer.md +0 -152
- package/templates/agents/sr-doc-sync.md +0 -247
- package/templates/agents/sr-frontend-developer.md +0 -85
- package/templates/agents/sr-frontend-reviewer.md +0 -145
- package/templates/agents/sr-merge-resolver.md +0 -195
- package/templates/agents/sr-performance-reviewer.md +0 -186
- package/templates/agents/sr-product-analyst.md +0 -36
- package/templates/agents/sr-product-manager.md +0 -148
- package/templates/agents/sr-security-reviewer.md +0 -191
- package/templates/agents/sr-test-writer.md +0 -176
- package/templates/codex-skills/enrich/SKILL.md +0 -191
- package/templates/codex-skills/merge-resolve/SKILL.md +0 -88
- package/templates/codex-skills/rails/sr-backend-developer/SKILL.md +0 -93
- package/templates/codex-skills/rails/sr-backend-reviewer/SKILL.md +0 -120
- package/templates/codex-skills/rails/sr-doc-sync/SKILL.md +0 -124
- package/templates/codex-skills/rails/sr-frontend-developer/SKILL.md +0 -106
- package/templates/codex-skills/rails/sr-frontend-reviewer/SKILL.md +0 -111
- package/templates/codex-skills/rails/sr-merge-resolver/SKILL.md +0 -156
- package/templates/codex-skills/rails/sr-performance-reviewer/SKILL.md +0 -109
- package/templates/codex-skills/rails/sr-product-analyst/SKILL.md +0 -85
- package/templates/codex-skills/rails/sr-product-manager/SKILL.md +0 -131
- package/templates/codex-skills/rails/sr-security-reviewer/SKILL.md +0 -121
- package/templates/codex-skills/rails/sr-test-writer/SKILL.md +0 -115
- package/templates/commands/specrails/auto-propose-backlog-specs.md +0 -312
- package/templates/commands/specrails/enrich.md +0 -1456
- package/templates/commands/specrails/get-backlog-specs.md +0 -226
- package/templates/commands/specrails/merge-resolve.md +0 -172
- package/templates/commands/specrails/reconfig.md +0 -80
- package/templates/commands/specrails/vpc-drift.md +0 -405
- package/templates/commands/test.md +0 -58
- package/templates/personas/persona.md +0 -43
- package/templates/personas/the-maintainer.md +0 -98
- package/templates/settings/perf-thresholds.yml +0 -25
package/bin/tui-installer.mjs
CHANGED
|
@@ -9,10 +9,11 @@
|
|
|
9
9
|
* --yes - skip TUI, write defaults immediately
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
import {
|
|
13
|
-
import { writeFileSync, mkdirSync, existsSync } from 'node:fs';
|
|
12
|
+
import { select } from '@inquirer/prompts';
|
|
13
|
+
import { writeFileSync, mkdirSync, existsSync, readFileSync } from 'node:fs';
|
|
14
14
|
import { execSync } from 'node:child_process';
|
|
15
15
|
import { resolve } from 'node:path';
|
|
16
|
+
import { fileURLToPath } from 'node:url';
|
|
16
17
|
|
|
17
18
|
// ─── Alternate screen buffer (fullscreen mode) ──────────────────────────────
|
|
18
19
|
|
|
@@ -31,51 +32,35 @@ function clearScreen() {
|
|
|
31
32
|
|
|
32
33
|
// ─── Agent registry ───────────────────────────────────────────────────────────
|
|
33
34
|
|
|
35
|
+
// The three core agents are the complete shipped set. Extend an install with
|
|
36
|
+
// user-owned custom-* agents declared in a profile (.specrails/profiles/**) —
|
|
37
|
+
// the installer never ships or manages non-core agents.
|
|
34
38
|
const AGENTS = [
|
|
35
|
-
|
|
36
|
-
{ id: 'sr-
|
|
37
|
-
|
|
38
|
-
{ id: 'sr-developer', category: 'Development', description: 'Full-stack implementation across all layers' },
|
|
39
|
-
{ id: 'sr-frontend-developer', category: 'Development', description: 'Frontend implementation (React, Vue, Angular, etc.)' },
|
|
40
|
-
{ id: 'sr-backend-developer', category: 'Development', description: 'Backend specialization (APIs, databases, services)' },
|
|
41
|
-
// Review
|
|
42
|
-
{ id: 'sr-reviewer', category: 'Review', description: 'General code review — the final quality gate' },
|
|
43
|
-
{ id: 'sr-frontend-reviewer', category: 'Review', description: 'Frontend review (UI, accessibility, performance)' },
|
|
44
|
-
{ id: 'sr-backend-reviewer', category: 'Review', description: 'Backend review (APIs, security, scalability)' },
|
|
45
|
-
{ id: 'sr-security-reviewer', category: 'Review', description: 'Security analysis — OWASP, vulnerabilities, hardening' },
|
|
46
|
-
{ id: 'sr-performance-reviewer', category: 'Review', description: 'Performance analysis — profiling, bottlenecks, optimization' },
|
|
47
|
-
// Product
|
|
48
|
-
{ id: 'sr-product-manager', category: 'Product', description: 'Product discovery, VPC personas, backlog management' },
|
|
49
|
-
{ id: 'sr-product-analyst', category: 'Product', description: 'Backlog analysis, spec gap analysis, reporting' },
|
|
50
|
-
// Utilities
|
|
51
|
-
{ id: 'sr-test-writer', category: 'Utilities', description: 'Comprehensive test generation (unit, integration, E2E)' },
|
|
52
|
-
{ id: 'sr-doc-sync', category: 'Utilities', description: 'Documentation sync — keeps docs aligned with code' },
|
|
53
|
-
{ id: 'sr-merge-resolver', category: 'Utilities', description: 'Merge conflict resolution with context awareness' },
|
|
39
|
+
{ id: 'sr-architect', category: 'Architecture', description: 'Architecture design, change specs, implementation planning' },
|
|
40
|
+
{ id: 'sr-developer', category: 'Development', description: 'Full-stack implementation across all layers' },
|
|
41
|
+
{ id: 'sr-reviewer', category: 'Review', description: 'Code review — correctness, tests, security, performance' },
|
|
54
42
|
];
|
|
55
43
|
|
|
56
44
|
const ALL_AGENT_IDS = AGENTS.map(a => a.id);
|
|
57
45
|
|
|
58
|
-
// Core agents — the three
|
|
59
|
-
//
|
|
60
|
-
//
|
|
46
|
+
// Core agents — the three the installer ships, which the implement pipeline
|
|
47
|
+
// depends on. They are the COMPLETE shipped set; any extra specialist comes
|
|
48
|
+
// from a user-authored profile (custom-*), never the installer.
|
|
61
49
|
const CORE_AGENTS = new Set([
|
|
62
50
|
'sr-architect',
|
|
63
51
|
'sr-developer',
|
|
64
52
|
'sr-reviewer',
|
|
65
53
|
]);
|
|
66
54
|
|
|
67
|
-
//
|
|
68
|
-
// product manager, test writer, layer specialists, reviewers, utilities) are
|
|
69
|
-
// opt-in so the default install is as lean as possible. Users can add optional
|
|
70
|
-
// agents via `/specrails:enrich` or by re-running init.
|
|
55
|
+
// The three core agents ARE the full set; the selection always equals them.
|
|
71
56
|
const DEFAULT_SELECTED = new Set([
|
|
72
57
|
...CORE_AGENTS,
|
|
73
58
|
]);
|
|
74
59
|
|
|
75
|
-
// ─── Model presets
|
|
76
|
-
// Claude
|
|
77
|
-
//
|
|
78
|
-
//
|
|
60
|
+
// ─── Model presets ──────────────────────────────────────────────────────────────
|
|
61
|
+
// Claude exposes distinct Core-defined cost/quality tiers. Other providers use
|
|
62
|
+
// an explicit provider-native default for every named preset; preset names never
|
|
63
|
+
// imply that Claude aliases should be copied into another provider's config.
|
|
79
64
|
|
|
80
65
|
const MODEL_PRESETS = {
|
|
81
66
|
balanced: {
|
|
@@ -89,22 +74,30 @@ const MODEL_PRESETS = {
|
|
|
89
74
|
overrides: {},
|
|
90
75
|
},
|
|
91
76
|
max: {
|
|
92
|
-
label: 'Max quality — Opus for architect
|
|
77
|
+
label: 'Max quality — Opus for the architect, Sonnet for the rest',
|
|
93
78
|
defaults: 'sonnet',
|
|
94
|
-
overrides: { 'sr-architect': 'opus'
|
|
79
|
+
overrides: { 'sr-architect': 'opus' },
|
|
95
80
|
},
|
|
96
81
|
};
|
|
97
82
|
|
|
98
|
-
// Per-provider default agent model.
|
|
99
|
-
//
|
|
100
|
-
// model instead of a Claude-flavoured preset. Keep in sync with scaffold.ts
|
|
101
|
-
// (GEMINI_DEFAULT_MODEL / the codex config.toml model).
|
|
83
|
+
// Per-provider default agent model. Keep in sync with install-config.ts and the
|
|
84
|
+
// provider renderers.
|
|
102
85
|
const PROVIDER_DEFAULT_MODEL = {
|
|
103
86
|
claude: 'sonnet',
|
|
104
87
|
codex: 'gpt-5.5-mini',
|
|
105
88
|
gemini: 'gemini-3.5-flash',
|
|
89
|
+
kimi: 'k3',
|
|
106
90
|
};
|
|
107
91
|
|
|
92
|
+
function resolveProviderModelPreset(provider, preset = 'balanced') {
|
|
93
|
+
if (provider === 'claude') return MODEL_PRESETS[preset];
|
|
94
|
+
return {
|
|
95
|
+
label: `${PROVIDER_DEFAULT_MODEL[provider]} for all agents`,
|
|
96
|
+
defaults: PROVIDER_DEFAULT_MODEL[provider],
|
|
97
|
+
overrides: {},
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
108
101
|
// ─── Provider registry ─────────────────────────────────────────────────────────
|
|
109
102
|
// Single source of truth for the AI CLIs the TUI can target. Add a provider here
|
|
110
103
|
// and it flows through detection, the --provider flag, and the interactive picker.
|
|
@@ -112,8 +105,19 @@ const PROVIDERS = [
|
|
|
112
105
|
{ id: 'claude', label: 'Claude Code (recommended)', versionCmd: 'claude --version', installLabel: 'Claude Code', installUrl: 'https://claude.ai/download' },
|
|
113
106
|
{ id: 'codex', label: 'Codex (OpenAI)', versionCmd: 'codex --version', installLabel: 'Codex CLI', installUrl: 'https://developers.openai.com/codex' },
|
|
114
107
|
{ id: 'gemini', label: 'Gemini CLI (Google)', versionCmd: 'gemini --version', installLabel: 'Gemini CLI', installUrl: 'https://github.com/google-gemini/gemini-cli' },
|
|
108
|
+
{ id: 'kimi', label: 'Kimi Code', versionCmd: 'kimi --version', installLabel: 'Kimi Code', installUrl: 'https://www.kimi.com/code/docs/en/' },
|
|
115
109
|
];
|
|
116
110
|
const VALID_PROVIDER_IDS = new Set(PROVIDERS.map(p => p.id));
|
|
111
|
+
const providerProbeTimeoutOverride = Number.parseInt(
|
|
112
|
+
process.env.SPECRAILS_PROVIDER_PROBE_TIMEOUT_MS ?? '',
|
|
113
|
+
10,
|
|
114
|
+
);
|
|
115
|
+
const PROVIDER_PROBE_TIMEOUT_MS =
|
|
116
|
+
Number.isFinite(providerProbeTimeoutOverride) &&
|
|
117
|
+
providerProbeTimeoutOverride >= 100 &&
|
|
118
|
+
providerProbeTimeoutOverride <= 30_000
|
|
119
|
+
? providerProbeTimeoutOverride
|
|
120
|
+
: 3_000;
|
|
117
121
|
|
|
118
122
|
// ─── Helpers ──────────────────────────────────────────────────────────────────
|
|
119
123
|
|
|
@@ -121,25 +125,46 @@ const VALID_PROVIDER_IDS = new Set(PROVIDERS.map(p => p.id));
|
|
|
121
125
|
function detectInstalledProviders() {
|
|
122
126
|
const installed = new Set();
|
|
123
127
|
for (const p of PROVIDERS) {
|
|
124
|
-
try {
|
|
128
|
+
try {
|
|
129
|
+
execSync(p.versionCmd, {
|
|
130
|
+
stdio: 'ignore',
|
|
131
|
+
timeout: PROVIDER_PROBE_TIMEOUT_MS,
|
|
132
|
+
});
|
|
133
|
+
installed.add(p.id);
|
|
134
|
+
} catch { /* absent, broken, or hung — do not block the installer */ }
|
|
125
135
|
}
|
|
126
136
|
return installed;
|
|
127
137
|
}
|
|
128
138
|
|
|
129
|
-
// Parse `--provider <id>` or `--provider=<id>` from process.argv.
|
|
130
|
-
//
|
|
131
|
-
//
|
|
132
|
-
function parseProviderArg() {
|
|
133
|
-
const args = process.argv.slice(2);
|
|
139
|
+
// Parse `--provider <id>` or `--provider=<id>` from process.argv. An explicit
|
|
140
|
+
// but invalid value is a configuration error, never an invitation to silently
|
|
141
|
+
// open a picker and install a different provider.
|
|
142
|
+
function parseProviderArg(args = process.argv.slice(2)) {
|
|
134
143
|
for (let i = 0; i < args.length; i++) {
|
|
135
144
|
const a = args[i];
|
|
136
|
-
if (a === '--provider'
|
|
145
|
+
if (a === '--provider') {
|
|
146
|
+
if (!args[i + 1] || args[i + 1].startsWith('-')) {
|
|
147
|
+
throw new Error(
|
|
148
|
+
`--provider requires one of: ${[...VALID_PROVIDER_IDS].join(', ')}`,
|
|
149
|
+
);
|
|
150
|
+
}
|
|
137
151
|
const v = args[i + 1].trim().toLowerCase();
|
|
138
|
-
|
|
152
|
+
if (!VALID_PROVIDER_IDS.has(v)) {
|
|
153
|
+
throw new Error(
|
|
154
|
+
`unsupported --provider '${args[i + 1]}' (expected: ${[...VALID_PROVIDER_IDS].join(', ')})`,
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
return v;
|
|
139
158
|
}
|
|
140
159
|
if (a.startsWith('--provider=')) {
|
|
141
160
|
const v = a.slice('--provider='.length).trim().toLowerCase();
|
|
142
|
-
|
|
161
|
+
if (!VALID_PROVIDER_IDS.has(v)) {
|
|
162
|
+
throw new Error(
|
|
163
|
+
`unsupported --provider '${a.slice('--provider='.length)}' ` +
|
|
164
|
+
`(expected: ${[...VALID_PROVIDER_IDS].join(', ')})`,
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
return v;
|
|
143
168
|
}
|
|
144
169
|
}
|
|
145
170
|
return null;
|
|
@@ -155,26 +180,6 @@ function detectGitRoot(dir) {
|
|
|
155
180
|
}
|
|
156
181
|
}
|
|
157
182
|
|
|
158
|
-
function buildCheckboxChoices() {
|
|
159
|
-
const choices = [];
|
|
160
|
-
let currentCategory = null;
|
|
161
|
-
for (const agent of AGENTS) {
|
|
162
|
-
if (agent.category !== currentCategory) {
|
|
163
|
-
if (currentCategory !== null) choices.push(new Separator(''));
|
|
164
|
-
choices.push(new Separator(`── ${agent.category} ${'─'.repeat(Math.max(0, 46 - agent.category.length))}`));
|
|
165
|
-
currentCategory = agent.category;
|
|
166
|
-
}
|
|
167
|
-
const isCore = CORE_AGENTS.has(agent.id);
|
|
168
|
-
choices.push({
|
|
169
|
-
value: agent.id,
|
|
170
|
-
name: `${agent.id.padEnd(28)} ${agent.description}${isCore ? ' (core)' : ''}`,
|
|
171
|
-
checked: DEFAULT_SELECTED.has(agent.id),
|
|
172
|
-
disabled: isCore ? 'core — always installed' : false,
|
|
173
|
-
});
|
|
174
|
-
}
|
|
175
|
-
return choices;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
183
|
function writeInstallConfig(specrailsDir, cfg) {
|
|
179
184
|
if (!existsSync(specrailsDir)) mkdirSync(specrailsDir, { recursive: true });
|
|
180
185
|
|
|
@@ -188,7 +193,6 @@ function writeInstallConfig(specrailsDir, cfg) {
|
|
|
188
193
|
'# Re-run: npx specrails-core@latest init to regenerate',
|
|
189
194
|
`version: 1`,
|
|
190
195
|
`provider: ${cfg.provider}`,
|
|
191
|
-
`tier: ${cfg.tier}`,
|
|
192
196
|
`agents:`,
|
|
193
197
|
` selected: [${cfg.selectedAgents.join(', ')}]`,
|
|
194
198
|
` excluded: [${cfg.excludedAgents.join(', ')}]`,
|
|
@@ -205,23 +209,46 @@ function writeInstallConfig(specrailsDir, cfg) {
|
|
|
205
209
|
function writeDefaultConfig(specrailsDir, provider) {
|
|
206
210
|
const defaultSelected = [...DEFAULT_SELECTED];
|
|
207
211
|
const defaultExcluded = ALL_AGENT_IDS.filter(id => !DEFAULT_SELECTED.has(id));
|
|
212
|
+
const modelSelection = resolveProviderModelPreset(provider);
|
|
208
213
|
writeInstallConfig(specrailsDir, {
|
|
209
214
|
provider,
|
|
210
|
-
tier: 'full',
|
|
211
215
|
selectedAgents: defaultSelected,
|
|
212
216
|
excludedAgents: defaultExcluded,
|
|
213
217
|
modelPreset: 'balanced',
|
|
214
|
-
modelDefaults:
|
|
215
|
-
modelOverrides:
|
|
218
|
+
modelDefaults: modelSelection.defaults,
|
|
219
|
+
modelOverrides: modelSelection.overrides,
|
|
216
220
|
});
|
|
217
221
|
}
|
|
218
222
|
|
|
223
|
+
function scaffoldDefaultProfile(specrailsDir, provider) {
|
|
224
|
+
try {
|
|
225
|
+
const scriptDir = fileURLToPath(new URL('..', import.meta.url));
|
|
226
|
+
const templateName = provider === 'kimi' ? 'kimi-default.json' : 'default.json';
|
|
227
|
+
const templatePath = resolve(scriptDir, 'templates/profiles', templateName);
|
|
228
|
+
const profilesDir = resolve(specrailsDir, 'profiles');
|
|
229
|
+
// Provider-bound defaults must coexist in a multi-provider project. Keep
|
|
230
|
+
// the historical filename for Claude and give Kimi its own stable fallback.
|
|
231
|
+
const targetName = provider === 'kimi' ? 'kimi-default.json' : 'project-default.json';
|
|
232
|
+
const targetPath = resolve(profilesDir, targetName);
|
|
233
|
+
if (existsSync(templatePath) && !existsSync(targetPath)) {
|
|
234
|
+
mkdirSync(profilesDir, { recursive: true });
|
|
235
|
+
writeFileSync(targetPath, readFileSync(templatePath));
|
|
236
|
+
console.log(` ✓ Profile scaffolded at .specrails/profiles/${targetName}`);
|
|
237
|
+
} else if (existsSync(targetPath)) {
|
|
238
|
+
console.log(` ↷ Profile already exists at .specrails/profiles/${targetName} — skipped`);
|
|
239
|
+
}
|
|
240
|
+
} catch (e) {
|
|
241
|
+
console.warn(` ⚠ Could not scaffold profile: ${e.message}`);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
219
245
|
// ─── Main ─────────────────────────────────────────────────────────────────────
|
|
220
246
|
|
|
221
247
|
async function run() {
|
|
222
248
|
const rawArgs = process.argv.slice(2);
|
|
223
249
|
const autoYes = rawArgs.includes('--yes') || rawArgs.includes('-y');
|
|
224
250
|
const withProfiles = rawArgs.includes('--with-profiles');
|
|
251
|
+
const argvProvider = parseProviderArg(rawArgs);
|
|
225
252
|
// First positional arg (skipping flag values that follow `--provider`,
|
|
226
253
|
// `--root-dir`, etc.) is the target directory.
|
|
227
254
|
const FLAGS_WITH_VALUES = new Set(['--provider', '--root-dir', '--from-config']);
|
|
@@ -246,35 +273,12 @@ async function run() {
|
|
|
246
273
|
|
|
247
274
|
const specrailsDir = resolve(rootDir, '.specrails');
|
|
248
275
|
|
|
249
|
-
// Optional: scaffold .specrails/profiles/project-default.json from the shipped template.
|
|
250
|
-
// Off by default to keep standalone installs zero-noise.
|
|
251
|
-
if (withProfiles) {
|
|
252
|
-
try {
|
|
253
|
-
const { readFileSync, writeFileSync, existsSync, mkdirSync } = await import('node:fs');
|
|
254
|
-
const { dirname } = await import('node:path');
|
|
255
|
-
const scriptDir = new URL('..', import.meta.url).pathname;
|
|
256
|
-
const templatePath = resolve(scriptDir, 'templates/profiles/default.json');
|
|
257
|
-
const profilesDir = resolve(specrailsDir, 'profiles');
|
|
258
|
-
const targetPath = resolve(profilesDir, 'project-default.json');
|
|
259
|
-
if (existsSync(templatePath) && !existsSync(targetPath)) {
|
|
260
|
-
mkdirSync(profilesDir, { recursive: true });
|
|
261
|
-
writeFileSync(targetPath, readFileSync(templatePath));
|
|
262
|
-
console.log(` ✓ Profile scaffolded at .specrails/profiles/project-default.json`);
|
|
263
|
-
} else if (existsSync(targetPath)) {
|
|
264
|
-
console.log(` ↷ Profile already exists at .specrails/profiles/project-default.json — skipped`);
|
|
265
|
-
}
|
|
266
|
-
} catch (e) {
|
|
267
|
-
console.warn(` ⚠ Could not scaffold profile: ${e.message}`);
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
|
|
271
276
|
// Auto-yes: write defaults and exit (no TUI needed)
|
|
272
277
|
//
|
|
273
278
|
// Honours an explicit --provider <id> argv flag when present; otherwise
|
|
274
279
|
// picks claude → codex → first-detected. Errors only when none detected.
|
|
275
280
|
if (autoYes) {
|
|
276
281
|
const installed = detectInstalledProviders();
|
|
277
|
-
const argvProvider = parseProviderArg();
|
|
278
282
|
let provider;
|
|
279
283
|
if (argvProvider) {
|
|
280
284
|
if (!installed.has(argvProvider)) {
|
|
@@ -291,15 +295,16 @@ async function run() {
|
|
|
291
295
|
provider = PROVIDERS.find(p => installed.has(p.id))?.id;
|
|
292
296
|
if (!provider) {
|
|
293
297
|
console.error('');
|
|
294
|
-
console.error(' ⚠ No supported AI CLI detected on PATH (Claude Code, Codex, or
|
|
298
|
+
console.error(' ⚠ No supported AI CLI detected on PATH (Claude Code, Codex, Gemini CLI, or Kimi Code).');
|
|
295
299
|
for (const p of PROVIDERS) console.error(` Install ${p.installLabel}: ${p.installUrl}`);
|
|
296
300
|
console.error('');
|
|
297
301
|
process.exit(1);
|
|
298
302
|
}
|
|
299
303
|
}
|
|
304
|
+
if (withProfiles) scaffoldDefaultProfile(specrailsDir, provider);
|
|
300
305
|
writeDefaultConfig(specrailsDir, provider);
|
|
301
306
|
console.log(` ✓ Default config written to .specrails/install-config.yaml`);
|
|
302
|
-
console.log(` ✓ Provider: ${provider},
|
|
307
|
+
console.log(` ✓ Provider: ${provider}, Agents: ${DEFAULT_SELECTED.size}, Preset: balanced\n`);
|
|
303
308
|
return;
|
|
304
309
|
}
|
|
305
310
|
|
|
@@ -328,7 +333,6 @@ async function run() {
|
|
|
328
333
|
// ── Step 1: Provider ────────────────────────────────────────────────────────
|
|
329
334
|
|
|
330
335
|
const installed = detectInstalledProviders();
|
|
331
|
-
const argvProvider = parseProviderArg();
|
|
332
336
|
let provider;
|
|
333
337
|
|
|
334
338
|
if (argvProvider) {
|
|
@@ -359,61 +363,30 @@ async function run() {
|
|
|
359
363
|
});
|
|
360
364
|
}
|
|
361
365
|
}
|
|
366
|
+
if (withProfiles) scaffoldDefaultProfile(specrailsDir, provider);
|
|
362
367
|
|
|
363
|
-
// ──
|
|
368
|
+
// ── Agents: the three core agents are the full shipped set ──────────────────
|
|
364
369
|
|
|
365
370
|
clearScreen();
|
|
366
371
|
console.log(` Provider: ${provider}\n`);
|
|
372
|
+
console.log(' Installing the three core agents: sr-architect, sr-developer, sr-reviewer.');
|
|
373
|
+
console.log(' Add specialists later via a profile (.specrails/profiles/**) with custom-* agents.\n');
|
|
367
374
|
|
|
368
|
-
const
|
|
369
|
-
message: 'Installation tier:',
|
|
370
|
-
default: 'quick',
|
|
371
|
-
choices: [
|
|
372
|
-
{
|
|
373
|
-
value: 'quick',
|
|
374
|
-
name: 'Quick — Ready to use immediately (recommended)',
|
|
375
|
-
description: 'Agents installed with sensible defaults. No AI step required.',
|
|
376
|
-
},
|
|
377
|
-
{
|
|
378
|
-
value: 'full',
|
|
379
|
-
name: 'Full — AI-powered setup',
|
|
380
|
-
description: 'After install, run /specrails:enrich to AI-customize all agents for your codebase',
|
|
381
|
-
},
|
|
382
|
-
],
|
|
383
|
-
});
|
|
384
|
-
|
|
385
|
-
// ── Step 3: Agent selection ─────────────────────────────────────────────────
|
|
386
|
-
|
|
387
|
-
clearScreen();
|
|
388
|
-
console.log(` Provider: ${provider} | Tier: ${tier}\n`);
|
|
389
|
-
console.log(' Select agents to install. Space = toggle, a = all/none, Enter = confirm.\n');
|
|
390
|
-
|
|
391
|
-
// Use most of the terminal height for agent list (reserve 6 lines for header/footer)
|
|
392
|
-
const termRows = process.stdout.rows || 24;
|
|
393
|
-
const agentPageSize = Math.max(10, termRows - 6);
|
|
394
|
-
|
|
395
|
-
const userSelected = await checkbox({
|
|
396
|
-
message: 'Agents to install:',
|
|
397
|
-
choices: buildCheckboxChoices(),
|
|
398
|
-
pageSize: agentPageSize,
|
|
399
|
-
// Core agents are installed unconditionally (disabled rows above), so an
|
|
400
|
-
// empty optional selection is valid — means "only core, nothing extra".
|
|
401
|
-
});
|
|
402
|
-
|
|
403
|
-
// Core agents are always included regardless of checkbox state
|
|
404
|
-
const selectedAgents = [...new Set([...CORE_AGENTS, ...userSelected])];
|
|
375
|
+
const selectedAgents = [...CORE_AGENTS];
|
|
405
376
|
const excludedAgents = ALL_AGENT_IDS.filter(id => !selectedAgents.includes(id));
|
|
406
377
|
|
|
407
|
-
// ── Step
|
|
378
|
+
// ── Step 2: Model preset ────────────────────────────────────────────────────
|
|
408
379
|
|
|
409
380
|
clearScreen();
|
|
410
|
-
console.log(` Provider: ${provider} |
|
|
381
|
+
console.log(` Provider: ${provider} | Agents: ${selectedAgents.length}\n`);
|
|
411
382
|
|
|
412
|
-
// Claude exposes real model tiers
|
|
413
|
-
//
|
|
383
|
+
// Claude exposes real model tiers. Other providers retain the same config
|
|
384
|
+
// shape but resolve the preset through their provider-native catalog.
|
|
414
385
|
let modelPreset = 'balanced';
|
|
415
|
-
let
|
|
416
|
-
|
|
386
|
+
let {
|
|
387
|
+
defaults: modelDefaults,
|
|
388
|
+
overrides: modelOverrides,
|
|
389
|
+
} = resolveProviderModelPreset(provider, modelPreset);
|
|
417
390
|
if (provider === 'claude') {
|
|
418
391
|
modelPreset = await select({
|
|
419
392
|
message: 'Model configuration:',
|
|
@@ -424,7 +397,7 @@ async function run() {
|
|
|
424
397
|
});
|
|
425
398
|
({ defaults: modelDefaults, overrides: modelOverrides } = MODEL_PRESETS[modelPreset]);
|
|
426
399
|
} else {
|
|
427
|
-
console.log(` → Model: ${modelDefaults} (${provider}
|
|
400
|
+
console.log(` → Model: ${modelDefaults} (${provider} provider preset)\n`);
|
|
428
401
|
}
|
|
429
402
|
|
|
430
403
|
// ── Write config & exit fullscreen ──────────────────────────────────────────
|
|
@@ -433,7 +406,6 @@ async function run() {
|
|
|
433
406
|
|
|
434
407
|
writeInstallConfig(specrailsDir, {
|
|
435
408
|
provider,
|
|
436
|
-
tier,
|
|
437
409
|
selectedAgents,
|
|
438
410
|
excludedAgents,
|
|
439
411
|
modelPreset,
|
|
@@ -442,12 +414,8 @@ async function run() {
|
|
|
442
414
|
});
|
|
443
415
|
|
|
444
416
|
console.log(`\n ✓ Config written to .specrails/install-config.yaml`);
|
|
445
|
-
console.log(` ✓ Provider: ${provider} |
|
|
446
|
-
|
|
447
|
-
console.log(`\n Next: run /specrails:enrich --from-config inside ${provider} to AI-customize your agents.\n`);
|
|
448
|
-
} else {
|
|
449
|
-
console.log(`\n Agents will be installed with template defaults.\n`);
|
|
450
|
-
}
|
|
417
|
+
console.log(` ✓ Provider: ${provider} | Agents: ${selectedAgents.length} | Preset: ${modelPreset}`);
|
|
418
|
+
console.log(`\n Agents will be installed with template defaults — no follow-up step required.\n`);
|
|
451
419
|
}
|
|
452
420
|
|
|
453
421
|
run().catch(err => {
|
package/commands/doctor.md
CHANGED
|
@@ -35,7 +35,7 @@ Each check is displayed as ✅ (pass) or ❌ (fail with fix instruction).
|
|
|
35
35
|
|
|
36
36
|
On all checks passed:
|
|
37
37
|
```
|
|
38
|
-
All 6 checks passed. Run /specrails:
|
|
38
|
+
All 6 checks passed. Run /specrails:implement to get started.
|
|
39
39
|
```
|
|
40
40
|
|
|
41
41
|
On failure:
|
package/dist/installer/cli.js
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* Phase 5 deletes the shell scripts, the `bin/` dispatcher collapses
|
|
9
9
|
* to a single `import { main } from './dist/installer/cli.js'` call.
|
|
10
10
|
*/
|
|
11
|
-
import { readFileSync } from 'node:fs';
|
|
11
|
+
import { readFileSync, realpathSync } from 'node:fs';
|
|
12
12
|
import path from 'node:path';
|
|
13
13
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
14
14
|
import { runDoctor } from './commands/doctor.js';
|
|
@@ -73,7 +73,7 @@ export function parseArgs(argv) {
|
|
|
73
73
|
function usageText() {
|
|
74
74
|
return [
|
|
75
75
|
'',
|
|
76
|
-
'specrails-core — AI agent workflow system',
|
|
76
|
+
'specrails-core — Provider-independent AI agent workflow system',
|
|
77
77
|
'',
|
|
78
78
|
'Usage:',
|
|
79
79
|
' specrails-core <command> [options]',
|
|
@@ -185,13 +185,23 @@ export async function main(argv = process.argv.slice(2)) {
|
|
|
185
185
|
*
|
|
186
186
|
* Comparing `import.meta.url` against `process.argv[1]` keeps the guard inert on
|
|
187
187
|
* import (so unit tests that `import { main }` never trigger a process.exit).
|
|
188
|
+
*
|
|
189
|
+
* SYMLINK CAVEAT: Node's ESM loader realpaths the entry module, so
|
|
190
|
+
* `import.meta.url` is the REAL path while `process.argv[1]` is the literal
|
|
191
|
+
* spawn argument. When the package lives behind a symlinked path (macOS
|
|
192
|
+
* `os.tmpdir()` = /var/folders → /private/var/folders — exactly where
|
|
193
|
+
* specrails-desktop's core-update channel stages the download), the raw
|
|
194
|
+
* comparison fails and main() silently never runs (child exits 0 having done
|
|
195
|
+
* nothing). Compare against the realpathed argv[1] too.
|
|
188
196
|
*/
|
|
189
197
|
const isDirectRun = (() => {
|
|
190
198
|
try {
|
|
191
199
|
const entry = process.argv[1];
|
|
192
200
|
if (!entry)
|
|
193
201
|
return false;
|
|
194
|
-
|
|
202
|
+
if (import.meta.url === pathToFileURL(entry).href)
|
|
203
|
+
return true;
|
|
204
|
+
return import.meta.url === pathToFileURL(realpathSync(entry)).href;
|
|
195
205
|
}
|
|
196
206
|
catch {
|
|
197
207
|
return false;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/installer/cli.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/installer/cli.ts"],"names":[],"mappings":"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"}
|