@agile-vibe-coding/avc 0.2.3 → 0.3.1

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 (261) hide show
  1. package/cli/agents/agent-selector.md +23 -0
  2. package/cli/agents/code-implementer.md +117 -0
  3. package/cli/agents/code-validator.md +80 -0
  4. package/cli/agents/context-reviewer-epic.md +101 -0
  5. package/cli/agents/context-reviewer-story.md +92 -0
  6. package/cli/agents/context-writer-epic.md +145 -0
  7. package/cli/agents/context-writer-story.md +111 -0
  8. package/cli/agents/doc-writer-epic.md +42 -0
  9. package/cli/agents/doc-writer-story.md +43 -0
  10. package/cli/agents/duplicate-detector.md +110 -0
  11. package/cli/agents/epic-story-decomposer.md +318 -39
  12. package/cli/agents/mission-scope-generator.md +68 -4
  13. package/cli/agents/mission-scope-validator.md +40 -6
  14. package/cli/agents/project-context-extractor.md +21 -6
  15. package/cli/agents/scaffolding-generator.md +99 -0
  16. package/cli/agents/seed-validator.md +71 -0
  17. package/cli/agents/story-scope-reviewer.md +147 -0
  18. package/cli/agents/story-splitter.md +83 -0
  19. package/cli/agents/validator-documentation.json +31 -0
  20. package/cli/agents/validator-documentation.md +3 -1
  21. package/cli/api-reference-tool.js +368 -0
  22. package/cli/checks/catalog.json +76 -0
  23. package/cli/checks/code/quality.json +26 -0
  24. package/cli/checks/code/testing.json +14 -0
  25. package/cli/checks/code/traceability.json +26 -0
  26. package/cli/checks/cross-refs/epic.json +171 -0
  27. package/cli/checks/cross-refs/story.json +149 -0
  28. package/cli/checks/epic/api.json +114 -0
  29. package/cli/checks/epic/backend.json +126 -0
  30. package/cli/checks/epic/cloud.json +126 -0
  31. package/cli/checks/epic/data.json +102 -0
  32. package/cli/checks/epic/database.json +114 -0
  33. package/cli/checks/epic/developer.json +182 -0
  34. package/cli/checks/epic/devops.json +174 -0
  35. package/cli/checks/epic/frontend.json +162 -0
  36. package/cli/checks/epic/mobile.json +102 -0
  37. package/cli/checks/epic/qa.json +90 -0
  38. package/cli/checks/epic/security.json +184 -0
  39. package/cli/checks/epic/solution-architect.json +192 -0
  40. package/cli/checks/epic/test-architect.json +90 -0
  41. package/cli/checks/epic/ui.json +102 -0
  42. package/cli/checks/epic/ux.json +90 -0
  43. package/cli/checks/fixes/epic-fix-template.md +10 -0
  44. package/cli/checks/fixes/story-fix-template.md +10 -0
  45. package/cli/checks/story/api.json +186 -0
  46. package/cli/checks/story/backend.json +102 -0
  47. package/cli/checks/story/cloud.json +102 -0
  48. package/cli/checks/story/data.json +210 -0
  49. package/cli/checks/story/database.json +102 -0
  50. package/cli/checks/story/developer.json +168 -0
  51. package/cli/checks/story/devops.json +102 -0
  52. package/cli/checks/story/frontend.json +174 -0
  53. package/cli/checks/story/mobile.json +102 -0
  54. package/cli/checks/story/qa.json +210 -0
  55. package/cli/checks/story/security.json +198 -0
  56. package/cli/checks/story/solution-architect.json +230 -0
  57. package/cli/checks/story/test-architect.json +210 -0
  58. package/cli/checks/story/ui.json +102 -0
  59. package/cli/checks/story/ux.json +102 -0
  60. package/cli/coding-order.js +401 -0
  61. package/cli/dependency-checker.js +72 -0
  62. package/cli/epic-story-validator.js +284 -799
  63. package/cli/index.js +0 -0
  64. package/cli/init-model-config.js +17 -10
  65. package/cli/init.js +514 -92
  66. package/cli/kanban-server-manager.js +1 -2
  67. package/cli/llm-claude.js +98 -31
  68. package/cli/llm-gemini.js +29 -5
  69. package/cli/llm-local.js +493 -0
  70. package/cli/llm-openai.js +262 -41
  71. package/cli/llm-provider.js +147 -8
  72. package/cli/llm-token-limits.js +113 -4
  73. package/cli/llm-verifier.js +209 -1
  74. package/cli/llm-xiaomi.js +143 -0
  75. package/cli/message-constants.js +3 -12
  76. package/cli/messaging-api.js +6 -12
  77. package/cli/micro-check-fixer.js +335 -0
  78. package/cli/micro-check-runner.js +449 -0
  79. package/cli/micro-check-scorer.js +148 -0
  80. package/cli/micro-check-validator.js +538 -0
  81. package/cli/model-pricing.js +23 -0
  82. package/cli/model-selector.js +3 -2
  83. package/cli/prompt-logger.js +57 -0
  84. package/cli/repl-ink.js +106 -346
  85. package/cli/repl-old.js +1 -2
  86. package/cli/seed-processor.js +194 -24
  87. package/cli/sprint-planning-processor.js +2638 -289
  88. package/cli/template-processor.js +50 -3
  89. package/cli/token-tracker.js +50 -23
  90. package/cli/tools/generate-story-validators.js +1 -1
  91. package/cli/validation-router.js +70 -8
  92. package/cli/worktree-runner.js +654 -0
  93. package/kanban/client/dist/assets/index-D_KC5EQT.css +1 -0
  94. package/kanban/client/dist/assets/index-DjY5zqW7.js +351 -0
  95. package/kanban/client/dist/index.html +2 -2
  96. package/kanban/client/src/App.jsx +43 -14
  97. package/kanban/client/src/components/ceremony/AskArchPopup.jsx +7 -3
  98. package/kanban/client/src/components/ceremony/AskModelPopup.jsx +23 -10
  99. package/kanban/client/src/components/ceremony/CeremonyWorkflowModal.jsx +320 -133
  100. package/kanban/client/src/components/ceremony/ProviderSwitcherButton.jsx +290 -0
  101. package/kanban/client/src/components/ceremony/SponsorCallModal.jsx +80 -13
  102. package/kanban/client/src/components/ceremony/SprintPlanningModal.jsx +156 -22
  103. package/kanban/client/src/components/ceremony/steps/ArchitectureStep.jsx +11 -11
  104. package/kanban/client/src/components/ceremony/steps/CompleteStep.jsx +3 -21
  105. package/kanban/client/src/components/ceremony/steps/ReviewAnswersStep.jsx +214 -10
  106. package/kanban/client/src/components/ceremony/steps/RunningStep.jsx +23 -2
  107. package/kanban/client/src/components/kanban/CardDetailModal.jsx +97 -10
  108. package/kanban/client/src/components/kanban/GroupingSelector.jsx +7 -1
  109. package/kanban/client/src/components/kanban/KanbanCard.jsx +23 -14
  110. package/kanban/client/src/components/kanban/RefineWorkItemPopup.jsx +9 -14
  111. package/kanban/client/src/components/kanban/RunButton.jsx +162 -0
  112. package/kanban/client/src/components/kanban/SeedButton.jsx +176 -0
  113. package/kanban/client/src/components/settings/AgentsTab.jsx +103 -75
  114. package/kanban/client/src/components/settings/ApiKeysTab.jsx +31 -2
  115. package/kanban/client/src/components/settings/CeremonyModelsTab.jsx +9 -2
  116. package/kanban/client/src/components/settings/CheckEditorPopup.jsx +507 -0
  117. package/kanban/client/src/components/settings/CostThresholdsTab.jsx +3 -2
  118. package/kanban/client/src/components/settings/ModelPricingTab.jsx +72 -7
  119. package/kanban/client/src/components/settings/OpenAIAuthSection.jsx +412 -0
  120. package/kanban/client/src/components/settings/SettingsModal.jsx +4 -4
  121. package/kanban/client/src/components/stats/CostModal.jsx +34 -3
  122. package/kanban/client/src/hooks/useGrouping.js +59 -0
  123. package/kanban/client/src/lib/api.js +118 -4
  124. package/kanban/client/src/lib/status-grouping.js +10 -0
  125. package/kanban/client/src/store/kanbanStore.js +8 -0
  126. package/kanban/server/index.js +23 -2
  127. package/kanban/server/routes/ceremony.js +153 -4
  128. package/kanban/server/routes/costs.js +9 -3
  129. package/kanban/server/routes/openai-oauth.js +366 -0
  130. package/kanban/server/routes/settings.js +447 -14
  131. package/kanban/server/routes/websocket.js +7 -2
  132. package/kanban/server/routes/work-items.js +141 -1
  133. package/kanban/server/services/CeremonyService.js +275 -24
  134. package/kanban/server/services/TaskRunnerService.js +261 -0
  135. package/kanban/server/workers/run-task-worker.js +121 -0
  136. package/kanban/server/workers/seed-worker.js +94 -0
  137. package/kanban/server/workers/sponsor-call-worker.js +14 -6
  138. package/kanban/server/workers/sprint-planning-worker.js +94 -12
  139. package/package.json +2 -3
  140. package/cli/agents/solver-epic-api.json +0 -15
  141. package/cli/agents/solver-epic-api.md +0 -39
  142. package/cli/agents/solver-epic-backend.json +0 -15
  143. package/cli/agents/solver-epic-backend.md +0 -39
  144. package/cli/agents/solver-epic-cloud.json +0 -15
  145. package/cli/agents/solver-epic-cloud.md +0 -39
  146. package/cli/agents/solver-epic-data.json +0 -15
  147. package/cli/agents/solver-epic-data.md +0 -39
  148. package/cli/agents/solver-epic-database.json +0 -15
  149. package/cli/agents/solver-epic-database.md +0 -39
  150. package/cli/agents/solver-epic-developer.json +0 -15
  151. package/cli/agents/solver-epic-developer.md +0 -39
  152. package/cli/agents/solver-epic-devops.json +0 -15
  153. package/cli/agents/solver-epic-devops.md +0 -39
  154. package/cli/agents/solver-epic-frontend.json +0 -15
  155. package/cli/agents/solver-epic-frontend.md +0 -39
  156. package/cli/agents/solver-epic-mobile.json +0 -15
  157. package/cli/agents/solver-epic-mobile.md +0 -39
  158. package/cli/agents/solver-epic-qa.json +0 -15
  159. package/cli/agents/solver-epic-qa.md +0 -39
  160. package/cli/agents/solver-epic-security.json +0 -15
  161. package/cli/agents/solver-epic-security.md +0 -39
  162. package/cli/agents/solver-epic-solution-architect.json +0 -15
  163. package/cli/agents/solver-epic-solution-architect.md +0 -39
  164. package/cli/agents/solver-epic-test-architect.json +0 -15
  165. package/cli/agents/solver-epic-test-architect.md +0 -39
  166. package/cli/agents/solver-epic-ui.json +0 -15
  167. package/cli/agents/solver-epic-ui.md +0 -39
  168. package/cli/agents/solver-epic-ux.json +0 -15
  169. package/cli/agents/solver-epic-ux.md +0 -39
  170. package/cli/agents/solver-story-api.json +0 -15
  171. package/cli/agents/solver-story-api.md +0 -39
  172. package/cli/agents/solver-story-backend.json +0 -15
  173. package/cli/agents/solver-story-backend.md +0 -39
  174. package/cli/agents/solver-story-cloud.json +0 -15
  175. package/cli/agents/solver-story-cloud.md +0 -39
  176. package/cli/agents/solver-story-data.json +0 -15
  177. package/cli/agents/solver-story-data.md +0 -39
  178. package/cli/agents/solver-story-database.json +0 -15
  179. package/cli/agents/solver-story-database.md +0 -39
  180. package/cli/agents/solver-story-developer.json +0 -15
  181. package/cli/agents/solver-story-developer.md +0 -39
  182. package/cli/agents/solver-story-devops.json +0 -15
  183. package/cli/agents/solver-story-devops.md +0 -39
  184. package/cli/agents/solver-story-frontend.json +0 -15
  185. package/cli/agents/solver-story-frontend.md +0 -39
  186. package/cli/agents/solver-story-mobile.json +0 -15
  187. package/cli/agents/solver-story-mobile.md +0 -39
  188. package/cli/agents/solver-story-qa.json +0 -15
  189. package/cli/agents/solver-story-qa.md +0 -39
  190. package/cli/agents/solver-story-security.json +0 -15
  191. package/cli/agents/solver-story-security.md +0 -39
  192. package/cli/agents/solver-story-solution-architect.json +0 -15
  193. package/cli/agents/solver-story-solution-architect.md +0 -39
  194. package/cli/agents/solver-story-test-architect.json +0 -15
  195. package/cli/agents/solver-story-test-architect.md +0 -39
  196. package/cli/agents/solver-story-ui.json +0 -15
  197. package/cli/agents/solver-story-ui.md +0 -39
  198. package/cli/agents/solver-story-ux.json +0 -15
  199. package/cli/agents/solver-story-ux.md +0 -39
  200. package/cli/agents/validator-epic-api.json +0 -93
  201. package/cli/agents/validator-epic-api.md +0 -137
  202. package/cli/agents/validator-epic-backend.json +0 -93
  203. package/cli/agents/validator-epic-backend.md +0 -130
  204. package/cli/agents/validator-epic-cloud.json +0 -93
  205. package/cli/agents/validator-epic-cloud.md +0 -137
  206. package/cli/agents/validator-epic-data.json +0 -93
  207. package/cli/agents/validator-epic-data.md +0 -130
  208. package/cli/agents/validator-epic-database.json +0 -93
  209. package/cli/agents/validator-epic-database.md +0 -137
  210. package/cli/agents/validator-epic-developer.json +0 -74
  211. package/cli/agents/validator-epic-developer.md +0 -153
  212. package/cli/agents/validator-epic-devops.json +0 -74
  213. package/cli/agents/validator-epic-devops.md +0 -153
  214. package/cli/agents/validator-epic-frontend.json +0 -74
  215. package/cli/agents/validator-epic-frontend.md +0 -153
  216. package/cli/agents/validator-epic-mobile.json +0 -93
  217. package/cli/agents/validator-epic-mobile.md +0 -130
  218. package/cli/agents/validator-epic-qa.json +0 -93
  219. package/cli/agents/validator-epic-qa.md +0 -130
  220. package/cli/agents/validator-epic-security.json +0 -74
  221. package/cli/agents/validator-epic-security.md +0 -154
  222. package/cli/agents/validator-epic-solution-architect.json +0 -74
  223. package/cli/agents/validator-epic-solution-architect.md +0 -156
  224. package/cli/agents/validator-epic-test-architect.json +0 -93
  225. package/cli/agents/validator-epic-test-architect.md +0 -130
  226. package/cli/agents/validator-epic-ui.json +0 -93
  227. package/cli/agents/validator-epic-ui.md +0 -130
  228. package/cli/agents/validator-epic-ux.json +0 -93
  229. package/cli/agents/validator-epic-ux.md +0 -130
  230. package/cli/agents/validator-story-api.json +0 -104
  231. package/cli/agents/validator-story-api.md +0 -152
  232. package/cli/agents/validator-story-backend.json +0 -104
  233. package/cli/agents/validator-story-backend.md +0 -152
  234. package/cli/agents/validator-story-cloud.json +0 -104
  235. package/cli/agents/validator-story-cloud.md +0 -152
  236. package/cli/agents/validator-story-data.json +0 -104
  237. package/cli/agents/validator-story-data.md +0 -152
  238. package/cli/agents/validator-story-database.json +0 -104
  239. package/cli/agents/validator-story-database.md +0 -152
  240. package/cli/agents/validator-story-developer.json +0 -104
  241. package/cli/agents/validator-story-developer.md +0 -152
  242. package/cli/agents/validator-story-devops.json +0 -104
  243. package/cli/agents/validator-story-devops.md +0 -152
  244. package/cli/agents/validator-story-frontend.json +0 -104
  245. package/cli/agents/validator-story-frontend.md +0 -152
  246. package/cli/agents/validator-story-mobile.json +0 -104
  247. package/cli/agents/validator-story-mobile.md +0 -152
  248. package/cli/agents/validator-story-qa.json +0 -104
  249. package/cli/agents/validator-story-qa.md +0 -152
  250. package/cli/agents/validator-story-security.json +0 -104
  251. package/cli/agents/validator-story-security.md +0 -152
  252. package/cli/agents/validator-story-solution-architect.json +0 -104
  253. package/cli/agents/validator-story-solution-architect.md +0 -152
  254. package/cli/agents/validator-story-test-architect.json +0 -104
  255. package/cli/agents/validator-story-test-architect.md +0 -152
  256. package/cli/agents/validator-story-ui.json +0 -104
  257. package/cli/agents/validator-story-ui.md +0 -152
  258. package/cli/agents/validator-story-ux.json +0 -104
  259. package/cli/agents/validator-story-ux.md +0 -152
  260. package/kanban/client/dist/assets/index-CiD8PS2e.js +0 -306
  261. 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 };