imhcode 1.0.0 → 1.0.2

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 (2) hide show
  1. package/bin/imhcode.js +1256 -511
  2. package/package.json +1 -2
package/bin/imhcode.js CHANGED
@@ -5,23 +5,24 @@
5
5
  *
6
6
  * Usage:
7
7
  * imhcode → Initialize framework in current directory
8
- * imhcode plan → Smart: brainstorm OR sprint-plan based on state
8
+ * imhcode plan → Smart: brainstorm (LLM) OR sprint-plan (LLM) based on state
9
9
  * imhcode execute [N] → Execute sprint N with intelligent model routing
10
10
  * imhcode test → Run the testing/security/SEO sprint
11
+ * imhcode report → Generate PROJECT_REPORT.md for the team
11
12
  * imhcode agent list → List all discovered agents
12
13
  * imhcode agent inspect <id> → Show full manifest + loaded skills
13
14
  * imhcode agent run <id> "<task>" → Run agent (dry-run by default)
14
15
  * --engine <cli> → Override engine (claude|opencode|codex|agy|qwen|mimo)
15
- * -m, --model <model> → Override model
16
- * --live → Call real LLM
17
- * --output <path> → Custom session output directory
16
+ * -m, --model <model> → Override model
17
+ * --live → Call real LLM
18
+ * --output <path> → Custom session output directory
18
19
  */
19
20
 
20
21
  'use strict';
21
22
 
22
23
  const fs = require('fs');
23
24
  const path = require('path');
24
- const { execSync } = require('child_process');
25
+ const { execSync, spawnSync } = require('child_process');
25
26
  const os = require('os');
26
27
  const readline = require('readline');
27
28
 
@@ -71,6 +72,11 @@ if (command === 'plan') {
71
72
  console.error(err.message ?? err);
72
73
  process.exit(1);
73
74
  });
75
+ } else if (command === 'report') {
76
+ runReportCommand(args.slice(1)).catch(err => {
77
+ console.error(err.message ?? err);
78
+ process.exit(1);
79
+ });
74
80
  } else if (command === 'agent') {
75
81
  runAgentCommand(subcommand, args.slice(2)).catch(err => {
76
82
  console.error(err.message ?? err);
@@ -100,9 +106,10 @@ function printGeneralHelp() {
100
106
 
101
107
  Usage:
102
108
  ${CLI_CMD} → Initialize project (engine scan + model routing setup)
103
- ${CLI_CMD} plan → Smart: brainstorm OR generate sprint plan
109
+ ${CLI_CMD} plan → Smart: brainstorm (LLM) OR generate sprint plan (LLM)
104
110
  ${CLI_CMD} execute [N] → Execute sprint N with intelligent model routing
105
111
  ${CLI_CMD} test → Run final testing/security/SEO sprint
112
+ ${CLI_CMD} report → Generate PROJECT_REPORT.md for the team
106
113
  ${CLI_CMD} agent list → List all 19 generic agents
107
114
  ${CLI_CMD} agent inspect <id> → Show agent manifest + loaded skills
108
115
  ${CLI_CMD} agent run <id> "<task>" → Run agent (dry-run by default)
@@ -112,58 +119,53 @@ function printGeneralHelp() {
112
119
  --output <path> → Save session to custom path
113
120
 
114
121
  Pipeline:
115
- 1. ${CLI_CMD} → Init project
116
- 2. Edit docs/start.md → Write your problem/prompt
117
- 3. ${CLI_CMD} plan → Generates docs/brainstorming.md with Q&A
122
+ 1. ${CLI_CMD} → Init project (no frontend/backend dirs yet)
123
+ 2. Edit docs/start.md → Answer scope questions + write your description
124
+ 3. ${CLI_CMD} plan → Generates docs/brainstorming.md (via planning LLM)
118
125
  4. Edit docs/brainstorming.md → Review/edit recommended answers
119
- 5. ${CLI_CMD} plan → Reads answers → generates sprint plans
120
- 6. ${CLI_CMD} execute 1 → Execute sprint 1 (pure code, no tests)
126
+ 5. ${CLI_CMD} plan → Reads answers → generates sprint plans (via planning LLM)
127
+ 6. ${CLI_CMD} execute 1 → Execute sprint 1 (each task uses its routed model)
121
128
  7. ${CLI_CMD} execute 2 → Execute sprint 2
122
129
  8. ${CLI_CMD} test → Final testing, security + SEO audit
130
+ 9. ${CLI_CMD} report → Generate PROJECT_REPORT.md
123
131
 
124
132
  Agents (19 generic — no persona names):
125
- planner → Project planning, brainstorming, sprint coordination
126
- designer → UX/UI design (Mimo v2.5 Pro preferred)
127
- nextjs-executor → Next.js full-stack (Mimo v2.5 Pro preferred)
128
- react-executor → React/Vite SPA
129
- vue-executor → Vue 3 / Nuxt 4
130
- laravel-executor → Laravel full-stack (DeepSeek V4 Pro preferred)
131
- python-executor → Python / Django / FastAPI
132
- java-executor → Java / Spring Boot
133
- flutter-executor → Flutter / Dart
134
- react-native-executor → React Native / Expo
135
- ios-executor → iOS / SwiftUI
136
- android-executor → Android / Kotlin
137
- systems-executor → Go / Rust / C++
138
- web3-executor → Solidity / Web3
139
- devops-executor → Docker / CI/CD
140
- tester → QA + E2E testing (GPT-5.5 preferred)
141
- security-auditor → Security audit (GPT-5.5 preferred)
142
- seo-optimizer → SEO / Content (GPT-5.5 preferred)
143
- debugger → Debugging / Root cause
133
+ planner → Project planning, brainstorming, sprint coordination [planning model]
134
+ designer → UX/UI design [frontend model — Mimo v2.5 Pro preferred]
135
+ nextjs-executor → Next.js full-stack [frontend model — Mimo v2.5 Pro preferred]
136
+ react-executor → React/Vite SPA [frontend model]
137
+ vue-executor → Vue 3 / Nuxt 4 [frontend model]
138
+ laravel-executor → Laravel full-stack [backend model — DeepSeek V4 Pro preferred]
139
+ python-executor → Python / Django / FastAPI [backend model]
140
+ java-executor → Java / Spring Boot [backend model]
141
+ flutter-executor → Flutter / Dart [backend model]
142
+ react-native-executor → React Native / Expo [backend model]
143
+ ios-executor → iOS / SwiftUI [backend model]
144
+ android-executor → Android / Kotlin [backend model]
145
+ systems-executor → Go / Rust / C++ [backend model]
146
+ web3-executor → Solidity / Web3 [backend model]
147
+ devops-executor → Docker / CI/CD [backend model]
148
+ tester → QA + E2E testing [testing model — GPT-5.5 preferred]
149
+ security-auditor → Security audit [testing model — GPT-5.5 preferred]
150
+ seo-optimizer → SEO / Content [review model — GPT-5.5 preferred]
151
+ debugger → Debugging / Root cause [review model]
144
152
 
145
153
  ${CLI_CMD} --version, -v → Print version
146
154
  ${CLI_CMD} --help, -h → Print this help
147
155
  `);
148
156
  }
149
157
 
150
- // ─── imhcode plan (Smart State Machine) ───────────────────────────────────────
158
+ // ─── imhcode plan (Smart State Machine + LLM-Powered) ─────────────────────────
151
159
 
152
160
  async function runPlanCommand(restArgs) {
153
161
  const cwd = process.cwd();
154
- const startMdPath = path.join(cwd, START_MD);
162
+ const startMdPath = path.join(cwd, START_MD);
155
163
  const brainstormPath = path.join(cwd, BRAINSTORM_MD);
156
- const briefPath = path.join(cwd, BRIEF_MD);
164
+ const hasSprintDocs = detectSprintDocs(cwd);
157
165
 
158
166
  console.log(`\n🕌 ${PLATFORM_NAME} — Plan Command\n`);
159
167
 
160
- // State detection
161
- const hasStartMd = fs.existsSync(startMdPath);
162
- const hasBrainstorm = fs.existsSync(brainstormPath);
163
- const hasBrief = fs.existsSync(briefPath);
164
- const hasSprintDocs = detectSprintDocs(cwd);
165
-
166
- if (!hasStartMd) {
168
+ if (!fs.existsSync(startMdPath)) {
167
169
  console.log(`❌ docs/start.md not found.\n`);
168
170
  console.log(` Create docs/start.md and write your project description inside it.`);
169
171
  console.log(` Then run "imhcode plan" again.\n`);
@@ -171,9 +173,9 @@ async function runPlanCommand(restArgs) {
171
173
  process.exit(1);
172
174
  }
173
175
 
174
- // Read the start.md prompt
175
176
  const startContent = fs.readFileSync(startMdPath, 'utf8');
176
- const userPrompt = extractPromptFromStartMd(startContent);
177
+ const userPrompt = extractPromptFromStartMd(startContent);
178
+ const scopeHints = extractScopeHints(startContent);
177
179
 
178
180
  if (!userPrompt || userPrompt.trim().length < 10) {
179
181
  console.log(`❌ docs/start.md has no project description.\n`);
@@ -184,31 +186,44 @@ async function runPlanCommand(restArgs) {
184
186
  process.exit(1);
185
187
  }
186
188
 
187
- // ── State 1: No brainstorming yet → generate brainstorming.md ────────────
188
- if (!hasBrainstorm) {
189
- console.log(`📋 Phase 2: Generating brainstorming document...\n`);
190
- console.log(` Reading your project description from docs/start.md...`);
191
- console.log(` Prompt: "${userPrompt.slice(0, 100)}${userPrompt.length > 100 ? '...' : ''}"\n`);
189
+ const config = loadLocalConfig(cwd);
190
+
191
+ // ── State 1: No brainstorming yet → generate brainstorming.md via LLM ──────
192
+ if (!fs.existsSync(brainstormPath)) {
193
+ console.log(`📋 Phase 2: Generating brainstorming document via planning AI...\n`);
194
+ console.log(` Project: "${userPrompt.slice(0, 100)}${userPrompt.length > 100 ? '...' : ''}"`);
195
+
196
+ const planningRouting = config?.model_routing?.planning;
197
+ if (planningRouting) {
198
+ console.log(` Model: ${planningRouting.model} via ${planningRouting.engine}`);
199
+ } else {
200
+ console.log(` Model: (fallback static template — run imhcode to configure model routing)`);
201
+ }
202
+ console.log('');
192
203
 
193
- await generateBrainstormingDoc(cwd, userPrompt);
204
+ await generateBrainstormingDoc(cwd, userPrompt, scopeHints, config);
194
205
 
195
206
  console.log(`\n✅ Brainstorming document created: docs/brainstorming.md\n`);
196
207
  console.log(`─`.repeat(60));
197
208
  console.log(`\n📝 NEXT STEPS:\n`);
198
209
  console.log(` 1. Open docs/brainstorming.md`);
199
- console.log(` 2. Review the auto-recommended answers`);
210
+ console.log(` 2. Review the AI-recommended answers`);
200
211
  console.log(` 3. Edit any answers you want to customize`);
201
212
  console.log(` 4. Run "imhcode plan" again to generate sprint plans\n`);
202
213
  console.log(`─`.repeat(60));
203
214
  return;
204
215
  }
205
216
 
206
- // ── State 2: Brainstorming exists, no sprint plans → generate sprints ─────
207
- if (hasBrainstorm && !hasSprintDocs) {
208
- console.log(`📋 Phase 3-4: Reading brainstorming answers → generating sprint plans...\n`);
217
+ // ── State 2: Brainstorming exists, no sprint plans → generate sprints via LLM
218
+ if (!hasSprintDocs) {
219
+ console.log(`📋 Phase 3-4: Reading brainstorming answers → generating sprint plans via AI...\n`);
209
220
 
210
221
  const brainstormContent = fs.readFileSync(brainstormPath, 'utf8');
211
- const config = loadLocalConfig(cwd);
222
+ const planningRouting = config?.model_routing?.planning;
223
+ if (planningRouting) {
224
+ console.log(` Model: ${planningRouting.model} via ${planningRouting.engine}`);
225
+ }
226
+ console.log('');
212
227
 
213
228
  await generateSprintPlans(cwd, userPrompt, brainstormContent, config);
214
229
 
@@ -218,27 +233,26 @@ async function runPlanCommand(restArgs) {
218
233
  console.log(` 1. Review docs/sprint-1/plan.md`);
219
234
  console.log(` 2. Run "imhcode execute 1" to start Sprint 1`);
220
235
  console.log(` 3. Then "imhcode execute 2", "imhcode execute 3", etc.`);
221
- console.log(` 4. Run "imhcode test" for the final testing sprint\n`);
236
+ console.log(` 4. Run "imhcode test" for the final testing sprint`);
237
+ console.log(` 5. Run "imhcode report" to generate the team report\n`);
222
238
  console.log(`─`.repeat(60));
223
239
  return;
224
240
  }
225
241
 
226
242
  // ── State 3: Sprints already exist ───────────────────────────────────────
227
- if (hasSprintDocs) {
228
- const currentSprint = detectCurrentSprint(cwd);
229
- console.log(`ℹ️ Sprint plans already exist (current sprint: Sprint ${currentSprint}).\n`);
230
- console.log(` Use "imhcode execute ${currentSprint}" to run the current sprint.`);
231
- console.log(` Use "imhcode test" to run the final testing sprint.\n`);
232
- console.log(` To re-plan from scratch, delete docs/brainstorming.md and run "imhcode plan".\n`);
233
- }
243
+ const currentSprint = detectCurrentSprint(cwd);
244
+ console.log(`ℹ️ Sprint plans already exist (current sprint: Sprint ${currentSprint}).\n`);
245
+ console.log(` Use "imhcode execute ${currentSprint}" to run the current sprint.`);
246
+ console.log(` Use "imhcode test" to run the final testing sprint.\n`);
247
+ console.log(` To re-plan from scratch, delete docs/brainstorming.md and run "imhcode plan".\n`);
234
248
  }
235
249
 
236
250
  // ─── imhcode execute [N] ──────────────────────────────────────────────────────
237
251
 
238
252
  async function runExecuteCommand(restArgs) {
239
253
  const cwd = process.cwd();
240
- const sprintNum = resolveSprintNum(restArgs, cwd);
241
- const sprintDir = path.join(cwd, DOCS_DIR, `sprint-${sprintNum}`);
254
+ const sprintNum = resolveSprintNum(restArgs, cwd);
255
+ const sprintDir = path.join(cwd, DOCS_DIR, `sprint-${sprintNum}`);
242
256
  const masterScript = path.join(sprintDir, 'run_all_tasks.sh');
243
257
  const progressPath = path.join(sprintDir, 'progress.md');
244
258
 
@@ -259,17 +273,17 @@ async function runExecuteCommand(restArgs) {
259
273
  // Read plan to show what will be executed
260
274
  const planPath = path.join(sprintDir, 'plan.md');
261
275
  if (fs.existsSync(planPath)) {
262
- const plan = fs.readFileSync(planPath, 'utf8');
276
+ const plan = fs.readFileSync(planPath, 'utf8');
263
277
  const taskCount = (plan.match(/^##\s+Task/gm) || []).length;
264
278
  console.log(` Sprint: ${sprintNum}`);
265
279
  console.log(` Tasks: ${taskCount}`);
266
280
  console.log(` Script: ${masterScript}\n`);
267
281
  }
268
282
 
269
- // Check model routing config
283
+ // Show active model routing
270
284
  const config = loadLocalConfig(cwd);
271
285
  if (config?.model_routing) {
272
- console.log(` Model Routing:`);
286
+ console.log(` Model Routing (active):`);
273
287
  for (const [cat, routing] of Object.entries(config.model_routing)) {
274
288
  if (routing && typeof routing === 'object') {
275
289
  console.log(` ${cat.padEnd(12)}: ${routing.model} (${routing.engine})`);
@@ -278,17 +292,13 @@ async function runExecuteCommand(restArgs) {
278
292
  console.log('');
279
293
  }
280
294
 
281
- try {
282
- fs.chmodSync(masterScript, 0o755);
283
- } catch { /* ignore on Windows */ }
295
+ try { fs.chmodSync(masterScript, 0o755); } catch { /* ignore on Windows */ }
284
296
 
285
297
  console.log(`─`.repeat(60));
286
298
  try {
287
299
  execSync(`sh "${masterScript}"`, { stdio: 'inherit', cwd });
288
300
  console.log(`─`.repeat(60));
289
301
  console.log(`\n🏁 Sprint ${sprintNum} execution complete!\n`);
290
-
291
- // Update compact context after sprint
292
302
  await updateCompactContext(cwd, sprintNum);
293
303
  } catch (err) {
294
304
  console.log(`─`.repeat(60));
@@ -301,48 +311,235 @@ async function runExecuteCommand(restArgs) {
301
311
  // ─── imhcode test ─────────────────────────────────────────────────────────────
302
312
 
303
313
  async function runTestCommand(restArgs) {
304
- const cwd = process.cwd();
305
- const lastSprint = detectLastSprint(cwd);
306
- const testingSprintNum = lastSprint + 1;
307
- const testSprintDir = path.join(cwd, DOCS_DIR, `sprint-${testingSprintNum}`);
308
- const testScript = path.join(testSprintDir, 'run_all_tasks.sh');
314
+ const cwd = process.cwd();
315
+ const lastSprint = detectLastSprint(cwd);
316
+ const testSprintNum = lastSprint + 1;
317
+ const testSprintDir = path.join(cwd, DOCS_DIR, `sprint-${testSprintNum}`);
318
+ const testScript = path.join(testSprintDir, 'run_all_tasks.sh');
309
319
 
310
320
  console.log(`\n🕌 ${PLATFORM_NAME} — Testing Sprint\n`);
311
321
 
312
322
  if (fs.existsSync(testScript)) {
313
- // Run existing test sprint
314
- console.log(` Running auto-generated testing sprint (Sprint ${testingSprintNum})...\n`);
315
- try {
316
- fs.chmodSync(testScript, 0o755);
317
- } catch { /* ignore */ }
323
+ console.log(` Running auto-generated testing sprint (Sprint ${testSprintNum})...\n`);
324
+ try { fs.chmodSync(testScript, 0o755); } catch { /* ignore */ }
318
325
  console.log(`─`.repeat(60));
319
326
  try {
320
327
  execSync(`sh "${testScript}"`, { stdio: 'inherit', cwd });
321
328
  console.log(`─`.repeat(60));
322
- console.log(`\n✅ Testing sprint complete! Check docs/sprint-${testingSprintNum}/ for reports.\n`);
329
+ console.log(`\n✅ Testing sprint complete! Check docs/sprint-${testSprintNum}/ for reports.\n`);
323
330
  } catch {
324
331
  console.error(`\n❌ Testing sprint failed. Check output above.\n`);
325
332
  process.exit(1);
326
333
  }
327
334
  } else {
328
- // Guide user to generate the test sprint
329
335
  console.log(` ℹ️ No testing sprint found yet.\n`);
330
- console.log(` The testing sprint is auto-generated when you run "imhcode plan" and`);
331
- console.log(` select "Fast Mode" or "Balanced Mode" for testing strategy.\n`);
336
+ console.log(` The testing sprint is auto-generated when you run "imhcode plan".\n`);
332
337
  console.log(` To generate it now, run:\n`);
333
- console.log(` imhcode agent run planner "Generate testing sprint for Sprint ${testingSprintNum}" --live\n`);
338
+ console.log(` imhcode agent run planner "Generate testing sprint for Sprint ${testSprintNum}" --live\n`);
334
339
  }
335
340
  }
336
341
 
342
+ // ─── imhcode report ───────────────────────────────────────────────────────────
343
+
344
+ async function runReportCommand(restArgs) {
345
+ const cwd = process.cwd();
346
+ const reportPath = path.join(cwd, 'PROJECT_REPORT.md');
347
+ const config = loadLocalConfig(cwd);
348
+ const lastSprint = detectLastSprint(cwd);
349
+
350
+ console.log(`\n🕌 ${PLATFORM_NAME} — Generating Project Report\n`);
351
+
352
+ // Gather all project data
353
+ const briefContent = safeRead(path.join(cwd, BRIEF_MD));
354
+ const brainstormContent = safeRead(path.join(cwd, BRAINSTORM_MD));
355
+ const startContent = safeRead(path.join(cwd, START_MD));
356
+ const contextContent = safeRead(path.join(cwd, CONTEXT_MD));
357
+
358
+ const userPrompt = extractPromptFromStartMd(startContent || '');
359
+
360
+ // Gather sprint data
361
+ const sprintData = [];
362
+ for (let i = 1; i <= lastSprint + 1; i++) {
363
+ const sprintDir = path.join(cwd, DOCS_DIR, `sprint-${i}`);
364
+ const planMd = safeRead(path.join(sprintDir, 'plan.md'));
365
+ const progressMd = safeRead(path.join(sprintDir, 'progress.md'));
366
+ const deferredMd = safeRead(path.join(sprintDir, 'deferred.md'));
367
+ if (planMd || progressMd) {
368
+ sprintData.push({ sprintNum: i, plan: planMd, progress: progressMd, deferred: deferredMd });
369
+ }
370
+ }
371
+
372
+ // Build model routing summary
373
+ let modelRoutingSummary = '';
374
+ if (config?.model_routing) {
375
+ const rows = Object.entries(config.model_routing).map(([cat, r]) =>
376
+ `| ${cat.padEnd(10)} | ${(r?.engine || '?').padEnd(12)} | ${r?.model || '?'} |`
377
+ ).join('\n');
378
+ modelRoutingSummary = `| Category | Engine | Model |\n|------------|--------------|-------|\n${rows}`;
379
+ }
380
+
381
+ // Build sprint log table
382
+ const sprintLogTable = sprintData.map(s => {
383
+ const titleMatch = s.plan?.match(/^# Sprint \d+: (.+)$/m);
384
+ const title = titleMatch ? titleMatch[1] : `Sprint ${s.sprintNum}`;
385
+ const tasksDone = (s.progress?.match(/- \[x\]/g) || []).length;
386
+ const tasksTotal = (s.progress?.match(/- \[/g) || []).length;
387
+ const status = tasksTotal > 0 && tasksDone === tasksTotal ? '✅ Complete' :
388
+ tasksDone > 0 ? `🔄 In Progress (${tasksDone}/${tasksTotal})` : '⬜ Pending';
389
+ return `| ${s.sprintNum} | ${title} | ${status} |`;
390
+ }).join('\n');
391
+
392
+ // Build agent usage table from sprint plans
393
+ const agentUsage = {};
394
+ for (const s of sprintData) {
395
+ if (!s.plan) continue;
396
+ const agentMatches = s.plan.matchAll(/`([a-z-]+-executor|planner|designer|tester|security-auditor|seo-optimizer|debugger)`/g);
397
+ for (const m of agentMatches) {
398
+ agentUsage[m[1]] = (agentUsage[m[1]] || 0) + 1;
399
+ }
400
+ }
401
+ const agentTable = Object.entries(agentUsage)
402
+ .sort((a, b) => b[1] - a[1])
403
+ .map(([agent, count]) => `| \`${agent}\` | ${getAgentCategory(agent)} | ${count} tasks |`)
404
+ .join('\n');
405
+
406
+ // Build deferred items list
407
+ const deferredItems = sprintData
408
+ .filter(s => s.deferred && !s.deferred.includes('None yet'))
409
+ .map(s => `\n### Sprint ${s.sprintNum} Deferred\n\n${s.deferred}`)
410
+ .join('');
411
+
412
+ // Detect stack from brainstorm/context
413
+ const stack = [];
414
+ if (brainstormContent || contextContent) {
415
+ const combined = (brainstormContent || '') + (contextContent || '');
416
+ if (/next\.?js/i.test(combined)) stack.push('Next.js');
417
+ if (/vue/i.test(combined)) stack.push('Vue 3 / Nuxt 4');
418
+ if (/react\s*native/i.test(combined)) stack.push('React Native');
419
+ if (/flutter/i.test(combined)) stack.push('Flutter');
420
+ if (/laravel/i.test(combined)) stack.push('Laravel');
421
+ if (/django|fastapi/i.test(combined)) stack.push('Python / FastAPI');
422
+ if (/spring\s*boot/i.test(combined)) stack.push('Java / Spring Boot');
423
+ if (/postgres/i.test(combined)) stack.push('PostgreSQL');
424
+ if (/redis/i.test(combined)) stack.push('Redis');
425
+ if (/docker/i.test(combined)) stack.push('Docker');
426
+ if (/tailwind/i.test(combined)) stack.push('Tailwind CSS');
427
+ if (/shadcn/i.test(combined)) stack.push('shadcn/ui');
428
+ }
429
+
430
+ const report = `# 📋 IMH-Code — Project Report
431
+
432
+ > **${PLATFORM_FULL}**
433
+ > Generated: ${new Date().toLocaleString()}
434
+
435
+ ---
436
+
437
+ ## 🎯 Project Summary
438
+
439
+ ${userPrompt || '*(See PROJECT_BRIEF.md for details)*'}
440
+
441
+ ---
442
+
443
+ ## 🏗️ Technology Stack
444
+
445
+ ${stack.length > 0 ? stack.map(s => `- ${s}`).join('\n') : '*(Stack detected from brainstorming and sprint plans)*'}
446
+
447
+ ---
448
+
449
+ ## 🤖 AI Model Routing Used
450
+
451
+ ${modelRoutingSummary || '*(No imhcode.config.json found)*'}
452
+
453
+ ---
454
+
455
+ ## 🏃 Sprint Execution Log
456
+
457
+ | Sprint | Title | Status |
458
+ |--------|-------|--------|
459
+ ${sprintLogTable || '| — | No sprints found | — |'}
460
+
461
+ ---
462
+
463
+ ## 🔧 Agent Execution Summary
464
+
465
+ | Agent | Category | Usage |
466
+ |-------|----------|-------|
467
+ ${agentTable || '*(No sprint plans found)*'}
468
+
469
+ ---
470
+
471
+ ## 🚀 How to Run This Project
472
+
473
+ \`\`\`bash
474
+ # 1. Install dependencies
475
+ ${stack.includes('Next.js') || stack.includes('Vue 3 / Nuxt 4') ? 'cd frontend && npm install' : ''}
476
+ ${stack.includes('Laravel') ? 'cd backend && composer install && php artisan key:generate' : ''}
477
+ ${stack.includes('Python / FastAPI') ? 'cd backend && pip install -r requirements.txt' : ''}
478
+
479
+ # 2. Set environment variables
480
+ cp .env.example .env # Edit with your config
481
+
482
+ # 3. Run development server
483
+ ${stack.includes('Next.js') ? 'cd frontend && npm run dev # → http://localhost:3000' : ''}
484
+ ${stack.includes('Vue 3 / Nuxt 4') ? 'cd frontend && npm run dev # → http://localhost:3000' : ''}
485
+ ${stack.includes('Laravel') ? 'cd backend && php artisan serve # → http://localhost:8000' : ''}
486
+ ${stack.includes('Python / FastAPI') ? 'cd backend && uvicorn main:app --reload' : ''}
487
+ \`\`\`
488
+
489
+ ---
490
+
491
+ ## 📂 Project Structure
492
+
493
+ \`\`\`
494
+ ${path.basename(cwd)}/
495
+ ├── docs/ ← Sprint plans & documentation
496
+ │ ├── start.md ← Project description (input)
497
+ │ ├── brainstorming.md ← Brainstorming Q&A
498
+ │ └── sprint-*/ ← Sprint plans, tasks, progress
499
+ ├── ${fs.existsSync(path.join(cwd, 'frontend')) ? 'frontend/ ← Frontend application\n├── ' : ''}${fs.existsSync(path.join(cwd, 'backend')) ? 'backend/ ← Backend application\n├── ' : ''}.imhcode/ ← IMH-Code context & sessions
500
+ ├── imhcode.config.json ← Engine & model routing config
501
+ └── PROJECT_BRIEF.md ← Central project context
502
+ \`\`\`
503
+
504
+ ---
505
+
506
+ ## 📌 Known Issues & Deferred Items
507
+
508
+ ${deferredItems || '*(No deferred items logged)*'}
509
+
510
+ ---
511
+
512
+ ## 📊 Development Metrics
513
+
514
+ | Metric | Value |
515
+ |--------|-------|
516
+ | Total Sprints | ${sprintData.length} |
517
+ | Agents Used | ${Object.keys(agentUsage).length} |
518
+ | Testing Mode | ${config?.testing_mode || 'fast'} |
519
+ | Primary Engine | ${config?.primary_engine || 'N/A'} |
520
+
521
+ ---
522
+
523
+ *Report generated by ${PLATFORM_NAME} — ${PLATFORM_FULL}*
524
+ `;
525
+
526
+ fs.writeFileSync(reportPath, report, 'utf8');
527
+ console.log(`✅ PROJECT_REPORT.md created!\n`);
528
+ console.log(` Path: ${reportPath}`);
529
+ console.log(` Sprints covered: ${sprintData.length}`);
530
+ console.log(` Agents referenced: ${Object.keys(agentUsage).length}\n`);
531
+ console.log(` Share this file with your team for a complete project overview.\n`);
532
+ }
533
+
337
534
  // ─── imhcode agent ────────────────────────────────────────────────────────────
338
535
 
339
536
  async function runAgentCommand(subcommand, restArgs) {
340
537
  const orchestrator = loadOrchestrator();
341
538
 
342
539
  switch (subcommand) {
343
- case 'list': return cmdList(orchestrator, restArgs);
540
+ case 'list': return cmdList(orchestrator, restArgs);
344
541
  case 'inspect': return cmdInspect(orchestrator, restArgs);
345
- case 'run': return cmdRun(orchestrator, restArgs);
542
+ case 'run': return cmdRun(orchestrator, restArgs);
346
543
  default:
347
544
  printAgentHelp();
348
545
  process.exit(0);
@@ -391,49 +588,33 @@ async function cmdList(orc, _args) {
391
588
  return;
392
589
  }
393
590
 
591
+ const config = loadLocalConfig(cwd);
592
+
394
593
  const rows = [...agents.values()].map(a => ({
395
- id: a.manifest.id,
396
- role: a.manifest.role,
397
- model: a.manifest.default_model,
594
+ id: a.manifest.id,
595
+ role: a.manifest.role,
398
596
  category: getAgentCategory(a.manifest.id),
597
+ model: config?.model_routing?.[getAgentCategory(a.manifest.id)]?.model || a.manifest.default_model,
598
+ engine: config?.model_routing?.[getAgentCategory(a.manifest.id)]?.engine || '?',
399
599
  }));
400
600
 
401
- console.log('┌─────────────────────────────────────────────────────────────────────────────┐');
402
- console.log(`│ ${PLATFORM_NAME} AGENT REGISTRY │`);
403
- console.log('├──────────────────────────┬────────────────┬──────────────┬──────────────────┤');
404
- console.log('│ ID │ Category │ Model │ Role │');
405
- console.log('├──────────────────────────┼────────────────┼──────────────┼──────────────────┤');
601
+ const colId = Math.max(...rows.map(r => r.id.length), 2);
602
+ const colRole = Math.max(...rows.map(r => r.role.length), 4);
603
+ const colCat = Math.max(...rows.map(r => r.category.length), 8);
604
+ const colEng = Math.max(...rows.map(r => r.engine.length), 6);
406
605
 
407
- for (const row of rows) {
408
- const id = row.id.padEnd(24).slice(0, 24);
409
- const cat = row.category.padEnd(14).slice(0, 14);
410
- const mdl = row.model.padEnd(12).slice(0, 12);
411
- const rol = row.role.padEnd(16).slice(0, 16);
412
- console.log(`│ ${id} │ ${cat} │ ${mdl} │ ${rol} │`);
413
- }
606
+ console.log(` ${'ID'.padEnd(colId)} ${'Role'.padEnd(colRole)} ${'Category'.padEnd(colCat)} ${'Engine'.padEnd(colEng)} Model`);
607
+ console.log(` ${'─'.repeat(colId)} ${'─'.repeat(colRole)} ${'─'.repeat(colCat)} ${'─'.repeat(colEng)} ${'─'.repeat(32)}`);
414
608
 
415
- console.log('└──────────────────────────┴────────────────┴──────────────┴──────────────────┘');
416
- console.log(`\n Total: ${agents.size} agent(s) Use "imhcode agent inspect <id>" for details.\n`);
609
+ for (const r of rows) {
610
+ console.log(` ${r.id.padEnd(colId)} ${r.role.padEnd(colRole)} ${r.category.padEnd(colCat)} ${r.engine.padEnd(colEng)} ${r.model}`);
611
+ }
417
612
 
418
613
  if (errors.length > 0) {
419
- console.log(`⚠️ ${errors.length} agent(s) failed to load:\n`);
420
- for (const { agentId, error } of errors) {
421
- console.log(` ❌ ${agentId}: ${error.split('\n')[0]}\n`);
422
- }
614
+ console.log(`\n ⚠️ ${errors.length} agent(s) failed to load:`);
615
+ errors.forEach(e => console.log(` • ${e.agentId}: ${e.error}`));
423
616
  }
424
- }
425
-
426
- function getAgentCategory(agentId) {
427
- const map = {
428
- 'planner': 'planning', 'designer': 'frontend',
429
- 'nextjs-executor': 'frontend', 'react-executor': 'frontend', 'vue-executor': 'frontend',
430
- 'laravel-executor': 'backend', 'python-executor': 'backend', 'java-executor': 'backend',
431
- 'flutter-executor': 'backend', 'react-native-executor': 'backend', 'ios-executor': 'backend',
432
- 'android-executor': 'backend', 'systems-executor': 'backend', 'web3-executor': 'backend',
433
- 'devops-executor': 'backend', 'tester': 'testing', 'security-auditor': 'testing',
434
- 'seo-optimizer': 'review', 'debugger': 'review',
435
- };
436
- return map[agentId] || 'backend';
617
+ console.log('');
437
618
  }
438
619
 
439
620
  async function cmdInspect(orc, args) {
@@ -444,7 +625,7 @@ async function cmdInspect(orc, args) {
444
625
  }
445
626
 
446
627
  const agentsDir = resolveAgentsDir();
447
- const cwd = process.cwd();
628
+ const cwd = process.cwd();
448
629
  console.log(`\n🔍 Loading agent: ${agentId}\n`);
449
630
 
450
631
  const { agents, errors } = await orc.loadRegistry(agentsDir, cwd);
@@ -459,36 +640,47 @@ async function cmdInspect(orc, args) {
459
640
  const { manifest, systemPrompt, skills, dir } = agent;
460
641
  const divider = '─'.repeat(72);
461
642
 
462
- // Load config to show routing
463
- const config = loadLocalConfig(cwd);
643
+ const config = loadLocalConfig(cwd);
464
644
  const category = getAgentCategory(manifest.id);
465
- const routing = config?.model_routing?.[category];
645
+ const routing = config?.model_routing?.[category];
466
646
 
467
647
  console.log(divider);
468
648
  console.log(` ${manifest.name} (v${manifest.version})`);
469
649
  console.log(divider);
470
- console.log(` ID: ${manifest.id}`);
471
- console.log(` Role: ${manifest.role}`);
472
- console.log(` Category: ${category}`);
473
- console.log(` Description: ${manifest.description.replace(/\n\s*/g, ' ')}`);
474
- console.log(` Directory: ${dir}`);
650
+ console.log(` ID: ${manifest.id}`);
651
+ console.log(` Role: ${manifest.role}`);
652
+ console.log(` Category: ${category}`);
653
+ console.log(` Description: ${manifest.description.replace(/\n\s*/g, ' ')}`);
654
+ console.log(` Directory: ${dir}`);
475
655
  console.log(` Default Model: ${manifest.default_model}`);
476
656
  if (routing) {
477
- console.log(` Routed Model: ${routing.model} via ${routing.engine} (from imhcode.config.json)`);
657
+ console.log(` Routed Model: ${routing.model} via ${routing.engine} (from imhcode.config.json) ✅`);
658
+ } else {
659
+ console.log(` Routed Model: (none — run imhcode to configure model routing)`);
478
660
  }
479
- console.log(` Fallbacks: ${manifest.fallback_engines.join(', ') || '(none)'}`);
661
+ console.log(` Fallbacks: ${manifest.fallback_engines.join(', ') || '(none)'}`);
480
662
  console.log(`\n Core Skills: ${skills.length} loaded`);
481
- for (const skill of skills) {
482
- console.log(` ► ${skill.id}`);
483
- }
484
- console.log(`\n${divider}\n`);
485
- console.log(` Run this agent with:`);
486
- console.log(` imhcode agent run ${manifest.id} "Your task" --live\n`);
663
+ skills.forEach(s => console.log(` • ${s.name} ${s.description?.slice(0, 80) ?? ''}`));
664
+
665
+ const promptLines = systemPrompt.split('\n').length;
666
+ console.log(`\n System Prompt: ${promptLines} lines\n`);
667
+ console.log(divider + '\n');
668
+ }
669
+
670
+ function printAgentHelp() {
671
+ console.log(`\n ${PLATFORM_NAME} — Agent Commands\n`);
672
+ console.log(` imhcode agent list → List all agents with routed models`);
673
+ console.log(` imhcode agent inspect <id> → Show agent details + routing`);
674
+ console.log(` imhcode agent run <id> "<task>" → Dry-run (no LLM call)`);
675
+ console.log(` imhcode agent run <id> "<task>" --live → Call real LLM with routed model`);
676
+ console.log(` --engine <cli> → Override engine`);
677
+ console.log(` -m, --model <m> → Override model`);
678
+ console.log(` --output <path> → Save session to custom path\n`);
487
679
  }
488
680
 
489
681
  async function cmdRun(orc, args) {
490
682
  const agentId = args[0];
491
- const task = args[1];
683
+ const task = args[1];
492
684
 
493
685
  if (!agentId || !task) {
494
686
  console.error(`❌ Usage: imhcode agent run <agent-id> "<task description>" [options]`);
@@ -499,23 +691,27 @@ async function cmdRun(orc, args) {
499
691
  process.exit(1);
500
692
  }
501
693
 
502
- const restArgs = args.slice(2);
503
- const live = restArgs.includes('--live');
504
- const engineIdx = restArgs.indexOf('--engine');
505
- const engine = engineIdx >= 0 ? restArgs[engineIdx + 1] : undefined;
506
- const mIndex = restArgs.indexOf('--model');
507
- const shortMIndex = restArgs.indexOf('-m');
508
- const modelIdx = mIndex >= 0 ? mIndex : shortMIndex;
509
- const model = modelIdx >= 0 ? restArgs[modelIdx + 1] : undefined;
510
- const criteriaIdx = restArgs.indexOf('--criteria');
511
- const criteria = criteriaIdx >= 0 ? restArgs[criteriaIdx + 1] : undefined;
512
- const outputIdx = restArgs.indexOf('--output');
513
- const outputDir = outputIdx >= 0 ? restArgs[outputIdx + 1] : undefined;
694
+ const restArgs = args.slice(2);
695
+ const live = restArgs.includes('--live');
696
+ const engineIdx = restArgs.indexOf('--engine');
697
+ const engine = engineIdx >= 0 ? restArgs[engineIdx + 1] : undefined;
698
+ const mIndex = restArgs.indexOf('--model');
699
+ const shortMIndex = restArgs.indexOf('-m');
700
+ const modelIdx = mIndex >= 0 ? mIndex : shortMIndex;
701
+ const model = modelIdx >= 0 ? restArgs[modelIdx + 1] : undefined;
702
+ const criteriaIdx = restArgs.indexOf('--criteria');
703
+ const criteria = criteriaIdx >= 0 ? restArgs[criteriaIdx + 1] : undefined;
704
+ const outputIdx = restArgs.indexOf('--output');
705
+ const outputDir = outputIdx >= 0 ? restArgs[outputIdx + 1] : undefined;
514
706
 
515
707
  const agentsDir = resolveAgentsDir();
516
- const cwd = process.cwd();
517
- const config = loadLocalConfig(cwd);
518
- const category = getAgentCategory(agentId);
708
+ const cwd = process.cwd();
709
+ const config = loadLocalConfig(cwd);
710
+ const category = getAgentCategory(agentId);
711
+
712
+ // Fix 0b Part A: Auto-inject routing when no explicit override provided
713
+ const routedEngine = engine ?? config?.model_routing?.[category]?.engine;
714
+ const routedModel = model ?? config?.model_routing?.[category]?.model;
519
715
 
520
716
  console.log(`\n🕌 ${PLATFORM_NAME} — Agent Execution`);
521
717
  console.log(` Agent: ${agentId}`);
@@ -523,12 +719,10 @@ async function cmdRun(orc, args) {
523
719
  console.log(` Task: ${task}`);
524
720
  console.log(` Mode: ${live ? '🔴 LIVE (CLI execution)' : '🟡 DRY-RUN (no CLI execution)'}`);
525
721
 
526
- // Show which model will be used
527
- if (!engine && !model && config?.model_routing?.[category]) {
528
- const r = config.model_routing[category];
529
- console.log(` Model: ${r.model} via ${r.engine} (from routing config)`);
530
- } else if (model) {
531
- console.log(` Model: ${model} (explicit override)`);
722
+ if (engine || model) {
723
+ console.log(` Model: ${routedModel} via ${routedEngine} (explicit override)`);
724
+ } else if (routedEngine && routedModel) {
725
+ console.log(` Model: ${routedModel} via ${routedEngine} (auto from imhcode.config.json )`);
532
726
  }
533
727
  console.log('');
534
728
 
@@ -540,62 +734,43 @@ async function cmdRun(orc, args) {
540
734
  process.exit(1);
541
735
  }
542
736
 
543
- const agent = orc.getAgent(agents, agentId);
544
- const result = await orc.runAgent(agent, task, { dryRun: !live, engine, model, outputDir, cwd }, criteria);
737
+ const agent = orc.getAgent(agents, agentId);
738
+
739
+ // Pass the routed engine + model to runAgent (Fix 0b Part A)
740
+ const result = await orc.runAgent(
741
+ agent, task,
742
+ { dryRun: !live, engine: routedEngine, model: routedModel, outputDir, cwd },
743
+ criteria
744
+ );
545
745
 
546
746
  console.log('\n' + '─'.repeat(72));
547
747
  if (result.errors.length > 0 && !result.dryRun) {
548
748
  console.error(`\n❌ [IMH-Code] Execution failed with errors:`);
549
749
  result.errors.forEach(e => console.error(` • ${e}`));
550
-
551
- // Check if the error is a limit/failover exhaustion
750
+
552
751
  const isLimitExhausted = result.errors.some(e => e.includes('limits') && e.includes('exhausted'));
553
752
  if (isLimitExhausted) {
554
753
  const currentSprint = detectCurrentSprint(cwd);
555
754
  console.error(`\n💡 [IMH-Code] All available assistant engines hit rate/token/quota limits.`);
556
- console.error(` The context has been saved in the session logs: ${result.sessionDir || 'sessions/'}`);
557
- console.error(` Please wait for your limits/quotas to reset, then resume development by running:`);
755
+ console.error(` Context saved in: ${result.sessionDir || 'sessions/'}`);
756
+ console.error(` Wait for limits to reset, then resume with:`);
558
757
  console.error(` imhcode execute ${currentSprint}\n`);
559
758
  }
560
759
  process.exit(1);
561
760
  }
562
761
 
563
- console.log(`\n✅ Execution complete`);
564
- console.log(` Duration: ${result.durationMs}ms`);
565
- console.log(` Model: ${result.model}`);
566
- console.log(` Dry-run: ${result.dryRun}`);
567
- if (result.sessionDir) console.log(` Session log: ${result.sessionDir}`);
568
- console.log('');
569
- }
570
-
571
- function printAgentHelp() {
572
- console.log(`
573
- imhcode agent <subcommand>
574
-
575
- Subcommands:
576
- list List all 19 generic agents
577
- inspect <id> Show agent manifest, skills, and routing
578
- run <id> "<task>" [flags] Build prompt and run
579
-
580
- Flags for "run":
581
- --live Run live LLM execution
582
- --engine <cli> Override engine (claude|opencode|codex|agy|qwen|mimo)
583
- -m, --model <model> Override model
584
- --criteria "<string>" Acceptance criteria
585
- --output <path> Custom session directory
586
-
587
- Agent IDs (short aliases work too):
588
- planner (alias: plan, pm, orchestrator)
589
- nextjs-executor (alias: nextjs, next)
590
- laravel-executor (alias: laravel, php)
591
- react-executor (alias: react, vite)
592
- vue-executor (alias: vue, nuxt)
593
- python-executor (alias: python, django, fastapi)
594
- tester (alias: qa, test)
595
- security-auditor (alias: security, audit)
596
- debugger (alias: debug, fix)
597
- ... and more (run imhcode agent list)
598
- `);
762
+ if (result.dryRun) {
763
+ console.log(`\n🟡 [DRY-RUN] Prompt built successfully — ${result.prompt.split('\n').length} lines`);
764
+ console.log(` Would execute with: ${routedModel || 'default'} via ${routedEngine || 'default'}`);
765
+ console.log(` Use --live to run with the real LLM.\n`);
766
+ if (result.output) console.log(result.output);
767
+ } else {
768
+ console.log(`\n✅ [IMH-Code] Task executed successfully`);
769
+ console.log(` Model: ${result.model}`);
770
+ console.log(` Duration: ${(result.durationMs / 1000).toFixed(1)}s`);
771
+ if (result.sessionDir) console.log(` Session: ${result.sessionDir}`);
772
+ console.log('');
773
+ }
599
774
  }
600
775
 
601
776
  // ─── Legacy Sprint Commands ────────────────────────────────────────────────────
@@ -612,7 +787,7 @@ async function runSprintLegacyCommand(subcommand, restArgs) {
612
787
  }
613
788
 
614
789
  async function cmdSprintDesign(restArgs) {
615
- const cwd = process.cwd();
790
+ const cwd = process.cwd();
616
791
  const sprintNum = resolveSprintNum(restArgs, cwd);
617
792
  const sprintDir = path.join(cwd, DOCS_DIR, `sprint-${sprintNum}`);
618
793
 
@@ -649,9 +824,9 @@ async function runInit() {
649
824
  console.log(`\n🕌 Initializing ${PLATFORM_NAME}...\n`);
650
825
  console.log(` ${PLATFORM_FULL}\n`);
651
826
 
652
- const packageRoot = path.join(__dirname, '..');
653
- const imhcodeScriptPath = path.join(packageRoot, 'bin', 'imhcode.js');
654
- const cwd = process.cwd();
827
+ const packageRoot = path.join(__dirname, '..');
828
+ const imhcodeScriptPath = path.join(packageRoot, 'bin', 'imhcode.js');
829
+ const cwd = process.cwd();
655
830
 
656
831
  // Ensure global ~/.imhcode exists
657
832
  if (!fs.existsSync(GLOBAL_DIR)) {
@@ -659,14 +834,14 @@ async function runInit() {
659
834
  }
660
835
 
661
836
  const itemsToCopy = [
662
- { src: '.github', dest: '.github', desc: 'GitHub integration files' },
663
- { src: 'AGENTS.md', dest: 'AGENTS.md', desc: 'Agent manifest' },
664
- { src: 'CLAUDE.md', dest: 'CLAUDE.md', desc: 'Claude/Cursor/Copilot integration' },
665
- { src: '.gitignore.template', dest: '.gitignore', desc: 'Auto-generated gitignore' },
666
- { src: 'SETUP.md', dest: 'SETUP.md', desc: 'Setup guide' },
667
- { src: 'USER_MANUAL.md', dest: 'USER_MANUAL.md', desc: 'User manual' },
668
- { src: 'agents', dest: 'agents', desc: 'YAML-driven agent manifests' },
669
- { src: 'skills', dest: 'skills', desc: 'Skill library (SKILL.md files)' },
837
+ { src: '.github', dest: '.github', desc: 'GitHub integration files' },
838
+ { src: 'AGENTS.md', dest: 'AGENTS.md', desc: 'Agent manifest' },
839
+ { src: 'CLAUDE.md', dest: 'CLAUDE.md', desc: 'Claude/Cursor/Copilot integration' },
840
+ { src: '.gitignore.template', dest: '.gitignore', desc: 'Auto-generated gitignore' },
841
+ { src: 'SETUP.md', dest: 'SETUP.md', desc: 'Setup guide' },
842
+ { src: 'USER_MANUAL.md', dest: 'USER_MANUAL.md', desc: 'User manual' },
843
+ { src: 'agents', dest: 'agents', desc: 'YAML-driven agent manifests' },
844
+ { src: 'skills', dest: 'skills', desc: 'Skill library (SKILL.md files)' },
670
845
  ];
671
846
 
672
847
  // Copy to global ~/.imhcode (unconditionally overwrite to apply updates)
@@ -709,9 +884,11 @@ async function runInit() {
709
884
  }
710
885
  }
711
886
 
712
- // Create local workspace directories
887
+ // Fix 1: Create only ESSENTIAL local directories at init time.
888
+ // frontend/, backend/, .worktrees/ are created LATER in generateSprintPlans()
889
+ // after brainstorming answers confirm what the user actually needs.
713
890
  const dirsToCreate = [
714
- 'frontend', 'backend', '.worktrees', DOCS_DIR,
891
+ DOCS_DIR,
715
892
  LOCAL_DIR_NAME,
716
893
  path.join(LOCAL_DIR_NAME, 'commands'),
717
894
  path.join(LOCAL_DIR_NAME, 'sessions'),
@@ -724,39 +901,52 @@ async function runInit() {
724
901
  }
725
902
  }
726
903
 
727
- // Create docs/start.md template
904
+ // Fix 2: Create docs/start.md template with scope questions
728
905
  const startMdPath = path.join(cwd, START_MD);
729
906
  if (!fs.existsSync(startMdPath)) {
730
- const startMdContent = `# 🕌 IMH-Code — Project Start
731
-
732
- > **Imam Hussain Coding Harness Platform**
733
- > Write your project description below, then run \`imhcode plan\`.
734
-
735
- ---
736
-
737
- ## 📝 Your Project Description
738
-
739
- Write your complete project idea below the markers. Be as detailed as possible.
740
- Include: what you're building, who it's for, key features, preferred stack (if any).
741
-
742
- <!-- WRITE_PROMPT_HERE -->
743
- I want to build a SaaS dashboard for managing hotel room bookings with real-time availability,
744
- a Next.js frontend, Laravel API backend, and PostgreSQL database.
745
- <!-- END_PROMPT -->
746
-
747
- ---
748
-
749
- ## 🚀 Next Step
750
-
751
- After writing your description, run in your terminal:
752
-
753
- \`\`\`bash
754
- imhcode plan
755
- \`\`\`
756
-
757
- This will analyze your description and generate **docs/brainstorming.md** with
758
- smart questions about your project, with recommended answers you can review and edit.
759
- `;
907
+ const startMdContent = [
908
+ '# 🕌 IMH-Code — Project Start',
909
+ '',
910
+ '> **Imam Hussain Coding Harness Platform**',
911
+ '> Answer the scope questions below, write your description, then run `imhcode plan`.',
912
+ '',
913
+ '---',
914
+ '',
915
+ '## ⚡ Quick Scope Check',
916
+ '',
917
+ '**Do you need a backend API / server-side logic?**',
918
+ '> **Answer:** yes *(change to: yes / no / unsure)*',
919
+ '',
920
+ '**Do you need a mobile app (iOS/Android)?**',
921
+ '> **Answer:** no *(change to: yes / no)*',
922
+ '',
923
+ '---',
924
+ '',
925
+ '## 📝 Your Project Description',
926
+ '',
927
+ 'Write your complete project idea below. Be as detailed as possible.',
928
+ 'Include: what you\'re building, who it\'s for, key features, preferred stack,',
929
+ 'design preferences, integrations needed, business constraints.',
930
+ '',
931
+ '<!-- WRITE_PROMPT_HERE -->',
932
+ 'I want to build a SaaS dashboard for managing hotel room bookings with real-time availability,',
933
+ 'a Next.js frontend, Laravel API backend, and PostgreSQL database. Target users are hotel managers.',
934
+ 'Key features: room calendar, booking CRUD, guest management, reporting, email notifications.',
935
+ '<!-- END_PROMPT -->',
936
+ '',
937
+ '---',
938
+ '',
939
+ '## 🚀 Next Step',
940
+ '',
941
+ 'After filling in the scope and your description, run:',
942
+ '',
943
+ '```bash',
944
+ 'imhcode plan',
945
+ '```',
946
+ '',
947
+ 'IMH-Code will invoke your configured **planning AI model** (e.g. Claude Opus, GPT-5.5)',
948
+ 'to generate `docs/brainstorming.md` with smart, project-specific questions and answers.',
949
+ ].join('\n');
760
950
  fs.writeFileSync(startMdPath, startMdContent, 'utf8');
761
951
  console.log(` Created docs/start.md (write your project here)`);
762
952
  }
@@ -776,7 +966,7 @@ smart questions about your project, with recommended answers you can review and
776
966
 
777
967
  // ── Interactive Engine & Model Setup ────────────────────────────────────────
778
968
  console.log('\n🔍 Scanning for local coding assistant CLIs...');
779
- const engines = scanAssistantCLIs();
969
+ const engines = scanAssistantCLIs();
780
970
  const foundEngines = Object.keys(engines).filter(k => engines[k].path);
781
971
 
782
972
  if (foundEngines.length === 0) {
@@ -835,22 +1025,22 @@ smart questions about your project, with recommended answers you can review and
835
1025
  console.log(`✅ Default model: ${defaultModel}`);
836
1026
  }
837
1027
 
838
- // ── Smart Model Routing Setup ────────────────────────────────────────────────
1028
+ // Fix 4: Smart Model Routing Setup with ranked scoring
839
1029
  const modelRouting = await setupModelRouting(engines, foundEngines, isInteractive);
840
1030
 
841
1031
  // Write config
842
1032
  const configPath = path.join(cwd, CONFIG_FILE);
843
1033
  const configData = {
844
1034
  primary_engine: primaryEngine,
845
- default_model: defaultModel || undefined,
846
- testing_mode: 'fast',
847
- model_routing: modelRouting,
1035
+ default_model: defaultModel || undefined,
1036
+ testing_mode: 'fast',
1037
+ model_routing: modelRouting,
848
1038
  available_engines: {},
849
1039
  };
850
1040
 
851
1041
  for (const key of foundEngines) {
852
1042
  configData.available_engines[key] = {
853
- path: engines[key].path,
1043
+ path: engines[key].path,
854
1044
  models: engines[key].models,
855
1045
  };
856
1046
  }
@@ -862,100 +1052,163 @@ smart questions about your project, with recommended answers you can review and
862
1052
  console.log(`\n✅ ${PLATFORM_NAME} initialized successfully!`);
863
1053
  console.log(`─`.repeat(60));
864
1054
  console.log(`\n🕌 HOW TO BUILD WITH IMH-CODE:\n`);
865
- console.log(` 1. Open docs/start.md → Write your project description`);
1055
+ console.log(` 1. Open docs/start.md → Answer scope questions + write your description`);
866
1056
  console.log(` 2. Run: imhcode plan`);
867
- console.log(` → Generates docs/brainstorming.md with smart questions`);
868
- console.log(` 3. Open docs/brainstorming.md → Review/edit answers`);
1057
+ console.log(` → Your planning AI (${modelRouting?.planning?.model || 'configured model'}) generates brainstorming.md`);
1058
+ console.log(` 3. Open docs/brainstorming.md → Review/edit AI-recommended answers`);
869
1059
  console.log(` 4. Run: imhcode plan`);
870
- console.log(` → Reads your answers generates sprint plans`);
871
- console.log(` 5. Run: imhcode execute 1 → Execute Sprint 1`);
872
- console.log(` 6. Run: imhcode execute 2 → Execute Sprint 2`);
1060
+ console.log(` → Your planning AI generates sprint plans with correct agent routing`);
1061
+ console.log(` 5. Run: imhcode execute 1 → Sprint 1 (frontend tasks → ${modelRouting?.frontend?.model || 'frontend model'})`);
1062
+ console.log(` 6. Run: imhcode execute 2 → Sprint 2 (backend tasks → ${modelRouting?.backend?.model || 'backend model'})`);
873
1063
  console.log(` 7. Run: imhcode test → Final testing + security + SEO`);
1064
+ console.log(` 8. Run: imhcode report → Generate PROJECT_REPORT.md`);
874
1065
  console.log(`\n Run "imhcode --help" for all commands.`);
875
1066
  console.log(`─`.repeat(60));
876
1067
  console.log('');
877
1068
  }
878
1069
 
879
- // ─── Model Routing Setup Wizard ───────────────────────────────────────────────
1070
+ // ─── Fix 4: Model Routing Setup Wizard (Ranked Scoring Algorithm) ─────────────
1071
+
1072
+ /**
1073
+ * Ranked priority lists per category.
1074
+ * The algorithm scores each available model against these lists
1075
+ * and selects the highest-ranked match found in the installed engines.
1076
+ */
1077
+ const MODEL_PRIORITY_RANKS = {
1078
+ frontend: [
1079
+ // Engine Model substring to match (lowercase, no hyphens/dots)
1080
+ ['mimo', 'mimov25pro'],
1081
+ ['mimo', 'mimov25'],
1082
+ ['opencode', 'mimov25pro'],
1083
+ ['opencode', 'mimov25'],
1084
+ ['codex', 'gpt55'],
1085
+ ['codex', 'gpt5'],
1086
+ ['agy', 'claudeopus46'],
1087
+ ['agy', 'claudeopus'],
1088
+ ['opencode', 'gemini35flash'],
1089
+ ['opencode', 'gemini25pro'],
1090
+ ['claude', 'claudeopus46'],
1091
+ ['claude', 'opus'],
1092
+ ],
1093
+ backend: [
1094
+ ['opencode', 'deepseekv4pro'],
1095
+ ['opencode', 'deepseekv4'],
1096
+ ['opencode', 'kimik27code'],
1097
+ ['opencode', 'kimik2'],
1098
+ ['opencode', 'qwen3coder480b'],
1099
+ ['opencode', 'qwen3coder'],
1100
+ ['codex', 'gpt55'],
1101
+ ['codex', 'gpt5'],
1102
+ ['opencode', 'gptoss120b'],
1103
+ ['qwen', 'qwen3codermax'],
1104
+ ['qwen', 'qwen3coder'],
1105
+ ['claude', 'claudesonnet46'],
1106
+ ['claude', 'sonnet'],
1107
+ ],
1108
+ planning: [
1109
+ ['agy', 'claudeopus46'],
1110
+ ['agy', 'claudeopus'],
1111
+ ['claude', 'claudeopus46'],
1112
+ ['claude', 'opus'],
1113
+ ['codex', 'gpt55'],
1114
+ ['codex', 'gpt5'],
1115
+ ['opencode', 'gemini31propreview'],
1116
+ ['opencode', 'gemini31pro'],
1117
+ ['opencode', 'deepseekv4pro'],
1118
+ ],
1119
+ testing: [
1120
+ ['codex', 'gpt55'],
1121
+ ['codex', 'gpt5'],
1122
+ ['agy', 'gptoss120bmedium'],
1123
+ ['agy', 'gptoss120b'],
1124
+ ['agy', 'claudeopus46'],
1125
+ ['agy', 'claudeopus'],
1126
+ ['opencode', 'deepseekv4pro'],
1127
+ ['claude', 'claudeopus46'],
1128
+ ],
1129
+ review: [
1130
+ ['codex', 'gpt55'],
1131
+ ['codex', 'gpt5'],
1132
+ ['agy', 'claudesonnet46'],
1133
+ ['agy', 'claudesonnet'],
1134
+ ['opencode', 'gptoss120b'],
1135
+ ['claude', 'claudesonnet46'],
1136
+ ['opencode', 'deepseekv4pro'],
1137
+ ],
1138
+ fast: [
1139
+ ['opencode', 'deepseekv4flash'],
1140
+ ['opencode', 'deepseekv4flash'],
1141
+ ['opencode', 'gemini35flash'],
1142
+ ['codex', 'gpt54mini'],
1143
+ ['codex', 'gptmini'],
1144
+ ['qwen', 'qwen3coderflash'],
1145
+ ['claude', 'claudehaiku35'],
1146
+ ['claude', 'haiku'],
1147
+ ],
1148
+ };
1149
+
1150
+ /**
1151
+ * Normalize a model/engine string for fuzzy matching:
1152
+ * lowercase, remove hyphens, dots, underscores, spaces.
1153
+ */
1154
+ function normalizeForMatch(s) {
1155
+ return (s || '').toLowerCase().replace(/[-._\s]/g, '');
1156
+ }
1157
+
1158
+ /**
1159
+ * Select the best model for a category from available engines using ranked scoring.
1160
+ * Returns { engine, model } or null if nothing found.
1161
+ */
1162
+ function selectBestModel(category, engines) {
1163
+ const ranks = MODEL_PRIORITY_RANKS[category] || [];
1164
+ for (const [preferredEngine, modelSubstring] of ranks) {
1165
+ const engData = engines[preferredEngine];
1166
+ if (!engData?.path || !engData.models?.length) continue;
1167
+ const match = engData.models.find(m => normalizeForMatch(m).includes(modelSubstring));
1168
+ if (match) return { engine: preferredEngine, model: match };
1169
+ }
1170
+ return null;
1171
+ }
880
1172
 
881
1173
  async function setupModelRouting(engines, foundEngines, isInteractive) {
882
1174
  const categories = {
883
- frontend: {
884
- label: 'Frontend (UI/UX, components, animations)',
885
- note: 'Mimo v2.5 Pro preferred → GPT-5.5 → Claude Opus',
886
- preferredEngines: ['mimo', 'codex', 'claude', 'opencode'],
887
- preferredModels: ['mimo-vl-v2.5-pro', 'gpt-5.5', 'claude-opus-4-6', 'deepseek-v4-pro'],
888
- },
889
- backend: {
890
- label: 'Backend (APIs, database, business logic)',
891
- note: 'DeepSeek V4 Pro preferred → GPT-5.5 → Qwen Coder',
892
- preferredEngines: ['opencode', 'codex', 'qwen', 'claude'],
893
- preferredModels: ['deepseek-v4-pro', 'gpt-5.5', 'qwen3-coder-max', 'claude-sonnet-4-5'],
894
- },
895
- planning: {
896
- label: 'Planning (brainstorming, sprint planning, architecture)',
897
- note: 'Claude Opus preferred → GPT-5.5',
898
- preferredEngines: ['claude', 'codex', 'opencode'],
899
- preferredModels: ['claude-opus-4-6', 'gpt-5.5', 'deepseek-v4-pro'],
900
- },
901
- testing: {
902
- label: 'Testing (QA, security audit, E2E)',
903
- note: 'GPT-5.5 preferred → Claude Opus → DeepSeek',
904
- preferredEngines: ['codex', 'claude', 'opencode'],
905
- preferredModels: ['gpt-5.5', 'claude-opus-4-6', 'deepseek-v4-pro'],
906
- },
907
- review: {
908
- label: 'Review (SEO, debugging, code review)',
909
- note: 'GPT-5.5 preferred → Claude Sonnet',
910
- preferredEngines: ['codex', 'claude', 'opencode'],
911
- preferredModels: ['gpt-5.5', 'claude-sonnet-4-5', 'deepseek-v4'],
912
- },
913
- fast: {
914
- label: 'Fast (boilerplate, config, simple tasks)',
915
- note: 'DeepSeek V4 Flash preferred → Gemini Flash → GPT Mini',
916
- preferredEngines: ['opencode', 'codex', 'qwen', 'claude'],
917
- preferredModels: ['deepseek-v4-flash', 'gpt-5.4-mini', 'qwen3-coder-flash', 'claude-haiku-3-5'],
918
- },
1175
+ frontend: { label: 'Frontend (UI/UX, components, animations)', note: 'Mimo v2.5 Pro → GPT-5.5 → Claude Opus' },
1176
+ backend: { label: 'Backend (APIs, database, business logic)', note: 'DeepSeek V4 Pro → Kimi K2.7 → Qwen3 Coder → GPT-5.5' },
1177
+ planning: { label: 'Planning (brainstorming, sprint planning)', note: 'Claude Opus 4.6 → GPT-5.5 → Gemini 3.1 Pro' },
1178
+ testing: { label: 'Testing (QA, security audit, E2E)', note: 'GPT-5.5 → GPT-OSS 120B → Claude Opus' },
1179
+ review: { label: 'Review (SEO, debugging, code review)', note: 'GPT-5.5 → Claude Sonnet → GPT-OSS 120B' },
1180
+ fast: { label: 'Fast (boilerplate, config, simple tasks)', note: 'DeepSeek V4 Flash → Gemini 3.5 Flash → GPT Mini' },
919
1181
  };
920
1182
 
921
- const routing = {};
922
-
923
- // Build recommended routing from available engines
924
1183
  const recommended = {};
925
- for (const [cat, cfg] of Object.entries(categories)) {
926
- let found = false;
927
- for (let i = 0; i < cfg.preferredEngines.length; i++) {
928
- const eng = cfg.preferredEngines[i];
929
- const mdl = cfg.preferredModels[i];
930
- const engData = engines[eng];
931
- if (engData?.path && engData.models.length > 0) {
932
- const match = engData.models.find(m => m.toLowerCase().includes(mdl.replace(/-/g, '').replace(/\./g, '')));
933
- recommended[cat] = { engine: eng, model: match || engData.models[0] };
934
- found = true;
935
- break;
936
- }
937
- }
938
- if (!found && foundEngines.length > 0) {
939
- // Fallback to primary engine
1184
+ for (const cat of Object.keys(categories)) {
1185
+ const best = selectBestModel(cat, engines);
1186
+ if (best) {
1187
+ recommended[cat] = best;
1188
+ } else if (foundEngines.length > 0) {
1189
+ // Fallback: primary engine first model
940
1190
  const fe = foundEngines[0];
941
1191
  recommended[cat] = { engine: fe, model: engines[fe].models[0] || 'default' };
942
1192
  }
943
1193
  }
944
1194
 
945
1195
  // Show recommended routing table
946
- console.log('\n' + '─'.repeat(60));
947
- console.log('🧠 Recommended Model Routing (based on your installed engines):\n');
948
- console.log(' Category │ Engine │ Model');
949
- console.log(' ─────────────────────────────────────────────────────────');
1196
+ console.log('\n' + '─'.repeat(70));
1197
+ console.log('🧠 Recommended Model Routing (ranked by quality for each category):\n');
1198
+ console.log(' Category │ Engine │ Model');
1199
+ console.log(' ──────────────┼───────────────┼───────────────────────────────────────');
950
1200
  for (const [cat, rec] of Object.entries(recommended)) {
951
1201
  const catLabel = cat.padEnd(12);
952
- const eng = (rec.engine || '?').padEnd(12);
953
- const mdl = rec.model || '?';
954
- const cfg = categories[cat];
955
- console.log(` ${catLabel} │ ${eng} │ ${mdl}`);
1202
+ const eng = (rec.engine || '?').padEnd(13);
1203
+ const mdl = rec.model || '?';
1204
+ const note = categories[cat]?.note || '';
1205
+ console.log(` ${catLabel} │ ${eng} │ ${mdl}`);
956
1206
  }
957
- console.log(' ' + '─'.repeat(57));
958
- console.log(`\n Preferences: ${categories.frontend.note}`);
1207
+ console.log(' ' + '─'.repeat(67));
1208
+ console.log(`\n Priority: Mimo v2.5 Pro (frontend) | DeepSeek V4 Pro (backend)`);
1209
+ console.log(` Claude Opus (planning) | GPT-5.5 (testing/review)`);
1210
+
1211
+ const routing = {};
959
1212
 
960
1213
  if (isInteractive) {
961
1214
  const answer = await askQuestion('\nAccept recommended routing? [Y/n] ');
@@ -963,9 +1216,8 @@ async function setupModelRouting(engines, foundEngines, isInteractive) {
963
1216
  // Let user customize each category
964
1217
  for (const [cat, cfg] of Object.entries(categories)) {
965
1218
  console.log(`\n Configure model for [${cat}] — ${cfg.label}`);
966
- console.log(` (${cfg.note})`);
1219
+ console.log(` Priority: ${cfg.note}`);
967
1220
 
968
- // Collect all available models across all engines
969
1221
  const allModels = [];
970
1222
  for (const eng of foundEngines) {
971
1223
  for (const m of engines[eng].models) {
@@ -979,9 +1231,9 @@ async function setupModelRouting(engines, foundEngines, isInteractive) {
979
1231
  }
980
1232
 
981
1233
  allModels.forEach((item, i) => {
982
- const rec = recommended[cat];
1234
+ const rec = recommended[cat];
983
1235
  const isRec = rec && rec.engine === item.engine && rec.model === item.model;
984
- console.log(` [${i + 1}] ${item.model} (${item.engine})${isRec ? ' ← Recommended' : ''}`);
1236
+ console.log(` [${i + 1}] ${item.model} (${item.engine})${isRec ? ' ← Recommended' : ''}`);
985
1237
  });
986
1238
 
987
1239
  let selectedIdx = allModels.findIndex(m => {
@@ -1011,27 +1263,208 @@ async function setupModelRouting(engines, foundEngines, isInteractive) {
1011
1263
  return routing;
1012
1264
  }
1013
1265
 
1014
- // ─── Brainstorming Generator ───────────────────────────────────────────────────
1266
+ // ─── Fix 0: LLM-Powered Planning ─────────────────────────────────────────────
1015
1267
 
1016
- async function generateBrainstormingDoc(cwd, userPrompt) {
1017
- // Analyze keywords in the prompt to determine which sections to include
1018
- const p = userPrompt.toLowerCase();
1268
+ /**
1269
+ * Invoke the configured planning engine to generate brainstorming or sprint plans.
1270
+ * Uses the orchestrator's runAgent() so failover, logging, and routing all work.
1271
+ *
1272
+ * @param {string} promptText - The full system prompt to send to the planning LLM
1273
+ * @param {object} config - Loaded imhcode.config.json
1274
+ * @param {string} cwd - Current working directory
1275
+ * @returns {string} The LLM output text, or null if unavailable
1276
+ */
1277
+ async function invokePlanningLLM(promptText, config, cwd) {
1278
+ // Check if orchestrator is built
1279
+ const distPath = path.join(__dirname, '..', 'dist', 'orchestrator', 'index.js');
1280
+ if (!fs.existsSync(distPath)) {
1281
+ console.warn(' ⚠️ Orchestrator not built — falling back to static template.');
1282
+ console.warn(' Run "npm run build" in the imhcode package to enable LLM-powered planning.');
1283
+ return null;
1284
+ }
1285
+
1286
+ const planningEngine = config?.model_routing?.planning?.engine;
1287
+ const planningModel = config?.model_routing?.planning?.model;
1288
+
1289
+ if (!planningEngine || !planningModel) {
1290
+ console.warn(' ⚠️ No planning model configured — falling back to static template.');
1291
+ console.warn(' Run "imhcode" to set up model routing.');
1292
+ return null;
1293
+ }
1294
+
1295
+ try {
1296
+ const orc = require(distPath);
1297
+ const agentsDir = (() => {
1298
+ const g = path.join(GLOBAL_DIR, 'agents');
1299
+ if (fs.existsSync(g)) return g;
1300
+ const l = path.join(cwd, 'agents');
1301
+ if (fs.existsSync(l)) return l;
1302
+ const p = path.join(__dirname, '..', 'agents');
1303
+ if (fs.existsSync(p)) return p;
1304
+ return null;
1305
+ })();
1306
+
1307
+ if (!agentsDir) {
1308
+ console.warn(' ⚠️ No agents directory found — falling back to static template.');
1309
+ return null;
1310
+ }
1019
1311
 
1020
- const hasFrontend = p.includes('frontend') || p.includes('ui') || p.includes('dashboard') ||
1021
- p.includes('design') || p.includes('page') || p.includes('web') ||
1022
- p.includes('next') || p.includes('react') || p.includes('vue');
1023
- const hasBackend = p.includes('backend') || p.includes('api') || p.includes('database') ||
1024
- p.includes('server') || p.includes('laravel') || p.includes('django') ||
1025
- p.includes('fastapi') || p.includes('auth') || p.includes('data');
1026
- const hasMobile = p.includes('mobile') || p.includes('flutter') || p.includes('ios') ||
1027
- p.includes('android') || p.includes('react native') || p.includes('expo');
1312
+ const { agents } = await orc.loadRegistry(agentsDir, cwd);
1313
+ const plannerAgent = orc.getAgent(agents, 'planner');
1028
1314
 
1029
- // Infer default stack
1030
- const defaultFrontend = hasFrontend ? (p.includes('vue') ? 'Vue 3 + Nuxt 4' : 'Next.js 15') : 'Next.js 15';
1031
- const defaultBackend = hasBackend ? (p.includes('python') || p.includes('django') ? 'Python/FastAPI' :
1032
- p.includes('java') ? 'Java/Spring Boot' : 'Laravel 11') : 'Laravel 11';
1315
+ console.log(`\n 🤖 Invoking planning AI: ${planningModel} via ${planningEngine}...`);
1033
1316
 
1034
- const content = `# 🧠 IMH-Code — Project Brainstorming
1317
+ const result = await orc.runAgent(
1318
+ plannerAgent,
1319
+ promptText,
1320
+ {
1321
+ dryRun: false,
1322
+ engine: planningEngine,
1323
+ model: planningModel,
1324
+ outputDir: path.join(cwd, LOCAL_DIR_NAME, 'sessions'),
1325
+ cwd,
1326
+ }
1327
+ );
1328
+
1329
+ if (result.errors.length > 0) {
1330
+ console.warn(` ⚠️ Planning LLM returned errors — falling back to static template.`);
1331
+ result.errors.forEach(e => console.warn(` ${e}`));
1332
+ return null;
1333
+ }
1334
+
1335
+ return result.output || null;
1336
+
1337
+ } catch (err) {
1338
+ console.warn(` ⚠️ Planning LLM invocation failed: ${err.message}`);
1339
+ console.warn(' Falling back to static template.');
1340
+ return null;
1341
+ }
1342
+ }
1343
+
1344
+ // ─── Fix 0 + Fix 3: Brainstorming Generator (LLM-Powered + Professional) ──────
1345
+
1346
+ /**
1347
+ * Extract scope hints from start.md (backend? mobile? worktrees?)
1348
+ */
1349
+ function extractScopeHints(startContent) {
1350
+ const lines = startContent.toLowerCase();
1351
+
1352
+ const needsBackend = (() => {
1353
+ const m = startContent.match(/do you need a backend.*?\n>\s*\*\*Answer:\*\*\s*(.+)/i);
1354
+ if (m) {
1355
+ const ans = m[1].toLowerCase().trim();
1356
+ return !ans.startsWith('no');
1357
+ }
1358
+ // Infer from description
1359
+ return /backend|api|database|server|laravel|django|fastapi|express|spring/i.test(lines);
1360
+ })();
1361
+
1362
+ const needsMobile = (() => {
1363
+ const m = startContent.match(/do you need a mobile.*?\n>\s*\*\*Answer:\*\*\s*(.+)/i);
1364
+ if (m) {
1365
+ const ans = m[1].toLowerCase().trim();
1366
+ return ans.startsWith('yes');
1367
+ }
1368
+ return /mobile|flutter|ios|android|react native|expo/i.test(lines);
1369
+ })();
1370
+
1371
+ return { needsBackend, needsMobile };
1372
+ }
1373
+
1374
+ async function generateBrainstormingDoc(cwd, userPrompt, scopeHints, config) {
1375
+ const { needsBackend, needsMobile } = scopeHints || {};
1376
+
1377
+ // Build the LLM prompt for brainstorming
1378
+ const llmPrompt = `You are the IMH-Code Planner — an expert software architect and technical product manager.
1379
+
1380
+ Your task is to analyze the following project description and generate a comprehensive, professional brainstorming document in Markdown format.
1381
+
1382
+ ## Project Description
1383
+
1384
+ ${userPrompt}
1385
+
1386
+ ## Scope Hints
1387
+ - Backend required: ${needsBackend ? 'YES' : 'NO'}
1388
+ - Mobile required: ${needsMobile ? 'YES' : 'NO'}
1389
+
1390
+ ## Instructions
1391
+
1392
+ Generate 25-35 smart, project-specific brainstorming questions with intelligent recommended answers. The questions must be:
1393
+ 1. **Tailored to this exact project** — not generic
1394
+ 2. **Professional and thorough** — cover all aspects a senior engineer would consider
1395
+ 3. **Formatted exactly** as shown below
1396
+
1397
+ ### Required Sections (include all that apply based on scope):
1398
+
1399
+ 1. **General Requirements** — goals, users, scale, timeline, success metrics
1400
+ 2. **Frontend** (ALWAYS include if web app) — must include:
1401
+ - Framework choice (Next.js / Vue 3+Nuxt / React+Vite / SvelteKit)
1402
+ - UI component library (shadcn/ui / Radix / Chakra / Mantine / custom)
1403
+ - **Color palette style** (Vibrant SaaS / Dark Premium / Minimal Neutral / Pastel Soft / Corporate Blue / Bold Brand)
1404
+ - **Design aesthetic** (Glassmorphism / Neumorphism / Brutalism / Claymorphism / Minimalist Clean / Modern SaaS)
1405
+ - **Typography preference** (Modern sans-serif like Inter / Serif editorial / Mono-accented / System fonts)
1406
+ - **Animation preference** (GSAP ScrollTrigger / Framer Motion / CSS transitions / None)
1407
+ - Dark mode strategy (system/toggle/always dark/light only)
1408
+ - Mobile responsive approach (mobile-first / desktop-first / equal)
1409
+ - **Git worktree snapshots** per sprint? (yes / no — creates .worktrees/ for branch snapshots)
1410
+ - Accessibility level (WCAG AA / basic / none)
1411
+ 3. **Backend** (only if needsBackend=YES) — framework, database, auth, API style, real-time, payments, file uploads, rate limiting
1412
+ 4. **Mobile** (only if needsMobile=YES) — platform, framework, offline support, push notifications
1413
+ 5. **Deployment** — platform, Docker, CI/CD, CDN
1414
+ 6. **Testing Strategy** — Fast/Balanced/Strict TDD, testing timing
1415
+ 7. **Security** — audit timing, OWASP, compliance needs
1416
+ 8. **SEO** (if web) — requirements, timing
1417
+
1418
+ ### CRITICAL Format — each question MUST follow this exact format:
1419
+
1420
+ **Q[N]: [Question text]?**
1421
+ > **Recommended:** [Smart, specific recommendation based on the project]
1422
+ > **Your Answer:** *(edit if needed)*
1423
+
1424
+ ### Output
1425
+
1426
+ Output ONLY the Markdown content. Start with:
1427
+ # 🧠 IMH-Code — Project Brainstorming
1428
+
1429
+ Do NOT include any preamble, explanation, or commentary outside the Markdown document.`;
1430
+
1431
+ // Try LLM first (Fix 0)
1432
+ const llmOutput = await invokePlanningLLM(llmPrompt, config, cwd);
1433
+
1434
+ let content;
1435
+ if (llmOutput && llmOutput.trim().length > 200) {
1436
+ // Ensure it starts correctly
1437
+ content = llmOutput.trim();
1438
+ if (!content.startsWith('#')) {
1439
+ content = `# 🧠 IMH-Code — Project Brainstorming\n\n` + content;
1440
+ }
1441
+ content += `\n\n---\n\n*Generated by ${PLATFORM_NAME} planning AI — ${new Date().toLocaleDateString()}*\n`;
1442
+ content += `\n*When ready, run \`imhcode plan\` to generate sprint plans from your answers.*\n`;
1443
+ console.log(`\n ✅ Brainstorming document generated by planning AI (${config?.model_routing?.planning?.model || 'LLM'})`);
1444
+ } else {
1445
+ // Fix 3: Professional static fallback with design questions
1446
+ content = generateStaticBrainstorming(userPrompt, scopeHints);
1447
+ console.log(`\n 📋 Brainstorming document generated (static template)`);
1448
+ }
1449
+
1450
+ const brainstormPath = path.join(cwd, BRAINSTORM_MD);
1451
+ fs.mkdirSync(path.join(cwd, DOCS_DIR), { recursive: true });
1452
+ fs.writeFileSync(brainstormPath, content, 'utf8');
1453
+ }
1454
+
1455
+ /**
1456
+ * Fix 3: Professional static brainstorming fallback (used when LLM unavailable)
1457
+ */
1458
+ function generateStaticBrainstorming(userPrompt, scopeHints) {
1459
+ const { needsBackend, needsMobile } = scopeHints || {};
1460
+ const p = userPrompt.toLowerCase();
1461
+
1462
+ const hasFrontend = true; // Always assume frontend
1463
+ const defaultFrontend = p.includes('vue') ? 'Vue 3 + Nuxt 4' : p.includes('react') && !p.includes('next') ? 'React + Vite' : 'Next.js 15';
1464
+ const defaultBackend = p.includes('python') || p.includes('django') ? 'Python / FastAPI' :
1465
+ p.includes('java') ? 'Java / Spring Boot' : 'Laravel 11';
1466
+
1467
+ return `# 🧠 IMH-Code — Project Brainstorming
1035
1468
 
1036
1469
  > Auto-generated by \`imhcode plan\` on ${new Date().toLocaleDateString()}
1037
1470
  > Review and edit the "**Your Answer**" fields below, then run \`imhcode plan\` again.
@@ -1052,96 +1485,129 @@ async function generateBrainstormingDoc(cwd, userPrompt) {
1052
1485
  > **Recommended:** Small-medium (< 1,000 users initially)
1053
1486
  > **Your Answer:** *(edit if needed)*
1054
1487
 
1055
- **Q4: What is the timeline?**
1488
+ **Q4: What is the timeline goal?**
1056
1489
  > **Recommended:** MVP in 2-4 sprints (4-8 weeks)
1057
1490
  > **Your Answer:** *(edit if needed)*
1058
1491
 
1492
+ **Q5: What are the key success metrics?**
1493
+ > **Recommended:** User signups, feature completion, performance benchmarks
1494
+ > **Your Answer:** *(edit if needed)*
1495
+
1059
1496
  ---
1060
- ${hasFrontend ? `
1497
+
1061
1498
  ## 🎨 Frontend
1062
1499
 
1063
- **Q5: Which frontend framework?**
1500
+ **Q6: Which frontend framework?**
1064
1501
  > **Recommended:** ${defaultFrontend}
1065
1502
  > **Your Answer:** *(edit if needed)*
1066
1503
 
1067
- **Q6: UI Component library?**
1504
+ **Q7: UI component library?**
1068
1505
  > **Recommended:** shadcn/ui + Tailwind CSS v4
1069
- > **Your Answer:** *(edit if needed)*
1506
+ > **Your Answer:** *(shadcn/ui / Radix / Chakra / Mantine / custom)*
1070
1507
 
1071
- **Q7: Do you need animations/3D effects?**
1072
- > **Recommended:** Light micro-animations (GSAP ScrollTrigger)
1073
- > **Your Answer:** *(yes specify / no)*
1508
+ **Q8: Color palette style?**
1509
+ > **Recommended:** Dark Premium (deep backgrounds with vibrant accents)
1510
+ > **Your Answer:** *(Vibrant SaaS / Dark Premium / Minimal Neutral / Pastel Soft / Corporate Blue / Bold Brand)*
1074
1511
 
1075
- **Q8: Mobile responsive?**
1076
- > **Recommended:** Yes (mobile-first responsive design)
1077
- > **Your Answer:** *(edit if needed)*
1512
+ **Q9: Design aesthetic / style?**
1513
+ > **Recommended:** Modern SaaS (glassmorphism elements, clean cards, subtle gradients)
1514
+ > **Your Answer:** *(Glassmorphism / Neumorphism / Brutalism / Claymorphism / Minimalist Clean / Modern SaaS)*
1515
+
1516
+ **Q10: Typography preference?**
1517
+ > **Recommended:** Modern sans-serif (Inter + Outfit)
1518
+ > **Your Answer:** *(Modern sans-serif / Serif editorial / Mono-accented / System fonts)*
1519
+
1520
+ **Q11: Animation & interaction style?**
1521
+ > **Recommended:** Subtle micro-animations (Framer Motion for components, CSS transitions)
1522
+ > **Your Answer:** *(GSAP ScrollTrigger / Framer Motion / CSS transitions / None)*
1078
1523
 
1079
- **Q9: Dark mode support?**
1080
- > **Recommended:** Yes (dark/light toggle)
1524
+ **Q12: Dark mode strategy?**
1525
+ > **Recommended:** System preference + manual toggle
1526
+ > **Your Answer:** *(system toggle / always dark / light only)*
1527
+
1528
+ **Q13: Mobile responsive approach?**
1529
+ > **Recommended:** Mobile-first responsive design
1530
+ > **Your Answer:** *(mobile-first / desktop-first / equal)*
1531
+
1532
+ **Q14: Git worktree snapshots per sprint?**
1533
+ > **Recommended:** Yes (creates .worktrees/ for branch snapshots at each sprint)
1081
1534
  > **Your Answer:** *(yes / no)*
1082
1535
 
1083
- **Q10: Preferred design style?**
1084
- > **Recommended:** Modern SaaS (glassmorphism, clean, premium)
1085
- > **Your Answer:** *(edit if needed)*
1086
- ` : ''}
1087
- ${hasBackend ? `
1536
+ **Q15: Accessibility level?**
1537
+ > **Recommended:** WCAG 2.1 AA
1538
+ > **Your Answer:** *(WCAG AA / basic / none)*
1539
+
1540
+ ---
1541
+ ${needsBackend ? `
1088
1542
  ## 🔧 Backend
1089
1543
 
1090
- **Q11: Which backend framework?**
1544
+ **Q16: Which backend framework?**
1091
1545
  > **Recommended:** ${defaultBackend}
1092
1546
  > **Your Answer:** *(edit if needed)*
1093
1547
 
1094
- **Q12: Database?**
1548
+ **Q17: Database?**
1095
1549
  > **Recommended:** PostgreSQL + Redis (caching)
1096
1550
  > **Your Answer:** *(edit if needed)*
1097
1551
 
1098
- **Q13: Authentication system?**
1552
+ **Q18: Authentication system?**
1099
1553
  > **Recommended:** JWT tokens + email verification
1100
1554
  > **Your Answer:** *(JWT / session / OAuth / other)*
1101
1555
 
1102
- **Q14: API architecture?**
1103
- > **Recommended:** RESTful API
1556
+ **Q19: API architecture?**
1557
+ > **Recommended:** RESTful API with versioning (/api/v1)
1104
1558
  > **Your Answer:** *(REST / GraphQL / both)*
1105
1559
 
1106
- **Q15: Do you need file uploads?**
1560
+ **Q20: File uploads?**
1107
1561
  > **Recommended:** Yes (S3-compatible storage)
1108
1562
  > **Your Answer:** *(yes / no)*
1109
1563
 
1110
- **Q16: Real-time features?**
1564
+ **Q21: Real-time features?**
1111
1565
  > **Recommended:** No (for MVP)
1112
1566
  > **Your Answer:** *(yes — specify / no)*
1113
1567
 
1114
- **Q17: Payment integration?**
1568
+ **Q22: Payment integration?**
1115
1569
  > **Recommended:** No (for MVP)
1116
1570
  > **Your Answer:** *(yes — specify provider / no)*
1571
+
1572
+ **Q23: Rate limiting & API security?**
1573
+ > **Recommended:** Yes (throttle 60 req/min per IP, API key auth for external)
1574
+ > **Your Answer:** *(yes / no)*
1575
+
1576
+ ---
1117
1577
  ` : ''}
1118
- ${hasMobile ? `
1578
+ ${needsMobile ? `
1119
1579
  ## 📱 Mobile
1120
1580
 
1121
- **Q18: Target platforms?**
1581
+ **Q24: Target platforms?**
1122
1582
  > **Recommended:** iOS + Android (cross-platform)
1123
1583
  > **Your Answer:** *(iOS only / Android only / both)*
1124
1584
 
1125
- **Q19: Mobile framework?**
1585
+ **Q25: Mobile framework?**
1126
1586
  > **Recommended:** Flutter
1127
1587
  > **Your Answer:** *(Flutter / React Native / both)*
1128
1588
 
1129
- **Q20: Offline support?**
1589
+ **Q26: Offline support?**
1130
1590
  > **Recommended:** No (for MVP)
1131
1591
  > **Your Answer:** *(yes / no)*
1592
+
1593
+ **Q27: Push notifications?**
1594
+ > **Recommended:** Yes (Firebase Cloud Messaging)
1595
+ > **Your Answer:** *(yes / no)*
1596
+
1597
+ ---
1132
1598
  ` : ''}
1133
1599
 
1134
1600
  ## 🚀 Deployment
1135
1601
 
1136
- **Q21: Deployment platform?**
1137
- > **Recommended:** Vercel (frontend) + DigitalOcean/Railway (backend)
1602
+ **Q28: Deployment platform?**
1603
+ > **Recommended:** Vercel (frontend) + Railway or DigitalOcean (backend)
1138
1604
  > **Your Answer:** *(edit if needed)*
1139
1605
 
1140
- **Q22: Do you need Docker containerization?**
1606
+ **Q29: Docker containerization?**
1141
1607
  > **Recommended:** Yes
1142
1608
  > **Your Answer:** *(yes / no)*
1143
1609
 
1144
- **Q23: CI/CD pipeline?**
1610
+ **Q30: CI/CD pipeline?**
1145
1611
  > **Recommended:** GitHub Actions
1146
1612
  > **Your Answer:** *(yes / no)*
1147
1613
 
@@ -1149,18 +1615,12 @@ ${hasMobile ? `
1149
1615
 
1150
1616
  ## 🧪 Testing Strategy
1151
1617
 
1152
- **Q24: How should testing be handled?**
1618
+ **Q31: How should testing be handled?**
1153
1619
 
1154
1620
  Options:
1155
- - **[A] Fast Mode (Recommended for MVPs)** — No testing during development sprints.
1156
- A dedicated final sprint handles all testing, security audit, SEO, and browser testing.
1157
- 3-5x faster for initial development.
1158
-
1621
+ - **[A] Fast Mode (Recommended for MVPs)** — No testing during dev sprints. Final sprint handles all testing, security, SEO, browser testing. 3-5x faster.
1159
1622
  - **[B] Balanced Mode** — Basic smoke tests per sprint. Full test suite at end.
1160
- ~80% development speed of Fast Mode.
1161
-
1162
- - **[C] Strict TDD Mode** — Full Red-Green-Refactor on every task.
1163
- Slowest but highest quality. Only for healthcare, finance, compliance projects.
1623
+ - **[C] Strict TDD Mode** — Red-Green-Refactor on every task. Healthcare/finance only.
1164
1624
 
1165
1625
  > **Recommended:** A (Fast Mode)
1166
1626
  > **Your Answer:** A *(change to B or C if needed)*
@@ -1169,15 +1629,15 @@ Options:
1169
1629
 
1170
1630
  ## 🔒 Security
1171
1631
 
1172
- **Q25: Security audit timing?**
1632
+ **Q32: Security audit timing?**
1173
1633
  > **Recommended:** Final sprint only (OWASP Top 10 + dependency scan)
1174
1634
  > **Your Answer:** *(final sprint only / every sprint)*
1175
1635
 
1176
1636
  ---
1177
1637
 
1178
- ## 🌐 SEO (if web app)
1638
+ ## 🌐 SEO
1179
1639
 
1180
- **Q26: SEO requirements?**
1640
+ **Q33: SEO requirements?**
1181
1641
  > **Recommended:** Technical SEO in final sprint (meta tags, Core Web Vitals, structured data)
1182
1642
  > **Your Answer:** *(final sprint only / every sprint / not needed)*
1183
1643
 
@@ -1193,125 +1653,337 @@ Write any additional requirements, constraints, or preferences here:
1193
1653
 
1194
1654
  *When ready, run \`imhcode plan\` to generate sprint plans from your answers.*
1195
1655
  `;
1196
-
1197
- const brainstormPath = path.join(cwd, BRAINSTORM_MD);
1198
- fs.mkdirSync(path.join(cwd, DOCS_DIR), { recursive: true });
1199
- fs.writeFileSync(brainstormPath, content, 'utf8');
1200
1656
  }
1201
1657
 
1202
- // ─── Sprint Plan Generator ────────────────────────────────────────────────────
1658
+ // ─── Fix 0 + Fix 5: Sprint Plan Generator (LLM-Powered + Stack-Aware) ─────────
1203
1659
 
1204
1660
  async function generateSprintPlans(cwd, userPrompt, brainstormContent, config) {
1205
1661
  // Parse answers from brainstorming
1206
- const testingMode = extractAnswer(brainstormContent, 'Q24', 'A').trim().toUpperCase();
1207
- const hasFrontend = brainstormContent.includes('frontend') || brainstormContent.includes('Next.js') || brainstormContent.includes('Vue');
1208
- const hasBackend = brainstormContent.includes('Laravel') || brainstormContent.includes('Python') || brainstormContent.includes('Django') || brainstormContent.includes('Java');
1209
-
1210
- const detectedTesting = testingMode === 'B' ? 'balanced' : testingMode === 'C' ? 'strict' : 'fast';
1662
+ const testingModeRaw = extractAnswer(brainstormContent, 'Q31', 'A').trim().toUpperCase().charAt(0);
1663
+ const detectedTesting = testingModeRaw === 'B' ? 'balanced' : testingModeRaw === 'C' ? 'strict' : 'fast';
1664
+
1665
+ // Detect scope from brainstorm content
1666
+ const b = brainstormContent.toLowerCase();
1667
+ const hasFrontend = true; // Always assume frontend
1668
+ const hasBackend = (() => {
1669
+ // Check Q31-equivalent backend answer or keyword detection
1670
+ const backendAnswer = extractAnswer(brainstormContent, 'Q16', '').trim();
1671
+ if (backendAnswer && backendAnswer !== '*(edit if needed)*') return true;
1672
+ return /laravel|django|fastapi|express|spring\s*boot|node\.js.*api|postgresql|mysql|redis/i.test(brainstormContent);
1673
+ })();
1674
+ const hasMobile = /flutter|react native|ios.*app|android.*app|expo/i.test(brainstormContent);
1675
+ const needsWorktrees = /worktree.*yes|yes.*worktree/i.test(brainstormContent);
1676
+ const hasPayments = /stripe|paypal|payment|yes.*payment/i.test(brainstormContent);
1677
+ const hasRealtime = /websocket|real-time.*yes|yes.*real-time|socket\.io/i.test(brainstormContent);
1678
+ const designStyle = (() => {
1679
+ const m = brainstormContent.match(/Your Answer:\s*\*(.*?(?:glassmorphism|neumorphism|brutalism|claymorphism|minimalist|modern saas).*?)\*/i);
1680
+ return m ? m[1].trim() : 'Modern SaaS';
1681
+ })();
1682
+ const colorStyle = (() => {
1683
+ const m = brainstormContent.match(/Your Answer:\s*\*(.*?(?:vibrant|dark premium|minimal neutral|pastel|corporate|bold).*?)\*/i);
1684
+ return m ? m[1].trim() : 'Dark Premium';
1685
+ })();
1211
1686
 
1212
1687
  // Save testing mode to config
1213
1688
  if (config) {
1214
1689
  config.testing_mode = detectedTesting;
1215
1690
  const configPath = path.join(cwd, CONFIG_FILE);
1216
- fs.writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf8');
1691
+ try { fs.writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf8'); } catch {}
1692
+ }
1693
+
1694
+ // Fix 5: Create workspace directories lazily based on brainstorm answers
1695
+ if (hasFrontend) {
1696
+ const frontendDir = path.join(cwd, 'frontend');
1697
+ if (!fs.existsSync(frontendDir)) {
1698
+ fs.mkdirSync(frontendDir, { recursive: true });
1699
+ console.log(` 📁 Created frontend/ (scope confirmed in brainstorming)`);
1700
+ }
1701
+ }
1702
+ if (hasBackend) {
1703
+ const backendDir = path.join(cwd, 'backend');
1704
+ if (!fs.existsSync(backendDir)) {
1705
+ fs.mkdirSync(backendDir, { recursive: true });
1706
+ console.log(` 📁 Created backend/ (scope confirmed in brainstorming)`);
1707
+ }
1708
+ }
1709
+ if (needsWorktrees) {
1710
+ const wtDir = path.join(cwd, '.worktrees');
1711
+ if (!fs.existsSync(wtDir)) {
1712
+ fs.mkdirSync(wtDir, { recursive: true });
1713
+ console.log(` 📁 Created .worktrees/ (git worktree snapshots enabled)`);
1714
+ }
1217
1715
  }
1218
1716
 
1219
1717
  // Generate PROJECT_BRIEF.md
1220
- const briefContent = generateProjectBrief(userPrompt, brainstormContent);
1718
+ const briefContent = generateProjectBrief(userPrompt, brainstormContent, {
1719
+ hasFrontend, hasBackend, hasMobile, designStyle, colorStyle, detectedTesting
1720
+ });
1221
1721
  fs.writeFileSync(path.join(cwd, BRIEF_MD), briefContent, 'utf8');
1222
1722
  console.log(` ✅ Created PROJECT_BRIEF.md`);
1223
1723
 
1224
- // Generate Sprint 1 (Foundation)
1225
- await generateSprint(cwd, 1, 'Foundation & Setup', [
1226
- { task: 'Initialize project structure and configure environments', agent: 'devops-executor', tier: 'light', deps: [] },
1227
- { task: 'Set up database schema and migrations', agent: hasBackend ? 'laravel-executor' : 'python-executor', tier: 'standard', deps: [1] },
1228
- { task: 'Implement authentication system (register, login, logout)', agent: hasBackend ? 'laravel-executor' : 'python-executor', tier: 'complex', deps: [2] },
1229
- ...(hasFrontend ? [
1230
- { task: 'Set up frontend project with design system and component library', agent: 'nextjs-executor', tier: 'standard', deps: [1] },
1231
- { task: 'Build authentication UI pages (login, register, forgot password)', agent: 'nextjs-executor', tier: 'standard', deps: [3, 4] },
1232
- ] : []),
1233
- ], detectedTesting);
1724
+ // Try LLM-powered sprint generation first (Fix 0)
1725
+ const llmSprintResult = await tryLLMSprintGeneration(
1726
+ cwd, userPrompt, brainstormContent, config,
1727
+ { hasFrontend, hasBackend, hasMobile, hasPayments, hasRealtime, designStyle, colorStyle, detectedTesting, needsWorktrees }
1728
+ );
1234
1729
 
1235
- // Generate Sprint 2 (Core Features)
1236
- await generateSprint(cwd, 2, 'Core Features', [
1237
- { task: 'Build main API endpoints for core business logic', agent: hasBackend ? 'laravel-executor' : 'python-executor', tier: 'complex', deps: [] },
1238
- ...(hasFrontend ? [
1239
- { task: 'Build dashboard layout with navigation and sidebar', agent: 'nextjs-executor', tier: 'standard', deps: [] },
1240
- { task: 'Implement main feature pages and components', agent: 'nextjs-executor', tier: 'complex', deps: [2] },
1241
- { task: 'Connect frontend to backend API with error handling', agent: 'nextjs-executor', tier: 'standard', deps: [1, 3] },
1242
- ] : []),
1243
- { task: 'Implement user settings and profile management', agent: hasBackend ? 'laravel-executor' : 'python-executor', tier: 'standard', deps: [1] },
1244
- ], detectedTesting);
1730
+ let lastSprintNum;
1245
1731
 
1246
- // Determine last sprint number
1247
- let lastSprintNum = 2;
1732
+ if (llmSprintResult) {
1733
+ console.log(` Sprint plans generated by planning AI`);
1734
+ lastSprintNum = llmSprintResult.sprintCount;
1735
+ } else {
1736
+ // Fix 5: Fallback to smart static generation
1737
+ lastSprintNum = await generateStaticSprintPlans(
1738
+ cwd,
1739
+ { hasFrontend, hasBackend, hasMobile, hasPayments, hasRealtime, designStyle, colorStyle, detectedTesting },
1740
+ config
1741
+ );
1742
+ }
1248
1743
 
1249
- // If testing mode is fast/balanced, auto-generate testing sprint
1744
+ // Auto-generate testing sprint if fast/balanced mode
1250
1745
  if (detectedTesting !== 'strict') {
1251
1746
  const testingSprintNum = lastSprintNum + 1;
1252
- await generateTestingSprint(cwd, testingSprintNum, hasFrontend, hasBackend);
1253
- console.log(` ✅ Created auto-generated Testing Sprint ${testingSprintNum}`);
1747
+ await generateTestingSprint(cwd, testingSprintNum, hasFrontend, hasBackend, config);
1748
+ console.log(` ✅ Created Testing Sprint ${testingSprintNum} (security + SEO + E2E)`);
1254
1749
  }
1255
1750
 
1256
1751
  // Update compact context
1257
- const contextContent = `# IMH-Code Project Context
1752
+ const contextContent = buildContextContent(userPrompt, {
1753
+ hasFrontend, hasBackend, hasMobile, detectedTesting, lastSprintNum, designStyle, colorStyle
1754
+ });
1755
+ fs.mkdirSync(path.join(cwd, LOCAL_DIR_NAME), { recursive: true });
1756
+ fs.writeFileSync(path.join(cwd, CONTEXT_MD), contextContent, 'utf8');
1757
+ console.log(` ✅ Created .imhcode/context.md`);
1758
+ }
1258
1759
 
1259
- Generated: ${new Date().toLocaleDateString()}
1260
- Project: ${userPrompt.slice(0, 100)}...
1261
- Testing Mode: ${detectedTesting}
1262
- Sprints: ${lastSprintNum + (detectedTesting !== 'strict' ? 1 : 0)} total
1760
+ /**
1761
+ * Attempt LLM-generated sprint plans. Returns { sprintCount } on success, null on failure.
1762
+ */
1763
+ async function tryLLMSprintGeneration(cwd, userPrompt, brainstormContent, config, scope) {
1764
+ const { hasFrontend, hasBackend, hasMobile, hasPayments, hasRealtime, designStyle, colorStyle, detectedTesting } = scope;
1263
1765
 
1264
- ## Stack
1265
- ${hasFrontend ? '- Frontend: Next.js 15 + shadcn/ui + Tailwind CSS v4' : ''}
1266
- ${hasBackend ? '- Backend: Laravel 11 + PostgreSQL + Redis' : ''}
1267
- - Auth: JWT tokens
1268
- - Deployment: Docker + GitHub Actions
1766
+ const agentList = [
1767
+ 'planner (planning)', 'designer (frontend)', 'nextjs-executor (frontend)', 'react-executor (frontend)',
1768
+ 'vue-executor (frontend)', 'laravel-executor (backend)', 'python-executor (backend)',
1769
+ 'java-executor (backend)', 'flutter-executor (backend)', 'react-native-executor (backend)',
1770
+ 'ios-executor (backend)', 'android-executor (backend)', 'systems-executor (backend)',
1771
+ 'web3-executor (backend)', 'devops-executor (backend)', 'tester (testing)',
1772
+ 'security-auditor (testing)', 'seo-optimizer (review)', 'debugger (review)',
1773
+ ].join('\n ');
1269
1774
 
1270
- ## Directory Structure
1271
- - frontend/ All frontend code
1272
- - backend/ All backend code
1273
- - docs/ — Sprint plans and documentation
1775
+ const modelRouting = config?.model_routing || {};
1776
+ const routingContext = Object.entries(modelRouting).map(([cat, r]) =>
1777
+ ` ${cat}: ${r?.model} via ${r?.engine}`
1778
+ ).join('\n');
1274
1779
 
1275
- ## Current Sprint
1276
- Sprint 1 (not started)
1780
+ const llmPrompt = `You are the IMH-Code Sprint Planner — an expert software architect.
1277
1781
 
1278
- ## Key Files
1279
- ${hasFrontend ? '- frontend/app/ — Next.js pages' : ''}
1280
- ${hasBackend ? '- backend/routes/api.php — API routes' : ''}
1281
- ${hasBackend ? '- backend/app/Models/ — Eloquent models' : ''}
1282
- `;
1782
+ Generate a complete sprint plan for the following project. Output ONLY valid JSON, nothing else.
1283
1783
 
1284
- fs.mkdirSync(path.join(cwd, LOCAL_DIR_NAME), { recursive: true });
1285
- fs.writeFileSync(path.join(cwd, CONTEXT_MD), contextContent, 'utf8');
1286
- console.log(` ✅ Created .imhcode/context.md (compact context)`);
1784
+ ## Project Description
1785
+ ${userPrompt}
1786
+
1787
+ ## Brainstorming Answers
1788
+ ${brainstormContent}
1789
+
1790
+ ## Scope
1791
+ - Frontend: ${hasFrontend ? 'YES' : 'NO'} (Design style: ${designStyle}, Colors: ${colorStyle})
1792
+ - Backend: ${hasBackend ? 'YES' : 'NO'}
1793
+ - Mobile: ${hasMobile ? 'YES' : 'NO'}
1794
+ - Payments: ${hasPayments ? 'YES' : 'NO'}
1795
+ - Realtime: ${hasRealtime ? 'YES' : 'NO'}
1796
+ - Testing: ${detectedTesting}
1797
+
1798
+ ## Available Agents
1799
+ ${agentList}
1800
+
1801
+ ## Model Routing (each agent will use its category model)
1802
+ ${routingContext}
1803
+
1804
+ ## Output Format
1805
+
1806
+ Return ONLY this JSON structure (no markdown, no explanation):
1807
+
1808
+ {
1809
+ "sprints": [
1810
+ {
1811
+ "num": 1,
1812
+ "title": "Foundation & Setup",
1813
+ "tasks": [
1814
+ {
1815
+ "num": 1,
1816
+ "task": "Detailed task description that a senior engineer would understand",
1817
+ "agent": "agent-id",
1818
+ "tier": "light|standard|complex",
1819
+ "deps": []
1820
+ }
1821
+ ]
1822
+ }
1823
+ ]
1824
+ }
1825
+
1826
+ ## Rules
1827
+ 1. Generate 2-4 sprints based on project complexity (NOT counting the testing sprint)
1828
+ 2. Sprint 1 = Foundation (project setup, DB schema, auth, design system)
1829
+ 3. Sprint 2 = Core Features (main functionality)
1830
+ 4. Sprint 3+ = Additional features, integrations (only if needed)
1831
+ 5. Task descriptions must be SPECIFIC to this project, not generic
1832
+ 6. Choose the RIGHT agent for each task:
1833
+ - nextjs-executor/react-executor/vue-executor/designer → frontend tasks
1834
+ - laravel-executor/python-executor/java-executor → backend tasks
1835
+ - devops-executor → infrastructure, Docker, CI/CD
1836
+ - planner → complex planning/architecture tasks
1837
+ 7. Respect dependencies (dep task numbers that must complete first)
1838
+ 8. Max 6 tasks per sprint for clean execution
1839
+ 9. If design style is Glassmorphism/Neumorphism — include a designer task for design tokens in Sprint 1
1840
+ 10. If payments needed — include payment integration task in a sprint
1841
+ 11. If realtime needed — include WebSocket/SSE task in a sprint`;
1842
+
1843
+ const llmOutput = await invokePlanningLLM(llmPrompt, config, cwd);
1844
+ if (!llmOutput) return null;
1845
+
1846
+ // Parse JSON from LLM output
1847
+ let parsed;
1848
+ try {
1849
+ // Strip markdown code fences if present
1850
+ const cleaned = llmOutput.replace(/```json\n?/g, '').replace(/```\n?/g, '').trim();
1851
+ parsed = JSON.parse(cleaned);
1852
+ } catch (err) {
1853
+ // Try to extract JSON object from the output
1854
+ const jsonMatch = llmOutput.match(/\{[\s\S]*"sprints"[\s\S]*\}/);
1855
+ if (!jsonMatch) {
1856
+ console.warn(' ⚠️ Planning AI returned non-JSON output — falling back to static template');
1857
+ return null;
1858
+ }
1859
+ try {
1860
+ parsed = JSON.parse(jsonMatch[0]);
1861
+ } catch {
1862
+ console.warn(' ⚠️ Could not parse planning AI JSON — falling back to static template');
1863
+ return null;
1864
+ }
1865
+ }
1866
+
1867
+ if (!parsed?.sprints?.length) return null;
1868
+
1869
+ // Generate sprint files from LLM-provided structure
1870
+ for (const sprint of parsed.sprints) {
1871
+ await generateSprint(cwd, sprint.num, sprint.title, sprint.tasks, detectedTesting, config);
1872
+ console.log(` ✅ Created Sprint ${sprint.num}: ${sprint.title} (${sprint.tasks.length} tasks)`);
1873
+ }
1874
+
1875
+ return { sprintCount: parsed.sprints.length };
1876
+ }
1877
+
1878
+ /**
1879
+ * Fix 5: Smart static sprint plan generator (fallback when LLM unavailable)
1880
+ * Generates tailored sprints based on detected scope.
1881
+ */
1882
+ async function generateStaticSprintPlans(cwd, scope, config) {
1883
+ const { hasFrontend, hasBackend, hasMobile, hasPayments, hasRealtime, designStyle, colorStyle, detectedTesting } = scope;
1884
+
1885
+ const frontendAgent = 'nextjs-executor';
1886
+ const backendAgent = hasBackend ? 'laravel-executor' : 'python-executor';
1887
+
1888
+ const needsDesignSprint = /glassmorphism|neumorphism|brutalism|claymorphism/i.test(designStyle);
1889
+
1890
+ let sprintNum = 1;
1891
+ const sprints = [];
1892
+
1893
+ // Sprint 1: Foundation
1894
+ const sprint1Tasks = [
1895
+ { task: 'Initialize monorepo structure, configure environments (.env, Docker compose, GitHub Actions skeleton)', agent: 'devops-executor', tier: 'light', deps: [] },
1896
+ ...(hasBackend ? [
1897
+ { task: `Design and implement database schema with migrations for core entities. Set up ${/laravel/i.test(backendAgent) ? 'Eloquent models' : 'ORM models'} with relationships, indexes, and seed factories`, agent: backendAgent, tier: 'standard', deps: [1] },
1898
+ { task: 'Implement full authentication system: user registration, login, logout, password reset, email verification, JWT/session management', agent: backendAgent, tier: 'complex', deps: [2] },
1899
+ ] : []),
1900
+ ...(needsDesignSprint ? [
1901
+ { task: `Design system tokens: ${colorStyle} color palette, typography scale, spacing system, ${designStyle} component patterns (glassmorphism/shadows/borders). Generate CSS custom properties and Tailwind config`, agent: 'designer', tier: 'standard', deps: [1] },
1902
+ ] : []),
1903
+ ...(hasFrontend ? [
1904
+ { task: `Set up ${frontendAgent.replace('-executor', '')} project with shadcn/ui, Tailwind CSS v4, ${needsDesignSprint ? designStyle + ' design tokens,' : ''} ESLint, Prettier, and base layout components`, agent: frontendAgent, tier: 'standard', deps: [1] },
1905
+ { task: 'Build authentication UI pages: login, register, forgot password, email verification. Connect to backend auth API with error handling and loading states', agent: frontendAgent, tier: 'standard', deps: hasBackend ? [3, needsDesignSprint ? 4 : 4] : [needsDesignSprint ? 4 : 4] },
1906
+ ] : []),
1907
+ ];
1908
+ sprints.push({ num: sprintNum++, title: 'Foundation & Setup', tasks: sprint1Tasks });
1909
+
1910
+ // Sprint 2: Core Features
1911
+ const sprint2Tasks = [
1912
+ ...(hasBackend ? [
1913
+ { task: 'Build main REST API endpoints for core business logic. Include request validation, error responses, pagination, and comprehensive API documentation', agent: backendAgent, tier: 'complex', deps: [] },
1914
+ { task: 'Implement user profile, settings management, role-based permissions, and admin panel endpoints', agent: backendAgent, tier: 'standard', deps: [1] },
1915
+ ] : []),
1916
+ ...(hasFrontend ? [
1917
+ { task: 'Build main dashboard layout: sidebar navigation, header with user menu, breadcrumbs, responsive grid. Implement route structure and page transitions', agent: frontendAgent, tier: 'standard', deps: [] },
1918
+ { task: 'Implement core feature pages and reusable data components (tables, forms, modals, filters). Connect to backend APIs with optimistic UI updates', agent: frontendAgent, tier: 'complex', deps: [hasBackend ? 3 : 1] },
1919
+ { task: 'Build user settings, profile management, and notification preference pages. Implement theme toggle and responsive mobile navigation', agent: frontendAgent, tier: 'standard', deps: [hasBackend ? 4 : 2] },
1920
+ ] : []),
1921
+ ];
1922
+ sprints.push({ num: sprintNum++, title: 'Core Features', tasks: sprint2Tasks });
1923
+
1924
+ // Sprint 3: Advanced Features (if payments, realtime, or mobile needed)
1925
+ const sprint3Tasks = [];
1926
+ if (hasPayments) {
1927
+ sprint3Tasks.push({ task: 'Integrate Stripe payment processing: subscription plans, checkout flow, webhooks for payment events, billing portal, invoice management', agent: backendAgent, tier: 'complex', deps: [] });
1928
+ if (hasFrontend) {
1929
+ sprint3Tasks.push({ task: 'Build pricing page, checkout UI with Stripe Elements, subscription management dashboard, billing history', agent: frontendAgent, tier: 'complex', deps: [1] });
1930
+ }
1931
+ }
1932
+ if (hasRealtime) {
1933
+ sprint3Tasks.push({ task: 'Implement WebSocket/SSE real-time features: live data updates, presence indicators, notification broadcasting. Set up Redis pub/sub', agent: backendAgent, tier: 'complex', deps: [] });
1934
+ if (hasFrontend) {
1935
+ sprint3Tasks.push({ task: 'Build real-time UI components: live activity feed, online users indicator, real-time notifications toast system', agent: frontendAgent, tier: 'standard', deps: [hasPayments ? 2 : 1] });
1936
+ }
1937
+ }
1938
+ if (hasMobile) {
1939
+ sprint3Tasks.push({ task: 'Build core mobile screens: auth flow, home/dashboard, main feature screens. Set up navigation, state management, and API integration', agent: 'flutter-executor', tier: 'complex', deps: [] });
1940
+ sprint3Tasks.push({ task: 'Implement push notifications, offline support, biometric auth, and app store metadata preparation', agent: 'flutter-executor', tier: 'standard', deps: [sprint3Tasks.length] });
1941
+ }
1942
+ if (sprint3Tasks.length > 0) {
1943
+ sprints.push({ num: sprintNum++, title: 'Advanced Features', tasks: sprint3Tasks });
1944
+ }
1945
+
1946
+ // Generate all sprint files
1947
+ for (const sprint of sprints) {
1948
+ await generateSprint(cwd, sprint.num, sprint.title, sprint.tasks, detectedTesting, config);
1949
+ console.log(` ✅ Created Sprint ${sprint.num}: ${sprint.title} (${sprint.tasks.length} tasks)`);
1950
+ }
1951
+
1952
+ return sprintNum - 1; // last sprint number
1287
1953
  }
1288
1954
 
1289
- async function generateSprint(cwd, sprintNum, title, tasks, testingMode) {
1955
+ // ─── Fix 0b Part B: Sprint File Generator (injects --engine/--model) ──────────
1956
+
1957
+ async function generateSprint(cwd, sprintNum, title, tasks, testingMode, config) {
1290
1958
  const sprintDir = path.join(cwd, DOCS_DIR, `sprint-${sprintNum}`);
1291
1959
  const tasksDir = path.join(sprintDir, 'tasks');
1292
1960
  fs.mkdirSync(tasksDir, { recursive: true });
1293
1961
 
1294
- // plan.md
1295
- const tddNote = testingMode === 'strict' ? '**Testing Mode: Strict TDD** — Write failing tests first.' :
1296
- testingMode === 'balanced' ? '**Testing Mode: Balanced** — Basic smoke tests per task.' :
1297
- '**Testing Mode: Fast** — No tests during this sprint. Tests handled in final sprint.';
1962
+ const tddNote = testingMode === 'strict' ? '**Testing Mode: Strict TDD** — Write failing tests first, then implement.' :
1963
+ testingMode === 'balanced' ? '**Testing Mode: Balanced** — Add basic smoke tests per task.' :
1964
+ '**Testing Mode: Fast** — No tests during this sprint. Final sprint handles all testing.';
1298
1965
 
1966
+ // plan.md
1299
1967
  let planMd = `# Sprint ${sprintNum}: ${title}
1300
1968
 
1301
1969
  > ${tddNote}
1302
1970
 
1303
1971
  ## Task Table
1304
1972
 
1305
- | # | Task | Agent | Tier | Depends On |
1306
- |---|------|-------|------|-----------|
1307
- ${tasks.map((t, i) => `| ${i+1} | ${t.task} | \`${t.agent}\` | ${t.tier} | ${t.deps.length ? t.deps.join(', ') : '—'} |`).join('\n')}
1973
+ | # | Task | Agent | Category | Model | Tier | Depends On |
1974
+ |---|------|-------|----------|-------|------|-----------|
1975
+ ${tasks.map((t, i) => {
1976
+ const cat = getAgentCategory(t.agent);
1977
+ const model = config?.model_routing?.[cat]?.model || t.agent;
1978
+ return `| ${i+1} | ${t.task} | \`${t.agent}\` | ${cat} | ${model} | ${t.tier} | ${t.deps?.length ? t.deps.join(', ') : '—'} |`;
1979
+ }).join('\n')}
1308
1980
 
1309
1981
  ## Sprint Goals
1310
1982
  - Complete all ${tasks.length} tasks in dependency order
1983
+ - Each task uses its category-optimized AI model
1311
1984
  - Update PROJECT_BRIEF.md after completion
1312
1985
  - Update .imhcode/context.md with what was built
1313
1986
  `;
1314
-
1315
1987
  fs.writeFileSync(path.join(sprintDir, 'plan.md'), planMd, 'utf8');
1316
1988
 
1317
1989
  // progress.md
@@ -1322,49 +1994,57 @@ Start: —
1322
1994
  End: —
1323
1995
 
1324
1996
  ## Task Status
1325
- ${tasks.map((t, i) => `- [ ] Task ${i+1}: ${t.task}`).join('\n')}
1997
+ ${tasks.map((t, i) => `- [ ] Task ${i+1}: ${t.task} [\`${t.agent}\`]`).join('\n')}
1326
1998
  `;
1327
1999
  fs.writeFileSync(path.join(sprintDir, 'progress.md'), progressMd, 'utf8');
1328
-
1329
- // deferred.md
1330
2000
  fs.writeFileSync(path.join(sprintDir, 'deferred.md'), `# Sprint ${sprintNum} Deferred Items\n\nNone yet.\n`, 'utf8');
1331
2001
 
1332
- // Individual task scripts
2002
+ // Fix 0b Part B: Individual task scripts with --engine/--model injected
1333
2003
  for (let i = 0; i < tasks.length; i++) {
1334
- const t = tasks[i];
2004
+ const t = tasks[i];
1335
2005
  const taskNum = i + 1;
1336
- const testingFlag = testingMode === 'strict' ? '# Testing mode: strict — include TDD instructions\nTASK="[STRICT TDD] ${t.task}: Write failing tests first, then implement."' :
1337
- testingMode === 'balanced' ? `TASK="[BALANCED] ${t.task}: Add basic smoke tests."` :
1338
- `TASK="${t.task}"`;
2006
+ const category = getAgentCategory(t.agent);
2007
+ const routedEngine = config?.model_routing?.[category]?.engine || '';
2008
+ const routedModel = config?.model_routing?.[category]?.model || '';
2009
+
2010
+ const engineFlag = routedEngine ? `--engine ${routedEngine}` : '';
2011
+ const modelFlag = routedModel ? `--model "${routedModel}"` : '';
2012
+
2013
+ const taskDesc = testingMode === 'strict' ? `[STRICT TDD] ${t.task}: Write failing tests first, then implement.` :
2014
+ testingMode === 'balanced' ? `[BALANCED] ${t.task}: Add basic smoke tests.` :
2015
+ t.task;
1339
2016
 
1340
2017
  const taskScript = `#!/bin/bash
1341
2018
  # IMH-Code — Sprint ${sprintNum} Task ${taskNum}
1342
- # Task: ${t.task}
1343
- # Agent: ${t.agent}
1344
- # Tier: ${t.tier}
1345
- CWD="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
2019
+ # Task: ${t.task}
2020
+ # Agent: ${t.agent} (${category})
2021
+ # Model: ${routedModel || 'default'} via ${routedEngine || 'default'}
2022
+ # Tier: ${t.tier}
2023
+ CWD="$(cd "$(dirname "\${BASH_SOURCE[0]}")" && pwd)"
1346
2024
  cd "$CWD/../../../.."
1347
2025
 
1348
- ${testingFlag}
2026
+ TASK="${taskDesc.replace(/"/g, '\\"')}"
1349
2027
 
1350
2028
  echo "📋 Running Task ${taskNum}: ${t.task}"
1351
- echo " Agent: ${t.agent} | Tier: ${t.tier}"
2029
+ echo " Agent: ${t.agent}"
2030
+ echo " Model: ${routedModel || 'default'} via ${routedEngine || 'default'}"
2031
+ echo " Tier: ${t.tier}"
1352
2032
 
1353
2033
  if command -v imhcode >/dev/null 2>&1; then
1354
- imhcode agent run ${t.agent} "$TASK" --live
2034
+ imhcode agent run ${t.agent} "$TASK" --live ${engineFlag} ${modelFlag}
1355
2035
  else
1356
- node "$(npm root -g)/imhcode/bin/imhcode.js" agent run ${t.agent} "$TASK" --live
2036
+ node "$(npm root -g)/imhcode/bin/imhcode.js" agent run ${t.agent} "$TASK" --live ${engineFlag} ${modelFlag}
1357
2037
  fi
1358
2038
  `;
1359
2039
  fs.writeFileSync(path.join(tasksDir, `task_${taskNum}.sh`), taskScript, { mode: 0o755 });
1360
2040
  }
1361
2041
 
1362
- // run_all_tasks.sh (respects dependency ordering)
2042
+ // run_all_tasks.sh
1363
2043
  const masterScript = `#!/bin/bash
1364
2044
  # IMH-Code — Sprint ${sprintNum}: ${title}
1365
- # Run all tasks in dependency order
2045
+ # Run all tasks in dependency order with correct AI model routing
1366
2046
  set -e
1367
- CWD="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
2047
+ CWD="$(cd "$(dirname "\${BASH_SOURCE[0]}")" && pwd)"
1368
2048
  TASKS_DIR="$CWD/tasks"
1369
2049
 
1370
2050
  echo ""
@@ -1374,8 +2054,11 @@ echo ""
1374
2054
 
1375
2055
  ${tasks.map((t, i) => {
1376
2056
  const taskNum = i + 1;
2057
+ const category = getAgentCategory(t.agent);
2058
+ const model = config?.model_routing?.[category]?.model || 'default';
1377
2059
  return `echo "\\n─────────────────────────────────────────────────────────────"
1378
2060
  echo "📋 Task ${taskNum}/${tasks.length}: ${t.task}"
2061
+ echo " Agent: ${t.agent} → ${model}"
1379
2062
  echo "─────────────────────────────────────────────────────────────"
1380
2063
  bash "$TASKS_DIR/task_${taskNum}.sh"`;
1381
2064
  }).join('\n\n')}
@@ -1386,32 +2069,30 @@ echo " Run: imhcode execute ${sprintNum + 1}"
1386
2069
  echo ""
1387
2070
  `;
1388
2071
  fs.writeFileSync(path.join(sprintDir, 'run_all_tasks.sh'), masterScript, { mode: 0o755 });
1389
-
1390
- console.log(` ✅ Created Sprint ${sprintNum}: ${title} (${tasks.length} tasks)`);
1391
2072
  }
1392
2073
 
1393
- async function generateTestingSprint(cwd, sprintNum, hasFrontend, hasBackend) {
2074
+ async function generateTestingSprint(cwd, sprintNum, hasFrontend, hasBackend, config) {
1394
2075
  const tasks = [
1395
- { task: 'Write unit tests for all backend API endpoints', agent: 'tester', tier: 'standard', deps: [] },
1396
- { task: 'Write integration tests for core API flows', agent: 'tester', tier: 'complex', deps: [1] },
1397
- ...(hasFrontend ? [
1398
- { task: 'Write component tests for all frontend pages and components', agent: 'tester', tier: 'standard', deps: [] },
1399
- { task: 'Run E2E browser tests with Playwright (all critical user flows)', agent: 'tester', tier: 'complex', deps: [3] },
2076
+ ...(hasBackend ? [
2077
+ { task: 'Write comprehensive unit tests for all backend API endpoints, service layer, and utility functions. Target 80%+ coverage', agent: 'tester', tier: 'standard', deps: [] },
2078
+ { task: 'Write integration tests for core API flows: auth, main CRUD operations, edge cases, and error handling', agent: 'tester', tier: 'complex', deps: [1] },
1400
2079
  ] : []),
1401
- { task: 'Run security audit: OWASP Top 10, dependency vulnerabilities, auth testing', agent: 'security-auditor', tier: 'complex', deps: [] },
2080
+ { task: 'Run full security audit: OWASP Top 10, dependency vulnerability scan (npm audit / composer audit), auth testing, SQL injection, XSS checks', agent: 'security-auditor', tier: 'complex', deps: [] },
1402
2081
  ...(hasFrontend ? [
1403
- { task: 'Run SEO audit: Core Web Vitals, meta tags, structured data, sitemap', agent: 'seo-optimizer', tier: 'standard', deps: [] },
1404
- { task: 'Run accessibility audit (WCAG 2.1 AA) and fix critical issues', agent: 'tester', tier: 'standard', deps: [3, 4] },
2082
+ { task: 'Write Playwright E2E tests covering all critical user flows: registration, login, core features, payment flow (if applicable)', agent: 'tester', tier: 'complex', deps: hasBackend ? [2] : [] },
2083
+ { task: 'Run SEO audit: Core Web Vitals (LCP, CLS, INP), meta tags, structured data, sitemap.xml, robots.txt, Open Graph tags', agent: 'seo-optimizer', tier: 'standard', deps: [] },
2084
+ { task: 'Run accessibility audit (WCAG 2.1 AA): screen reader compatibility, keyboard navigation, color contrast, ARIA labels. Fix all critical issues', agent: 'tester', tier: 'standard', deps: [] },
1405
2085
  ] : []),
1406
- { task: 'Generate final test coverage report and fix failing tests', agent: 'tester', tier: 'standard', deps: [] },
2086
+ { task: 'Generate final test coverage report. Fix any failing tests. Document known issues in PROJECT_REPORT.md', agent: 'tester', tier: 'standard', deps: [] },
1407
2087
  ];
1408
2088
 
1409
- await generateSprint(cwd, sprintNum, 'Testing, Security & SEO Audit', tasks, 'fast');
2089
+ await generateSprint(cwd, sprintNum, 'Testing, Security & SEO Audit', tasks, 'fast', config);
1410
2090
  }
1411
2091
 
1412
2092
  // ─── Helper Functions ─────────────────────────────────────────────────────────
1413
2093
 
1414
- function generateProjectBrief(userPrompt, brainstormContent) {
2094
+ function generateProjectBrief(userPrompt, brainstormContent, scope) {
2095
+ const { hasFrontend, hasBackend, hasMobile, designStyle, colorStyle, detectedTesting } = scope || {};
1415
2096
  return `# PROJECT_BRIEF.md
1416
2097
 
1417
2098
  > **IMH-Code — Imam Hussain Coding Harness Platform**
@@ -1425,9 +2106,20 @@ ${userPrompt}
1425
2106
  ## Status
1426
2107
 
1427
2108
  - **Current Sprint**: Sprint 1
1428
- - **Testing Mode**: Fast (final sprint only)
2109
+ - **Testing Mode**: ${detectedTesting || 'fast'} (final sprint only)
1429
2110
  - **Generated**: ${new Date().toLocaleDateString()}
1430
2111
 
2112
+ ## Design Specification
2113
+
2114
+ - **Design Style**: ${designStyle || 'Modern SaaS'}
2115
+ - **Color Palette**: ${colorStyle || 'Dark Premium'}
2116
+
2117
+ ## Scope
2118
+
2119
+ - **Frontend**: ${hasFrontend ? '✅ Yes' : '❌ No'}
2120
+ - **Backend**: ${hasBackend ? '✅ Yes' : '❌ No'}
2121
+ - **Mobile**: ${hasMobile ? '✅ Yes' : '❌ No'}
2122
+
1431
2123
  ## Key Architecture Decisions
1432
2124
 
1433
2125
  *(Will be updated as sprints complete)*
@@ -1442,21 +2134,71 @@ ${userPrompt}
1442
2134
  `;
1443
2135
  }
1444
2136
 
2137
+ function buildContextContent(userPrompt, scope) {
2138
+ const { hasFrontend, hasBackend, hasMobile, detectedTesting, designStyle, colorStyle } = scope || {};
2139
+ return `# IMH-Code Project Context
2140
+
2141
+ Generated: ${new Date().toLocaleDateString()}
2142
+ Project: ${userPrompt.slice(0, 150)}...
2143
+ Testing Mode: ${detectedTesting}
2144
+ Design Style: ${designStyle} / ${colorStyle}
2145
+
2146
+ ## Stack
2147
+ ${hasFrontend ? '- Frontend: Next.js 15 + shadcn/ui + Tailwind CSS v4' : ''}
2148
+ ${hasBackend ? '- Backend: Laravel 11 + PostgreSQL + Redis' : ''}
2149
+ ${hasMobile ? '- Mobile: Flutter' : ''}
2150
+ - Auth: JWT tokens
2151
+ - Deployment: Docker + GitHub Actions
2152
+
2153
+ ## Directory Structure
2154
+ ${hasFrontend ? '- frontend/ — All frontend code' : ''}
2155
+ ${hasBackend ? '- backend/ — All backend code' : ''}
2156
+ - docs/ — Sprint plans and documentation
2157
+
2158
+ ## Current Sprint
2159
+ Sprint 1 (not started)
2160
+ `;
2161
+ }
2162
+
1445
2163
  function extractPromptFromStartMd(content) {
1446
2164
  const match = content.match(/<!-- WRITE_PROMPT_HERE -->([\s\S]*?)<!-- END_PROMPT -->/);
1447
2165
  if (match) return match[1].trim();
1448
- // Fallback: return everything after the first heading
1449
2166
  const lines = content.split('\n').filter(l => !l.startsWith('#') && l.trim().length > 0);
1450
2167
  return lines.join(' ').slice(0, 500);
1451
2168
  }
1452
2169
 
1453
2170
  function extractAnswer(brainstormContent, questionKey, defaultAnswer) {
1454
- const regex = new RegExp(`\\*\\*${questionKey}.*?\\*\\*Your Answer:\\*\\*([^\\n*]+)`, 's');
2171
+ const regex = new RegExp(`\\*\\*${questionKey}.*?\\*\\*Your Answer:\\*\\*\\s*([^\\n*]+)`, 's');
1455
2172
  const match = brainstormContent.match(regex);
1456
- if (match) return match[1].trim();
2173
+ if (match) return match[1].replace(/\*\(.*?\)\*/g, '').trim();
1457
2174
  return defaultAnswer;
1458
2175
  }
1459
2176
 
2177
+ function getAgentCategory(agentId) {
2178
+ const map = {
2179
+ 'planner': 'planning',
2180
+ 'designer': 'frontend',
2181
+ 'nextjs-executor': 'frontend',
2182
+ 'react-executor': 'frontend',
2183
+ 'vue-executor': 'frontend',
2184
+ 'laravel-executor': 'backend',
2185
+ 'python-executor': 'backend',
2186
+ 'java-executor': 'backend',
2187
+ 'flutter-executor': 'backend',
2188
+ 'react-native-executor': 'backend',
2189
+ 'ios-executor': 'backend',
2190
+ 'android-executor': 'backend',
2191
+ 'systems-executor': 'backend',
2192
+ 'web3-executor': 'backend',
2193
+ 'devops-executor': 'backend',
2194
+ 'tester': 'testing',
2195
+ 'security-auditor': 'testing',
2196
+ 'seo-optimizer': 'review',
2197
+ 'debugger': 'review',
2198
+ };
2199
+ return map[agentId] || 'backend';
2200
+ }
2201
+
1460
2202
  function detectSprintDocs(cwd) {
1461
2203
  const docsDir = path.join(cwd, DOCS_DIR);
1462
2204
  if (!fs.existsSync(docsDir)) return false;
@@ -1484,14 +2226,11 @@ function resolveSprintNum(restArgs, cwd) {
1484
2226
  const n = parseInt(numStr, 10);
1485
2227
  if (!isNaN(n)) return n;
1486
2228
  }
1487
-
1488
- // Try PROJECT_BRIEF.md
1489
2229
  const briefPath = path.join(cwd, BRIEF_MD);
1490
2230
  if (fs.existsSync(briefPath)) {
1491
2231
  const m = fs.readFileSync(briefPath, 'utf8').match(/Current Sprint:\s*Sprint\s*(\d+)/i);
1492
2232
  if (m) return parseInt(m[1], 10);
1493
2233
  }
1494
-
1495
2234
  return detectCurrentSprint(cwd);
1496
2235
  }
1497
2236
 
@@ -1503,13 +2242,19 @@ function loadLocalConfig(cwd) {
1503
2242
  return null;
1504
2243
  }
1505
2244
 
2245
+ function safeRead(filePath) {
2246
+ try { return fs.existsSync(filePath) ? fs.readFileSync(filePath, 'utf8') : null; } catch { return null; }
2247
+ }
2248
+
1506
2249
  async function updateCompactContext(cwd, completedSprint) {
1507
2250
  const contextPath = path.join(cwd, CONTEXT_MD);
1508
2251
  if (!fs.existsSync(contextPath)) return;
1509
-
1510
2252
  try {
1511
2253
  let content = fs.readFileSync(contextPath, 'utf8');
1512
- content = content.replace(/Current Sprint\nSprint \d+ \(not started\)/, `Current Sprint\nSprint ${completedSprint + 1}`);
2254
+ content = content.replace(
2255
+ /Current Sprint\nSprint \d+ \(not started\)/,
2256
+ `Current Sprint\nSprint ${completedSprint + 1}`
2257
+ );
1513
2258
  fs.writeFileSync(contextPath, content, 'utf8');
1514
2259
  } catch { /* non-critical */ }
1515
2260
  }
@@ -1523,12 +2268,12 @@ function askQuestion(query) {
1523
2268
 
1524
2269
  function scanAssistantCLIs() {
1525
2270
  const engines = {
1526
- claude: { name: 'Claude Code', path: resolveBinary('claude', ['~/.local/bin/claude', '/usr/local/bin/claude', '/opt/homebrew/bin/claude']), models: [], modelsCmd: b => `"${b}" --list-models 2>/dev/null || echo ''` },
1527
- opencode: { name: 'OpenCode', path: resolveBinary('opencode', ['~/.opencode/bin/opencode', '/usr/local/bin/opencode']), models: [], modelsCmd: b => `"${b}" models 2>/dev/null` },
1528
- codex: { name: 'Codex (OpenAI)', path: resolveBinary('codex', ['~/Library/PhpWebStudy/env/node/bin/codex', '/usr/local/bin/codex']), models: [], modelsCmd: b => `"${b}" debug models 2>/dev/null` },
1529
- agy: { name: 'Antigravity CLI (agy)', path: resolveBinary('agy', ['~/.local/bin/agy', '/usr/local/bin/agy', '/opt/homebrew/bin/agy']), models: [], modelsCmd: b => `"${b}" models 2>/dev/null || echo ''` },
1530
- qwen: { name: 'QwenCode (qwen)', path: resolveBinary('qwen', ['~/.local/bin/qwen', '/usr/local/bin/qwen', '/opt/homebrew/bin/qwen']), models: [], modelsCmd: b => `"${b}" models 2>/dev/null || echo ''` },
1531
- mimo: { name: 'MimoCode (mimo)', path: resolveBinary('mimo', ['~/.local/bin/mimo', '/usr/local/bin/mimo', '/opt/homebrew/bin/mimo', '~/.mimo/bin/mimo']), models: [], modelsCmd: b => `"${b}" models 2>/dev/null || echo ''` },
2271
+ claude: { name: 'Claude Code', path: resolveBinary('claude', ['~/.local/bin/claude', '/usr/local/bin/claude', '/opt/homebrew/bin/claude']), models: [], modelsCmd: b => `"${b}" --list-models 2>/dev/null || echo ''` },
2272
+ opencode: { name: 'OpenCode', path: resolveBinary('opencode', ['~/.opencode/bin/opencode', '/usr/local/bin/opencode']), models: [], modelsCmd: b => `"${b}" models 2>/dev/null` },
2273
+ codex: { name: 'Codex (OpenAI)', path: resolveBinary('codex', ['~/Library/PhpWebStudy/env/node/bin/codex', '/usr/local/bin/codex']), models: [], modelsCmd: b => `"${b}" debug models 2>/dev/null` },
2274
+ agy: { name: 'Antigravity CLI (agy)', path: resolveBinary('agy', ['~/.local/bin/agy', '/usr/local/bin/agy', '/opt/homebrew/bin/agy']), models: [], modelsCmd: b => `"${b}" models 2>/dev/null || echo ''` },
2275
+ qwen: { name: 'QwenCode (qwen)', path: resolveBinary('qwen', ['~/.local/bin/qwen', '/usr/local/bin/qwen', '/opt/homebrew/bin/qwen']), models: [], modelsCmd: b => `"${b}" models 2>/dev/null || echo ''` },
2276
+ mimo: { name: 'MimoCode (mimo)', path: resolveBinary('mimo', ['~/.local/bin/mimo', '/usr/local/bin/mimo', '/opt/homebrew/bin/mimo', '~/.mimo/bin/mimo']), models: [], modelsCmd: b => `"${b}" models 2>/dev/null || echo ''` },
1532
2277
  };
1533
2278
 
1534
2279
  for (const [key, eng] of Object.entries(engines)) {
@@ -1593,7 +2338,7 @@ function registerCliGlobally(imhcodeScriptPath) {
1593
2338
  } else {
1594
2339
  const localBinDir = path.join(os.homedir(), '.local', 'bin');
1595
2340
  const imhBinDir = path.join(GLOBAL_DIR, 'bin');
1596
- [localBinDir, imhBinDir].forEach(dir => { if (!fs.existsSync(dir)) { try { fs.mkdirSync(dir, { recursive: true }); } catch { } } });
2341
+ [localBinDir, imhBinDir].forEach(dir => { if (!fs.existsSync(dir)) { try { fs.mkdirSync(dir, { recursive: true }); } catch {} } });
1597
2342
 
1598
2343
  const shimContent = `#!/bin/sh\nexec node "${imhcodeScriptPath}" "$@"\n`;
1599
2344
  [path.join(localBinDir, 'imhcode'), path.join(imhBinDir, 'imhcode')].forEach(t => {