agentic-orchestrator 0.1.28 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (836) hide show
  1. package/.claude/settings.local.json +46 -1
  2. package/.cortexrc +28 -0
  3. package/.github/agents/copilot-instructions.md +29 -0
  4. package/.github/copilot-instructions.md +93 -0
  5. package/.vscode/settings.json +13 -0
  6. package/.vscode/tms.code-snippets +223 -0
  7. package/AGENTS.md +72 -1
  8. package/Agentic-Orchestrator.iml +12 -11
  9. package/CLAUDE.md +72 -1
  10. package/CONSTITUTION.md +504 -0
  11. package/FUTURE-ENHANCEMENTS.md +85 -0
  12. package/NEXT-TASKS.md +25 -0
  13. package/PROMPTS.md +161 -0
  14. package/README.md +126 -29
  15. package/agentic/orchestrator/agents.yaml +4 -3
  16. package/agentic/orchestrator/defaults/policy.defaults.yaml +39 -3
  17. package/agentic/orchestrator/gates.yaml +15 -3
  18. package/agentic/orchestrator/policy.yaml +47 -3
  19. package/agentic/orchestrator/prompts/builder.system.md +69 -20
  20. package/agentic/orchestrator/prompts/planner-intake.system.md +149 -0
  21. package/agentic/orchestrator/prompts/planner.system.md +113 -40
  22. package/agentic/orchestrator/prompts/qa.system.md +73 -18
  23. package/agentic/orchestrator/prompts/reconciler.system.md +119 -0
  24. package/agentic/orchestrator/schemas/agents.schema.json +89 -1
  25. package/agentic/orchestrator/schemas/execution-control.schema.json +242 -0
  26. package/agentic/orchestrator/schemas/index.schema.json +234 -0
  27. package/agentic/orchestrator/schemas/intake.review.schema.json +82 -0
  28. package/agentic/orchestrator/schemas/organizer-ordering-artifact.schema.json +75 -0
  29. package/agentic/orchestrator/schemas/plan.schema.json +44 -0
  30. package/agentic/orchestrator/schemas/policy.schema.json +238 -9
  31. package/agentic/orchestrator/schemas/policy.user.schema.json +129 -1
  32. package/agentic/orchestrator/schemas/spec.manifest.bootstrap.schema.json +101 -0
  33. package/agentic/orchestrator/schemas/spec.manifest.verified.schema.json +80 -0
  34. package/agentic/orchestrator/schemas/state.schema.json +298 -3
  35. package/agentic/orchestrator/tools/catalog.json +145 -15
  36. package/agentic/orchestrator/tools/schemas/input/doctor.run.input.schema.json +18 -0
  37. package/agentic/orchestrator/tools/schemas/input/evidence.latest.input.schema.json +4 -0
  38. package/agentic/orchestrator/tools/schemas/input/evidence.verify_chain.input.schema.json +13 -0
  39. package/agentic/orchestrator/tools/schemas/input/feature.intake_submit.input.schema.json +11 -0
  40. package/agentic/orchestrator/tools/schemas/input/feature.question_answer.input.schema.json +15 -0
  41. package/agentic/orchestrator/tools/schemas/input/feature.question_create.input.schema.json +21 -0
  42. package/agentic/orchestrator/tools/schemas/input/feature.question_list.input.schema.json +13 -0
  43. package/agentic/orchestrator/tools/schemas/input/feature.ready_to_merge.input.schema.json +5 -0
  44. package/agentic/orchestrator/tools/schemas/input/feature.send_message.input.schema.json +1 -1
  45. package/agentic/orchestrator/tools/schemas/input/replay.timeline_get.input.schema.json +32 -0
  46. package/agentic/orchestrator/tools/schemas/input/repo.conflict_abort.input.schema.json +16 -0
  47. package/agentic/orchestrator/tools/schemas/input/repo.conflict_files.input.schema.json +16 -0
  48. package/agentic/orchestrator/tools/schemas/input/repo.reconcile_mainline.input.schema.json +37 -0
  49. package/agentic/orchestrator/tools/schemas/input/repo.resolve_conflict.input.schema.json +40 -0
  50. package/agentic/orchestrator/tools/schemas/input/runtime.execution_request_list.input.schema.json +7 -0
  51. package/agentic/orchestrator/tools/schemas/input/runtime.execution_request_submit.input.schema.json +25 -0
  52. package/agentic/orchestrator/tools/schemas/output/doctor.run.output.schema.json +34 -0
  53. package/agentic/orchestrator/tools/schemas/output/evidence.verify_chain.output.schema.json +23 -0
  54. package/agentic/orchestrator/tools/schemas/output/feature.get_context.output.schema.json +62 -2
  55. package/agentic/orchestrator/tools/schemas/output/feature.intake_submit.output.schema.json +24 -0
  56. package/agentic/orchestrator/tools/schemas/output/feature.question_answer.output.schema.json +21 -0
  57. package/agentic/orchestrator/tools/schemas/output/feature.question_create.output.schema.json +12 -0
  58. package/agentic/orchestrator/tools/schemas/output/feature.question_list.output.schema.json +14 -0
  59. package/agentic/orchestrator/tools/schemas/output/feature.ready_to_merge.output.schema.json +31 -0
  60. package/agentic/orchestrator/tools/schemas/output/feature.send_message.output.schema.json +8 -18
  61. package/agentic/orchestrator/tools/schemas/output/replay.timeline_get.output.schema.json +64 -0
  62. package/agentic/orchestrator/tools/schemas/output/repo.conflict_abort.output.schema.json +16 -0
  63. package/agentic/orchestrator/tools/schemas/output/repo.conflict_files.output.schema.json +22 -0
  64. package/agentic/orchestrator/tools/schemas/output/repo.reconcile_mainline.output.schema.json +61 -0
  65. package/agentic/orchestrator/tools/schemas/output/repo.resolve_conflict.output.schema.json +19 -0
  66. package/agentic/orchestrator/tools/schemas/output/report.dashboard.output.schema.json +26 -0
  67. package/agentic/orchestrator/tools/schemas/output/runtime.execution_request_list.output.schema.json +17 -0
  68. package/agentic/orchestrator/tools/schemas/output/runtime.execution_request_submit.output.schema.json +24 -0
  69. package/agentic/orchestrator/tools.md +13 -0
  70. package/apps/control-plane/scripts/validate-mcp-contracts.ts +1 -1
  71. package/apps/control-plane/src/application/kernel-tool-wiring.ts +140 -2
  72. package/apps/control-plane/src/application/services/activity-monitor-service.ts +44 -1
  73. package/apps/control-plane/src/application/services/bootstrap-manifest-generator-service.ts +251 -0
  74. package/apps/control-plane/src/application/services/checkpoint-service.ts +87 -27
  75. package/apps/control-plane/src/application/services/collision-override-service.ts +906 -0
  76. package/apps/control-plane/src/application/services/collision-queue-service.ts +129 -38
  77. package/apps/control-plane/src/application/services/cost-tracking-service.ts +94 -0
  78. package/apps/control-plane/src/application/services/execution-control-service.ts +599 -0
  79. package/apps/control-plane/src/application/services/feature-deletion-service.ts +37 -1
  80. package/apps/control-plane/src/application/services/feature-lifecycle-service.ts +182 -4
  81. package/apps/control-plane/src/application/services/feature-send-message-service.ts +17 -8
  82. package/apps/control-plane/src/application/services/feature-state-service.ts +191 -6
  83. package/apps/control-plane/src/application/services/gate-service.ts +121 -2
  84. package/apps/control-plane/src/application/services/git-reconciliation-service.ts +1591 -0
  85. package/apps/control-plane/src/application/services/intake-service.ts +1468 -0
  86. package/apps/control-plane/src/application/services/merge-service.ts +308 -17
  87. package/apps/control-plane/src/application/services/notifier-service.ts +3 -1
  88. package/apps/control-plane/src/application/services/performance-analytics-service.ts +75 -0
  89. package/apps/control-plane/src/application/services/plan-service.ts +336 -20
  90. package/apps/control-plane/src/application/services/question-service.ts +693 -0
  91. package/apps/control-plane/src/application/services/reactions-service.ts +73 -17
  92. package/apps/control-plane/src/application/services/replay-timeline-service.ts +295 -0
  93. package/apps/control-plane/src/application/services/reporting-service.ts +194 -10
  94. package/apps/control-plane/src/application/services/run-lease-service.ts +121 -5
  95. package/apps/control-plane/src/application/services/worktree-watchdog-service.ts +95 -8
  96. package/apps/control-plane/src/application/tools/tool-metadata.ts +7 -0
  97. package/apps/control-plane/src/application/usage-types.ts +138 -0
  98. package/apps/control-plane/src/cli/add-command-handler.ts +162 -0
  99. package/apps/control-plane/src/cli/answer-command-handler.ts +113 -0
  100. package/apps/control-plane/src/cli/attach-command-handler.ts +12 -3
  101. package/apps/control-plane/src/cli/cli-argument-parser.ts +133 -11
  102. package/apps/control-plane/src/cli/collision-command-handler.ts +113 -0
  103. package/apps/control-plane/src/cli/command-catalog.ts +479 -0
  104. package/apps/control-plane/src/cli/complete-command-handler.ts +23 -0
  105. package/apps/control-plane/src/cli/completion-command-handler.ts +25 -0
  106. package/apps/control-plane/src/cli/completion-resolver.ts +319 -0
  107. package/apps/control-plane/src/cli/completion-shell-renderer.ts +58 -0
  108. package/apps/control-plane/src/cli/dashboard-command-handler.ts +110 -1
  109. package/apps/control-plane/src/cli/dashboard-runtime-runner.ts +1036 -0
  110. package/apps/control-plane/src/cli/dashboard-runtime.ts +31 -0
  111. package/apps/control-plane/src/cli/help-command-handler.ts +17 -185
  112. package/apps/control-plane/src/cli/init-command-handler.ts +51 -6
  113. package/apps/control-plane/src/cli/merge-command-handler.ts +200 -0
  114. package/apps/control-plane/src/cli/questions-command-handler.ts +70 -0
  115. package/apps/control-plane/src/cli/replay-command-handler.ts +98 -0
  116. package/apps/control-plane/src/cli/resume-command-handler.ts +231 -16
  117. package/apps/control-plane/src/cli/retry-command-handler.ts +229 -17
  118. package/apps/control-plane/src/cli/retry-resume-decision.ts +75 -0
  119. package/apps/control-plane/src/cli/rollback-command-handler.ts +4 -2
  120. package/apps/control-plane/src/cli/run-command-handler.ts +35 -1
  121. package/apps/control-plane/src/cli/spec-ingestion-service.ts +45 -55
  122. package/apps/control-plane/src/cli/spec-preparation.ts +114 -0
  123. package/apps/control-plane/src/cli/spec-utils.ts +90 -11
  124. package/apps/control-plane/src/cli/status-command-handler.ts +122 -0
  125. package/apps/control-plane/src/cli/types.ts +41 -3
  126. package/apps/control-plane/src/core/collisions.ts +150 -31
  127. package/apps/control-plane/src/core/constants.ts +18 -1
  128. package/apps/control-plane/src/core/error-codes.ts +39 -0
  129. package/apps/control-plane/src/core/execution-control.ts +56 -0
  130. package/apps/control-plane/src/core/feature-resume-phase.ts +118 -0
  131. package/apps/control-plane/src/core/gate-freshness.ts +359 -0
  132. package/apps/control-plane/src/core/gate-log-extractor.ts +97 -0
  133. package/apps/control-plane/src/core/gates.ts +90 -1
  134. package/apps/control-plane/src/core/intake-artifacts.ts +295 -0
  135. package/apps/control-plane/src/core/kernel-types.ts +11 -0
  136. package/apps/control-plane/src/core/kernel.ts +604 -16
  137. package/apps/control-plane/src/core/mainline-conflict.ts +22 -0
  138. package/apps/control-plane/src/core/merge-repair.ts +149 -0
  139. package/apps/control-plane/src/core/path-layout.ts +46 -2
  140. package/apps/control-plane/src/core/path-rules.ts +11 -3
  141. package/apps/control-plane/src/core/plan-submit-recovery.ts +130 -0
  142. package/apps/control-plane/src/core/questions.ts +49 -0
  143. package/apps/control-plane/src/core/runtime-sessions.ts +4 -0
  144. package/apps/control-plane/src/core/schemas.ts +40 -1
  145. package/apps/control-plane/src/core/tool-caller.ts +25 -1
  146. package/apps/control-plane/src/core/utils/index-normalizer.ts +25 -4
  147. package/apps/control-plane/src/core/worktree-diff.ts +66 -0
  148. package/apps/control-plane/src/index.ts +29 -1
  149. package/apps/control-plane/src/interfaces/cli/bootstrap.ts +300 -6
  150. package/apps/control-plane/src/mcp/kernel-tool-executor.ts +17 -0
  151. package/apps/control-plane/src/mcp/tool-runtime.ts +63 -4
  152. package/apps/control-plane/src/providers/api-worker-provider.ts +62 -15
  153. package/apps/control-plane/src/providers/cli-worker-provider.ts +1037 -61
  154. package/apps/control-plane/src/providers/output-parsers/generic-output-parser.ts +99 -1
  155. package/apps/control-plane/src/providers/output-parsers/types.ts +2 -0
  156. package/apps/control-plane/src/providers/provider-defaults.ts +116 -7
  157. package/apps/control-plane/src/providers/providers.ts +225 -21
  158. package/apps/control-plane/src/providers/worker-provider-factory.ts +26 -2
  159. package/apps/control-plane/src/supervisor/artifact-stager.ts +52 -0
  160. package/apps/control-plane/src/supervisor/build-wave-executor.ts +477 -166
  161. package/apps/control-plane/src/supervisor/execution-enrollment-service.ts +408 -0
  162. package/apps/control-plane/src/supervisor/organizer-enrollment-scheduler.ts +117 -0
  163. package/apps/control-plane/src/supervisor/organizer-sidecar-service.ts +394 -0
  164. package/apps/control-plane/src/supervisor/plan-conformance-scorer.ts +2 -5
  165. package/apps/control-plane/src/supervisor/planner-phase.ts +85 -0
  166. package/apps/control-plane/src/supervisor/planning-wave-executor.ts +993 -64
  167. package/apps/control-plane/src/supervisor/prompt-bundle-loader.ts +20 -1
  168. package/apps/control-plane/src/supervisor/qa-wave-executor.ts +384 -177
  169. package/apps/control-plane/src/supervisor/run-coordinator.ts +723 -20
  170. package/apps/control-plane/src/supervisor/runtime.ts +485 -9
  171. package/apps/control-plane/src/supervisor/session-orchestrator.ts +220 -1
  172. package/apps/control-plane/src/supervisor/types.ts +152 -1
  173. package/apps/control-plane/src/supervisor/worker-decision-loop.ts +1030 -92
  174. package/apps/control-plane/test/activity-monitor.spec.ts +76 -0
  175. package/apps/control-plane/test/add-command-handler.spec.ts +189 -0
  176. package/apps/control-plane/test/application/services/feature-state-service.spec.ts +208 -0
  177. package/apps/control-plane/test/artifact-stager.spec.ts +93 -0
  178. package/apps/control-plane/test/batch-operations.spec.ts +58 -0
  179. package/apps/control-plane/test/bootstrap-edge-cases.spec.ts +50 -2
  180. package/apps/control-plane/test/bootstrap-manifest-generator-service.spec.ts +99 -0
  181. package/apps/control-plane/test/bootstrap.spec.ts +177 -4
  182. package/apps/control-plane/test/checkpoint-service.spec.ts +977 -29
  183. package/apps/control-plane/test/cli-argument-parser.spec.ts +119 -0
  184. package/apps/control-plane/test/cli-helpers.spec.ts +1202 -12
  185. package/apps/control-plane/test/cli.unit.spec.ts +797 -16
  186. package/apps/control-plane/test/collision-command-handler.spec.ts +182 -0
  187. package/apps/control-plane/test/collision-override-service.spec.ts +878 -0
  188. package/apps/control-plane/test/collision-queue.spec.ts +430 -2
  189. package/apps/control-plane/test/collisions.spec.ts +209 -1
  190. package/apps/control-plane/test/core-utils.spec.ts +61 -0
  191. package/apps/control-plane/test/cost-tracking.spec.ts +224 -0
  192. package/apps/control-plane/test/dashboard-api.integration.spec.ts +185 -5
  193. package/apps/control-plane/test/dashboard-client.spec.ts +948 -0
  194. package/apps/control-plane/test/dashboard-command.spec.ts +138 -6
  195. package/apps/control-plane/test/dashboard-runtime-runner.spec.ts +1550 -0
  196. package/apps/control-plane/test/dashboard-runtime.spec.ts +138 -0
  197. package/apps/control-plane/test/dashboard-ui-utils.spec.ts +56 -12
  198. package/apps/control-plane/test/dependency-scheduler.spec.ts +7 -1
  199. package/apps/control-plane/test/env-file.spec.ts +76 -0
  200. package/apps/control-plane/test/execution-control-service.spec.ts +535 -0
  201. package/apps/control-plane/test/execution-enrollment-service.spec.ts +648 -0
  202. package/apps/control-plane/test/feature-lifecycle.spec.ts +126 -0
  203. package/apps/control-plane/test/feature-resume-phase.spec.ts +164 -0
  204. package/apps/control-plane/test/feature-send-message-service.spec.ts +161 -0
  205. package/apps/control-plane/test/feature-state-service.spec.ts +295 -0
  206. package/apps/control-plane/test/fs.spec.ts +80 -0
  207. package/apps/control-plane/test/gate-freshness.spec.ts +590 -0
  208. package/apps/control-plane/test/gate-log-extractor.spec.ts +170 -0
  209. package/apps/control-plane/test/gates.spec.ts +108 -0
  210. package/apps/control-plane/test/git-reconciliation-service.spec.ts +2307 -0
  211. package/apps/control-plane/test/helpers.ts +65 -0
  212. package/apps/control-plane/test/incremental-gates.spec.ts +271 -0
  213. package/apps/control-plane/test/index-normalizer.spec.ts +98 -0
  214. package/apps/control-plane/test/init-wizard.spec.ts +17 -0
  215. package/apps/control-plane/test/intake-artifacts.spec.ts +203 -0
  216. package/apps/control-plane/test/intake-service.spec.ts +3176 -0
  217. package/apps/control-plane/test/kernel-collision-replay.spec.ts +3 -2
  218. package/apps/control-plane/test/kernel-tool-executor.spec.ts +77 -0
  219. package/apps/control-plane/test/kernel-tool-wiring.spec.ts +279 -0
  220. package/apps/control-plane/test/kernel.branches.spec.ts +15 -2
  221. package/apps/control-plane/test/kernel.coverage.spec.ts +7 -3
  222. package/apps/control-plane/test/kernel.coverage2.spec.ts +731 -2
  223. package/apps/control-plane/test/kernel.spec.ts +464 -2
  224. package/apps/control-plane/test/mainline-conflict.spec.ts +66 -0
  225. package/apps/control-plane/test/mcp-helpers.spec.ts +79 -0
  226. package/apps/control-plane/test/mcp.spec.ts +177 -13
  227. package/apps/control-plane/test/merge-command-handler.spec.ts +531 -0
  228. package/apps/control-plane/test/merge-service.spec.ts +570 -4
  229. package/apps/control-plane/test/notifier-service.spec.ts +26 -0
  230. package/apps/control-plane/test/organizer-enrollment-scheduler.spec.ts +340 -0
  231. package/apps/control-plane/test/organizer-ordering-artifact.spec.ts +95 -0
  232. package/apps/control-plane/test/organizer-sidecar-service.spec.ts +468 -0
  233. package/apps/control-plane/test/output-loop-detector.spec.ts +6 -0
  234. package/apps/control-plane/test/path-layout.spec.ts +70 -0
  235. package/apps/control-plane/test/performance-analytics.spec.ts +124 -0
  236. package/apps/control-plane/test/plan-conformance-scorer.spec.ts +53 -0
  237. package/apps/control-plane/test/plan-service.spec.ts +686 -4
  238. package/apps/control-plane/test/planning-wave-executor.spec.ts +3272 -86
  239. package/apps/control-plane/test/policy-loader-service.spec.ts +5 -0
  240. package/apps/control-plane/test/prompt-overlay.spec.ts +65 -0
  241. package/apps/control-plane/test/provider-command-runner-epipe.spec.ts +64 -0
  242. package/apps/control-plane/test/providers/api-worker-provider.spec.ts +129 -0
  243. package/apps/control-plane/test/providers/cli-worker-provider.spec.ts +148 -0
  244. package/apps/control-plane/test/providers/usage-types.spec.ts +98 -0
  245. package/apps/control-plane/test/providers.spec.ts +293 -16
  246. package/apps/control-plane/test/question-command-handlers.spec.ts +156 -0
  247. package/apps/control-plane/test/question-service.spec.ts +1119 -0
  248. package/apps/control-plane/test/reactions.spec.ts +114 -0
  249. package/apps/control-plane/test/replay-command-handler.spec.ts +144 -0
  250. package/apps/control-plane/test/replay-timeline-service.spec.ts +459 -0
  251. package/apps/control-plane/test/response.spec.ts +31 -0
  252. package/apps/control-plane/test/resume-command.spec.ts +757 -9
  253. package/apps/control-plane/test/retry-resume-decision.spec.ts +133 -0
  254. package/apps/control-plane/test/rollback-command-handler.spec.ts +334 -0
  255. package/apps/control-plane/test/rollback-command.spec.ts +120 -0
  256. package/apps/control-plane/test/run-coordinator.spec.ts +3062 -404
  257. package/apps/control-plane/test/schemas/state.schema.spec.ts +71 -0
  258. package/apps/control-plane/test/service-retry-paths.spec.ts +112 -0
  259. package/apps/control-plane/test/services.spec.ts +472 -2
  260. package/apps/control-plane/test/session-management.spec.ts +346 -1
  261. package/apps/control-plane/test/spec-ingestion.spec.ts +102 -28
  262. package/apps/control-plane/test/spec-preparation.spec.ts +182 -0
  263. package/apps/control-plane/test/supervisor-collaborators.spec.ts +191 -3
  264. package/apps/control-plane/test/supervisor.calltool.spec.ts +198 -0
  265. package/apps/control-plane/test/supervisor.spec.ts +95 -16
  266. package/apps/control-plane/test/supervisor.unit.spec.ts +385 -18
  267. package/apps/control-plane/test/tool-runtime.spec.ts +122 -0
  268. package/apps/control-plane/test/worker-decision-loop.spec.ts +3479 -476
  269. package/apps/control-plane/test/worker-execution-policy.spec.ts +1416 -6
  270. package/apps/control-plane/test/worker-provider-adapters.spec.ts +1894 -37
  271. package/apps/control-plane/test/worker-provider-factory.spec.ts +81 -0
  272. package/apps/control-plane/test/worktree-watchdog-service.spec.ts +125 -0
  273. package/apps/control-plane/vitest.config.ts +5 -0
  274. package/config/agentic/orchestrator/agents.yaml +22 -1
  275. package/config/agentic/orchestrator/gates.yaml +24 -7
  276. package/config/agentic/orchestrator/policy.yaml +23 -1
  277. package/config/agentic/orchestrator/prompts/builder.system.md +69 -20
  278. package/config/agentic/orchestrator/prompts/organizer.system.md +85 -0
  279. package/config/agentic/orchestrator/prompts/overrides/builder.claude.md +28 -0
  280. package/config/agentic/orchestrator/prompts/overrides/builder.codex.md +28 -0
  281. package/config/agentic/orchestrator/prompts/overrides/planner.claude.md +20 -0
  282. package/config/agentic/orchestrator/prompts/overrides/planner.codex.md +20 -0
  283. package/config/agentic/orchestrator/prompts/planner-intake.system.md +149 -0
  284. package/config/agentic/orchestrator/prompts/planner.system.md +113 -40
  285. package/config/agentic/orchestrator/prompts/qa.system.md +75 -18
  286. package/config/agentic/orchestrator/prompts/reconciler.system.md +119 -0
  287. package/dist/apps/control-plane/application/kernel-tool-wiring.d.ts +26 -2
  288. package/dist/apps/control-plane/application/kernel-tool-wiring.js +40 -2
  289. package/dist/apps/control-plane/application/kernel-tool-wiring.js.map +1 -1
  290. package/dist/apps/control-plane/application/services/activity-monitor-service.js +37 -1
  291. package/dist/apps/control-plane/application/services/activity-monitor-service.js.map +1 -1
  292. package/dist/apps/control-plane/application/services/bootstrap-manifest-generator-service.d.ts +4 -0
  293. package/dist/apps/control-plane/application/services/bootstrap-manifest-generator-service.js +188 -0
  294. package/dist/apps/control-plane/application/services/bootstrap-manifest-generator-service.js.map +1 -0
  295. package/dist/apps/control-plane/application/services/checkpoint-service.d.ts +5 -0
  296. package/dist/apps/control-plane/application/services/checkpoint-service.js +69 -24
  297. package/dist/apps/control-plane/application/services/checkpoint-service.js.map +1 -1
  298. package/dist/apps/control-plane/application/services/collision-override-service.d.ts +139 -0
  299. package/dist/apps/control-plane/application/services/collision-override-service.js +568 -0
  300. package/dist/apps/control-plane/application/services/collision-override-service.js.map +1 -0
  301. package/dist/apps/control-plane/application/services/collision-queue-service.d.ts +15 -0
  302. package/dist/apps/control-plane/application/services/collision-queue-service.js +92 -33
  303. package/dist/apps/control-plane/application/services/collision-queue-service.js.map +1 -1
  304. package/dist/apps/control-plane/application/services/cost-tracking-service.d.ts +11 -0
  305. package/dist/apps/control-plane/application/services/cost-tracking-service.js +75 -0
  306. package/dist/apps/control-plane/application/services/cost-tracking-service.js.map +1 -1
  307. package/dist/apps/control-plane/application/services/execution-control-service.d.ts +75 -0
  308. package/dist/apps/control-plane/application/services/execution-control-service.js +421 -0
  309. package/dist/apps/control-plane/application/services/execution-control-service.js.map +1 -0
  310. package/dist/apps/control-plane/application/services/feature-deletion-service.d.ts +1 -0
  311. package/dist/apps/control-plane/application/services/feature-deletion-service.js +23 -1
  312. package/dist/apps/control-plane/application/services/feature-deletion-service.js.map +1 -1
  313. package/dist/apps/control-plane/application/services/feature-lifecycle-service.d.ts +24 -1
  314. package/dist/apps/control-plane/application/services/feature-lifecycle-service.js +132 -3
  315. package/dist/apps/control-plane/application/services/feature-lifecycle-service.js.map +1 -1
  316. package/dist/apps/control-plane/application/services/feature-send-message-service.js +16 -8
  317. package/dist/apps/control-plane/application/services/feature-send-message-service.js.map +1 -1
  318. package/dist/apps/control-plane/application/services/feature-state-service.d.ts +36 -0
  319. package/dist/apps/control-plane/application/services/feature-state-service.js +163 -6
  320. package/dist/apps/control-plane/application/services/feature-state-service.js.map +1 -1
  321. package/dist/apps/control-plane/application/services/gate-service.d.ts +2 -1
  322. package/dist/apps/control-plane/application/services/gate-service.js +95 -5
  323. package/dist/apps/control-plane/application/services/gate-service.js.map +1 -1
  324. package/dist/apps/control-plane/application/services/git-reconciliation-service.d.ts +92 -0
  325. package/dist/apps/control-plane/application/services/git-reconciliation-service.js +1097 -0
  326. package/dist/apps/control-plane/application/services/git-reconciliation-service.js.map +1 -0
  327. package/dist/apps/control-plane/application/services/intake-service.d.ts +63 -0
  328. package/dist/apps/control-plane/application/services/intake-service.js +1050 -0
  329. package/dist/apps/control-plane/application/services/intake-service.js.map +1 -0
  330. package/dist/apps/control-plane/application/services/merge-service.d.ts +5 -1
  331. package/dist/apps/control-plane/application/services/merge-service.js +233 -18
  332. package/dist/apps/control-plane/application/services/merge-service.js.map +1 -1
  333. package/dist/apps/control-plane/application/services/notifier-service.d.ts +1 -1
  334. package/dist/apps/control-plane/application/services/notifier-service.js +1 -0
  335. package/dist/apps/control-plane/application/services/notifier-service.js.map +1 -1
  336. package/dist/apps/control-plane/application/services/performance-analytics-service.d.ts +11 -0
  337. package/dist/apps/control-plane/application/services/performance-analytics-service.js +59 -0
  338. package/dist/apps/control-plane/application/services/performance-analytics-service.js.map +1 -1
  339. package/dist/apps/control-plane/application/services/plan-service.d.ts +5 -0
  340. package/dist/apps/control-plane/application/services/plan-service.js +254 -15
  341. package/dist/apps/control-plane/application/services/plan-service.js.map +1 -1
  342. package/dist/apps/control-plane/application/services/question-service.d.ts +72 -0
  343. package/dist/apps/control-plane/application/services/question-service.js +507 -0
  344. package/dist/apps/control-plane/application/services/question-service.js.map +1 -0
  345. package/dist/apps/control-plane/application/services/reactions-service.d.ts +2 -0
  346. package/dist/apps/control-plane/application/services/reactions-service.js +60 -17
  347. package/dist/apps/control-plane/application/services/reactions-service.js.map +1 -1
  348. package/dist/apps/control-plane/application/services/replay-timeline-service.d.ts +39 -0
  349. package/dist/apps/control-plane/application/services/replay-timeline-service.js +205 -0
  350. package/dist/apps/control-plane/application/services/replay-timeline-service.js.map +1 -0
  351. package/dist/apps/control-plane/application/services/reporting-service.d.ts +59 -0
  352. package/dist/apps/control-plane/application/services/reporting-service.js +121 -9
  353. package/dist/apps/control-plane/application/services/reporting-service.js.map +1 -1
  354. package/dist/apps/control-plane/application/services/run-lease-service.d.ts +20 -0
  355. package/dist/apps/control-plane/application/services/run-lease-service.js +81 -4
  356. package/dist/apps/control-plane/application/services/run-lease-service.js.map +1 -1
  357. package/dist/apps/control-plane/application/services/worktree-watchdog-service.d.ts +10 -0
  358. package/dist/apps/control-plane/application/services/worktree-watchdog-service.js +65 -8
  359. package/dist/apps/control-plane/application/services/worktree-watchdog-service.js.map +1 -1
  360. package/dist/apps/control-plane/application/tools/tool-metadata.js +7 -0
  361. package/dist/apps/control-plane/application/tools/tool-metadata.js.map +1 -1
  362. package/dist/apps/control-plane/application/usage-types.d.ts +65 -0
  363. package/dist/apps/control-plane/application/usage-types.js +75 -0
  364. package/dist/apps/control-plane/application/usage-types.js.map +1 -0
  365. package/dist/apps/control-plane/cli/add-command-handler.d.ts +18 -0
  366. package/dist/apps/control-plane/cli/add-command-handler.js +110 -0
  367. package/dist/apps/control-plane/cli/add-command-handler.js.map +1 -0
  368. package/dist/apps/control-plane/cli/answer-command-handler.d.ts +8 -0
  369. package/dist/apps/control-plane/cli/answer-command-handler.js +96 -0
  370. package/dist/apps/control-plane/cli/answer-command-handler.js.map +1 -0
  371. package/dist/apps/control-plane/cli/attach-command-handler.js +8 -3
  372. package/dist/apps/control-plane/cli/attach-command-handler.js.map +1 -1
  373. package/dist/apps/control-plane/cli/cli-argument-parser.js +131 -11
  374. package/dist/apps/control-plane/cli/cli-argument-parser.js.map +1 -1
  375. package/dist/apps/control-plane/cli/collision-command-handler.d.ts +8 -0
  376. package/dist/apps/control-plane/cli/collision-command-handler.js +90 -0
  377. package/dist/apps/control-plane/cli/collision-command-handler.js.map +1 -0
  378. package/dist/apps/control-plane/cli/command-catalog.d.ts +21 -0
  379. package/dist/apps/control-plane/cli/command-catalog.js +416 -0
  380. package/dist/apps/control-plane/cli/command-catalog.js.map +1 -0
  381. package/dist/apps/control-plane/cli/complete-command-handler.d.ts +15 -0
  382. package/dist/apps/control-plane/cli/complete-command-handler.js +26 -0
  383. package/dist/apps/control-plane/cli/complete-command-handler.js.map +1 -0
  384. package/dist/apps/control-plane/cli/completion-command-handler.d.ts +8 -0
  385. package/dist/apps/control-plane/cli/completion-command-handler.js +20 -0
  386. package/dist/apps/control-plane/cli/completion-command-handler.js.map +1 -0
  387. package/dist/apps/control-plane/cli/completion-resolver.d.ts +1 -0
  388. package/dist/apps/control-plane/cli/completion-resolver.js +250 -0
  389. package/dist/apps/control-plane/cli/completion-resolver.js.map +1 -0
  390. package/dist/apps/control-plane/cli/completion-shell-renderer.d.ts +3 -0
  391. package/dist/apps/control-plane/cli/completion-shell-renderer.js +53 -0
  392. package/dist/apps/control-plane/cli/completion-shell-renderer.js.map +1 -0
  393. package/dist/apps/control-plane/cli/dashboard-command-handler.d.ts +1 -0
  394. package/dist/apps/control-plane/cli/dashboard-command-handler.js +83 -1
  395. package/dist/apps/control-plane/cli/dashboard-command-handler.js.map +1 -1
  396. package/dist/apps/control-plane/cli/dashboard-runtime-runner.d.ts +81 -0
  397. package/dist/apps/control-plane/cli/dashboard-runtime-runner.js +724 -0
  398. package/dist/apps/control-plane/cli/dashboard-runtime-runner.js.map +1 -0
  399. package/dist/apps/control-plane/cli/dashboard-runtime.d.ts +1 -0
  400. package/dist/apps/control-plane/cli/dashboard-runtime.js +26 -0
  401. package/dist/apps/control-plane/cli/dashboard-runtime.js.map +1 -0
  402. package/dist/apps/control-plane/cli/help-command-handler.js +13 -172
  403. package/dist/apps/control-plane/cli/help-command-handler.js.map +1 -1
  404. package/dist/apps/control-plane/cli/init-command-handler.js +51 -6
  405. package/dist/apps/control-plane/cli/init-command-handler.js.map +1 -1
  406. package/dist/apps/control-plane/cli/merge-command-handler.d.ts +8 -0
  407. package/dist/apps/control-plane/cli/merge-command-handler.js +139 -0
  408. package/dist/apps/control-plane/cli/merge-command-handler.js.map +1 -0
  409. package/dist/apps/control-plane/cli/questions-command-handler.d.ts +8 -0
  410. package/dist/apps/control-plane/cli/questions-command-handler.js +59 -0
  411. package/dist/apps/control-plane/cli/questions-command-handler.js.map +1 -0
  412. package/dist/apps/control-plane/cli/replay-command-handler.d.ts +15 -0
  413. package/dist/apps/control-plane/cli/replay-command-handler.js +55 -0
  414. package/dist/apps/control-plane/cli/replay-command-handler.js.map +1 -0
  415. package/dist/apps/control-plane/cli/resume-command-handler.d.ts +2 -0
  416. package/dist/apps/control-plane/cli/resume-command-handler.js +180 -17
  417. package/dist/apps/control-plane/cli/resume-command-handler.js.map +1 -1
  418. package/dist/apps/control-plane/cli/retry-command-handler.js +202 -16
  419. package/dist/apps/control-plane/cli/retry-command-handler.js.map +1 -1
  420. package/dist/apps/control-plane/cli/retry-resume-decision.d.ts +26 -0
  421. package/dist/apps/control-plane/cli/retry-resume-decision.js +61 -0
  422. package/dist/apps/control-plane/cli/retry-resume-decision.js.map +1 -0
  423. package/dist/apps/control-plane/cli/rollback-command-handler.js +3 -2
  424. package/dist/apps/control-plane/cli/rollback-command-handler.js.map +1 -1
  425. package/dist/apps/control-plane/cli/run-command-handler.js +26 -2
  426. package/dist/apps/control-plane/cli/run-command-handler.js.map +1 -1
  427. package/dist/apps/control-plane/cli/spec-ingestion-service.d.ts +2 -0
  428. package/dist/apps/control-plane/cli/spec-ingestion-service.js +37 -48
  429. package/dist/apps/control-plane/cli/spec-ingestion-service.js.map +1 -1
  430. package/dist/apps/control-plane/cli/spec-preparation.d.ts +14 -0
  431. package/dist/apps/control-plane/cli/spec-preparation.js +81 -0
  432. package/dist/apps/control-plane/cli/spec-preparation.js.map +1 -0
  433. package/dist/apps/control-plane/cli/spec-utils.d.ts +4 -0
  434. package/dist/apps/control-plane/cli/spec-utils.js +70 -11
  435. package/dist/apps/control-plane/cli/spec-utils.js.map +1 -1
  436. package/dist/apps/control-plane/cli/status-command-handler.js +69 -0
  437. package/dist/apps/control-plane/cli/status-command-handler.js.map +1 -1
  438. package/dist/apps/control-plane/cli/types.d.ts +41 -4
  439. package/dist/apps/control-plane/cli/types.js +9 -1
  440. package/dist/apps/control-plane/cli/types.js.map +1 -1
  441. package/dist/apps/control-plane/core/collisions.d.ts +37 -19
  442. package/dist/apps/control-plane/core/collisions.js +87 -12
  443. package/dist/apps/control-plane/core/collisions.js.map +1 -1
  444. package/dist/apps/control-plane/core/constants.d.ts +17 -1
  445. package/dist/apps/control-plane/core/constants.js +18 -1
  446. package/dist/apps/control-plane/core/constants.js.map +1 -1
  447. package/dist/apps/control-plane/core/error-codes.d.ts +39 -0
  448. package/dist/apps/control-plane/core/error-codes.js +39 -0
  449. package/dist/apps/control-plane/core/error-codes.js.map +1 -1
  450. package/dist/apps/control-plane/core/execution-control.d.ts +45 -0
  451. package/dist/apps/control-plane/core/execution-control.js +2 -0
  452. package/dist/apps/control-plane/core/execution-control.js.map +1 -0
  453. package/dist/apps/control-plane/core/feature-resume-phase.d.ts +3 -0
  454. package/dist/apps/control-plane/core/feature-resume-phase.js +88 -0
  455. package/dist/apps/control-plane/core/feature-resume-phase.js.map +1 -0
  456. package/dist/apps/control-plane/core/gate-freshness.d.ts +48 -0
  457. package/dist/apps/control-plane/core/gate-freshness.js +267 -0
  458. package/dist/apps/control-plane/core/gate-freshness.js.map +1 -0
  459. package/dist/apps/control-plane/core/gate-log-extractor.d.ts +22 -0
  460. package/dist/apps/control-plane/core/gate-log-extractor.js +66 -0
  461. package/dist/apps/control-plane/core/gate-log-extractor.js.map +1 -0
  462. package/dist/apps/control-plane/core/gates.d.ts +11 -2
  463. package/dist/apps/control-plane/core/gates.js +67 -3
  464. package/dist/apps/control-plane/core/gates.js.map +1 -1
  465. package/dist/apps/control-plane/core/intake-artifacts.d.ts +109 -0
  466. package/dist/apps/control-plane/core/intake-artifacts.js +143 -0
  467. package/dist/apps/control-plane/core/intake-artifacts.js.map +1 -0
  468. package/dist/apps/control-plane/core/kernel-types.d.ts +8 -0
  469. package/dist/apps/control-plane/core/kernel.d.ts +256 -8
  470. package/dist/apps/control-plane/core/kernel.js +400 -14
  471. package/dist/apps/control-plane/core/kernel.js.map +1 -1
  472. package/dist/apps/control-plane/core/mainline-conflict.d.ts +7 -0
  473. package/dist/apps/control-plane/core/mainline-conflict.js +20 -0
  474. package/dist/apps/control-plane/core/mainline-conflict.js.map +1 -0
  475. package/dist/apps/control-plane/core/merge-repair.d.ts +35 -0
  476. package/dist/apps/control-plane/core/merge-repair.js +99 -0
  477. package/dist/apps/control-plane/core/merge-repair.js.map +1 -0
  478. package/dist/apps/control-plane/core/path-layout.d.ts +10 -0
  479. package/dist/apps/control-plane/core/path-layout.js +32 -2
  480. package/dist/apps/control-plane/core/path-layout.js.map +1 -1
  481. package/dist/apps/control-plane/core/path-rules.js +9 -3
  482. package/dist/apps/control-plane/core/path-rules.js.map +1 -1
  483. package/dist/apps/control-plane/core/plan-submit-recovery.d.ts +22 -0
  484. package/dist/apps/control-plane/core/plan-submit-recovery.js +78 -0
  485. package/dist/apps/control-plane/core/plan-submit-recovery.js.map +1 -0
  486. package/dist/apps/control-plane/core/questions.d.ts +40 -0
  487. package/dist/apps/control-plane/core/questions.js +2 -0
  488. package/dist/apps/control-plane/core/questions.js.map +1 -0
  489. package/dist/apps/control-plane/core/runtime-sessions.d.ts +4 -0
  490. package/dist/apps/control-plane/core/schemas.d.ts +2 -0
  491. package/dist/apps/control-plane/core/schemas.js +31 -1
  492. package/dist/apps/control-plane/core/schemas.js.map +1 -1
  493. package/dist/apps/control-plane/core/tool-caller.d.ts +18 -1
  494. package/dist/apps/control-plane/core/utils/index-normalizer.js +17 -4
  495. package/dist/apps/control-plane/core/utils/index-normalizer.js.map +1 -1
  496. package/dist/apps/control-plane/core/worktree-diff.d.ts +4 -0
  497. package/dist/apps/control-plane/core/worktree-diff.js +52 -0
  498. package/dist/apps/control-plane/core/worktree-diff.js.map +1 -0
  499. package/dist/apps/control-plane/index.d.ts +10 -2
  500. package/dist/apps/control-plane/index.js +9 -2
  501. package/dist/apps/control-plane/index.js.map +1 -1
  502. package/dist/apps/control-plane/interfaces/cli/bootstrap.js +236 -6
  503. package/dist/apps/control-plane/interfaces/cli/bootstrap.js.map +1 -1
  504. package/dist/apps/control-plane/mcp/kernel-tool-executor.js +16 -0
  505. package/dist/apps/control-plane/mcp/kernel-tool-executor.js.map +1 -1
  506. package/dist/apps/control-plane/mcp/tool-runtime.d.ts +5 -0
  507. package/dist/apps/control-plane/mcp/tool-runtime.js +40 -5
  508. package/dist/apps/control-plane/mcp/tool-runtime.js.map +1 -1
  509. package/dist/apps/control-plane/providers/api-worker-provider.d.ts +2 -2
  510. package/dist/apps/control-plane/providers/api-worker-provider.js +40 -9
  511. package/dist/apps/control-plane/providers/api-worker-provider.js.map +1 -1
  512. package/dist/apps/control-plane/providers/cli-worker-provider.d.ts +59 -3
  513. package/dist/apps/control-plane/providers/cli-worker-provider.js +758 -46
  514. package/dist/apps/control-plane/providers/cli-worker-provider.js.map +1 -1
  515. package/dist/apps/control-plane/providers/output-parsers/generic-output-parser.js +91 -1
  516. package/dist/apps/control-plane/providers/output-parsers/generic-output-parser.js.map +1 -1
  517. package/dist/apps/control-plane/providers/output-parsers/types.d.ts +2 -0
  518. package/dist/apps/control-plane/providers/provider-defaults.d.ts +12 -0
  519. package/dist/apps/control-plane/providers/provider-defaults.js +103 -7
  520. package/dist/apps/control-plane/providers/provider-defaults.js.map +1 -1
  521. package/dist/apps/control-plane/providers/providers.d.ts +50 -4
  522. package/dist/apps/control-plane/providers/providers.js +145 -14
  523. package/dist/apps/control-plane/providers/providers.js.map +1 -1
  524. package/dist/apps/control-plane/providers/worker-provider-factory.d.ts +2 -0
  525. package/dist/apps/control-plane/providers/worker-provider-factory.js +8 -1
  526. package/dist/apps/control-plane/providers/worker-provider-factory.js.map +1 -1
  527. package/dist/apps/control-plane/supervisor/artifact-stager.d.ts +5 -0
  528. package/dist/apps/control-plane/supervisor/artifact-stager.js +45 -0
  529. package/dist/apps/control-plane/supervisor/artifact-stager.js.map +1 -0
  530. package/dist/apps/control-plane/supervisor/build-wave-executor.d.ts +24 -1
  531. package/dist/apps/control-plane/supervisor/build-wave-executor.js +362 -150
  532. package/dist/apps/control-plane/supervisor/build-wave-executor.js.map +1 -1
  533. package/dist/apps/control-plane/supervisor/execution-enrollment-service.d.ts +41 -0
  534. package/dist/apps/control-plane/supervisor/execution-enrollment-service.js +311 -0
  535. package/dist/apps/control-plane/supervisor/execution-enrollment-service.js.map +1 -0
  536. package/dist/apps/control-plane/supervisor/organizer-enrollment-scheduler.d.ts +15 -0
  537. package/dist/apps/control-plane/supervisor/organizer-enrollment-scheduler.js +93 -0
  538. package/dist/apps/control-plane/supervisor/organizer-enrollment-scheduler.js.map +1 -0
  539. package/dist/apps/control-plane/supervisor/organizer-sidecar-service.d.ts +44 -0
  540. package/dist/apps/control-plane/supervisor/organizer-sidecar-service.js +311 -0
  541. package/dist/apps/control-plane/supervisor/organizer-sidecar-service.js.map +1 -0
  542. package/dist/apps/control-plane/supervisor/plan-conformance-scorer.js +2 -5
  543. package/dist/apps/control-plane/supervisor/plan-conformance-scorer.js.map +1 -1
  544. package/dist/apps/control-plane/supervisor/planner-phase.d.ts +3 -0
  545. package/dist/apps/control-plane/supervisor/planner-phase.js +70 -0
  546. package/dist/apps/control-plane/supervisor/planner-phase.js.map +1 -0
  547. package/dist/apps/control-plane/supervisor/planning-wave-executor.d.ts +42 -0
  548. package/dist/apps/control-plane/supervisor/planning-wave-executor.js +753 -55
  549. package/dist/apps/control-plane/supervisor/planning-wave-executor.js.map +1 -1
  550. package/dist/apps/control-plane/supervisor/prompt-bundle-loader.js +19 -1
  551. package/dist/apps/control-plane/supervisor/prompt-bundle-loader.js.map +1 -1
  552. package/dist/apps/control-plane/supervisor/qa-wave-executor.d.ts +21 -0
  553. package/dist/apps/control-plane/supervisor/qa-wave-executor.js +287 -156
  554. package/dist/apps/control-plane/supervisor/qa-wave-executor.js.map +1 -1
  555. package/dist/apps/control-plane/supervisor/run-coordinator.d.ts +30 -1
  556. package/dist/apps/control-plane/supervisor/run-coordinator.js +561 -17
  557. package/dist/apps/control-plane/supervisor/run-coordinator.js.map +1 -1
  558. package/dist/apps/control-plane/supervisor/runtime.d.ts +84 -0
  559. package/dist/apps/control-plane/supervisor/runtime.js +393 -3
  560. package/dist/apps/control-plane/supervisor/runtime.js.map +1 -1
  561. package/dist/apps/control-plane/supervisor/session-orchestrator.d.ts +54 -0
  562. package/dist/apps/control-plane/supervisor/session-orchestrator.js +176 -1
  563. package/dist/apps/control-plane/supervisor/session-orchestrator.js.map +1 -1
  564. package/dist/apps/control-plane/supervisor/types.d.ts +142 -1
  565. package/dist/apps/control-plane/supervisor/types.js.map +1 -1
  566. package/dist/apps/control-plane/supervisor/worker-decision-loop.d.ts +68 -2
  567. package/dist/apps/control-plane/supervisor/worker-decision-loop.js +723 -89
  568. package/dist/apps/control-plane/supervisor/worker-decision-loop.js.map +1 -1
  569. package/docs/core/ARCHITECTURE.md +227 -0
  570. package/docs/core/DECISIONS.md +94 -0
  571. package/docs/core/DOMAIN-LOGIC.md +60 -0
  572. package/docs/core/PATTERNS.md +201 -0
  573. package/docs/core/TROUBLESHOOTING.md +347 -0
  574. package/docs/core/intentgraph-dependencies.json +39860 -0
  575. package/docs/core/intentgraph.index.json +46580 -0
  576. package/docs/plans/2026-03-10-gate-failure-targeted-repair-design.md +224 -0
  577. package/docs/plans/2026-03-10-gate-failure-targeted-repair.md +1032 -0
  578. package/docs/superpowers/plans/2026-03-16-provider-cli-config.md +743 -0
  579. package/docs/superpowers/plans/2026-03-23-reconcile-divergence-fix.md +777 -0
  580. package/docs/superpowers/plans/2026-03-28-ordering-agent-implementation.md +1754 -0
  581. package/docs/superpowers/plans/2026-03-29-drop-zone-and-provider-optimization.md +1108 -0
  582. package/docs/superpowers/plans/2026-03-29-merge-target-feature-branch.md +685 -0
  583. package/docs/superpowers/plans/2026-03-29-organizer-sidecar-runtime-loop.md +1289 -0
  584. package/docs/superpowers/specs/2026-03-23-reconcile-divergence-fix-design.md +118 -0
  585. package/docs/superpowers/specs/2026-03-28-ordering-agent-spec-audit-design.md +50 -0
  586. package/docs/superpowers/specs/2026-03-29-drop-zone-and-provider-optimization-design.md +254 -0
  587. package/docs/superpowers/specs/2026-03-29-merge-target-feature-branch-design.md +152 -0
  588. package/docs/superpowers/specs/2026-03-29-organizer-sidecar-runtime-loop-design.md +225 -0
  589. package/package.json +3 -2
  590. package/packages/web-dashboard/package.json +2 -1
  591. package/packages/web-dashboard/src/app/analytics/page.tsx +36 -2
  592. package/packages/web-dashboard/src/app/api/actions/route.ts +274 -63
  593. package/packages/web-dashboard/src/app/api/actions/status/route.ts +35 -0
  594. package/packages/web-dashboard/src/app/api/analytics/provider/route.ts +18 -0
  595. package/packages/web-dashboard/src/app/api/collisions/approve/route.ts +58 -0
  596. package/packages/web-dashboard/src/app/api/features/[id]/checkpoint-diff/route.ts +36 -0
  597. package/packages/web-dashboard/src/app/api/features/[id]/checkpoints/route.ts +29 -0
  598. package/packages/web-dashboard/src/app/api/features/[id]/conflicts/abort/route.ts +29 -0
  599. package/packages/web-dashboard/src/app/api/features/[id]/conflicts/files/route.ts +30 -0
  600. package/packages/web-dashboard/src/app/api/features/[id]/conflicts/resolve/route.ts +51 -0
  601. package/packages/web-dashboard/src/app/api/features/[id]/conflicts/route.ts +75 -0
  602. package/packages/web-dashboard/src/app/api/features/[id]/diff/route.ts +16 -2
  603. package/packages/web-dashboard/src/app/api/features/[id]/files/route.ts +26 -0
  604. package/packages/web-dashboard/src/app/api/features/[id]/gate-history/route.ts +27 -0
  605. package/packages/web-dashboard/src/app/api/features/[id]/genealogy/route.ts +26 -0
  606. package/packages/web-dashboard/src/app/api/features/[id]/history/run/[runId]/route.ts +20 -0
  607. package/packages/web-dashboard/src/app/api/features/[id]/history/runs/route.ts +34 -0
  608. package/packages/web-dashboard/src/app/api/features/[id]/intake-workspace/route.ts +20 -0
  609. package/packages/web-dashboard/src/app/api/features/[id]/live-output/route.ts +74 -0
  610. package/packages/web-dashboard/src/app/api/features/[id]/plan/amend/route.ts +21 -0
  611. package/packages/web-dashboard/src/app/api/features/[id]/plan-progress/route.ts +20 -0
  612. package/packages/web-dashboard/src/app/api/features/[id]/planner-artifacts/[artifact]/route.ts +78 -0
  613. package/packages/web-dashboard/src/app/api/features/[id]/planner-lifecycle/route.ts +20 -0
  614. package/packages/web-dashboard/src/app/api/features/[id]/planning-workspace/route.ts +20 -0
  615. package/packages/web-dashboard/src/app/api/features/[id]/questions/[questionId]/answer/route.ts +27 -0
  616. package/packages/web-dashboard/src/app/api/features/[id]/questions/route.ts +18 -0
  617. package/packages/web-dashboard/src/app/api/features/[id]/review/route.ts +14 -7
  618. package/packages/web-dashboard/src/app/api/features/[id]/route.ts +57 -2
  619. package/packages/web-dashboard/src/app/api/features/[id]/spec/route.ts +30 -0
  620. package/packages/web-dashboard/src/app/api/features/[id]/triage/route.ts +83 -0
  621. package/packages/web-dashboard/src/app/api/features/[id]/worker-events/route.ts +40 -0
  622. package/packages/web-dashboard/src/app/api/launch/preview/route.ts +86 -0
  623. package/packages/web-dashboard/src/app/api/launch/submit/route.ts +180 -0
  624. package/packages/web-dashboard/src/app/api/mainline/status/route.ts +74 -0
  625. package/packages/web-dashboard/src/app/api/merge-queue/route.ts +13 -0
  626. package/packages/web-dashboard/src/app/api/policy/budget/route.ts +14 -0
  627. package/packages/web-dashboard/src/app/api/projects/route.ts +11 -7
  628. package/packages/web-dashboard/src/app/api/reconciler/queue/route.ts +47 -0
  629. package/packages/web-dashboard/src/app/api/run/route.ts +26 -2
  630. package/packages/web-dashboard/src/app/api/runtime/events/route.ts +227 -0
  631. package/packages/web-dashboard/src/app/api/runtime/operations/route.ts +269 -0
  632. package/packages/web-dashboard/src/app/api/runtime/questions/route.ts +11 -0
  633. package/packages/web-dashboard/src/app/api/runtime/runs/route.ts +80 -0
  634. package/packages/web-dashboard/src/app/api/status/route.ts +4 -2
  635. package/packages/web-dashboard/src/app/feature/[id]/page.tsx +32 -42
  636. package/packages/web-dashboard/src/app/globals.css +34 -3
  637. package/packages/web-dashboard/src/app/launch/page.tsx +357 -0
  638. package/packages/web-dashboard/src/app/layout.tsx +23 -1
  639. package/packages/web-dashboard/src/app/page.tsx +263 -272
  640. package/packages/web-dashboard/src/components/dashboard/attention-strip.tsx +52 -0
  641. package/packages/web-dashboard/src/components/dashboard/collision-approval-drawer.tsx +185 -0
  642. package/packages/web-dashboard/src/components/dashboard/command-center-header.tsx +102 -0
  643. package/packages/web-dashboard/src/components/dashboard/mainline-status-banner.tsx +84 -0
  644. package/packages/web-dashboard/src/components/dashboard/merged-archive.tsx +36 -0
  645. package/packages/web-dashboard/src/components/dashboard/prioritized-queues.tsx +98 -0
  646. package/packages/web-dashboard/src/components/dashboard/reconciler-queue-card.tsx +115 -0
  647. package/packages/web-dashboard/src/components/dashboard/secondary-diagnostics-rail.tsx +48 -0
  648. package/packages/web-dashboard/src/components/dashboard/task-filter-bar.tsx +74 -0
  649. package/packages/web-dashboard/src/components/dashboard/triage-drawer.tsx +455 -0
  650. package/packages/web-dashboard/src/components/diff-viewer.tsx +19 -3
  651. package/packages/web-dashboard/src/components/evidence-viewer.tsx +65 -51
  652. package/packages/web-dashboard/src/components/feature-card.tsx +90 -7
  653. package/packages/web-dashboard/src/components/feature-cost-panel.tsx +112 -11
  654. package/packages/web-dashboard/src/components/feature-list-view.tsx +25 -4
  655. package/packages/web-dashboard/src/components/features/runtime-inspector/EventsTimelineView.tsx +260 -0
  656. package/packages/web-dashboard/src/components/features/runtime-inspector/OperationsListView.tsx +172 -0
  657. package/packages/web-dashboard/src/components/features/runtime-inspector/RuntimeInspectorPanel.tsx +896 -0
  658. package/packages/web-dashboard/src/components/filter-bar.tsx +7 -39
  659. package/packages/web-dashboard/src/components/focus/ActionableRiskList.tsx +46 -0
  660. package/packages/web-dashboard/src/components/focus/AgentRolePerformanceCard.tsx +200 -0
  661. package/packages/web-dashboard/src/components/focus/BlockedGuidanceBanner.tsx +149 -0
  662. package/packages/web-dashboard/src/components/focus/CheckpointInspector.tsx +123 -0
  663. package/packages/web-dashboard/src/components/focus/CheckpointRail.tsx +118 -0
  664. package/packages/web-dashboard/src/components/focus/CheckpointScrubber.tsx +249 -0
  665. package/packages/web-dashboard/src/components/focus/CollisionApprovalBanner.tsx +192 -0
  666. package/packages/web-dashboard/src/components/focus/CollisionRadar.tsx +136 -0
  667. package/packages/web-dashboard/src/components/focus/ConflictStatusCard.tsx +52 -0
  668. package/packages/web-dashboard/src/components/focus/ContextSidebar.tsx +108 -0
  669. package/packages/web-dashboard/src/components/focus/DiagnosisPanel.tsx +68 -0
  670. package/packages/web-dashboard/src/components/focus/FeatureDecisionBanner.tsx +68 -0
  671. package/packages/web-dashboard/src/components/focus/FeatureQuestionAnswerPanel.tsx +167 -0
  672. package/packages/web-dashboard/src/components/focus/FocusHeader.tsx +54 -0
  673. package/packages/web-dashboard/src/components/focus/FocusLayout.tsx +283 -0
  674. package/packages/web-dashboard/src/components/focus/GateFlakinessSummary.tsx +144 -0
  675. package/packages/web-dashboard/src/components/focus/GenealogyTree.tsx +34 -0
  676. package/packages/web-dashboard/src/components/focus/HeroBlock.tsx +67 -0
  677. package/packages/web-dashboard/src/components/focus/LiveAgentConsole.tsx +277 -0
  678. package/packages/web-dashboard/src/components/focus/MergeQueueCard.tsx +78 -0
  679. package/packages/web-dashboard/src/components/focus/OperationalSummaryCard.tsx +227 -0
  680. package/packages/web-dashboard/src/components/focus/PinnedActions.tsx +96 -0
  681. package/packages/web-dashboard/src/components/focus/PlanAmendmentPanel.tsx +250 -0
  682. package/packages/web-dashboard/src/components/focus/PlanProgressPanel.tsx +133 -0
  683. package/packages/web-dashboard/src/components/focus/PlannerArtifactViewer.tsx +158 -0
  684. package/packages/web-dashboard/src/components/focus/PlannerLifecycleHeader.tsx +141 -0
  685. package/packages/web-dashboard/src/components/focus/ProgressSnapshotCard.tsx +113 -0
  686. package/packages/web-dashboard/src/components/focus/RecentMaterialChanges.tsx +69 -0
  687. package/packages/web-dashboard/src/components/focus/RoleLogViewer.tsx +436 -0
  688. package/packages/web-dashboard/src/components/focus/RunHistoryBrowser.tsx +62 -0
  689. package/packages/web-dashboard/src/components/focus/SpecViewer.tsx +172 -0
  690. package/packages/web-dashboard/src/components/focus/TabBar.tsx +33 -0
  691. package/packages/web-dashboard/src/components/focus/UsageBurnChart.tsx +212 -0
  692. package/packages/web-dashboard/src/components/focus/VerificationSummaryCard.tsx +122 -0
  693. package/packages/web-dashboard/src/components/focus/tabs/ChangesTab.tsx +325 -0
  694. package/packages/web-dashboard/src/components/focus/tabs/ConflictsTab.tsx +395 -0
  695. package/packages/web-dashboard/src/components/focus/tabs/GatesQaTab.tsx +38 -0
  696. package/packages/web-dashboard/src/components/focus/tabs/HistoryTab.tsx +213 -0
  697. package/packages/web-dashboard/src/components/focus/tabs/IntakeTab.tsx +429 -0
  698. package/packages/web-dashboard/src/components/focus/tabs/OverviewTab.tsx +217 -0
  699. package/packages/web-dashboard/src/components/focus/tabs/PlanningTab.tsx +390 -0
  700. package/packages/web-dashboard/src/components/focus/tabs/ReviewTab.tsx +497 -0
  701. package/packages/web-dashboard/src/components/focus/tabs/RuntimeTab.tsx +213 -0
  702. package/packages/web-dashboard/src/components/focus/tabs/TranscriptTab.tsx +315 -0
  703. package/packages/web-dashboard/src/components/gate-results.tsx +2 -2
  704. package/packages/web-dashboard/src/components/human-input-panel.tsx +33 -57
  705. package/packages/web-dashboard/src/components/kanban-board.tsx +4 -0
  706. package/packages/web-dashboard/src/components/launch/launch-draft-card.tsx +131 -0
  707. package/packages/web-dashboard/src/components/plan-viewer.tsx +147 -69
  708. package/packages/web-dashboard/src/components/quick-launch-panel.tsx +20 -47
  709. package/packages/web-dashboard/src/components/summary-bar.tsx +30 -76
  710. package/packages/web-dashboard/src/lib/aop-client.ts +2484 -36
  711. package/packages/web-dashboard/src/lib/blocked-state-guidance.ts +475 -0
  712. package/packages/web-dashboard/src/lib/collision-radar.ts +136 -0
  713. package/packages/web-dashboard/src/lib/dashboard-action-states.ts +204 -0
  714. package/packages/web-dashboard/src/lib/dashboard-runtime-client.ts +439 -0
  715. package/packages/web-dashboard/src/lib/dashboard-utils.ts +179 -18
  716. package/packages/web-dashboard/src/lib/drop-zone-utils.ts +92 -0
  717. package/packages/web-dashboard/src/lib/focus-detail-derivations.ts +958 -0
  718. package/packages/web-dashboard/src/lib/focus-view.ts +300 -0
  719. package/packages/web-dashboard/src/lib/health-diagnosis.ts +356 -0
  720. package/packages/web-dashboard/src/lib/launch-contracts.ts +77 -0
  721. package/packages/web-dashboard/src/lib/launch-markdown.ts +107 -0
  722. package/packages/web-dashboard/src/lib/launch-page-preview.ts +89 -0
  723. package/packages/web-dashboard/src/lib/live-feed.ts +1 -1
  724. package/packages/web-dashboard/src/lib/multi-project-config.ts +33 -0
  725. package/packages/web-dashboard/src/lib/orchestrator-tools.ts +845 -59
  726. package/packages/web-dashboard/src/lib/planner-workspace.ts +1285 -0
  727. package/packages/web-dashboard/src/lib/review-contracts.ts +5 -3
  728. package/packages/web-dashboard/src/lib/runtime-files.ts +285 -0
  729. package/packages/web-dashboard/src/lib/tool-catalog.ts +51 -0
  730. package/packages/web-dashboard/src/lib/types.ts +731 -3
  731. package/packages/web-dashboard/src/lib/usage-burn.ts +175 -0
  732. package/packages/web-dashboard/src/lib/worktree-diff.ts +128 -0
  733. package/packages/web-dashboard/src/styles/dashboard.module.css +1742 -459
  734. package/packages/web-dashboard/test/api/actions/route.spec.ts +675 -0
  735. package/packages/web-dashboard/test/api/features/diff.route.spec.ts +57 -0
  736. package/packages/web-dashboard/test/api/features/feature.route.spec.ts +99 -0
  737. package/packages/web-dashboard/test/api/features/live-output.route.spec.ts +123 -0
  738. package/packages/web-dashboard/test/api/features/plan-amend.route.spec.ts +95 -0
  739. package/packages/web-dashboard/test/api/features/planner-workspaces.route.spec.ts +162 -0
  740. package/packages/web-dashboard/test/api/features/question-answer.route.spec.ts +99 -0
  741. package/packages/web-dashboard/test/api/features/triage.route.spec.ts +195 -0
  742. package/packages/web-dashboard/test/api/launch/preview.route.spec.ts +149 -0
  743. package/packages/web-dashboard/test/api/launch/submit.route.spec.ts +382 -0
  744. package/packages/web-dashboard/test/api/runtime/events/route.spec.ts +164 -0
  745. package/packages/web-dashboard/test/api/runtime/operations/route.spec.ts +156 -0
  746. package/packages/web-dashboard/test/api/runtime/runs/route.spec.ts +112 -0
  747. package/packages/web-dashboard/test/components/changes-tab.spec.tsx +76 -0
  748. package/packages/web-dashboard/test/components/command-center-root.spec.tsx +87 -0
  749. package/packages/web-dashboard/test/components/diagnosis-panel.spec.tsx +59 -0
  750. package/packages/web-dashboard/test/components/feature-card.spec.tsx +45 -0
  751. package/packages/web-dashboard/test/components/focus-layout.spec.tsx +299 -0
  752. package/packages/web-dashboard/test/components/gate-results.spec.tsx +39 -0
  753. package/packages/web-dashboard/test/components/gates-qa-tab.spec.tsx +118 -0
  754. package/packages/web-dashboard/test/components/human-input-panel.spec.tsx +54 -0
  755. package/packages/web-dashboard/test/components/intake-tab.spec.tsx +210 -0
  756. package/packages/web-dashboard/test/components/kanban-board.spec.tsx +35 -0
  757. package/packages/web-dashboard/test/components/launch-draft-card.spec.tsx +54 -0
  758. package/packages/web-dashboard/test/components/launch-page.spec.tsx +79 -0
  759. package/packages/web-dashboard/test/components/overview-tab.spec.tsx +236 -0
  760. package/packages/web-dashboard/test/components/planning-tab.spec.tsx +202 -0
  761. package/packages/web-dashboard/test/components/review-tab.spec.tsx +169 -0
  762. package/packages/web-dashboard/test/components/role-log-viewer.spec.ts +42 -0
  763. package/packages/web-dashboard/test/components/runtime-inspector.spec.tsx +22 -0
  764. package/packages/web-dashboard/test/components/runtime-tab.spec.tsx +133 -0
  765. package/packages/web-dashboard/test/components/transcript-tab.spec.tsx +46 -0
  766. package/packages/web-dashboard/test/components/triage-drawer.spec.tsx +159 -0
  767. package/packages/web-dashboard/test/lib/aop-client.spec.ts +235 -0
  768. package/packages/web-dashboard/test/lib/dashboard-runtime-client.spec.ts +144 -0
  769. package/packages/web-dashboard/test/lib/focus-detail-derivations.spec.ts +314 -0
  770. package/packages/web-dashboard/test/lib/focus-view.spec.ts +248 -0
  771. package/packages/web-dashboard/test/lib/health-diagnosis.spec.ts +277 -0
  772. package/packages/web-dashboard/test/lib/launch-markdown.spec.ts +36 -0
  773. package/packages/web-dashboard/test/lib/multi-project-config.spec.ts +54 -0
  774. package/packages/web-dashboard/test/lib/orchestrator-tools.spec.ts +352 -0
  775. package/packages/web-dashboard/test/lib/planner-workspace.spec.ts +289 -0
  776. package/packages/web-dashboard/test/lib/worktree-diff.spec.ts +119 -0
  777. package/packages/web-dashboard/vitest.config.ts +2 -0
  778. package/spec-files/completed/agentic_orchestrator_add_feature_to_active_execution_spec.md +557 -0
  779. package/spec-files/completed/agentic_orchestrator_dashboard_command_center_redesign_spec.md +1147 -0
  780. package/spec-files/completed/agentic_orchestrator_execution_mode_spec.md +18 -16
  781. package/spec-files/completed/agentic_orchestrator_feature_focus_view_track_a_spec.md +672 -0
  782. package/spec-files/completed/agentic_orchestrator_feature_focus_view_track_b_spec.md +794 -0
  783. package/spec-files/completed/agentic_orchestrator_feature_focus_view_track_c_decision_centric_remediation_spec.md +1037 -0
  784. package/spec-files/completed/agentic_orchestrator_feature_focus_view_ux_redesign_spec.md +1432 -0
  785. package/spec-files/completed/agentic_orchestrator_focus_plan_tab_intake_planning_workspace_spec.md +921 -0
  786. package/spec-files/completed/agentic_orchestrator_intentional_collision_override_spec.md +584 -0
  787. package/spec-files/completed/agentic_orchestrator_interactive_planning_intake_and_requirements_verification_spec.md +1185 -0
  788. package/spec-files/completed/agentic_orchestrator_reactive_execution_enrollment_spec.md +864 -0
  789. package/spec-files/{outstanding → completed}/agentic_orchestrator_runtime_inspection_spec.md +92 -19
  790. package/spec-files/completed/agentic_orchestrator_scope_aware_run_lease_spec.md +408 -0
  791. package/spec-files/completed/git-reconciliation-engine.md +827 -0
  792. package/spec-files/outstanding/agentic_orchestrator_dashboard_quick_launch_and_control_surface_spec.md +331 -0
  793. package/spec-files/outstanding/agentic_orchestrator_enterprise_governance_dashboard_spec.md +16 -6
  794. package/spec-files/outstanding/agentic_orchestrator_evidence_integrity_doctor_spec.md +60 -9
  795. package/spec-files/outstanding/agentic_orchestrator_focus_plan_tab_execution_contract_workspace_spec.md +616 -0
  796. package/spec-files/outstanding/agentic_orchestrator_headless_standby_dashboard_runtime_spec.md +310 -0
  797. package/spec-files/outstanding/agentic_orchestrator_human_input_interaction_protocol_spec.md +175 -72
  798. package/spec-files/outstanding/agentic_orchestrator_interactive_rename_cleanup_spec.md +197 -0
  799. package/spec-files/outstanding/agentic_orchestrator_interactive_resume_and_reconciliation_disposition_spec.md +412 -0
  800. package/spec-files/outstanding/agentic_orchestrator_knowledge_canary_spec.md +166 -137
  801. package/spec-files/outstanding/agentic_orchestrator_observability_replay_spec.md +3 -3
  802. package/spec-files/outstanding/agentic_orchestrator_phase_specific_agent_profiles_and_token_telemetry_spec.md +303 -0
  803. package/spec-files/outstanding/agentic_orchestrator_planning_review_quality_spec.md +18 -5
  804. package/spec-files/outstanding/agentic_orchestrator_policy_stratification_spec.md +225 -0
  805. package/spec-files/outstanding/agentic_orchestrator_quality_adoption_execution_spec.md +77 -50
  806. package/spec-files/outstanding/agentic_orchestrator_ready_to_merge_branch_handoff_spec.md +724 -0
  807. package/spec-files/outstanding/agentic_orchestrator_remove_deterministic_mode_spec.md +263 -0
  808. package/spec-files/outstanding/agentic_orchestrator_request_more_context_and_dashboard_human_input_spec.md +456 -0
  809. package/spec-files/outstanding/agentic_orchestrator_spec_coverage_and_reconciliation_enforcement_spec.md +1411 -0
  810. package/spec-files/outstanding/agentic_orchestrator_spec_ordering_agent_spec.md +370 -0
  811. package/spec-files/outstanding/shadow_workspace_implementation_spec.md +1 -1
  812. package/spec-files/progress.md +2026 -120
  813. package/specs/001-runtime-inspection/checklists/requirements.md +35 -0
  814. package/specs/001-runtime-inspection/design.md +338 -0
  815. package/specs/001-runtime-inspection/spec.md +95 -0
  816. package/specs/002-scope-aware-lease/checklists/requirements.md +35 -0
  817. package/specs/002-scope-aware-lease/contracts/lease-registry.schema.json +101 -0
  818. package/specs/002-scope-aware-lease/data-model.md +236 -0
  819. package/specs/002-scope-aware-lease/plan.md +766 -0
  820. package/specs/002-scope-aware-lease/quickstart.md +150 -0
  821. package/specs/002-scope-aware-lease/research.md +135 -0
  822. package/specs/002-scope-aware-lease/spec.md +128 -0
  823. package/specs/002-scope-aware-lease/tasks.md +767 -0
  824. package/tsconfig.json +1 -1
  825. package/vitest.config.ts +28 -0
  826. package/ARCHITECTURE_ADHERENCE_ANALYSIS.md +0 -871
  827. package/packages/web-dashboard/next-env.d.ts +0 -6
  828. package/packages/web-dashboard/src/components/detail-panel.tsx +0 -1124
  829. package/packages/web-dashboard/src/components/review-workspace.tsx +0 -1162
  830. /package/spec-files/{outstanding → completed}/agentic_orchestrator_artifact_database_publishing_spec.md +0 -0
  831. /package/spec-files/{outstanding → completed}/agentic_orchestrator_cli_shell_tab_completion_spec.md +0 -0
  832. /package/spec-files/{outstanding → completed}/agentic_orchestrator_dashboard_diff_and_agent_console_spec.md +0 -0
  833. /package/spec-files/{outstanding → completed}/agentic_orchestrator_performance_improvements_spec.md +0 -0
  834. /package/spec-files/{outstanding → completed}/agentic_orchestrator_persistent_worker_runtime_spec.md +0 -0
  835. /package/spec-files/{outstanding → completed}/agentic_orchestrator_provider_auth_bootstrap_spec.md +0 -0
  836. /package/spec-files/{outstanding → completed}/agentic_orchestrator_real_worker_provider_execution_spec.md +0 -0
@@ -1,7 +1,15 @@
1
- import { TOOLS } from '../core/constants.js';
1
+ import path from 'node:path';
2
+ import { STATUS, TOOLS } from '../core/constants.js';
2
3
  import { ERROR_CODES } from '../core/error-codes.js';
3
- import type { ExecutionMode, WorkerProvider, WorkerRunInput } from '../providers/providers.js';
4
+ import type {
5
+ ExecutionMode,
6
+ ProviderSelection,
7
+ WorkerProvider,
8
+ WorkerRunInput,
9
+ } from '../providers/providers.js';
10
+ import type { NormalizedUsageRecord } from '../application/usage-types.js';
4
11
  import type { RuntimeRole, SupervisorToolCaller } from './types.js';
12
+ import { resolvePlannerPhaseFromContext } from './planner-phase.js';
5
13
  import type { ActivityMonitorService } from '../application/services/activity-monitor-service.js';
6
14
  import { appendWorkerRuntimeEvent } from './worker-event-journal.js';
7
15
  import type {
@@ -22,6 +30,7 @@ const PLAN_TOP_LEVEL_KEYS = new Set([
22
30
  'files',
23
31
  'contracts',
24
32
  'acceptance_criteria',
33
+ 'plan_trace',
25
34
  'gate_targets',
26
35
  'risk',
27
36
  'revision_of',
@@ -29,28 +38,71 @@ const PLAN_TOP_LEVEL_KEYS = new Set([
29
38
  'verification_overrides',
30
39
  ]);
31
40
 
41
+ /** Input payload for a single worker decision turn. */
32
42
  export interface WorkerDecisionInput {
43
+ /** Agent role executing this turn (planner, builder, or qa). */
33
44
  role: RuntimeRole;
45
+ /** Target feature identifier. */
34
46
  featureId: string;
47
+ /** Aggregated context bundle passed to the worker provider. */
35
48
  contextBundle: AnyRecord;
49
+ /** Natural-language instructions for the worker. */
36
50
  instructions: string;
51
+ /** Tool results from a previous turn, used for context-refresh retries. */
37
52
  lastToolResults?: AnyRecord[];
38
53
  }
39
54
 
55
+ /** Outcome of a single worker decision turn, summarising all actions taken and diagnostics. */
40
56
  export interface WorkerDecisionResult {
57
+ /** Whether a plan was submitted during this turn. */
41
58
  planSubmission: boolean;
59
+ /** Whether an intake manifest was submitted during this turn. */
60
+ intakeSubmission: boolean;
61
+ /** Whether at least one code patch was applied. */
42
62
  patchApplied: boolean;
63
+ /** Whether a log note was recorded. */
43
64
  noteLogged: boolean;
65
+ /** Whether a structured request (e.g. context refresh) was handled. */
44
66
  requestHandled: boolean;
67
+ /** Whether the worker emitted a human-input question. */
68
+ questionRequested: boolean;
69
+ /** Whether the worker stalled requesting context without making progress. */
70
+ contextStall: boolean;
71
+ /** Number of context-refresh requests seen across outputs. */
72
+ contextRequestCount: number;
73
+ /** ISO timestamp of the most recent context-refresh request, if any. */
74
+ lastContextRequestAt: string | null;
75
+ /** Role that issued the most recent context-refresh request. */
76
+ lastContextRequestRole: RuntimeRole | null;
77
+ /** Whether the provider output failed validation. */
45
78
  invalidOutput: boolean;
79
+ /** Structured error code if an error occurred, otherwise null. */
80
+ errorCode?: string | null;
81
+ /** True when the turn produced no forward progress. */
46
82
  noProgress: boolean;
83
+ /** Classified output types emitted by the worker (e.g. PATCH, PLAN_SUBMISSION, NOTE). */
47
84
  outputTypes: string[];
85
+ /** Raw output records returned by the provider. */
48
86
  rawOutputs: AnyRecord[];
87
+ /** Priority-ordered list of output types processed. */
49
88
  priorityOrder: string[];
89
+ /** Accumulated tool-call results from the turn. */
50
90
  toolResults: AnyRecord[];
91
+ /** Outcome classification for interactive-mode executions. */
92
+ interactiveOutcome?:
93
+ | 'progress_applied'
94
+ | 'no_new_work'
95
+ | 'checkpoint_invalid'
96
+ | 'provider_output_invalid'
97
+ | null;
98
+ /** Worktree checkpoint captured at the end of an interactive turn. */
99
+ checkpoint?: CheckpointRecord | null;
100
+ usageRecords?: NormalizedUsageRecord[];
51
101
  }
52
102
 
103
+ /** Strategy interface for executing a single worker decision turn. */
53
104
  export interface WorkerDecisionRunner {
105
+ /** Run one decision turn for the given input and return the aggregated result. */
54
106
  execute(input: WorkerDecisionInput): Promise<WorkerDecisionResult>;
55
107
  }
56
108
 
@@ -58,6 +110,24 @@ function asRecord(value: unknown): AnyRecord {
58
110
  return value && typeof value === 'object' ? (value as AnyRecord) : {};
59
111
  }
60
112
 
113
+ function extractNonErrorMessage(value: unknown): string | null {
114
+ if (!value || typeof value !== 'object') {
115
+ return typeof value === 'string' ? value : null;
116
+ }
117
+ const obj = value as AnyRecord;
118
+ const normalized = obj['normalizedResponse'] as AnyRecord | undefined;
119
+ if (normalized?.['error'] && typeof normalized['error'] === 'object') {
120
+ const err = normalized['error'] as AnyRecord;
121
+ if (typeof err['message'] === 'string') {
122
+ return err['message'];
123
+ }
124
+ }
125
+ if (typeof obj['message'] === 'string') {
126
+ return obj['message'];
127
+ }
128
+ return null;
129
+ }
130
+
61
131
  function asNonEmptyString(value: unknown): string | null {
62
132
  if (typeof value !== 'string') {
63
133
  return null;
@@ -106,21 +176,43 @@ function asOutputs(result: Record<string, unknown>): AnyRecord[] {
106
176
  return [asRecord(result)];
107
177
  }
108
178
 
179
+ function readInteractiveFallbackReason(result: Record<string, unknown>): string | null {
180
+ return asNonEmptyString(asRecord(result.provider_meta).parse_fallback_reason);
181
+ }
182
+
183
+ function isBlockingAskUserInputOutput(output: AnyRecord): boolean {
184
+ const request = asRecord(output.request ?? output);
185
+ const action = asNonEmptyString(request.action ?? request.request_type)?.toLowerCase();
186
+ const prompt = asNonEmptyString(request.prompt);
187
+ return action === 'ask_user_input' && prompt !== null;
188
+ }
189
+
109
190
  function makeEmptyResult(): WorkerDecisionResult {
110
191
  return {
111
192
  planSubmission: false,
193
+ intakeSubmission: false,
112
194
  patchApplied: false,
113
195
  noteLogged: false,
114
196
  requestHandled: false,
197
+ questionRequested: false,
198
+ contextStall: false,
199
+ contextRequestCount: 0,
200
+ lastContextRequestAt: null,
201
+ lastContextRequestRole: null,
115
202
  invalidOutput: false,
203
+ errorCode: null,
116
204
  noProgress: false,
117
205
  outputTypes: [],
118
206
  rawOutputs: [],
119
207
  priorityOrder: [],
120
208
  toolResults: [],
209
+ interactiveOutcome: null,
210
+ checkpoint: null,
211
+ usageRecords: [],
121
212
  };
122
213
  }
123
214
 
215
+ /** No-op decision runner that always returns an empty result with no progress. */
124
216
  export const NOOP_WORKER_DECISION_RUNNER: WorkerDecisionRunner = {
125
217
  execute: () => Promise.resolve(makeEmptyResult()),
126
218
  };
@@ -132,6 +224,10 @@ interface WorkerDecisionLoopDependencies {
132
224
  repoRoot?: string;
133
225
  runId?: string | (() => string);
134
226
  resolveExecutionMode?: (featureId: string, role: RuntimeRole) => Promise<ExecutionMode>;
227
+ resolveRuntimeSelection?: (
228
+ featureId: string,
229
+ role: RuntimeRole,
230
+ ) => ProviderSelection | Promise<ProviderSelection>;
135
231
  resolveInteractiveConfig?: () => InteractiveExecutionConfig;
136
232
  watchdog?: WorktreeWatchdogService;
137
233
  checkpointService?: CheckpointService;
@@ -141,11 +237,192 @@ interface WorkerDecisionLoopDependencies {
141
237
 
142
238
  interface InteractiveRunSummary {
143
239
  workerOutput: Record<string, unknown>;
144
- finalCheckpoint: CheckpointRecord;
240
+ finalCheckpoint: CheckpointRecord | null;
145
241
  changedFiles: string[];
242
+ hasNetNewWorktreeChanges: boolean;
146
243
  checkpointInvalid: boolean;
244
+ fallbackReason: string | null;
245
+ }
246
+
247
+ interface PlannerExecutionState {
248
+ currentPlanVersion: number | null;
249
+ planMutationApplied: boolean;
147
250
  }
148
251
 
252
+ interface WorkerRunResult {
253
+ workerOutput: Record<string, unknown>;
254
+ interactiveSummary: InteractiveRunSummary | null;
255
+ executionMode: ExecutionMode;
256
+ runtimeSelection: ProviderSelection;
257
+ usage: NormalizedUsageRecord | null;
258
+ }
259
+
260
+ interface RequestRoutingResult {
261
+ contextRefreshRequested: boolean;
262
+ refreshedContext: AnyRecord | null;
263
+ }
264
+
265
+ interface IntakeClarificationAmbiguity {
266
+ id: string;
267
+ summary: string;
268
+ obligationIds: string[];
269
+ }
270
+
271
+ interface IntakeClarificationAnswer {
272
+ questionId: string;
273
+ ambiguityIds: string[];
274
+ answer: string;
275
+ answeredAt: string | null;
276
+ }
277
+
278
+ interface ToolFailureDetails {
279
+ code: string | null;
280
+ message: string | null;
281
+ details: AnyRecord;
282
+ }
283
+
284
+ function normalizeList(values: string[]): string[] {
285
+ return Array.from(new Set(values.map((item) => item.trim()).filter((item) => item.length > 0)));
286
+ }
287
+
288
+ function readToolFailureDetails(error: unknown): ToolFailureDetails | null {
289
+ if (!error || typeof error !== 'object') {
290
+ return null;
291
+ }
292
+
293
+ const direct = asRecord((error as { error?: unknown }).error);
294
+ const normalized = asRecord(
295
+ asRecord((error as { normalizedResponse?: unknown }).normalizedResponse).error,
296
+ );
297
+ const payload = Object.keys(normalized).length > 0 ? normalized : direct;
298
+ if (Object.keys(payload).length === 0) {
299
+ return null;
300
+ }
301
+
302
+ return {
303
+ code: asNonEmptyString(payload.code),
304
+ message: asNonEmptyString(payload.message),
305
+ details: asRecord(payload.details),
306
+ };
307
+ }
308
+
309
+ function readAllIntakeAmbiguities(contextBundle: AnyRecord): IntakeClarificationAmbiguity[] {
310
+ const intake = asRecord(contextBundle.intake);
311
+ const review = asRecord(intake.review);
312
+ const ambiguities = Array.isArray(review.ambiguities) ? review.ambiguities : [];
313
+ const results: IntakeClarificationAmbiguity[] = [];
314
+ for (const item of ambiguities) {
315
+ const record = asRecord(item);
316
+ const id = asNonEmptyString(record.id);
317
+ const summary = asNonEmptyString(record.summary);
318
+ if (!id || !summary) {
319
+ continue;
320
+ }
321
+ results.push({
322
+ id,
323
+ summary,
324
+ obligationIds: asStringArray(record.obligation_ids),
325
+ });
326
+ }
327
+ return results;
328
+ }
329
+
330
+ function readOpenIntakeAmbiguities(contextBundle: AnyRecord): IntakeClarificationAmbiguity[] {
331
+ const intake = asRecord(contextBundle.intake);
332
+ const review = asRecord(intake.review);
333
+ const openIds = new Set(
334
+ (Array.isArray(review.ambiguities) ? review.ambiguities : [])
335
+ .map((item) => asRecord(item))
336
+ .filter((item) => asNonEmptyString(item.status) === 'open')
337
+ .map((item) => asNonEmptyString(item.id))
338
+ .filter((item): item is string => item !== null),
339
+ );
340
+ return readAllIntakeAmbiguities(contextBundle).filter((item) => openIds.has(item.id));
341
+ }
342
+
343
+ function readIntakeAmbiguitiesForRecovery(
344
+ contextBundle: AnyRecord,
345
+ ambiguityIds: string[],
346
+ ): IntakeClarificationAmbiguity[] {
347
+ const normalizedIds = normalizeList(ambiguityIds);
348
+ if (normalizedIds.length === 0) {
349
+ return readOpenIntakeAmbiguities(contextBundle);
350
+ }
351
+
352
+ const byId = new Map(readAllIntakeAmbiguities(contextBundle).map((item) => [item.id, item]));
353
+ return normalizedIds.map((ambiguityId) => {
354
+ const existing = byId.get(ambiguityId);
355
+ if (existing) {
356
+ return existing;
357
+ }
358
+ return {
359
+ id: ambiguityId,
360
+ summary: 'Clarify this ambiguity before verifying the intake manifest.',
361
+ obligationIds: [],
362
+ };
363
+ });
364
+ }
365
+
366
+ function hasOpenIntakeQuestion(contextBundle: AnyRecord): boolean {
367
+ const humanInput = asRecord(contextBundle.human_input);
368
+ const openQuestions = Array.isArray(humanInput.open_questions) ? humanInput.open_questions : [];
369
+ return openQuestions.length > 0;
370
+ }
371
+
372
+ function readAnsweredIntakeClarifications(contextBundle: AnyRecord): IntakeClarificationAnswer[] {
373
+ const intake = asRecord(contextBundle.intake);
374
+ const review = asRecord(intake.review);
375
+ const clarificationAnswers = Array.isArray(review.clarification_answers)
376
+ ? review.clarification_answers
377
+ : [];
378
+ return clarificationAnswers
379
+ .map((item) => asRecord(item))
380
+ .filter((item) => asStringArray(item.ambiguity_ids).length > 0)
381
+ .map((item) => ({
382
+ questionId: asNonEmptyString(item.question_id) ?? 'unknown',
383
+ ambiguityIds: asStringArray(item.ambiguity_ids),
384
+ answer:
385
+ typeof item.answer === 'string'
386
+ ? item.answer
387
+ : JSON.stringify(asRecord(item.answer) ?? {}, null, 2),
388
+ answeredAt: asNonEmptyString(item.answered_at),
389
+ }));
390
+ }
391
+
392
+ function buildIntakeClarificationPrompt(
393
+ ambiguities: IntakeClarificationAmbiguity[],
394
+ recoveryReason: string,
395
+ priorAnswers: IntakeClarificationAnswer[],
396
+ ): string {
397
+ const intro =
398
+ ambiguities.length === 1
399
+ ? 'Execution planning cannot begin because this intake ambiguity is still unresolved:'
400
+ : 'Execution planning cannot begin because these intake ambiguities are still unresolved:';
401
+ const items = ambiguities.map((ambiguity) => `- ${ambiguity.id}: ${ambiguity.summary}`);
402
+ const priorAnswerLines = ambiguities.flatMap((ambiguity) =>
403
+ priorAnswers
404
+ .filter((answer) => answer.ambiguityIds.includes(ambiguity.id))
405
+ .map(
406
+ (answer) =>
407
+ `- ${ambiguity.id} via ${answer.questionId}${
408
+ answer.answeredAt ? ` at ${answer.answeredAt}` : ''
409
+ }: ${answer.answer}`,
410
+ ),
411
+ );
412
+ const priorAnswersBlock =
413
+ priorAnswerLines.length > 0
414
+ ? `\nPrior answered clarification evidence:\n${priorAnswerLines.join('\n')}\nUse this prior answer evidence. Only ask a narrower follow-up if it is still insufficient to resolve the ambiguity.`
415
+ : '';
416
+ return `${intro}\n${items.join('\n')}${priorAnswersBlock}\nRespond in free text and explicitly address each ambiguity ID. Recovery reason: ${recoveryReason}.`;
417
+ }
418
+
419
+ /**
420
+ * Core decision loop that drives a single agent worker turn.
421
+ *
422
+ * Invokes the provider, classifies outputs (plans, patches, notes, requests),
423
+ * dispatches tool calls, handles context-refresh retries, and supports both
424
+ * deterministic and interactive execution modes.
425
+ */
149
426
  export class WorkerDecisionLoop implements WorkerDecisionRunner {
150
427
  private readonly provider: WorkerProvider;
151
428
  private readonly toolCaller: SupervisorToolCaller;
@@ -155,6 +432,9 @@ export class WorkerDecisionLoop implements WorkerDecisionRunner {
155
432
  private readonly resolveExecutionModeOverride:
156
433
  | ((featureId: string, role: RuntimeRole) => Promise<ExecutionMode>)
157
434
  | undefined;
435
+ private readonly resolveRuntimeSelectionOverride:
436
+ | ((featureId: string, role: RuntimeRole) => ProviderSelection | Promise<ProviderSelection>)
437
+ | undefined;
158
438
  private readonly resolveInteractiveConfigOverride: (() => InteractiveExecutionConfig) | undefined;
159
439
  private readonly watchdog: WorktreeWatchdogService | undefined;
160
440
  private readonly checkpointService: CheckpointService | undefined;
@@ -170,6 +450,7 @@ export class WorkerDecisionLoop implements WorkerDecisionRunner {
170
450
  this.repoRoot = dependencies.repoRoot ?? null;
171
451
  this.runId = dependencies.runId ?? null;
172
452
  this.resolveExecutionModeOverride = dependencies.resolveExecutionMode;
453
+ this.resolveRuntimeSelectionOverride = dependencies.resolveRuntimeSelection;
173
454
  this.resolveInteractiveConfigOverride = dependencies.resolveInteractiveConfig;
174
455
  this.watchdog = dependencies.watchdog;
175
456
  this.checkpointService = dependencies.checkpointService;
@@ -177,11 +458,21 @@ export class WorkerDecisionLoop implements WorkerDecisionRunner {
177
458
  this.resolveRoleSessionId = dependencies.resolveRoleSessionId;
178
459
  }
179
460
 
461
+ /**
462
+ * Execute one decision turn: invoke the worker, process all outputs, and
463
+ * optionally retry once on a context-refresh request.
464
+ * @returns Aggregated result describing every action taken and diagnostics.
465
+ */
180
466
  async execute(input: WorkerDecisionInput): Promise<WorkerDecisionResult> {
181
467
  const result = makeEmptyResult();
468
+ const plannerState: PlannerExecutionState = {
469
+ currentPlanVersion: readPlanVersion(asRecord(input.contextBundle.plan).plan_version),
470
+ planMutationApplied: false,
471
+ };
182
472
  if (typeof this.provider.runWorker !== 'function') {
183
473
  return result;
184
474
  }
475
+ const runtimeSelection = await this.resolveRuntimeSelection(input.featureId, input.role);
185
476
  const requestedExecutionMode = await this.resolveExecutionMode(input.featureId, input.role);
186
477
  const interactiveEligible = this.isInteractiveEligible(requestedExecutionMode, input.role);
187
478
  const executionMode: ExecutionMode =
@@ -201,6 +492,7 @@ export class WorkerDecisionLoop implements WorkerDecisionRunner {
201
492
  valid: true,
202
493
  errorCode: null,
203
494
  executionMode,
495
+ runtimeSelection,
204
496
  });
205
497
  }
206
498
  await this.appendWorkerEvent({
@@ -215,17 +507,124 @@ export class WorkerDecisionLoop implements WorkerDecisionRunner {
215
507
  valid: true,
216
508
  errorCode: null,
217
509
  executionMode,
510
+ runtimeSelection,
511
+ });
512
+ let finalRun = await this.runWorkerTurn(
513
+ input,
514
+ executionMode,
515
+ runtimeSelection,
516
+ interactiveEligible,
517
+ );
518
+ if (finalRun.usage) {
519
+ result.usageRecords.push(finalRun.usage);
520
+ }
521
+ const firstPass = await this.processOutputs({
522
+ input,
523
+ workerRun: finalRun,
524
+ result,
525
+ plannerState,
526
+ allowContextRefreshRetry: true,
527
+ });
528
+
529
+ if (firstPass.contextRefreshRequested && firstPass.refreshedContext) {
530
+ finalRun = await this.runWorkerTurn(
531
+ {
532
+ ...input,
533
+ contextBundle: firstPass.refreshedContext,
534
+ lastToolResults: this.buildContextRetryToolResults(input, firstPass.refreshedContext),
535
+ },
536
+ executionMode,
537
+ runtimeSelection,
538
+ interactiveEligible,
539
+ );
540
+ if (finalRun.usage) {
541
+ result.usageRecords.push(finalRun.usage);
542
+ }
543
+ const secondPass = await this.processOutputs({
544
+ input: {
545
+ ...input,
546
+ contextBundle: firstPass.refreshedContext,
547
+ lastToolResults: this.buildContextRetryToolResults(input, firstPass.refreshedContext),
548
+ },
549
+ workerRun: finalRun,
550
+ result,
551
+ plannerState,
552
+ allowContextRefreshRetry: false,
553
+ });
554
+
555
+ if (secondPass.contextRefreshRequested) {
556
+ const hasInteractiveWork =
557
+ finalRun.interactiveSummary?.hasNetNewWorktreeChanges === true &&
558
+ finalRun.interactiveSummary.changedFiles.length > 0;
559
+ if (!hasInteractiveWork) {
560
+ result.contextStall = true;
561
+ result.errorCode = ERROR_CODES.PROVIDER_CONTEXT_STALL;
562
+ }
563
+ }
564
+ }
565
+
566
+ this.finalizeInteractiveOutcome(result, finalRun.interactiveSummary);
567
+
568
+ const hasProgress =
569
+ result.planSubmission ||
570
+ result.intakeSubmission ||
571
+ result.patchApplied ||
572
+ result.requestHandled ||
573
+ result.questionRequested;
574
+ result.noProgress = !hasProgress;
575
+
576
+ await this.appendWorkerEvent({
577
+ eventType: 'worker_completed',
578
+ featureId: input.featureId,
579
+ role: input.role,
580
+ outputTypes: result.outputTypes,
581
+ patchCount: result.outputTypes.filter((type) => type === 'PATCH').length,
582
+ planSubmissionCount: result.outputTypes.filter(
583
+ (type) => type === 'PLAN_SUBMISSION' || type === 'INTAKE_SUBMISSION',
584
+ ).length,
585
+ requestCount: result.outputTypes.filter((type) => type === 'REQUEST').length,
586
+ noteCount: result.outputTypes.filter((type) => type === 'NOTE').length,
587
+ valid: !result.invalidOutput && result.errorCode === null,
588
+ errorCode: result.errorCode,
589
+ interactiveOutcome: result.interactiveOutcome ?? null,
590
+ checkpointId: result.checkpoint?.checkpoint_id ?? null,
591
+ checkpointDiffHash:
592
+ typeof result.checkpoint?.diff_hash === 'string' ? result.checkpoint.diff_hash : null,
593
+ checkpointNetNewWorktreeChange: result.checkpoint?.net_new_worktree_change ?? null,
594
+ checkpointValidationStatus:
595
+ typeof result.checkpoint?.validation_status === 'string'
596
+ ? result.checkpoint.validation_status
597
+ : null,
598
+ executionMode,
599
+ runtimeSelection,
600
+ usage: finalRun.usage,
218
601
  });
219
602
 
603
+ if (this.activityMonitor) {
604
+ await this.activityMonitor.checkAndNotifyStuck(input.featureId);
605
+ }
606
+
607
+ return result;
608
+ }
609
+
610
+ private async runWorkerTurn(
611
+ input: WorkerDecisionInput,
612
+ executionMode: ExecutionMode,
613
+ runtimeSelection: ProviderSelection,
614
+ interactiveEligible: boolean,
615
+ ): Promise<WorkerRunResult> {
220
616
  let workerOutput: Record<string, unknown>;
221
617
  let interactiveSummary: InteractiveRunSummary | null = null;
222
618
  try {
223
619
  if (interactiveEligible) {
224
- interactiveSummary = await this.runInteractiveWorker(input);
620
+ interactiveSummary =
621
+ input.role === 'planner'
622
+ ? await this.runInteractivePlanner(input, runtimeSelection)
623
+ : await this.runInteractiveWorker(input, runtimeSelection);
225
624
  workerOutput = interactiveSummary.workerOutput;
226
625
  } else {
227
626
  workerOutput = await this.provider.runWorker(
228
- this.buildRunInput(input, executionMode, undefined),
627
+ this.buildRunInput(input, executionMode, undefined, runtimeSelection),
229
628
  );
230
629
  }
231
630
  } catch (error) {
@@ -270,92 +669,177 @@ export class WorkerDecisionLoop implements WorkerDecisionRunner {
270
669
  signal: typeof typed.details?.signal === 'string' ? typed.details.signal : null,
271
670
  exitCode:
272
671
  typeof typed.details?.exit_code === 'number' ? typed.details.exit_code : undefined,
672
+ stderr:
673
+ typeof typed.details?.stderr === 'string' && typed.details.stderr.length > 0
674
+ ? typed.details.stderr
675
+ : undefined,
273
676
  executionMode,
677
+ runtimeSelection,
274
678
  });
275
679
  throw error;
276
680
  }
277
681
 
278
- const outputs = asOutputs(workerOutput);
279
- result.rawOutputs = outputs.map((output) => structuredClone(output));
280
- const allowedTypes = new Set(['PLAN_SUBMISSION', 'PATCH', 'NOTE', 'REQUEST']);
281
- let planSubmissionCount = 0;
282
- let patchCount = 0;
283
- let requestCount = 0;
284
- let noteCount = 0;
682
+ // Extract usage telemetry from provider output (if available).
683
+ const rawUsage = workerOutput.usage;
684
+ const usage: NormalizedUsageRecord | null =
685
+ rawUsage &&
686
+ typeof rawUsage === 'object' &&
687
+ 'status' in rawUsage &&
688
+ typeof (rawUsage as NormalizedUsageRecord).status === 'string'
689
+ ? (rawUsage as NormalizedUsageRecord)
690
+ : null;
691
+
692
+ return {
693
+ workerOutput,
694
+ interactiveSummary,
695
+ executionMode,
696
+ runtimeSelection,
697
+ usage,
698
+ };
699
+ }
700
+
701
+ private buildContextRetryToolResults(
702
+ input: WorkerDecisionInput,
703
+ refreshedContext: AnyRecord,
704
+ ): AnyRecord[] {
705
+ return [
706
+ ...(input.lastToolResults ?? []),
707
+ {
708
+ tool_name: TOOLS.FEATURE_GET_CONTEXT,
709
+ feature_id: input.featureId,
710
+ refreshed_context: structuredClone(refreshedContext),
711
+ },
712
+ ];
713
+ }
714
+
715
+ private async processOutputs(input: {
716
+ input: WorkerDecisionInput;
717
+ workerRun: WorkerRunResult;
718
+ result: WorkerDecisionResult;
719
+ plannerState: PlannerExecutionState;
720
+ allowContextRefreshRetry: boolean;
721
+ }): Promise<RequestRoutingResult> {
722
+ const { result, plannerState, allowContextRefreshRetry } = input;
723
+ const workerInput = input.input;
724
+ const outputs = asOutputs(input.workerRun.workerOutput);
725
+ result.rawOutputs.push(...outputs.map((output) => structuredClone(output)));
726
+
727
+ const blockingQuestionOutput = outputs.find((output) => isBlockingAskUserInputOutput(output));
728
+ if (blockingQuestionOutput) {
729
+ result.outputTypes.push('REQUEST');
730
+ await this.routeRequest(
731
+ workerInput,
732
+ blockingQuestionOutput,
733
+ result,
734
+ plannerState,
735
+ allowContextRefreshRetry,
736
+ );
737
+ return { contextRefreshRequested: false, refreshedContext: null };
738
+ }
739
+
740
+ const allowedTypes = new Set([
741
+ 'PLAN_SUBMISSION',
742
+ 'INTAKE_SUBMISSION',
743
+ 'PATCH',
744
+ 'NOTE',
745
+ 'REQUEST',
746
+ ]);
285
747
  for (const output of outputs) {
286
748
  const outputType = asNonEmptyString(output.type)?.toUpperCase();
287
749
  if (!outputType) {
288
750
  result.invalidOutput = true;
751
+ result.errorCode = ERROR_CODES.PROVIDER_OUTPUT_INVALID;
752
+ result.interactiveOutcome = input.workerRun.interactiveSummary
753
+ ? 'provider_output_invalid'
754
+ : null;
289
755
  continue;
290
756
  }
757
+
291
758
  result.outputTypes.push(outputType);
292
759
  if (!allowedTypes.has(outputType)) {
293
760
  result.invalidOutput = true;
761
+ result.errorCode = ERROR_CODES.PROVIDER_OUTPUT_INVALID;
762
+ result.interactiveOutcome = input.workerRun.interactiveSummary
763
+ ? 'provider_output_invalid'
764
+ : null;
294
765
  continue;
295
766
  }
296
767
 
297
768
  if (outputType === 'PLAN_SUBMISSION') {
298
- planSubmissionCount += 1;
299
- await this.routePlanSubmission(input, output, result);
769
+ await this.routePlanSubmission(workerInput, output, result, plannerState);
770
+ continue;
771
+ }
772
+ if (outputType === 'INTAKE_SUBMISSION') {
773
+ await this.routeIntakeSubmission(workerInput, output, result, plannerState);
300
774
  continue;
301
775
  }
302
776
  if (outputType === 'PATCH') {
303
- patchCount += 1;
304
- if (interactiveSummary) {
305
- const hasPatchPayload = Boolean(asNonEmptyString(output.unified_diff ?? output.diff));
306
- if (hasPatchPayload) {
307
- result.patchApplied = true;
308
- }
309
- } else {
310
- await this.routePatch(input, output, result);
777
+ if (!input.workerRun.interactiveSummary) {
778
+ await this.routePatch(workerInput, output, result);
311
779
  }
312
780
  continue;
313
781
  }
314
782
  if (outputType === 'NOTE') {
315
- noteCount += 1;
316
- await this.routeNote(input.featureId, output, result);
783
+ if (
784
+ input.workerRun.interactiveSummary &&
785
+ input.workerRun.interactiveSummary.fallbackReason !== null &&
786
+ !input.workerRun.interactiveSummary.hasNetNewWorktreeChanges
787
+ ) {
788
+ result.invalidOutput = true;
789
+ result.errorCode = ERROR_CODES.PROVIDER_OUTPUT_INVALID;
790
+ result.interactiveOutcome = 'provider_output_invalid';
791
+ continue;
792
+ }
793
+ await this.routeNote(workerInput.featureId, output, result);
317
794
  continue;
318
795
  }
319
- if (outputType === 'REQUEST') {
320
- requestCount += 1;
321
- await this.routeRequest(input, output, result);
796
+
797
+ const requestResult = await this.routeRequest(
798
+ workerInput,
799
+ output,
800
+ result,
801
+ plannerState,
802
+ allowContextRefreshRetry,
803
+ );
804
+ if (requestResult.contextRefreshRequested) {
805
+ return requestResult;
322
806
  }
323
807
  }
324
808
 
325
- if (interactiveSummary) {
809
+ return { contextRefreshRequested: false, refreshedContext: null };
810
+ }
811
+
812
+ private finalizeInteractiveOutcome(
813
+ result: WorkerDecisionResult,
814
+ interactiveSummary: InteractiveRunSummary | null,
815
+ ): void {
816
+ if (!interactiveSummary) {
817
+ return;
818
+ }
819
+
820
+ result.checkpoint = structuredClone(interactiveSummary.finalCheckpoint);
821
+ if (interactiveSummary.finalCheckpoint) {
326
822
  result.toolResults.push({
327
823
  checkpoint: structuredClone(interactiveSummary.finalCheckpoint),
328
824
  });
329
- if (interactiveSummary.changedFiles.length > 0) {
330
- result.patchApplied = true;
331
- }
332
- if (interactiveSummary.checkpointInvalid) {
333
- result.invalidOutput = true;
334
- }
335
825
  }
336
-
337
- const hasProgress = result.planSubmission || result.patchApplied || result.requestHandled;
338
- result.noProgress = !hasProgress;
339
-
340
- await this.appendWorkerEvent({
341
- eventType: 'worker_completed',
342
- featureId: input.featureId,
343
- role: input.role,
344
- outputTypes: result.outputTypes,
345
- patchCount,
346
- planSubmissionCount,
347
- requestCount,
348
- noteCount,
349
- valid: !result.invalidOutput,
350
- errorCode: result.invalidOutput ? ERROR_CODES.PROVIDER_OUTPUT_INVALID : null,
351
- executionMode,
352
- });
353
-
354
- if (this.activityMonitor) {
355
- await this.activityMonitor.checkAndNotifyStuck(input.featureId);
826
+ if (
827
+ interactiveSummary.finalCheckpoint &&
828
+ interactiveSummary.hasNetNewWorktreeChanges &&
829
+ interactiveSummary.changedFiles.length > 0
830
+ ) {
831
+ result.patchApplied = true;
832
+ }
833
+ if (interactiveSummary.checkpointInvalid) {
834
+ result.errorCode = ERROR_CODES.INTERACTIVE_CHECKPOINT_INVALID;
835
+ result.interactiveOutcome = 'checkpoint_invalid';
836
+ } else if (result.invalidOutput) {
837
+ result.interactiveOutcome = 'provider_output_invalid';
838
+ } else if (result.patchApplied) {
839
+ result.interactiveOutcome = 'progress_applied';
840
+ } else if (!result.planSubmission && !result.requestHandled && !result.questionRequested) {
841
+ result.interactiveOutcome = 'no_new_work';
356
842
  }
357
-
358
- return result;
359
843
  }
360
844
 
361
845
  private async resolveExecutionMode(featureId: string, role: RuntimeRole): Promise<ExecutionMode> {
@@ -365,21 +849,37 @@ export class WorkerDecisionLoop implements WorkerDecisionRunner {
365
849
  return 'deterministic';
366
850
  }
367
851
 
852
+ private async resolveRuntimeSelection(
853
+ featureId: string,
854
+ role: RuntimeRole,
855
+ ): Promise<ProviderSelection> {
856
+ if (this.resolveRuntimeSelectionOverride) {
857
+ return await this.resolveRuntimeSelectionOverride(featureId, role);
858
+ }
859
+ return this.provider.selection;
860
+ }
861
+
368
862
  private isInteractiveEligible(executionMode: ExecutionMode, role: RuntimeRole): boolean {
369
863
  if (executionMode !== 'interactive') {
370
864
  return false;
371
865
  }
372
- if (role !== 'builder' && role !== 'qa') {
866
+ const capabilities = this.provider.getCapabilities?.();
867
+ const supportsInteractive = !capabilities
868
+ ? true
869
+ : capabilities.supportsInteractiveMode && capabilities.supportsWorkingDirectory;
870
+ if (!supportsInteractive) {
373
871
  return false;
374
872
  }
375
- if (!this.repoRoot || !this.watchdog || !this.checkpointService || !this.resolveWorktreePath) {
873
+ if (role === 'planner') {
874
+ return Boolean(this.repoRoot);
875
+ }
876
+ if (role !== 'builder' && role !== 'qa' && role !== 'reconciler') {
376
877
  return false;
377
878
  }
378
- const capabilities = this.provider.getCapabilities?.();
379
- if (!capabilities) {
380
- return true;
879
+ if (!this.repoRoot || !this.watchdog || !this.checkpointService || !this.resolveWorktreePath) {
880
+ return false;
381
881
  }
382
- return capabilities.supportsInteractiveMode && capabilities.supportsWorkingDirectory;
882
+ return true;
383
883
  }
384
884
 
385
885
  private resolveInteractiveConfig(): InteractiveExecutionConfig {
@@ -400,17 +900,23 @@ export class WorkerDecisionLoop implements WorkerDecisionRunner {
400
900
  input: WorkerDecisionInput,
401
901
  executionMode: ExecutionMode,
402
902
  workingDirectory: string | undefined,
903
+ runtimeSelection: ProviderSelection,
403
904
  ): WorkerRunInput {
404
905
  return {
405
906
  role: input.role,
406
907
  feature_id: input.featureId,
908
+ ...(input.role === 'planner'
909
+ ? { planner_phase: resolvePlannerPhaseFromContext(input.contextBundle) }
910
+ : {}),
407
911
  context_bundle: input.contextBundle,
408
- instructions: input.instructions,
912
+ instructions: this.resolvePromptInstructions(input, executionMode),
409
913
  last_tool_results: input.lastToolResults ?? [],
410
914
  runtime_selection: {
411
- provider: this.provider.selection.provider,
412
- model: this.provider.selection.model,
413
- provider_config_ref: this.provider.selection.provider_config_ref,
915
+ provider: runtimeSelection.provider,
916
+ model: runtimeSelection.model,
917
+ provider_config_env: runtimeSelection.provider_config_env ?? null,
918
+ provider_config_ref: runtimeSelection.provider_config_ref,
919
+ agent_config: runtimeSelection.agent_config ?? null,
414
920
  },
415
921
  execution_mode: executionMode,
416
922
  working_directory: workingDirectory,
@@ -418,16 +924,21 @@ export class WorkerDecisionLoop implements WorkerDecisionRunner {
418
924
  };
419
925
  }
420
926
 
421
- private async runInteractiveWorker(input: WorkerDecisionInput): Promise<InteractiveRunSummary> {
927
+ private async runInteractiveWorker(
928
+ input: WorkerDecisionInput,
929
+ runtimeSelection: ProviderSelection,
930
+ ): Promise<InteractiveRunSummary> {
422
931
  if (!this.repoRoot || !this.watchdog || !this.checkpointService || !this.resolveWorktreePath) {
423
932
  const fallbackOutput = await this.provider.runWorker(
424
- this.buildRunInput(input, 'deterministic', undefined),
933
+ this.buildRunInput(input, 'deterministic', undefined, runtimeSelection),
425
934
  );
426
935
  return {
427
936
  workerOutput: fallbackOutput,
428
937
  finalCheckpoint: this.createSyntheticCheckpoint(input.featureId),
429
938
  changedFiles: [],
939
+ hasNetNewWorktreeChanges: false,
430
940
  checkpointInvalid: false,
941
+ fallbackReason: readInteractiveFallbackReason(fallbackOutput),
431
942
  };
432
943
  }
433
944
 
@@ -444,6 +955,7 @@ export class WorkerDecisionLoop implements WorkerDecisionRunner {
444
955
 
445
956
  let latestCheckpoint: CheckpointRecord | null = null;
446
957
  let checkpointInvalid = false;
958
+ let lastCheckpointFailureReason: string | null = null;
447
959
  let lastCheckpointAt = 0;
448
960
  const checkpointDebounceMs = 5_000;
449
961
  let checkpointQueue = Promise.resolve();
@@ -464,10 +976,14 @@ export class WorkerDecisionLoop implements WorkerDecisionRunner {
464
976
  });
465
977
  if (checkpoint) {
466
978
  latestCheckpoint = checkpoint.checkpoint;
467
- checkpointInvalid = checkpointInvalid || !checkpoint.valid || checkpoint.blockMerge;
979
+ checkpointInvalid = checkpointInvalid || checkpoint.blockMerge;
468
980
  }
469
- } catch {
981
+ } catch (checkpointError: unknown) {
470
982
  checkpointInvalid = true;
983
+ lastCheckpointFailureReason =
984
+ checkpointError instanceof Error
985
+ ? checkpointError.message
986
+ : (extractNonErrorMessage(checkpointError) ?? 'checkpoint creation failed');
471
987
  } finally {
472
988
  lastCheckpointAt = Date.now();
473
989
  }
@@ -491,15 +1007,20 @@ export class WorkerDecisionLoop implements WorkerDecisionRunner {
491
1007
 
492
1008
  try {
493
1009
  const workerOutput = await this.provider.runWorker(
494
- this.buildRunInput(input, 'interactive', worktreePath),
1010
+ this.buildRunInput(input, 'interactive', worktreePath, runtimeSelection),
495
1011
  );
496
1012
  await enqueueCheckpoint('final');
497
1013
  const changedFiles = latestCheckpoint?.files_changed ?? [];
1014
+ const hasNetNewWorktreeChanges = latestCheckpoint?.net_new_worktree_change === true;
498
1015
  return {
499
1016
  workerOutput,
500
- finalCheckpoint: latestCheckpoint ?? this.createSyntheticCheckpoint(input.featureId),
1017
+ finalCheckpoint:
1018
+ latestCheckpoint ??
1019
+ this.createSyntheticCheckpoint(input.featureId, lastCheckpointFailureReason),
501
1020
  changedFiles,
1021
+ hasNetNewWorktreeChanges,
502
1022
  checkpointInvalid,
1023
+ fallbackReason: readInteractiveFallbackReason(workerOutput),
503
1024
  };
504
1025
  } finally {
505
1026
  clearInterval(timer);
@@ -509,34 +1030,152 @@ export class WorkerDecisionLoop implements WorkerDecisionRunner {
509
1030
  }
510
1031
  }
511
1032
 
512
- private createSyntheticCheckpoint(featureId: string): CheckpointRecord {
1033
+ private createSyntheticCheckpoint(
1034
+ featureId: string,
1035
+ failureReason: string | null = null,
1036
+ ): CheckpointRecord {
513
1037
  return {
514
1038
  checkpoint_id: `checkpoint-synthetic-${Date.now()}`,
515
1039
  timestamp: new Date().toISOString(),
516
1040
  files_changed: [],
517
- validation_status: 'skipped',
518
- violations: [],
1041
+ validation_status: failureReason ? 'invalid' : 'skipped',
1042
+ violations: failureReason ? [failureReason] : [],
519
1043
  diff_snapshot: `.aop/features/${featureId}/checkpoints/synthetic.diff`,
1044
+ net_new_worktree_change: false,
520
1045
  };
521
1046
  }
522
1047
 
1048
+ private async runInteractivePlanner(
1049
+ input: WorkerDecisionInput,
1050
+ runtimeSelection: ProviderSelection,
1051
+ ): Promise<InteractiveRunSummary> {
1052
+ const workerOutput = await this.provider.runWorker(
1053
+ this.buildRunInput(
1054
+ input,
1055
+ 'interactive',
1056
+ this.resolvePlannerWorkingDirectory(input.featureId),
1057
+ runtimeSelection,
1058
+ ),
1059
+ );
1060
+ return {
1061
+ workerOutput,
1062
+ finalCheckpoint: null,
1063
+ changedFiles: [],
1064
+ hasNetNewWorktreeChanges: false,
1065
+ checkpointInvalid: false,
1066
+ fallbackReason: readInteractiveFallbackReason(workerOutput),
1067
+ };
1068
+ }
1069
+
1070
+ private resolvePromptInstructions(
1071
+ input: WorkerDecisionInput,
1072
+ executionMode: ExecutionMode,
1073
+ ): string {
1074
+ const baseInstructions = input.instructions.trim();
1075
+ if (executionMode !== 'interactive') {
1076
+ return baseInstructions;
1077
+ }
1078
+
1079
+ if (input.role === 'builder' || input.role === 'qa' || input.role === 'reconciler') {
1080
+ const interactiveOverride =
1081
+ input.role === 'builder'
1082
+ ? [
1083
+ 'Interactive mode override:',
1084
+ '- Edit planned files directly in the working directory.',
1085
+ '- Ignore any generic instruction that asks you to emit PATCH or unified diff output.',
1086
+ '- Use the accepted plan, allowed areas, planned file list, and latest evidence in the context summary below as your execution contract.',
1087
+ '- Return NOTE only after making planned file changes.',
1088
+ '- If the safe fix surface exceeds the accepted plan, return REQUEST.action=more_context with a concrete blocker.',
1089
+ '- Use ask_user_input only for genuine human decisions, approvals, or policy exceptions you cannot resolve from the plan and repo.',
1090
+ ].join('\n')
1091
+ : input.role === 'qa'
1092
+ ? [
1093
+ 'Interactive mode override:',
1094
+ '- Edit files directly in the working directory.',
1095
+ '- Ignore any generic instruction that asks you to emit PATCH or unified diff output.',
1096
+ '- Use the accepted plan, qa_test_index, and latest evidence in the context summary below as your verification contract.',
1097
+ '- Return NOTE only after making file changes that address a reproduced failure or verification gap.',
1098
+ '- Use more_context/context_refresh only when evidence is stale or the accepted plan does not authorize the safe fix surface.',
1099
+ '- Use ask_user_input only for genuine operator decisions, approvals, or risk acknowledgements.',
1100
+ ].join('\n')
1101
+ : [
1102
+ 'Interactive mode override:',
1103
+ '- Edit files directly in the conflicted worktree.',
1104
+ '- Ignore any generic instruction that asks you to emit PATCH or unified diff output.',
1105
+ '- Use the spec, accepted plan, conflict status, approved collision context, and latest evidence in the context summary below as your reconciliation contract.',
1106
+ '- Return NOTE only after resolving conflicted files and performing proportionate verification.',
1107
+ '- Use more_context/context_refresh only when the conflict snapshot or surrounding repo state is stale.',
1108
+ '- Use ask_user_input only when preserving mainline semantics and feature intent requires an operator choice.',
1109
+ ].join('\n');
1110
+ return baseInstructions.length > 0
1111
+ ? `${interactiveOverride}\n\nAdditional task context:\n${baseInstructions}`
1112
+ : interactiveOverride;
1113
+ }
1114
+
1115
+ if (input.role === 'planner') {
1116
+ const plannerOverride =
1117
+ resolvePlannerPhaseFromContext(input.contextBundle) === 'intake'
1118
+ ? [
1119
+ 'Interactive mode override:',
1120
+ '- Read and update the intake artifacts directly on disk.',
1121
+ '- Emit INTAKE_SUBMISSION when the verified manifest is ready.',
1122
+ '- Emit REQUEST.action=ask_user_input only for blocking requirement clarification.',
1123
+ '- If you ask for user input, stop there for the turn and wait for the persisted answer before promoting the manifest.',
1124
+ '- Never self-assert human_review_confirmed without an answered manifest-review confirmation question in context.',
1125
+ '- Return NOTE only when you intentionally keep intake unchanged and can justify that decision from the observed feature state.',
1126
+ ].join('\n')
1127
+ : [
1128
+ 'Interactive mode override:',
1129
+ '- Read and update the planning artifacts directly on disk.',
1130
+ '- Emit PLAN_SUBMISSION or REQUEST.action=amend_plan when the accepted plan must change.',
1131
+ '- Return NOTE only when you intentionally keep the accepted plan unchanged and can justify that decision from the observed feature state.',
1132
+ ].join('\n');
1133
+ return baseInstructions.length > 0
1134
+ ? `${plannerOverride}\n\nAdditional task context:\n${baseInstructions}`
1135
+ : plannerOverride;
1136
+ }
1137
+
1138
+ return baseInstructions;
1139
+ }
1140
+
1141
+ private resolvePlannerWorkingDirectory(featureId: string): string | undefined {
1142
+ if (!this.repoRoot) {
1143
+ return undefined;
1144
+ }
1145
+ return path.join(this.repoRoot, '.aop', 'features', featureId);
1146
+ }
1147
+
523
1148
  private async routePlanSubmission(
524
1149
  input: WorkerDecisionInput,
525
1150
  output: AnyRecord,
526
1151
  result: WorkerDecisionResult,
1152
+ plannerState: PlannerExecutionState,
527
1153
  ): Promise<void> {
528
1154
  if (input.role !== 'planner') {
529
1155
  return;
530
1156
  }
531
1157
 
1158
+ if (plannerState.planMutationApplied) {
1159
+ return;
1160
+ }
1161
+
532
1162
  const planJson = sanitizePlannerPlan(asRecord(output.plan_json ?? output.plan));
533
1163
  if (Object.keys(planJson).length === 0) {
534
1164
  return;
535
1165
  }
536
1166
 
537
- const contextPlan = asRecord(input.contextBundle.plan);
538
- const existingVersion = readPlanVersion(contextPlan.plan_version);
1167
+ if (
1168
+ (await this.requestIntakeClarificationForPlanMutation(
1169
+ input,
1170
+ result,
1171
+ ERROR_CODES.VERIFIED_MANIFEST_REQUIRED,
1172
+ )) === true
1173
+ ) {
1174
+ return;
1175
+ }
1176
+
539
1177
  const requestedExpectedVersion = readPlanVersion(output.expected_plan_version);
1178
+ const existingVersion = plannerState.currentPlanVersion;
540
1179
 
541
1180
  if (existingVersion == null) {
542
1181
  const response = await this.toolCaller.callTool('planner', TOOLS.PLAN_SUBMIT, {
@@ -544,6 +1183,7 @@ export class WorkerDecisionLoop implements WorkerDecisionRunner {
544
1183
  plan_json: planJson,
545
1184
  });
546
1185
  result.toolResults.push(asRecord(response.data));
1186
+ this.recordPlannerMutation(plannerState, response.data, planJson);
547
1187
  result.planSubmission = true;
548
1188
  return;
549
1189
  }
@@ -555,15 +1195,102 @@ export class WorkerDecisionLoop implements WorkerDecisionRunner {
555
1195
  plan_json: planJson,
556
1196
  });
557
1197
  result.toolResults.push(asRecord(response.data));
1198
+ this.recordPlannerMutation(plannerState, response.data, planJson);
558
1199
  result.planSubmission = true;
559
1200
  }
560
1201
 
1202
+ private async routeIntakeSubmission(
1203
+ input: WorkerDecisionInput,
1204
+ output: AnyRecord,
1205
+ result: WorkerDecisionResult,
1206
+ plannerState: PlannerExecutionState,
1207
+ ): Promise<void> {
1208
+ if (input.role !== 'planner' || plannerState.planMutationApplied) {
1209
+ return;
1210
+ }
1211
+
1212
+ const intakeSubmission = asRecord(output.intake_submission);
1213
+ if (!intakeSubmission) {
1214
+ return;
1215
+ }
1216
+
1217
+ try {
1218
+ const response = await this.toolCaller.callTool('planner', TOOLS.FEATURE_INTAKE_SUBMIT, {
1219
+ feature_id: input.featureId,
1220
+ intake_submission: intakeSubmission,
1221
+ });
1222
+ result.toolResults.push(asRecord(response.data));
1223
+ result.intakeSubmission = true;
1224
+ } catch (error) {
1225
+ const failure = readToolFailureDetails(error);
1226
+ const plannerPhase = resolvePlannerPhaseFromContext(input.contextBundle);
1227
+ if (failure?.code !== ERROR_CODES.INTAKE_SUBMISSION_INVALID || plannerPhase !== 'intake') {
1228
+ throw error;
1229
+ }
1230
+
1231
+ const ambiguityIds = normalizeList([
1232
+ ...asStringArray(failure.details.missing_ambiguity_evidence_ids),
1233
+ ...asStringArray(failure.details.open_ambiguity_ids),
1234
+ ]);
1235
+ if (!hasOpenIntakeQuestion(input.contextBundle)) {
1236
+ const ambiguities = readIntakeAmbiguitiesForRecovery(input.contextBundle, ambiguityIds);
1237
+ const priorAnswers = readAnsweredIntakeClarifications(input.contextBundle).filter(
1238
+ (answer) =>
1239
+ ambiguityIds.length === 0 ||
1240
+ answer.ambiguityIds.some((ambiguityId) => ambiguityIds.includes(ambiguityId)),
1241
+ );
1242
+ const sessionId =
1243
+ this.resolveRoleSessionId?.(input.role, input.featureId) ?? `bootstrap:${input.role}`;
1244
+ const response = await this.toolCaller.callTool(
1245
+ 'orchestrator',
1246
+ TOOLS.FEATURE_QUESTION_CREATE,
1247
+ {
1248
+ feature_id: input.featureId,
1249
+ role: 'planner',
1250
+ session_id: sessionId,
1251
+ question_type: 'clarification',
1252
+ prompt: buildIntakeClarificationPrompt(
1253
+ ambiguities,
1254
+ failure.code ?? ERROR_CODES.INTAKE_SUBMISSION_INVALID,
1255
+ priorAnswers,
1256
+ ),
1257
+ details: {
1258
+ ambiguity_ids: ambiguities.map((ambiguity) => ambiguity.id),
1259
+ obligation_ids: normalizeList(
1260
+ ambiguities.flatMap((ambiguity) => ambiguity.obligationIds),
1261
+ ),
1262
+ prior_answered_ambiguity_ids: ambiguities
1263
+ .filter((ambiguity) =>
1264
+ priorAnswers.some((answer) => answer.ambiguityIds.includes(ambiguity.id)),
1265
+ )
1266
+ .map((ambiguity) => ambiguity.id),
1267
+ recovery_reason: failure.code ?? ERROR_CODES.INTAKE_SUBMISSION_INVALID,
1268
+ recovery_source: 'intake_submission_validation',
1269
+ validation_message: failure.message,
1270
+ },
1271
+ expected_answer: {
1272
+ kind: 'free_text',
1273
+ },
1274
+ blocking: true,
1275
+ phase: STATUS.INTAKE,
1276
+ request_action: 'ask_user_input',
1277
+ resume_status: STATUS.INTAKE,
1278
+ resume_phase: STATUS.INTAKE,
1279
+ },
1280
+ );
1281
+ result.toolResults.push(asRecord(response.data));
1282
+ }
1283
+ result.requestHandled = true;
1284
+ result.questionRequested = true;
1285
+ }
1286
+ }
1287
+
561
1288
  private async routePatch(
562
1289
  input: WorkerDecisionInput,
563
1290
  output: AnyRecord,
564
1291
  result: WorkerDecisionResult,
565
1292
  ): Promise<void> {
566
- if (input.role !== 'builder' && input.role !== 'qa') {
1293
+ if (input.role !== 'builder' && input.role !== 'qa' && input.role !== 'reconciler') {
567
1294
  return;
568
1295
  }
569
1296
 
@@ -602,11 +1329,13 @@ export class WorkerDecisionLoop implements WorkerDecisionRunner {
602
1329
  input: WorkerDecisionInput,
603
1330
  output: AnyRecord,
604
1331
  result: WorkerDecisionResult,
605
- ): Promise<void> {
1332
+ plannerState: PlannerExecutionState,
1333
+ allowContextRefreshRetry: boolean,
1334
+ ): Promise<RequestRoutingResult> {
606
1335
  const request = asRecord(output.request ?? output);
607
1336
  const action = asNonEmptyString(request.action ?? request.request_type)?.toLowerCase();
608
1337
  if (!action) {
609
- return;
1338
+ return { contextRefreshRequested: false, refreshedContext: null };
610
1339
  }
611
1340
 
612
1341
  if (action === 'prioritize') {
@@ -615,13 +1344,13 @@ export class WorkerDecisionLoop implements WorkerDecisionRunner {
615
1344
  result.priorityOrder = featureOrder;
616
1345
  result.requestHandled = true;
617
1346
  }
618
- return;
1347
+ return { contextRefreshRequested: false, refreshedContext: null };
619
1348
  }
620
1349
 
621
1350
  if (action === 'lock_acquire') {
622
1351
  const resources = asStringArray(request.resources);
623
1352
  if (resources.length === 0) {
624
- return;
1353
+ return { contextRefreshRequested: false, refreshedContext: null };
625
1354
  }
626
1355
  const response = await this.toolCaller.callTool('orchestrator', TOOLS.LOCKS_ACQUIRE, {
627
1356
  feature_id: input.featureId,
@@ -629,13 +1358,13 @@ export class WorkerDecisionLoop implements WorkerDecisionRunner {
629
1358
  });
630
1359
  result.toolResults.push(asRecord(response.data));
631
1360
  result.requestHandled = true;
632
- return;
1361
+ return { contextRefreshRequested: false, refreshedContext: null };
633
1362
  }
634
1363
 
635
1364
  if (action === 'lock_release') {
636
1365
  const resources = asStringArray(request.resources);
637
1366
  if (resources.length === 0) {
638
- return;
1367
+ return { contextRefreshRequested: false, refreshedContext: null };
639
1368
  }
640
1369
  const response = await this.toolCaller.callTool('orchestrator', TOOLS.LOCKS_RELEASE, {
641
1370
  feature_id: input.featureId,
@@ -643,36 +1372,108 @@ export class WorkerDecisionLoop implements WorkerDecisionRunner {
643
1372
  });
644
1373
  result.toolResults.push(asRecord(response.data));
645
1374
  result.requestHandled = true;
646
- return;
1375
+ return { contextRefreshRequested: false, refreshedContext: null };
647
1376
  }
648
1377
 
649
1378
  if (action === 'more_context' || action === 'context_refresh') {
1379
+ result.contextRequestCount += 1;
1380
+ result.lastContextRequestAt = new Date().toISOString();
1381
+ result.lastContextRequestRole = input.role;
1382
+ if (!allowContextRefreshRetry) {
1383
+ return { contextRefreshRequested: true, refreshedContext: null };
1384
+ }
650
1385
  const response = await this.toolCaller.callTool(input.role, TOOLS.FEATURE_GET_CONTEXT, {
651
1386
  feature_id: input.featureId,
652
1387
  });
653
1388
  result.toolResults.push(asRecord(response.data));
1389
+ this.refreshPlannerStateFromContext(plannerState, response.data);
1390
+ return {
1391
+ contextRefreshRequested: true,
1392
+ refreshedContext: asRecord(response.data) ?? {},
1393
+ };
1394
+ }
1395
+
1396
+ if (action === 'ask_user_input') {
1397
+ const prompt = asNonEmptyString(request.prompt);
1398
+ if (!prompt) {
1399
+ return { contextRefreshRequested: false, refreshedContext: null };
1400
+ }
1401
+ const sessionId =
1402
+ this.resolveRoleSessionId?.(input.role, input.featureId) ?? `bootstrap:${input.role}`;
1403
+ const currentStatus = asNonEmptyString(
1404
+ asRecord(asRecord(input.contextBundle.state).front_matter).status,
1405
+ );
1406
+ const plannerPhase =
1407
+ input.role === 'planner' ? resolvePlannerPhaseFromContext(input.contextBundle) : 'planning';
1408
+ const response = await this.toolCaller.callTool(
1409
+ 'orchestrator',
1410
+ TOOLS.FEATURE_QUESTION_CREATE,
1411
+ {
1412
+ feature_id: input.featureId,
1413
+ role: input.role,
1414
+ session_id: sessionId,
1415
+ question_type: asNonEmptyString(request.question_type) ?? 'clarification',
1416
+ prompt,
1417
+ details: asRecord(request.details) ?? {},
1418
+ expected_answer: asRecord(request.expected_answer) ?? undefined,
1419
+ blocking: request.blocking !== false,
1420
+ phase: plannerPhase === 'intake' ? STATUS.INTAKE : (currentStatus ?? input.role),
1421
+ request_action: action,
1422
+ resume_status: plannerPhase === 'intake' ? STATUS.INTAKE : undefined,
1423
+ resume_phase: plannerPhase === 'intake' ? STATUS.INTAKE : undefined,
1424
+ },
1425
+ );
1426
+ result.toolResults.push(asRecord(response.data));
654
1427
  result.requestHandled = true;
655
- return;
1428
+ result.questionRequested = true;
1429
+ try {
1430
+ await this.toolCaller.callTool('orchestrator', TOOLS.FEATURE_LOG_APPEND, {
1431
+ feature_id: input.featureId,
1432
+ note: JSON.stringify({
1433
+ action,
1434
+ question_id: asRecord(response.data)?.question_id ?? null,
1435
+ role: input.role,
1436
+ prompt,
1437
+ }),
1438
+ });
1439
+ } catch (_error) {
1440
+ // Best effort log for observability.
1441
+ }
1442
+ return { contextRefreshRequested: false, refreshedContext: null };
656
1443
  }
657
1444
 
658
1445
  if (action === 'amend_plan' && input.role === 'planner') {
1446
+ if (plannerState.planMutationApplied) {
1447
+ return { contextRefreshRequested: false, refreshedContext: null };
1448
+ }
1449
+
659
1450
  const planJson = sanitizePlannerPlan(asRecord(request.plan_json));
660
1451
  if (Object.keys(planJson).length === 0) {
661
- return;
1452
+ return { contextRefreshRequested: false, refreshedContext: null };
1453
+ }
1454
+
1455
+ if (
1456
+ (await this.requestIntakeClarificationForPlanMutation(
1457
+ input,
1458
+ result,
1459
+ ERROR_CODES.VERIFIED_MANIFEST_REQUIRED,
1460
+ )) === true
1461
+ ) {
1462
+ return { contextRefreshRequested: false, refreshedContext: null };
662
1463
  }
663
1464
 
664
- const contextPlan = asRecord(input.contextBundle.plan);
665
- const existingVersion = readPlanVersion(contextPlan.plan_version);
666
1465
  const requestedExpectedVersion = readPlanVersion(request.expected_plan_version);
1466
+ const existingVersion = plannerState.currentPlanVersion;
667
1467
  if (existingVersion == null) {
668
1468
  const response = await this.toolCaller.callTool('planner', TOOLS.PLAN_SUBMIT, {
669
1469
  feature_id: input.featureId,
670
1470
  plan_json: planJson,
671
1471
  });
672
1472
  result.toolResults.push(asRecord(response.data));
1473
+ this.recordPlannerMutation(plannerState, response.data, planJson);
673
1474
  result.requestHandled = true;
674
1475
  result.planSubmission = true;
675
- return;
1476
+ return { contextRefreshRequested: false, refreshedContext: null };
676
1477
  }
677
1478
 
678
1479
  const response = await this.toolCaller.callTool('planner', TOOLS.PLAN_UPDATE, {
@@ -681,8 +1482,122 @@ export class WorkerDecisionLoop implements WorkerDecisionRunner {
681
1482
  plan_json: planJson,
682
1483
  });
683
1484
  result.toolResults.push(asRecord(response.data));
1485
+ this.recordPlannerMutation(plannerState, response.data, planJson);
684
1486
  result.requestHandled = true;
685
1487
  result.planSubmission = true;
1488
+ return { contextRefreshRequested: false, refreshedContext: null };
1489
+ }
1490
+
1491
+ try {
1492
+ await this.toolCaller.callTool('orchestrator', TOOLS.FEATURE_LOG_APPEND, {
1493
+ feature_id: input.featureId,
1494
+ note: JSON.stringify({
1495
+ action: 'unknown_request_action',
1496
+ requested_action: action,
1497
+ role: input.role,
1498
+ }),
1499
+ });
1500
+ } catch (_error) {
1501
+ // Best effort observability for unknown actions.
1502
+ }
1503
+ return { contextRefreshRequested: false, refreshedContext: null };
1504
+ }
1505
+
1506
+ private async requestIntakeClarificationForPlanMutation(
1507
+ input: WorkerDecisionInput,
1508
+ result: WorkerDecisionResult,
1509
+ recoveryReason: string,
1510
+ ): Promise<boolean> {
1511
+ if (
1512
+ input.role !== 'planner' ||
1513
+ resolvePlannerPhaseFromContext(input.contextBundle) !== 'intake'
1514
+ ) {
1515
+ return false;
1516
+ }
1517
+
1518
+ const verifiedManifest = asRecord(asRecord(input.contextBundle.intake).verified_manifest);
1519
+ if (Object.keys(verifiedManifest).length > 0) {
1520
+ return false;
1521
+ }
1522
+
1523
+ if (hasOpenIntakeQuestion(input.contextBundle)) {
1524
+ result.requestHandled = true;
1525
+ return true;
1526
+ }
1527
+
1528
+ const ambiguities = readOpenIntakeAmbiguities(input.contextBundle);
1529
+ const priorAnswers = readAnsweredIntakeClarifications(input.contextBundle);
1530
+ if (ambiguities.length === 0) {
1531
+ result.requestHandled = true;
1532
+ return true;
1533
+ }
1534
+
1535
+ const sessionId =
1536
+ this.resolveRoleSessionId?.(input.role, input.featureId) ?? `bootstrap:${input.role}`;
1537
+ const response = await this.toolCaller.callTool('orchestrator', TOOLS.FEATURE_QUESTION_CREATE, {
1538
+ feature_id: input.featureId,
1539
+ role: input.role,
1540
+ session_id: sessionId,
1541
+ question_type: 'clarification',
1542
+ prompt: buildIntakeClarificationPrompt(ambiguities, recoveryReason, priorAnswers),
1543
+ details: {
1544
+ ambiguity_ids: ambiguities.map((ambiguity) => ambiguity.id),
1545
+ obligation_ids: ambiguities.flatMap((ambiguity) => ambiguity.obligationIds),
1546
+ recovery_reason: recoveryReason,
1547
+ recovery_source: 'worker_decision_loop',
1548
+ },
1549
+ expected_answer: {
1550
+ kind: 'free_text',
1551
+ },
1552
+ blocking: true,
1553
+ phase: STATUS.INTAKE,
1554
+ request_action: 'ask_user_input',
1555
+ resume_status: STATUS.INTAKE,
1556
+ resume_phase: STATUS.INTAKE,
1557
+ });
1558
+ result.toolResults.push(asRecord(response.data));
1559
+ result.requestHandled = true;
1560
+ result.questionRequested = true;
1561
+
1562
+ try {
1563
+ await this.toolCaller.callTool('orchestrator', TOOLS.FEATURE_LOG_APPEND, {
1564
+ feature_id: input.featureId,
1565
+ note: JSON.stringify({
1566
+ action: 'ask_user_input',
1567
+ question_id: asRecord(response.data)?.question_id ?? null,
1568
+ role: input.role,
1569
+ recovery_reason: recoveryReason,
1570
+ recovery_source: 'worker_decision_loop',
1571
+ ambiguity_ids: ambiguities.map((ambiguity) => ambiguity.id),
1572
+ }),
1573
+ });
1574
+ } catch (_error) {
1575
+ // Best effort observability for intake rerouting.
1576
+ }
1577
+ return true;
1578
+ }
1579
+
1580
+ private refreshPlannerStateFromContext(
1581
+ plannerState: PlannerExecutionState,
1582
+ context: unknown,
1583
+ ): void {
1584
+ const refreshedPlanVersion = readPlanVersion(asRecord(asRecord(context).plan).plan_version);
1585
+ if (refreshedPlanVersion != null) {
1586
+ plannerState.currentPlanVersion = refreshedPlanVersion;
1587
+ }
1588
+ }
1589
+
1590
+ private recordPlannerMutation(
1591
+ plannerState: PlannerExecutionState,
1592
+ responseData: unknown,
1593
+ planJson: AnyRecord,
1594
+ ): void {
1595
+ plannerState.planMutationApplied = true;
1596
+ const acceptedPlanVersion =
1597
+ readPlanVersion(asRecord(responseData).plan_version) ??
1598
+ readPlanVersion(planJson.plan_version);
1599
+ if (acceptedPlanVersion != null) {
1600
+ plannerState.currentPlanVersion = acceptedPlanVersion;
686
1601
  }
687
1602
  }
688
1603
 
@@ -709,6 +1624,11 @@ export class WorkerDecisionLoop implements WorkerDecisionRunner {
709
1624
  noteCount: number;
710
1625
  valid: boolean;
711
1626
  errorCode: string | null;
1627
+ interactiveOutcome?: WorkerDecisionResult['interactiveOutcome'];
1628
+ checkpointId?: string | null;
1629
+ checkpointDiffHash?: string | null;
1630
+ checkpointNetNewWorktreeChange?: boolean | null;
1631
+ checkpointValidationStatus?: string | null;
712
1632
  watchdogReason?: string | null;
713
1633
  timeoutMs?: number;
714
1634
  idleTimeoutMs?: number;
@@ -717,6 +1637,9 @@ export class WorkerDecisionLoop implements WorkerDecisionRunner {
717
1637
  elapsedMs?: number;
718
1638
  signal?: string | null;
719
1639
  exitCode?: number;
1640
+ stderr?: string;
1641
+ runtimeSelection: ProviderSelection;
1642
+ usage?: NormalizedUsageRecord | null;
720
1643
  }): Promise<void> {
721
1644
  if (!this.repoRoot) {
722
1645
  return;
@@ -738,8 +1661,22 @@ export class WorkerDecisionLoop implements WorkerDecisionRunner {
738
1661
  note_count: event.noteCount,
739
1662
  valid: event.valid,
740
1663
  error_code: event.errorCode,
741
- provider: this.provider.selection.provider,
742
- model: this.provider.selection.model,
1664
+ interactive_outcome: event.interactiveOutcome ?? null,
1665
+ checkpoint_id: event.checkpointId ?? null,
1666
+ checkpoint_diff_hash: event.checkpointDiffHash ?? null,
1667
+ checkpoint_net_new_worktree_change: event.checkpointNetNewWorktreeChange ?? null,
1668
+ checkpoint_validation_status: event.checkpointValidationStatus ?? null,
1669
+ provider: event.runtimeSelection.provider,
1670
+ model: event.runtimeSelection.model,
1671
+ usage: event.usage
1672
+ ? {
1673
+ status: event.usage.status,
1674
+ input_tokens: event.usage.input_tokens,
1675
+ output_tokens: event.usage.output_tokens,
1676
+ total_tokens: event.usage.total_tokens,
1677
+ estimated_cost_usd: event.usage.estimated_cost_usd,
1678
+ }
1679
+ : null,
743
1680
  watchdog_reason: event.watchdogReason ?? null,
744
1681
  timeout_ms: event.timeoutMs,
745
1682
  idle_timeout_ms: event.idleTimeoutMs,
@@ -748,6 +1685,7 @@ export class WorkerDecisionLoop implements WorkerDecisionRunner {
748
1685
  elapsed_ms: event.elapsedMs,
749
1686
  signal: event.signal ?? null,
750
1687
  exit_code: event.exitCode,
1688
+ stderr: event.stderr,
751
1689
  };
752
1690
 
753
1691
  await appendWorkerRuntimeEvent({