chati-dev 2.0.4 → 2.0.6

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 (124) hide show
  1. package/README.md +48 -36
  2. package/framework/agents/{clarity → planning}/architect.md +1 -1
  3. package/framework/agents/{clarity → planning}/brief.md +1 -1
  4. package/framework/agents/{clarity → planning}/brownfield-wu.md +1 -1
  5. package/framework/agents/{clarity → planning}/detail.md +1 -1
  6. package/framework/agents/{clarity → planning}/greenfield-wu.md +1 -1
  7. package/framework/agents/{clarity → planning}/phases.md +1 -1
  8. package/framework/agents/{clarity → planning}/tasks.md +1 -1
  9. package/framework/agents/{clarity → planning}/ux.md +1 -1
  10. package/framework/agents/quality/qa-planning.md +5 -5
  11. package/framework/constitution.md +6 -6
  12. package/framework/context/governance.md +3 -3
  13. package/framework/context/quality.md +1 -1
  14. package/framework/context/root.md +1 -1
  15. package/framework/data/entity-registry.yaml +9 -9
  16. package/framework/domains/agents/qa-implementation.yaml +1 -1
  17. package/framework/domains/constitution.yaml +2 -2
  18. package/framework/domains/global.yaml +1 -1
  19. package/framework/hooks/mode-governance.js +5 -5
  20. package/framework/hooks/model-governance.js +38 -18
  21. package/framework/hooks/prism-engine.js +1 -1
  22. package/framework/hooks/session-digest.js +1 -1
  23. package/framework/i18n/en.yaml +1 -3
  24. package/framework/i18n/es.yaml +1 -3
  25. package/framework/i18n/fr.yaml +1 -3
  26. package/framework/i18n/pt.yaml +1 -3
  27. package/framework/intelligence/context-engine.md +3 -3
  28. package/framework/orchestrator/chati.md +148 -78
  29. package/framework/quality-gates/planning-gate.md +1 -1
  30. package/framework/schemas/context.schema.json +1 -1
  31. package/framework/schemas/session.schema.json +3 -3
  32. package/framework/tasks/architect-api-design.md +1 -1
  33. package/framework/tasks/architect-consolidate.md +1 -1
  34. package/framework/tasks/architect-db-design.md +1 -1
  35. package/framework/tasks/architect-design.md +1 -1
  36. package/framework/tasks/architect-security-review.md +1 -1
  37. package/framework/tasks/architect-stack-selection.md +1 -1
  38. package/framework/tasks/brief-consolidate.md +1 -1
  39. package/framework/tasks/brief-constraint-identify.md +1 -1
  40. package/framework/tasks/brief-extract-requirements.md +1 -1
  41. package/framework/tasks/brief-stakeholder-map.md +1 -1
  42. package/framework/tasks/brief-validate-completeness.md +1 -1
  43. package/framework/tasks/brownfield-wu-architecture-map.md +1 -1
  44. package/framework/tasks/brownfield-wu-deep-discovery.md +1 -1
  45. package/framework/tasks/brownfield-wu-dependency-scan.md +1 -1
  46. package/framework/tasks/brownfield-wu-migration-plan.md +1 -1
  47. package/framework/tasks/brownfield-wu-report.md +1 -1
  48. package/framework/tasks/brownfield-wu-risk-assess.md +1 -1
  49. package/framework/tasks/detail-acceptance-criteria.md +1 -1
  50. package/framework/tasks/detail-consolidate.md +1 -1
  51. package/framework/tasks/detail-edge-case-analysis.md +1 -1
  52. package/framework/tasks/detail-expand-prd.md +1 -1
  53. package/framework/tasks/detail-nfr-extraction.md +1 -1
  54. package/framework/tasks/greenfield-wu-analyze-empty.md +1 -1
  55. package/framework/tasks/greenfield-wu-report.md +1 -1
  56. package/framework/tasks/greenfield-wu-scaffold-detection.md +1 -1
  57. package/framework/tasks/greenfield-wu-tech-stack-assess.md +1 -1
  58. package/framework/tasks/orchestrator-deviation.md +3 -3
  59. package/framework/tasks/orchestrator-escalate.md +2 -2
  60. package/framework/tasks/orchestrator-handoff.md +6 -6
  61. package/framework/tasks/orchestrator-health.md +1 -1
  62. package/framework/tasks/orchestrator-mode-switch.md +20 -20
  63. package/framework/tasks/orchestrator-resume.md +6 -6
  64. package/framework/tasks/orchestrator-route.md +7 -7
  65. package/framework/tasks/orchestrator-status.md +8 -8
  66. package/framework/tasks/orchestrator-suggest-mode.md +13 -13
  67. package/framework/tasks/phases-breakdown.md +1 -1
  68. package/framework/tasks/phases-dependency-mapping.md +1 -1
  69. package/framework/tasks/phases-mvp-scoping.md +1 -1
  70. package/framework/tasks/qa-impl-regression-check.md +2 -2
  71. package/framework/tasks/qa-planning-consolidate.md +3 -3
  72. package/framework/tasks/qa-planning-coverage-plan.md +1 -1
  73. package/framework/tasks/qa-planning-gate-define.md +7 -7
  74. package/framework/tasks/qa-planning-risk-matrix.md +1 -1
  75. package/framework/tasks/qa-planning-test-strategy.md +1 -1
  76. package/framework/tasks/tasks-acceptance-write.md +1 -1
  77. package/framework/tasks/tasks-consolidate.md +1 -1
  78. package/framework/tasks/tasks-decompose.md +1 -1
  79. package/framework/tasks/tasks-estimate.md +1 -1
  80. package/framework/tasks/ux-a11y-check.md +1 -1
  81. package/framework/tasks/ux-component-map.md +1 -1
  82. package/framework/tasks/ux-consolidate.md +1 -1
  83. package/framework/tasks/ux-user-flow.md +1 -1
  84. package/framework/tasks/ux-wireframe.md +1 -1
  85. package/framework/workflows/brownfield-discovery.yaml +7 -7
  86. package/framework/workflows/brownfield-fullstack.yaml +9 -9
  87. package/framework/workflows/brownfield-service.yaml +5 -5
  88. package/framework/workflows/brownfield-ui.yaml +5 -5
  89. package/framework/workflows/greenfield-fullstack.yaml +9 -9
  90. package/package.json +2 -2
  91. package/scripts/bundle-framework.js +1 -1
  92. package/scripts/health-check.js +8 -8
  93. package/scripts/populate-entity-registry.js +1 -1
  94. package/scripts/validate-agents.js +1 -1
  95. package/scripts/validate-tasks.js +1 -1
  96. package/src/autonomy/autonomous-gate.js +1 -1
  97. package/src/autonomy/progress-reporter.js +9 -9
  98. package/src/config/mcp-configs.js +16 -85
  99. package/src/context/engine.js +2 -2
  100. package/src/context/layers/l1-global.js +3 -3
  101. package/src/dashboard/layout.js +7 -7
  102. package/src/dashboard/renderer.js +2 -2
  103. package/src/gates/g1-planning-complete.js +9 -9
  104. package/src/installer/core.js +11 -11
  105. package/src/installer/templates.js +1 -1
  106. package/src/installer/validator.js +8 -8
  107. package/src/intelligence/registry-manager.js +4 -4
  108. package/src/memory/session-digest.js +1 -1
  109. package/src/orchestrator/agent-selector.js +10 -10
  110. package/src/orchestrator/intent-classifier.js +4 -4
  111. package/src/orchestrator/pipeline-manager.js +3 -3
  112. package/src/orchestrator/pipeline-state.js +1 -1
  113. package/src/orchestrator/session-manager.js +3 -3
  114. package/src/tasks/executor.js +1 -1
  115. package/src/tasks/loader.js +1 -1
  116. package/src/terminal/handoff-parser.js +127 -0
  117. package/src/terminal/index.js +9 -0
  118. package/src/terminal/prompt-builder.js +313 -0
  119. package/src/terminal/run-agent.js +248 -0
  120. package/src/terminal/run-parallel.js +238 -0
  121. package/src/terminal/spawner.js +29 -18
  122. package/src/wizard/i18n.js +1 -3
  123. package/src/wizard/index.js +10 -15
  124. package/src/wizard/questions.js +7 -70
@@ -0,0 +1,238 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * CLI runner for parallel agent terminal execution.
4
+ *
5
+ * Called by the orchestrator via the Bash tool to spawn multiple agents
6
+ * simultaneously in separate Claude Code processes.
7
+ *
8
+ * Usage:
9
+ * node run-parallel.js --agents detail,architect,ux \
10
+ * --task-ids expand-prd,architect-design,ux-wireframe \
11
+ * --project-dir /path/to/project --previous-agent brief \
12
+ * --timeout 900000
13
+ *
14
+ * Outputs consolidated JSON to stdout for the orchestrator to parse.
15
+ */
16
+
17
+ import { fileURLToPath } from 'url';
18
+ import { buildAgentPrompt } from './prompt-builder.js';
19
+ import { spawnParallelGroup } from './spawner.js';
20
+ import { TerminalMonitor } from './monitor.js';
21
+ import { collectResults, mergeHandoffs, buildConsolidatedHandoff } from './collector.js';
22
+ import { parseAgentOutput } from './handoff-parser.js';
23
+
24
+ // ---------------------------------------------------------------------------
25
+ // CLI argument parsing
26
+ // ---------------------------------------------------------------------------
27
+
28
+ function parseArgs(argv) {
29
+ const args = {};
30
+ for (let i = 2; i < argv.length; i++) {
31
+ const arg = argv[i];
32
+ if (arg.startsWith('--')) {
33
+ const key = arg.slice(2);
34
+ const next = argv[i + 1];
35
+ if (next && !next.startsWith('--')) {
36
+ args[key] = next;
37
+ i++;
38
+ } else {
39
+ args[key] = 'true';
40
+ }
41
+ }
42
+ }
43
+ return args;
44
+ }
45
+
46
+ // ---------------------------------------------------------------------------
47
+ // Main
48
+ // ---------------------------------------------------------------------------
49
+
50
+ async function main() {
51
+ const args = parseArgs(process.argv);
52
+
53
+ if (!args.agents) {
54
+ outputError('Missing required argument: --agents (comma-separated)');
55
+ process.exit(1);
56
+ }
57
+ if (!args['task-ids']) {
58
+ outputError('Missing required argument: --task-ids (comma-separated)');
59
+ process.exit(1);
60
+ }
61
+
62
+ const agents = args.agents.split(',').map(s => s.trim());
63
+ const taskIds = args['task-ids'].split(',').map(s => s.trim());
64
+
65
+ if (agents.length !== taskIds.length) {
66
+ outputError(`Agent count (${agents.length}) must match task-id count (${taskIds.length})`);
67
+ process.exit(1);
68
+ }
69
+
70
+ const projectDir = args['project-dir'] || process.cwd();
71
+ const previousAgent = args['previous-agent'] || null;
72
+ const timeout = parseInt(args.timeout, 10) || 900_000; // default 15 minutes
73
+
74
+ // Load session state
75
+ let sessionState = {};
76
+ try {
77
+ const { existsSync, readFileSync } = await import('fs');
78
+ const { join } = await import('path');
79
+ const sessionPath = join(projectDir, '.chati', 'session.yaml');
80
+ if (existsSync(sessionPath)) {
81
+ const raw = readFileSync(sessionPath, 'utf-8');
82
+ // Minimal parse
83
+ sessionState = {};
84
+ for (const line of raw.split('\n')) {
85
+ const m = line.trim().match(/^([\w_-]+):\s*(.+)/);
86
+ if (m) sessionState[m[1]] = m[2].trim().replace(/^["']|["']$/g, '');
87
+ }
88
+ }
89
+ } catch { /* optional */ }
90
+
91
+ // Build prompts for all agents
92
+ const configs = [];
93
+ const startTime = Date.now();
94
+
95
+ for (let i = 0; i < agents.length; i++) {
96
+ try {
97
+ const promptResult = buildAgentPrompt({
98
+ agent: agents[i],
99
+ taskId: taskIds[i],
100
+ projectDir,
101
+ previousAgent,
102
+ sessionState,
103
+ });
104
+
105
+ configs.push({
106
+ agent: agents[i],
107
+ taskId: taskIds[i],
108
+ model: promptResult.model,
109
+ prompt: promptResult.prompt,
110
+ workingDir: projectDir,
111
+ timeout,
112
+ });
113
+ } catch (err) {
114
+ outputError(`Failed to build prompt for ${agents[i]}: ${err.message}`);
115
+ process.exit(1);
116
+ }
117
+ }
118
+
119
+ // Spawn all terminals in parallel
120
+ let group;
121
+ try {
122
+ group = spawnParallelGroup(configs);
123
+ } catch (err) {
124
+ outputError(`Failed to spawn parallel group: ${err.message}`);
125
+ process.exit(1);
126
+ }
127
+
128
+ // Monitor until completion
129
+ const monitor = new TerminalMonitor({ pollInterval: 2000, timeout });
130
+
131
+ for (const terminal of group.terminals) {
132
+ monitor.addTerminal(terminal);
133
+ }
134
+
135
+ await new Promise((resolve) => {
136
+ monitor.onComplete(() => {
137
+ monitor.stopMonitoring();
138
+ resolve();
139
+ });
140
+
141
+ // Safety timeout
142
+ const safetyTimer = setTimeout(() => {
143
+ monitor.stopMonitoring();
144
+ resolve();
145
+ }, timeout + 10_000);
146
+
147
+ monitor.onComplete(() => clearTimeout(safetyTimer));
148
+ monitor.startMonitoring();
149
+ });
150
+
151
+ const elapsed = Date.now() - startTime;
152
+
153
+ // Collect and merge results
154
+ const rawResults = collectResults(group.groupId, group.terminals);
155
+
156
+ // Parse handoffs from each terminal's stdout
157
+ const agentResults = rawResults.results.map(r => {
158
+ const parsed = parseAgentOutput(r.stdout);
159
+ return {
160
+ ...r,
161
+ handoff: parsed.found ? parsed.handoff : null,
162
+ handoffFound: parsed.found,
163
+ };
164
+ });
165
+
166
+ // Merge handoffs
167
+ const mergeInput = agentResults.map(r => ({
168
+ agent: r.agent,
169
+ status: r.handoff?.status || (r.exitCode === 0 ? 'complete' : 'failed'),
170
+ outputs: r.handoff?.outputs || [],
171
+ decisions: r.handoff?.decisions || {},
172
+ blockers: r.handoff?.blockers || [],
173
+ summary: r.handoff?.summary || '',
174
+ }));
175
+
176
+ const merged = mergeHandoffs(mergeInput);
177
+ const nextAgent = determineNextAgent(agents);
178
+ const consolidated = buildConsolidatedHandoff(merged, nextAgent);
179
+
180
+ // Output consolidated result
181
+ const output = {
182
+ status: rawResults.summary.failed === 0 ? 'complete' : 'partial',
183
+ groupId: group.groupId,
184
+ agents: agents.map((a, i) => ({
185
+ agent: a,
186
+ model: configs[i].model,
187
+ status: agentResults[i].handoff?.status || (agentResults[i].exitCode === 0 ? 'complete' : 'failed'),
188
+ score: agentResults[i].handoff?.score || null,
189
+ exitCode: agentResults[i].exitCode,
190
+ handoffFound: agentResults[i].handoffFound,
191
+ })),
192
+ mergedHandoff: consolidated,
193
+ summary: rawResults.summary,
194
+ elapsed,
195
+ performance: {
196
+ sequentialEstimate: elapsed * agents.length,
197
+ parallelActual: elapsed,
198
+ timeSaved: elapsed * (agents.length - 1),
199
+ },
200
+ };
201
+
202
+ process.stdout.write(JSON.stringify(output, null, 2) + '\n');
203
+ process.exit(rawResults.summary.failed > 0 ? 1 : 0);
204
+ }
205
+
206
+ // ---------------------------------------------------------------------------
207
+ // Helpers
208
+ // ---------------------------------------------------------------------------
209
+
210
+ /**
211
+ * Determine the next sequential agent after a parallel group.
212
+ * GROUP 1 (detail+architect+ux) → phases
213
+ * GROUP 2 (dev tasks) → qa-implementation
214
+ */
215
+ function determineNextAgent(agents) {
216
+ const groupKey = agents.sort().join(',');
217
+ if (groupKey.includes('architect') && groupKey.includes('detail') && groupKey.includes('ux')) {
218
+ return 'phases';
219
+ }
220
+ if (agents.every(a => a === 'dev')) {
221
+ return 'qa-implementation';
222
+ }
223
+ return null;
224
+ }
225
+
226
+ function outputError(message) {
227
+ process.stdout.write(JSON.stringify({ status: 'error', error: message }) + '\n');
228
+ }
229
+
230
+ // Guard pattern
231
+ if (process.argv[1] === fileURLToPath(import.meta.url)) {
232
+ main().catch(err => {
233
+ outputError(err.message);
234
+ process.exit(1);
235
+ });
236
+ }
237
+
238
+ export { parseArgs, determineNextAgent };
@@ -40,8 +40,10 @@ export function _resetCounter() {
40
40
 
41
41
  /**
42
42
  * @typedef {object} SpawnConfig
43
- * @property {string} agent - Agent name (e.g. "architect")
44
- * @property {string} taskId - Task identifier
43
+ * @property {string} agent - Agent name (e.g. "architect")
44
+ * @property {string} taskId - Task identifier
45
+ * @property {string} [model] - LLM model (haiku/sonnet/opus)
46
+ * @property {string} [prompt] - Full prompt string (from prompt-builder, piped via stdin)
45
47
  * @property {object} [contextPayload] - Context to inject via env var
46
48
  * @property {string[]} [writeScope] - Override write scope
47
49
  * @property {string} [workingDir] - Working directory for the process
@@ -54,6 +56,7 @@ export function _resetCounter() {
54
56
  * @property {object|null} process - child_process.ChildProcess (null when dry)
55
57
  * @property {string} agent - Agent name
56
58
  * @property {string} taskId - Task identifier
59
+ * @property {string} model - Model used for this terminal
57
60
  * @property {string} startedAt - ISO timestamp
58
61
  * @property {string} status - "running" | "exited" | "killed"
59
62
  * @property {number|null} exitCode - Process exit code (null while running)
@@ -68,7 +71,7 @@ export function _resetCounter() {
68
71
  * perform any I/O and is therefore fully testable in isolation.
69
72
  *
70
73
  * @param {SpawnConfig} config
71
- * @returns {{ command: string, args: string[], env: Record<string, string> }}
74
+ * @returns {{ command: string, args: string[], env: Record<string, string>, terminalId: string, prompt: string|null }}
72
75
  */
73
76
  export function buildSpawnCommand(config) {
74
77
  if (!config || typeof config !== 'object') {
@@ -89,6 +92,7 @@ export function buildSpawnCommand(config) {
89
92
  CHATI_TERMINAL_ID: terminalId,
90
93
  CHATI_AGENT: config.agent,
91
94
  CHATI_TASK_ID: config.taskId,
95
+ CHATI_SPAWNED: 'true',
92
96
  };
93
97
 
94
98
  if (config.contextPayload) {
@@ -99,19 +103,18 @@ export function buildSpawnCommand(config) {
99
103
  }
100
104
  }
101
105
 
102
- // Build the prompt that will be sent to claude CLI
103
- const prompt = `Execute task ${config.taskId} as agent ${config.agent}. ` +
104
- `Write scope: ${isolationEnv.CHATI_WRITE_SCOPE || 'none'}. ` +
105
- `Terminal ID: ${terminalId}.`;
106
-
106
+ // Build CLI args — prompt is piped via stdin, NOT as a CLI argument
107
107
  const command = 'claude';
108
- const args = [
109
- '--print',
110
- '--dangerously-skip-permissions',
111
- prompt,
112
- ];
108
+ const args = ['--print', '--dangerously-skip-permissions'];
109
+
110
+ if (config.model) {
111
+ args.push('--model', config.model);
112
+ }
113
113
 
114
- return { command, args, env, terminalId };
114
+ // Prompt is returned separately for stdin piping (avoids ARG_MAX limits)
115
+ const prompt = config.prompt || null;
116
+
117
+ return { command, args, env, terminalId, prompt };
115
118
  }
116
119
 
117
120
  /**
@@ -121,7 +124,7 @@ export function buildSpawnCommand(config) {
121
124
  * @returns {TerminalHandle}
122
125
  */
123
126
  export function spawnTerminal(config) {
124
- const { command, args, env, terminalId } = buildSpawnCommand(config);
127
+ const { command, args, env, terminalId, prompt } = buildSpawnCommand(config);
125
128
 
126
129
  const cwd = config.workingDir || process.cwd();
127
130
  const timeout = config.timeout || 300_000; // default 5 minutes
@@ -129,15 +132,22 @@ export function spawnTerminal(config) {
129
132
  const child = spawn(command, args, {
130
133
  cwd,
131
134
  env: { ...process.env, ...env },
132
- stdio: ['ignore', 'pipe', 'pipe'],
135
+ stdio: ['pipe', 'pipe', 'pipe'],
133
136
  });
134
137
 
138
+ // Pipe prompt via stdin (avoids shell argument length limits)
139
+ if (prompt) {
140
+ child.stdin.write(prompt);
141
+ }
142
+ child.stdin.end();
143
+
135
144
  /** @type {TerminalHandle} */
136
145
  const handle = {
137
146
  id: terminalId,
138
147
  process: child,
139
148
  agent: config.agent,
140
149
  taskId: config.taskId,
150
+ model: config.model || 'sonnet',
141
151
  startedAt: new Date().toISOString(),
142
152
  status: 'running',
143
153
  exitCode: null,
@@ -250,11 +260,11 @@ export function killTerminal(handle) {
250
260
  * Return the current status snapshot of a terminal.
251
261
  *
252
262
  * @param {TerminalHandle} handle
253
- * @returns {{ id: string, agent: string, status: string, elapsed: number, exitCode: number|null }}
263
+ * @returns {{ id: string, agent: string, model: string, status: string, elapsed: number, exitCode: number|null }}
254
264
  */
255
265
  export function getTerminalStatus(handle) {
256
266
  if (!handle) {
257
- return { id: 'unknown', agent: 'unknown', status: 'unknown', elapsed: 0, exitCode: null };
267
+ return { id: 'unknown', agent: 'unknown', model: 'unknown', status: 'unknown', elapsed: 0, exitCode: null };
258
268
  }
259
269
 
260
270
  const elapsed = Date.now() - new Date(handle.startedAt).getTime();
@@ -262,6 +272,7 @@ export function getTerminalStatus(handle) {
262
272
  return {
263
273
  id: handle.id,
264
274
  agent: handle.agent,
275
+ model: handle.model || 'unknown',
265
276
  status: handle.status,
266
277
  elapsed,
267
278
  exitCode: handle.exitCode,
@@ -15,15 +15,13 @@ const FALLBACK_EN = {
15
15
  brownfield: 'Brownfield (existing project integration)',
16
16
  detected_brownfield: 'Detected package.json and src/ in current directory',
17
17
  suggestion_brownfield: 'Suggestion: Brownfield',
18
- select_ides: 'Select IDE(s) for Chati.dev configuration:',
19
- select_mcps: 'Select MCPs to install (project-level):',
20
18
  confirmation_title: 'Installation Summary',
21
19
  project_label: 'Project',
22
20
  language_label: 'Language',
23
21
  ides_label: 'IDEs',
24
22
  mcps_label: 'MCPs',
25
23
  will_install: 'Will install:',
26
- agents_count: '13 agent definitions (CLARITY, BUILD, DEPLOY phases)',
24
+ agents_count: '13 agent definitions (PLANNING, BUILD, DEPLOY phases)',
27
25
  workflows_count: '5 workflow blueprints',
28
26
  templates_count: '5 templates (PRD, Brownfield PRD, Architecture, Task, QA Gate)',
29
27
  constitution: 'Constitution (17 Articles + Preamble)',
@@ -3,17 +3,18 @@ import { readFileSync } from 'fs';
3
3
  import { join, dirname, basename } from 'path';
4
4
  import { fileURLToPath } from 'url';
5
5
  import { logBanner } from '../utils/logger.js';
6
- import { stepLanguage, stepProjectType, stepIDEs, stepMCPs, stepConfirmation } from './questions.js';
6
+ import { stepLanguage, stepProjectType, stepConfirmation } from './questions.js';
7
7
  import { createSpinner, showStep, showValidation, showQuickStart } from './feedback.js';
8
8
  import { installFramework } from '../installer/core.js';
9
9
  import { validateInstallation } from '../installer/validator.js';
10
10
  import { t } from './i18n.js';
11
+ import { DEFAULT_MCPS } from '../config/mcp-configs.js';
11
12
 
12
13
  const __dirname = dirname(fileURLToPath(import.meta.url));
13
14
  const VERSION = JSON.parse(readFileSync(join(__dirname, '..', '..', 'package.json'), 'utf-8')).version;
14
15
 
15
16
  /**
16
- * Run the 6-step installer wizard
17
+ * Run the 4-step installer wizard
17
18
  */
18
19
  export async function runWizard(targetDir, options = {}) {
19
20
  // Load ASCII logo
@@ -34,13 +35,11 @@ export async function runWizard(targetDir, options = {}) {
34
35
  // Step 2: Project Type
35
36
  const projectType = options.projectType || await stepProjectType(targetDir);
36
37
 
37
- // Step 3: IDE Selection
38
- const selectedIDEs = options.ides || await stepIDEs();
38
+ // Auto-configured: Claude Code + default MCPs
39
+ const selectedIDEs = options.ides || ['claude-code'];
40
+ const selectedMCPs = options.mcps || DEFAULT_MCPS;
39
41
 
40
- // Step 4: MCP Selection
41
- const selectedMCPs = options.mcps || await stepMCPs(projectType);
42
-
43
- // Step 5: Confirmation
42
+ // Step 3: Confirmation
44
43
  const projectName = basename(targetDir);
45
44
  const config = {
46
45
  projectName,
@@ -54,7 +53,7 @@ export async function runWizard(targetDir, options = {}) {
54
53
 
55
54
  await stepConfirmation(config);
56
55
 
57
- // Step 6: Installation + Validation
56
+ // Step 4: Installation + Validation
58
57
  console.log();
59
58
  const installSpinner = createSpinner(t('installer.installing'));
60
59
  installSpinner.start();
@@ -71,10 +70,7 @@ export async function runWizard(targetDir, options = {}) {
71
70
  showStep(t('installer.created_claude_md'));
72
71
  showStep(t('installer.created_memories'));
73
72
  showStep(t('installer.installed_intelligence'));
74
-
75
- if (selectedMCPs.length > 0) {
76
- showStep(`${t('installer.configured_mcps')} ${selectedMCPs.join(', ')}`);
77
- }
73
+ showStep(`${t('installer.configured_mcps')} ${selectedMCPs.join(', ')}`);
78
74
 
79
75
  // Validation
80
76
  console.log();
@@ -96,9 +92,8 @@ export async function runWizard(targetDir, options = {}) {
96
92
  console.log();
97
93
  p.outro(t('installer.success'));
98
94
 
99
- const primaryIDE = selectedIDEs[0] || 'your IDE';
100
95
  showQuickStart(t('installer.quick_start_title'), [
101
- `${t('installer.quick_start_1')} (${primaryIDE})`,
96
+ `${t('installer.quick_start_1')} (Claude Code)`,
102
97
  t('installer.quick_start_2'),
103
98
  t('installer.quick_start_3'),
104
99
  ]);
@@ -1,10 +1,8 @@
1
1
  import * as p from '@clack/prompts';
2
2
  import { t, SUPPORTED_LANGUAGES, loadLanguage } from './i18n.js';
3
- import { getIDEChoices } from '../config/ide-configs.js';
4
- import { getMCPChoices, getMCPWarnings } from '../config/mcp-configs.js';
5
3
  import { detectProjectType } from '../utils/detector.js';
6
4
  import { showSummary, showChecklist } from './feedback.js';
7
- import { brand, dim, success, yellow } from '../utils/colors.js';
5
+ import { brand, dim, success } from '../utils/colors.js';
8
6
 
9
7
  /**
10
8
  * Step 1: Language Selection (always in English)
@@ -60,77 +58,16 @@ export async function stepProjectType(targetDir) {
60
58
  }
61
59
 
62
60
  /**
63
- * Step 3: IDE Selection (Multi-select)
64
- */
65
- export async function stepIDEs() {
66
- const ideChoices = getIDEChoices();
67
-
68
- const selectedIDEs = await p.multiselect({
69
- message: t('installer.select_ides'),
70
- options: ideChoices.map(ide => ({
71
- value: ide.value,
72
- label: `${ide.label} ${dim('--')} ${dim(ide.hint)}`,
73
- })),
74
- initialValues: ['claude-code'],
75
- required: true,
76
- });
77
-
78
- if (p.isCancel(selectedIDEs)) {
79
- p.cancel('Installation cancelled.');
80
- process.exit(0);
81
- }
82
-
83
- return selectedIDEs;
84
- }
85
-
86
- /**
87
- * Step 4: MCP Selection (Multi-select)
88
- */
89
- export async function stepMCPs(projectType) {
90
- const mcpChoices = getMCPChoices();
91
-
92
- const selectedMCPs = await p.multiselect({
93
- message: t('installer.select_mcps'),
94
- options: mcpChoices.map(mcp => ({
95
- value: mcp.value,
96
- label: `${mcp.label} ${dim('--')} ${dim(mcp.hint)}`,
97
- })),
98
- initialValues: mcpChoices.filter(m => m.initialValue).map(m => m.value),
99
- required: false,
100
- });
101
-
102
- if (p.isCancel(selectedMCPs)) {
103
- p.cancel('Installation cancelled.');
104
- process.exit(0);
105
- }
106
-
107
- // Check for MCP warnings
108
- const warnings = getMCPWarnings(projectType, selectedMCPs);
109
- for (const warn of warnings) {
110
- if (warn.level === 'critical') {
111
- const continueAnyway = await p.confirm({
112
- message: `${yellow('Warning:')} ${warn.message}\nContinue anyway?`,
113
- initialValue: false,
114
- });
115
-
116
- if (p.isCancel(continueAnyway) || !continueAnyway) {
117
- return stepMCPs(projectType); // Re-prompt
118
- }
119
- }
120
- }
121
-
122
- return selectedMCPs;
123
- }
124
-
125
- /**
126
- * Step 5: Confirmation
61
+ * Step 3: Confirmation
127
62
  */
128
63
  export async function stepConfirmation(config) {
129
- const { projectName, projectType, language, selectedIDEs, selectedMCPs } = config;
64
+ const { projectName, projectType, language, selectedMCPs } = config;
130
65
 
131
66
  const langName = SUPPORTED_LANGUAGES.find(l => l.value === language)?.label || language;
132
- const ideNames = selectedIDEs.join(', ');
133
- const mcpNames = selectedMCPs.length > 0 ? selectedMCPs.join(', ') : 'None';
67
+ const ideNames = 'Claude Code (auto-configured)';
68
+ const mcpNames = selectedMCPs.length > 0
69
+ ? `${selectedMCPs.join(', ')} (auto-installed)`
70
+ : 'None';
134
71
 
135
72
  console.log();
136
73
  console.log(brand(t('installer.confirmation_title') + ':'));