@agile-vibe-coding/avc 0.2.3 → 0.3.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 (262) hide show
  1. package/README.md +475 -3
  2. package/cli/agents/agent-selector.md +23 -0
  3. package/cli/agents/code-implementer.md +117 -0
  4. package/cli/agents/code-validator.md +80 -0
  5. package/cli/agents/context-reviewer-epic.md +101 -0
  6. package/cli/agents/context-reviewer-story.md +92 -0
  7. package/cli/agents/context-writer-epic.md +145 -0
  8. package/cli/agents/context-writer-story.md +111 -0
  9. package/cli/agents/doc-writer-epic.md +42 -0
  10. package/cli/agents/doc-writer-story.md +43 -0
  11. package/cli/agents/duplicate-detector.md +110 -0
  12. package/cli/agents/epic-story-decomposer.md +318 -39
  13. package/cli/agents/mission-scope-generator.md +68 -4
  14. package/cli/agents/mission-scope-validator.md +40 -6
  15. package/cli/agents/project-context-extractor.md +21 -6
  16. package/cli/agents/scaffolding-generator.md +99 -0
  17. package/cli/agents/seed-validator.md +71 -0
  18. package/cli/agents/story-scope-reviewer.md +147 -0
  19. package/cli/agents/story-splitter.md +83 -0
  20. package/cli/agents/validator-documentation.json +31 -0
  21. package/cli/agents/validator-documentation.md +3 -1
  22. package/cli/api-reference-tool.js +368 -0
  23. package/cli/checks/catalog.json +76 -0
  24. package/cli/checks/code/quality.json +26 -0
  25. package/cli/checks/code/testing.json +14 -0
  26. package/cli/checks/code/traceability.json +26 -0
  27. package/cli/checks/cross-refs/epic.json +171 -0
  28. package/cli/checks/cross-refs/story.json +149 -0
  29. package/cli/checks/epic/api.json +114 -0
  30. package/cli/checks/epic/backend.json +126 -0
  31. package/cli/checks/epic/cloud.json +126 -0
  32. package/cli/checks/epic/data.json +102 -0
  33. package/cli/checks/epic/database.json +114 -0
  34. package/cli/checks/epic/developer.json +182 -0
  35. package/cli/checks/epic/devops.json +174 -0
  36. package/cli/checks/epic/frontend.json +162 -0
  37. package/cli/checks/epic/mobile.json +102 -0
  38. package/cli/checks/epic/qa.json +90 -0
  39. package/cli/checks/epic/security.json +184 -0
  40. package/cli/checks/epic/solution-architect.json +192 -0
  41. package/cli/checks/epic/test-architect.json +90 -0
  42. package/cli/checks/epic/ui.json +102 -0
  43. package/cli/checks/epic/ux.json +90 -0
  44. package/cli/checks/fixes/epic-fix-template.md +10 -0
  45. package/cli/checks/fixes/story-fix-template.md +10 -0
  46. package/cli/checks/story/api.json +186 -0
  47. package/cli/checks/story/backend.json +102 -0
  48. package/cli/checks/story/cloud.json +102 -0
  49. package/cli/checks/story/data.json +210 -0
  50. package/cli/checks/story/database.json +102 -0
  51. package/cli/checks/story/developer.json +168 -0
  52. package/cli/checks/story/devops.json +102 -0
  53. package/cli/checks/story/frontend.json +174 -0
  54. package/cli/checks/story/mobile.json +102 -0
  55. package/cli/checks/story/qa.json +210 -0
  56. package/cli/checks/story/security.json +198 -0
  57. package/cli/checks/story/solution-architect.json +230 -0
  58. package/cli/checks/story/test-architect.json +210 -0
  59. package/cli/checks/story/ui.json +102 -0
  60. package/cli/checks/story/ux.json +102 -0
  61. package/cli/coding-order.js +401 -0
  62. package/cli/dependency-checker.js +72 -0
  63. package/cli/epic-story-validator.js +284 -799
  64. package/cli/index.js +0 -0
  65. package/cli/init-model-config.js +17 -10
  66. package/cli/init.js +514 -92
  67. package/cli/kanban-server-manager.js +1 -2
  68. package/cli/llm-claude.js +98 -31
  69. package/cli/llm-gemini.js +29 -5
  70. package/cli/llm-local.js +493 -0
  71. package/cli/llm-openai.js +262 -41
  72. package/cli/llm-provider.js +147 -8
  73. package/cli/llm-token-limits.js +113 -4
  74. package/cli/llm-verifier.js +209 -1
  75. package/cli/llm-xiaomi.js +143 -0
  76. package/cli/message-constants.js +3 -12
  77. package/cli/messaging-api.js +6 -12
  78. package/cli/micro-check-fixer.js +335 -0
  79. package/cli/micro-check-runner.js +449 -0
  80. package/cli/micro-check-scorer.js +148 -0
  81. package/cli/micro-check-validator.js +538 -0
  82. package/cli/model-pricing.js +23 -0
  83. package/cli/model-selector.js +3 -2
  84. package/cli/prompt-logger.js +57 -0
  85. package/cli/repl-ink.js +106 -346
  86. package/cli/repl-old.js +1 -2
  87. package/cli/seed-processor.js +194 -24
  88. package/cli/sprint-planning-processor.js +2638 -289
  89. package/cli/template-processor.js +50 -3
  90. package/cli/token-tracker.js +50 -23
  91. package/cli/tools/generate-story-validators.js +1 -1
  92. package/cli/validation-router.js +70 -8
  93. package/cli/worktree-runner.js +654 -0
  94. package/kanban/client/dist/assets/index-D_KC5EQT.css +1 -0
  95. package/kanban/client/dist/assets/index-DjY5zqW7.js +351 -0
  96. package/kanban/client/dist/index.html +2 -2
  97. package/kanban/client/src/App.jsx +43 -14
  98. package/kanban/client/src/components/ceremony/AskArchPopup.jsx +7 -3
  99. package/kanban/client/src/components/ceremony/AskModelPopup.jsx +23 -10
  100. package/kanban/client/src/components/ceremony/CeremonyWorkflowModal.jsx +320 -133
  101. package/kanban/client/src/components/ceremony/ProviderSwitcherButton.jsx +290 -0
  102. package/kanban/client/src/components/ceremony/SponsorCallModal.jsx +80 -13
  103. package/kanban/client/src/components/ceremony/SprintPlanningModal.jsx +156 -22
  104. package/kanban/client/src/components/ceremony/steps/ArchitectureStep.jsx +11 -11
  105. package/kanban/client/src/components/ceremony/steps/CompleteStep.jsx +3 -21
  106. package/kanban/client/src/components/ceremony/steps/ReviewAnswersStep.jsx +214 -10
  107. package/kanban/client/src/components/ceremony/steps/RunningStep.jsx +23 -2
  108. package/kanban/client/src/components/kanban/CardDetailModal.jsx +97 -10
  109. package/kanban/client/src/components/kanban/GroupingSelector.jsx +7 -1
  110. package/kanban/client/src/components/kanban/KanbanCard.jsx +23 -14
  111. package/kanban/client/src/components/kanban/RefineWorkItemPopup.jsx +9 -14
  112. package/kanban/client/src/components/kanban/RunButton.jsx +162 -0
  113. package/kanban/client/src/components/kanban/SeedButton.jsx +176 -0
  114. package/kanban/client/src/components/settings/AgentsTab.jsx +103 -75
  115. package/kanban/client/src/components/settings/ApiKeysTab.jsx +31 -2
  116. package/kanban/client/src/components/settings/CeremonyModelsTab.jsx +9 -2
  117. package/kanban/client/src/components/settings/CheckEditorPopup.jsx +507 -0
  118. package/kanban/client/src/components/settings/CostThresholdsTab.jsx +3 -2
  119. package/kanban/client/src/components/settings/ModelPricingTab.jsx +72 -7
  120. package/kanban/client/src/components/settings/OpenAIAuthSection.jsx +412 -0
  121. package/kanban/client/src/components/settings/SettingsModal.jsx +4 -4
  122. package/kanban/client/src/components/stats/CostModal.jsx +34 -3
  123. package/kanban/client/src/hooks/useGrouping.js +59 -0
  124. package/kanban/client/src/lib/api.js +118 -4
  125. package/kanban/client/src/lib/status-grouping.js +10 -0
  126. package/kanban/client/src/store/kanbanStore.js +8 -0
  127. package/kanban/server/index.js +23 -2
  128. package/kanban/server/routes/ceremony.js +153 -4
  129. package/kanban/server/routes/costs.js +9 -3
  130. package/kanban/server/routes/openai-oauth.js +366 -0
  131. package/kanban/server/routes/settings.js +447 -14
  132. package/kanban/server/routes/websocket.js +7 -2
  133. package/kanban/server/routes/work-items.js +141 -1
  134. package/kanban/server/services/CeremonyService.js +275 -24
  135. package/kanban/server/services/TaskRunnerService.js +261 -0
  136. package/kanban/server/workers/run-task-worker.js +121 -0
  137. package/kanban/server/workers/seed-worker.js +94 -0
  138. package/kanban/server/workers/sponsor-call-worker.js +14 -6
  139. package/kanban/server/workers/sprint-planning-worker.js +94 -12
  140. package/package.json +2 -3
  141. package/cli/agents/solver-epic-api.json +0 -15
  142. package/cli/agents/solver-epic-api.md +0 -39
  143. package/cli/agents/solver-epic-backend.json +0 -15
  144. package/cli/agents/solver-epic-backend.md +0 -39
  145. package/cli/agents/solver-epic-cloud.json +0 -15
  146. package/cli/agents/solver-epic-cloud.md +0 -39
  147. package/cli/agents/solver-epic-data.json +0 -15
  148. package/cli/agents/solver-epic-data.md +0 -39
  149. package/cli/agents/solver-epic-database.json +0 -15
  150. package/cli/agents/solver-epic-database.md +0 -39
  151. package/cli/agents/solver-epic-developer.json +0 -15
  152. package/cli/agents/solver-epic-developer.md +0 -39
  153. package/cli/agents/solver-epic-devops.json +0 -15
  154. package/cli/agents/solver-epic-devops.md +0 -39
  155. package/cli/agents/solver-epic-frontend.json +0 -15
  156. package/cli/agents/solver-epic-frontend.md +0 -39
  157. package/cli/agents/solver-epic-mobile.json +0 -15
  158. package/cli/agents/solver-epic-mobile.md +0 -39
  159. package/cli/agents/solver-epic-qa.json +0 -15
  160. package/cli/agents/solver-epic-qa.md +0 -39
  161. package/cli/agents/solver-epic-security.json +0 -15
  162. package/cli/agents/solver-epic-security.md +0 -39
  163. package/cli/agents/solver-epic-solution-architect.json +0 -15
  164. package/cli/agents/solver-epic-solution-architect.md +0 -39
  165. package/cli/agents/solver-epic-test-architect.json +0 -15
  166. package/cli/agents/solver-epic-test-architect.md +0 -39
  167. package/cli/agents/solver-epic-ui.json +0 -15
  168. package/cli/agents/solver-epic-ui.md +0 -39
  169. package/cli/agents/solver-epic-ux.json +0 -15
  170. package/cli/agents/solver-epic-ux.md +0 -39
  171. package/cli/agents/solver-story-api.json +0 -15
  172. package/cli/agents/solver-story-api.md +0 -39
  173. package/cli/agents/solver-story-backend.json +0 -15
  174. package/cli/agents/solver-story-backend.md +0 -39
  175. package/cli/agents/solver-story-cloud.json +0 -15
  176. package/cli/agents/solver-story-cloud.md +0 -39
  177. package/cli/agents/solver-story-data.json +0 -15
  178. package/cli/agents/solver-story-data.md +0 -39
  179. package/cli/agents/solver-story-database.json +0 -15
  180. package/cli/agents/solver-story-database.md +0 -39
  181. package/cli/agents/solver-story-developer.json +0 -15
  182. package/cli/agents/solver-story-developer.md +0 -39
  183. package/cli/agents/solver-story-devops.json +0 -15
  184. package/cli/agents/solver-story-devops.md +0 -39
  185. package/cli/agents/solver-story-frontend.json +0 -15
  186. package/cli/agents/solver-story-frontend.md +0 -39
  187. package/cli/agents/solver-story-mobile.json +0 -15
  188. package/cli/agents/solver-story-mobile.md +0 -39
  189. package/cli/agents/solver-story-qa.json +0 -15
  190. package/cli/agents/solver-story-qa.md +0 -39
  191. package/cli/agents/solver-story-security.json +0 -15
  192. package/cli/agents/solver-story-security.md +0 -39
  193. package/cli/agents/solver-story-solution-architect.json +0 -15
  194. package/cli/agents/solver-story-solution-architect.md +0 -39
  195. package/cli/agents/solver-story-test-architect.json +0 -15
  196. package/cli/agents/solver-story-test-architect.md +0 -39
  197. package/cli/agents/solver-story-ui.json +0 -15
  198. package/cli/agents/solver-story-ui.md +0 -39
  199. package/cli/agents/solver-story-ux.json +0 -15
  200. package/cli/agents/solver-story-ux.md +0 -39
  201. package/cli/agents/validator-epic-api.json +0 -93
  202. package/cli/agents/validator-epic-api.md +0 -137
  203. package/cli/agents/validator-epic-backend.json +0 -93
  204. package/cli/agents/validator-epic-backend.md +0 -130
  205. package/cli/agents/validator-epic-cloud.json +0 -93
  206. package/cli/agents/validator-epic-cloud.md +0 -137
  207. package/cli/agents/validator-epic-data.json +0 -93
  208. package/cli/agents/validator-epic-data.md +0 -130
  209. package/cli/agents/validator-epic-database.json +0 -93
  210. package/cli/agents/validator-epic-database.md +0 -137
  211. package/cli/agents/validator-epic-developer.json +0 -74
  212. package/cli/agents/validator-epic-developer.md +0 -153
  213. package/cli/agents/validator-epic-devops.json +0 -74
  214. package/cli/agents/validator-epic-devops.md +0 -153
  215. package/cli/agents/validator-epic-frontend.json +0 -74
  216. package/cli/agents/validator-epic-frontend.md +0 -153
  217. package/cli/agents/validator-epic-mobile.json +0 -93
  218. package/cli/agents/validator-epic-mobile.md +0 -130
  219. package/cli/agents/validator-epic-qa.json +0 -93
  220. package/cli/agents/validator-epic-qa.md +0 -130
  221. package/cli/agents/validator-epic-security.json +0 -74
  222. package/cli/agents/validator-epic-security.md +0 -154
  223. package/cli/agents/validator-epic-solution-architect.json +0 -74
  224. package/cli/agents/validator-epic-solution-architect.md +0 -156
  225. package/cli/agents/validator-epic-test-architect.json +0 -93
  226. package/cli/agents/validator-epic-test-architect.md +0 -130
  227. package/cli/agents/validator-epic-ui.json +0 -93
  228. package/cli/agents/validator-epic-ui.md +0 -130
  229. package/cli/agents/validator-epic-ux.json +0 -93
  230. package/cli/agents/validator-epic-ux.md +0 -130
  231. package/cli/agents/validator-story-api.json +0 -104
  232. package/cli/agents/validator-story-api.md +0 -152
  233. package/cli/agents/validator-story-backend.json +0 -104
  234. package/cli/agents/validator-story-backend.md +0 -152
  235. package/cli/agents/validator-story-cloud.json +0 -104
  236. package/cli/agents/validator-story-cloud.md +0 -152
  237. package/cli/agents/validator-story-data.json +0 -104
  238. package/cli/agents/validator-story-data.md +0 -152
  239. package/cli/agents/validator-story-database.json +0 -104
  240. package/cli/agents/validator-story-database.md +0 -152
  241. package/cli/agents/validator-story-developer.json +0 -104
  242. package/cli/agents/validator-story-developer.md +0 -152
  243. package/cli/agents/validator-story-devops.json +0 -104
  244. package/cli/agents/validator-story-devops.md +0 -152
  245. package/cli/agents/validator-story-frontend.json +0 -104
  246. package/cli/agents/validator-story-frontend.md +0 -152
  247. package/cli/agents/validator-story-mobile.json +0 -104
  248. package/cli/agents/validator-story-mobile.md +0 -152
  249. package/cli/agents/validator-story-qa.json +0 -104
  250. package/cli/agents/validator-story-qa.md +0 -152
  251. package/cli/agents/validator-story-security.json +0 -104
  252. package/cli/agents/validator-story-security.md +0 -152
  253. package/cli/agents/validator-story-solution-architect.json +0 -104
  254. package/cli/agents/validator-story-solution-architect.md +0 -152
  255. package/cli/agents/validator-story-test-architect.json +0 -104
  256. package/cli/agents/validator-story-test-architect.md +0 -152
  257. package/cli/agents/validator-story-ui.json +0 -104
  258. package/cli/agents/validator-story-ui.md +0 -152
  259. package/cli/agents/validator-story-ux.json +0 -104
  260. package/cli/agents/validator-story-ux.md +0 -152
  261. package/kanban/client/dist/assets/index-CiD8PS2e.js +0 -306
  262. package/kanban/client/dist/assets/index-nLh0m82Q.css +0 -1
@@ -136,8 +136,17 @@ class SeedProcessor {
136
136
  */
137
137
  async getProviderForStageInstance(stageName) {
138
138
  const stageConfig = this.stagesConfig?.[stageName] || {};
139
- const provider = stageConfig.provider || this._providerName;
140
- const model = stageConfig.model || this._modelName;
139
+ let provider = stageConfig.provider || this._providerName;
140
+ let model = stageConfig.model || this._modelName;
141
+
142
+ // Resolve to an available provider if current one has no credentials
143
+ const resolved = await LLMProvider.resolveAvailableProvider(provider, model);
144
+ if (resolved.fellBack) {
145
+ console.warn(`[WARN] ${provider} has no API key — falling back to ${resolved.provider} for stage "${stageName}"`);
146
+ provider = resolved.provider;
147
+ model = resolved.model;
148
+ }
149
+
141
150
  const cacheKey = `${stageName}:${provider}:${model}`;
142
151
 
143
152
  if (this._stageProviders[cacheKey]) return this._stageProviders[cacheKey];
@@ -397,6 +406,11 @@ Decompose this Story into:
397
406
 
398
407
  Return your response as JSON following the exact structure specified in your instructions.`;
399
408
 
409
+ // If previous iteration had violations, include them so the LLM can fix
410
+ if (contextData._previousViolations?.length > 0) {
411
+ prompt += `\n\n## PREVIOUS VALIDATION ISSUES (FIX THESE)\n\nYour previous decomposition had these issues:\n${contextData._previousViolations.map(v => `- [${v.severity}] ${v.description}: ${v.fix || ''}`).join('\n')}\n\nPlease fix ALL issues in your new decomposition.`;
412
+ }
413
+
400
414
  this.debug('[INFO] Calling LLM for Task/Subtask decomposition', {
401
415
  provider: this._providerName,
402
416
  model: this._modelName,
@@ -428,36 +442,134 @@ Return your response as JSON following the exact structure specified in your ins
428
442
  return hierarchy;
429
443
  }
430
444
 
431
- // STAGE 4: Validate Task/Subtask structure
432
- validateTaskSubtaskStructure(hierarchy) {
433
- this.debug('[INFO] validateTaskSubtaskStructure() called', { taskCount: hierarchy.tasks?.length });
434
-
445
+ // STAGE 4: Structural validation (deterministic, no LLM)
446
+ // Returns issues array instead of throwing — enables retry loop
447
+ _validateStructure(hierarchy) {
448
+ const issues = [];
435
449
  const { tasks } = hierarchy;
436
450
 
451
+ if (!tasks || !Array.isArray(tasks) || tasks.length === 0) {
452
+ issues.push({ severity: 'critical', category: 'structure', description: 'No tasks array in decomposition', fix: 'Return a tasks array with 2-5 tasks' });
453
+ return issues;
454
+ }
455
+
437
456
  if (tasks.length < 2 || tasks.length > 5) {
438
- this.debug('[WARNING] Unexpected task count', { count: tasks.length, expected: '2-5' });
439
- sendWarning(`Expected 2-5 Tasks, got ${tasks.length}`);
457
+ issues.push({ severity: 'minor', category: 'structure', description: `Expected 2-5 tasks, got ${tasks.length}`, fix: `Adjust to 2-5 tasks` });
440
458
  }
441
459
 
442
460
  for (const task of tasks) {
461
+ // ID format
462
+ if (!task.id || !task.id.match(/^context-\d{4}-\d{4}-\d{4}[a-z]?$/)) {
463
+ issues.push({ severity: 'critical', category: 'structure', description: `Invalid Task ID: ${task.id}`, fix: `Use format context-XXXX-XXXX-XXXX` });
464
+ }
465
+ // Subtask count
443
466
  const subtaskCount = task.subtasks?.length || 0;
444
467
  if (subtaskCount < 1 || subtaskCount > 3) {
445
- this.debug('[WARNING] Unexpected subtask count', { task: task.name, count: subtaskCount, expected: '1-3' });
446
- sendWarning(`Task ${task.name} has ${subtaskCount} Subtasks (expected 1-3)`);
468
+ issues.push({ severity: 'minor', category: 'structure', description: `Task "${task.name}" has ${subtaskCount} subtasks (expected 1-3)`, fix: 'Adjust subtask count' });
447
469
  }
470
+ // Subtask IDs
471
+ for (const subtask of task.subtasks || []) {
472
+ if (!subtask.id || !subtask.id.match(/^context-\d{4}-\d{4}-\d{4}-\d{4}$/)) {
473
+ issues.push({ severity: 'critical', category: 'structure', description: `Invalid Subtask ID: ${subtask.id}`, fix: `Use format context-XXXX-XXXX-XXXX-XXXX` });
474
+ }
475
+ }
476
+ // Missing acceptance criteria
477
+ if (!task.acceptance || task.acceptance.length === 0) {
478
+ issues.push({ severity: 'major', category: 'quality', description: `Task "${task.name}" has no acceptance criteria`, fix: 'Add 2-5 testable acceptance criteria' });
479
+ }
480
+ }
481
+
482
+ return issues;
483
+ }
448
484
 
449
- // Validate Task ID format (context-XXXX-XXXX-XXXX)
450
- if (!task.id || !task.id.match(/^context-\d{4}-\d{4}-\d{4}$/)) {
451
- throw new Error(`Invalid Task ID format: ${task.id}`);
485
+ // STAGE 4b: Semantic validation via LLM (optional, if provider available)
486
+ async _validateSemantics(hierarchy, contextData) {
487
+ try {
488
+ const agentInstructions = fs.readFileSync(
489
+ path.join(this.agentsPath, 'seed-validator.md'), 'utf8'
490
+ );
491
+
492
+ const { storyWork } = contextData;
493
+ const threshold = this.stagesConfig?.validation?.acceptanceThreshold ?? 80;
494
+
495
+ const prompt = `## Story\n\n**Name:** ${storyWork.name}\n**Description:** ${storyWork.description}\n**Acceptance Criteria:**\n${(storyWork.acceptance || []).map((ac, i) => `${i + 1}. ${ac}`).join('\n')}\n\n## Decomposition\n\n${JSON.stringify(hierarchy.tasks, null, 2)}\n\n## Acceptance Threshold\n${threshold}`;
496
+
497
+ const provider = await this.getProviderForStageInstance('validation');
498
+ const result = await provider.generateJSON(prompt, agentInstructions);
499
+ return result;
500
+ } catch (err) {
501
+ this.debug('[WARNING] Semantic validation failed — skipping', { error: err.message });
502
+ return { score: 100, passed: true, issues: [] };
503
+ }
504
+ }
505
+
506
+ // Decompose→Validate→Refine loop
507
+ async decomposeWithValidation(contextData, progressCallback = null) {
508
+ const maxIterations = this.stagesConfig?.decomposition?.maxIterationsSeed
509
+ ?? this.stagesConfig?.maxValidationIterations ?? 3;
510
+ const threshold = this.stagesConfig?.validation?.acceptanceThreshold ?? 80;
511
+
512
+ let hierarchy = null;
513
+ let allIssues = [];
514
+ let bestHierarchy = null;
515
+ let bestScore = 0;
516
+
517
+ for (let iter = 1; iter <= maxIterations; iter++) {
518
+ progressCallback?.(`Decomposing story (iteration ${iter}/${maxIterations})...`);
519
+ this.debug(`[INFO] Decompose iteration ${iter}/${maxIterations}`);
520
+
521
+ // Inject violations from previous iteration into context
522
+ if (allIssues.length > 0) {
523
+ contextData._previousViolations = allIssues;
452
524
  }
453
525
 
454
- // Validate Subtask ID format (context-XXXX-XXXX-XXXX-XXXX)
455
- for (const subtask of task.subtasks || []) {
456
- if (!subtask.id || !subtask.id.match(/^context-\d{4}-\d{4}-\d{4}-\d{4}$/)) {
457
- throw new Error(`Invalid Subtask ID format: ${subtask.id}`);
526
+ hierarchy = await this.decomposeIntoTasksSubtasks(contextData);
527
+
528
+ // Structural validation (deterministic)
529
+ const structuralIssues = this._validateStructure(hierarchy);
530
+ const hasCritical = structuralIssues.some(i => i.severity === 'critical');
531
+
532
+ if (hasCritical) {
533
+ this.debug(`[WARNING] Structural issues (iter ${iter})`, { issues: structuralIssues });
534
+ allIssues = structuralIssues;
535
+ if (iter === maxIterations) {
536
+ this.debug('[ERROR] Max iterations with critical structural issues — using best result');
537
+ break;
458
538
  }
539
+ continue; // Retry — don't bother with semantic validation if structure is broken
540
+ }
541
+
542
+ // Semantic validation (LLM)
543
+ progressCallback?.(`Validating decomposition (iteration ${iter}/${maxIterations})...`);
544
+ const semanticResult = await this._validateSemantics(hierarchy, contextData);
545
+ const score = semanticResult?.score ?? 100;
546
+
547
+ // Track best result
548
+ if (score > bestScore) {
549
+ bestScore = score;
550
+ bestHierarchy = JSON.parse(JSON.stringify(hierarchy));
551
+ }
552
+
553
+ allIssues = [
554
+ ...structuralIssues,
555
+ ...(semanticResult?.issues || []),
556
+ ];
557
+
558
+ this.debug(`[INFO] Validation result (iter ${iter})`, { score, issueCount: allIssues.length, passed: semanticResult?.passed });
559
+
560
+ if (semanticResult?.passed || score >= threshold) {
561
+ progressCallback?.(`Validation passed (score: ${score}, threshold: ${threshold})`);
562
+ break;
563
+ }
564
+
565
+ if (iter === maxIterations) {
566
+ progressCallback?.(`Max iterations — accepting score ${score} (threshold: ${threshold})`);
567
+ this.debug(`[WARNING] Max iterations reached — accepting best score ${bestScore}`);
459
568
  }
460
569
  }
570
+
571
+ // Use best result if final iteration didn't improve
572
+ return bestHierarchy && bestScore > (hierarchy?._score ?? 0) ? bestHierarchy : hierarchy;
461
573
  }
462
574
 
463
575
  // STAGE 5-6: Generate contexts
@@ -723,13 +835,9 @@ Return your response as JSON following the exact structure specified in your ins
723
835
  sendInfo('Reading Story context...');
724
836
  const contextData = this.readStoryContext();
725
837
 
726
- // Stage 3: Decompose
727
- this.debug('[INFO] Stage 2b: Decomposing Story into Tasks/Subtasks via LLM');
728
- let hierarchy = await this.decomposeIntoTasksSubtasks(contextData);
729
-
730
- // Stage 4: Validate
731
- this.debug('[INFO] Stage 2c: Validating decomposition structure');
732
- this.validateTaskSubtaskStructure(hierarchy);
838
+ // Stage 3+4: Decompose with validation loop
839
+ this.debug('[INFO] Stage 2b: Decomposing Story with validation loop');
840
+ let hierarchy = await this.decomposeWithValidation(contextData);
733
841
 
734
842
  // Stage 5-7: Generate contexts and write files
735
843
  this.debug('[INFO] Stage 2/3: Generating context files and writing to disk');
@@ -789,4 +897,66 @@ Return your response as JSON following the exact structure specified in your ins
789
897
  }
790
898
  }
791
899
 
900
+ /**
901
+ * Worker-compatible execution — uses callbacks instead of REPL output functions.
902
+ * Called by seed-worker.js (forked process).
903
+ *
904
+ * @param {Function} progressCallback - (message, substep?, meta?) → void
905
+ * @param {Function} [itemWrittenCallback] - ({ itemId, itemType }) → void
906
+ * @param {Function} [cancelledCheck] - () → boolean, returns true if cancelled
907
+ * @returns {Promise<{ taskCount: number, subtaskCount: number, taskIds: string[] }>}
908
+ */
909
+ async executeWithCallback(progressCallback, itemWrittenCallback = null, cancelledCheck = null) {
910
+ const execStartTime = Date.now();
911
+ this.debug('[INFO] SeedProcessor.executeWithCallback() started', {
912
+ storyId: this.storyId,
913
+ provider: this._providerName,
914
+ model: this._modelName,
915
+ });
916
+
917
+ // Stage 1: Validate
918
+ progressCallback?.('Validating prerequisites...');
919
+ if (cancelledCheck?.()) throw new Error('CEREMONY_CANCELLED');
920
+ this.validatePrerequisites();
921
+
922
+ // Stage 2a: Read context
923
+ progressCallback?.('Reading story context...');
924
+ if (cancelledCheck?.()) throw new Error('CEREMONY_CANCELLED');
925
+ const contextData = this.readStoryContext();
926
+
927
+ // Stage 2b+2c: Decompose with validation loop
928
+ if (cancelledCheck?.()) throw new Error('CEREMONY_CANCELLED');
929
+ let hierarchy = await this.decomposeWithValidation(contextData, progressCallback);
930
+
931
+ // Stage 3: Write files
932
+ progressCallback?.('Writing task and subtask files...');
933
+ if (cancelledCheck?.()) throw new Error('CEREMONY_CANCELLED');
934
+
935
+ // Temporarily override _itemWrittenCallback on writeTaskSubtaskFiles
936
+ const origCallback = this._itemWrittenCallback;
937
+ this._itemWrittenCallback = itemWrittenCallback;
938
+ const { taskCount, subtaskCount, taskIds } = await this.writeTaskSubtaskFiles(hierarchy, contextData);
939
+ this._itemWrittenCallback = origCallback;
940
+
941
+ // Stage 4: Update parent story
942
+ progressCallback?.('Updating story metadata...');
943
+ this.updateStoryWorkJson(taskIds);
944
+
945
+ // Finalize token tracking
946
+ if (this.llmProvider) {
947
+ this.tokenTracker.finalizeRun(this.ceremonyName);
948
+ }
949
+
950
+ const duration = Date.now() - execStartTime;
951
+ this.debug('[INFO] SeedProcessor.executeWithCallback() complete', {
952
+ storyId: this.storyId,
953
+ duration: `${duration}ms`,
954
+ taskCount,
955
+ subtaskCount,
956
+ });
957
+
958
+ return { taskCount, subtaskCount, taskIds };
959
+ }
960
+ }
961
+
792
962
  export { SeedProcessor };