muonroi-cli 1.8.4 → 1.8.5

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 (458) hide show
  1. package/LICENSE +17 -5
  2. package/dist/packages/agent-harness-core/src/driver.d.ts +27 -1
  3. package/dist/packages/agent-harness-core/src/driver.js +46 -0
  4. package/dist/packages/agent-harness-core/src/event-tee.d.ts +48 -0
  5. package/dist/packages/agent-harness-core/src/event-tee.js +77 -0
  6. package/dist/packages/agent-harness-core/src/mcp-server.d.ts +11 -0
  7. package/dist/packages/agent-harness-core/src/mcp-server.js +87 -15
  8. package/dist/packages/agent-harness-core/src/protocol.d.ts +66 -2
  9. package/dist/packages/agent-harness-core/src/protocol.js +15 -0
  10. package/dist/packages/agent-harness-core/src/visual-quality.d.ts +58 -0
  11. package/dist/packages/agent-harness-core/src/visual-quality.js +141 -0
  12. package/dist/packages/agent-harness-opentui/src/agent-mode.d.ts +6 -0
  13. package/dist/packages/agent-harness-opentui/src/agent-mode.js +14 -1
  14. package/dist/packages/agent-harness-opentui/src/input-bridge.d.ts +2 -10
  15. package/dist/packages/agent-harness-opentui/src/input-bridge.js +103 -16
  16. package/dist/packages/agent-harness-opentui/src/install.d.ts +8 -0
  17. package/dist/packages/agent-harness-opentui/src/install.js +10 -0
  18. package/dist/packages/agent-harness-opentui/src/semantic.js +12 -10
  19. package/dist/packages/agent-harness-opentui/src/visual-capture.d.ts +56 -0
  20. package/dist/packages/agent-harness-opentui/src/visual-capture.js +103 -0
  21. package/dist/src/agent-harness/mock-model.d.ts +28 -0
  22. package/dist/src/agent-harness/mock-model.js +63 -1
  23. package/dist/src/agent-harness/test-spawn.js +31 -0
  24. package/dist/src/cli/config/screen-providers.js +1 -1
  25. package/dist/src/cli/cost-forensics.d.ts +10 -0
  26. package/dist/src/cli/cost-forensics.js +18 -3
  27. package/dist/src/cli/keys-bundle.d.ts +1 -1
  28. package/dist/src/cli/keys-bundle.js +1 -1
  29. package/dist/src/cli/keys.d.ts +2 -2
  30. package/dist/src/cli/keys.js +19 -81
  31. package/dist/src/council/clarifier.d.ts +28 -2
  32. package/dist/src/council/clarifier.js +81 -15
  33. package/dist/src/council/context.js +49 -15
  34. package/dist/src/council/debate-checkpoint.d.ts +129 -0
  35. package/dist/src/council/debate-checkpoint.js +176 -0
  36. package/dist/src/council/debate-planner.js +51 -3
  37. package/dist/src/council/debate-summary.d.ts +25 -0
  38. package/dist/src/council/debate-summary.js +85 -0
  39. package/dist/src/council/debate.d.ts +169 -2
  40. package/dist/src/council/debate.js +1210 -134
  41. package/dist/src/council/index.d.ts +85 -1
  42. package/dist/src/council/index.js +634 -196
  43. package/dist/src/council/leader.d.ts +26 -0
  44. package/dist/src/council/leader.js +150 -9
  45. package/dist/src/council/llm.d.ts +32 -0
  46. package/dist/src/council/llm.js +231 -38
  47. package/dist/src/council/panel-select.d.ts +30 -0
  48. package/dist/src/council/panel-select.js +72 -0
  49. package/dist/src/council/planner.js +23 -0
  50. package/dist/src/council/preflight.d.ts +7 -0
  51. package/dist/src/council/preflight.js +14 -2
  52. package/dist/src/council/prompts.d.ts +30 -3
  53. package/dist/src/council/prompts.js +234 -64
  54. package/dist/src/council/stance-recall.d.ts +42 -0
  55. package/dist/src/council/stance-recall.js +57 -0
  56. package/dist/src/council/strip-think.d.ts +17 -0
  57. package/dist/src/council/strip-think.js +33 -0
  58. package/dist/src/council/types.d.ts +128 -0
  59. package/dist/src/ee/artifact-cache.d.ts +16 -0
  60. package/dist/src/ee/artifact-cache.js +32 -0
  61. package/dist/src/ee/auth.d.ts +1 -0
  62. package/dist/src/ee/auth.js +15 -2
  63. package/dist/src/ee/bridge.d.ts +10 -0
  64. package/dist/src/ee/bridge.js +58 -0
  65. package/dist/src/ee/client.js +81 -18
  66. package/dist/src/ee/export-transcripts.d.ts +1 -0
  67. package/dist/src/ee/export-transcripts.js +8 -10
  68. package/dist/src/ee/extract-session.js +29 -0
  69. package/dist/src/ee/extract-style.d.ts +58 -0
  70. package/dist/src/ee/extract-style.js +270 -0
  71. package/dist/src/ee/recall-ledger.d.ts +9 -0
  72. package/dist/src/ee/recall-ledger.js +3 -0
  73. package/dist/src/ee/scope.d.ts +1 -0
  74. package/dist/src/ee/scope.js +26 -1
  75. package/dist/src/ee/search.d.ts +7 -0
  76. package/dist/src/ee/search.js +24 -0
  77. package/dist/src/ee/transcript-emit.js +2 -0
  78. package/dist/src/ee/types.d.ts +22 -0
  79. package/dist/src/ee/who-am-i-brain.d.ts +35 -0
  80. package/dist/src/ee/who-am-i-brain.js +220 -0
  81. package/dist/src/ee/who-am-i.d.ts +10 -3
  82. package/dist/src/ee/who-am-i.js +12 -0
  83. package/dist/src/ee/workflow-event.d.ts +48 -0
  84. package/dist/src/ee/workflow-event.js +81 -0
  85. package/dist/src/flow/compaction/compress.d.ts +3 -3
  86. package/dist/src/flow/compaction/compress.js +45 -8
  87. package/dist/src/flow/compaction/extract.d.ts +4 -7
  88. package/dist/src/flow/compaction/extract.js +50 -10
  89. package/dist/src/flow/compaction/index.d.ts +13 -1
  90. package/dist/src/flow/compaction/index.js +70 -3
  91. package/dist/src/flow/compaction/input-guard.d.ts +24 -0
  92. package/dist/src/flow/compaction/input-guard.js +43 -0
  93. package/dist/src/flow/fold-planning.d.ts +36 -0
  94. package/dist/src/flow/fold-planning.js +83 -0
  95. package/dist/src/flow/hierarchy.d.ts +146 -0
  96. package/dist/src/flow/hierarchy.js +427 -0
  97. package/dist/src/flow/index.d.ts +1 -0
  98. package/dist/src/flow/index.js +2 -0
  99. package/dist/src/flow/run-artifacts.d.ts +102 -0
  100. package/dist/src/flow/run-artifacts.js +208 -0
  101. package/dist/src/generated/version.d.ts +1 -1
  102. package/dist/src/generated/version.js +1 -1
  103. package/dist/src/gsd/assessment-schema.d.ts +44 -0
  104. package/dist/src/gsd/assessment-schema.js +134 -0
  105. package/dist/src/gsd/capability-registry.d.ts +45 -0
  106. package/dist/src/gsd/capability-registry.js +337 -0
  107. package/dist/src/gsd/complexity-assessor.d.ts +39 -0
  108. package/dist/src/gsd/complexity-assessor.js +152 -0
  109. package/dist/src/gsd/config-bridge.d.ts +7 -0
  110. package/dist/src/gsd/config-bridge.js +114 -0
  111. package/dist/src/gsd/config-loader.d.ts +27 -0
  112. package/dist/src/gsd/config-loader.js +50 -0
  113. package/dist/src/gsd/council-context.d.ts +44 -0
  114. package/dist/src/gsd/council-context.js +114 -0
  115. package/dist/src/gsd/ee-closure.d.ts +28 -0
  116. package/dist/src/gsd/ee-closure.js +49 -0
  117. package/dist/src/gsd/flags.d.ts +55 -0
  118. package/dist/src/gsd/flags.js +83 -0
  119. package/dist/src/gsd/gsd-dispatch.d.ts +58 -0
  120. package/dist/src/gsd/gsd-dispatch.js +131 -0
  121. package/dist/src/gsd/gsd-runtime.d.ts +22 -0
  122. package/dist/src/gsd/gsd-runtime.js +37 -0
  123. package/dist/src/gsd/host-adapter.d.ts +11 -0
  124. package/dist/src/gsd/host-adapter.js +29 -0
  125. package/dist/src/gsd/index.d.ts +24 -1
  126. package/dist/src/gsd/index.js +27 -0
  127. package/dist/src/gsd/loop-host-contract.d.ts +21 -0
  128. package/dist/src/gsd/loop-host-contract.js +39 -0
  129. package/dist/src/gsd/loop-host.d.ts +69 -0
  130. package/dist/src/gsd/loop-host.js +245 -0
  131. package/dist/src/gsd/loop-resolver.d.ts +36 -0
  132. package/dist/src/gsd/loop-resolver.js +79 -0
  133. package/dist/src/gsd/model-tier.d.ts +13 -0
  134. package/dist/src/gsd/model-tier.js +45 -0
  135. package/dist/src/gsd/mutation-gate.d.ts +16 -0
  136. package/dist/src/gsd/mutation-gate.js +41 -0
  137. package/dist/src/gsd/native-roadmap.d.ts +89 -0
  138. package/dist/src/gsd/native-roadmap.js +343 -0
  139. package/dist/src/gsd/native-state.d.ts +47 -0
  140. package/dist/src/gsd/native-state.js +220 -0
  141. package/dist/src/gsd/paths.d.ts +23 -0
  142. package/dist/src/gsd/paths.js +66 -0
  143. package/dist/src/gsd/phase-dag.d.ts +12 -0
  144. package/dist/src/gsd/phase-dag.js +94 -0
  145. package/dist/src/gsd/phase-sync.d.ts +42 -0
  146. package/dist/src/gsd/phase-sync.js +321 -0
  147. package/dist/src/gsd/pil-gate-context.d.ts +13 -0
  148. package/dist/src/gsd/pil-gate-context.js +64 -0
  149. package/dist/src/gsd/pil-gate-critic.d.ts +19 -0
  150. package/dist/src/gsd/pil-gate-critic.js +74 -0
  151. package/dist/src/gsd/plan-council-prompts.d.ts +25 -0
  152. package/dist/src/gsd/plan-council-prompts.js +79 -0
  153. package/dist/src/gsd/plan-council.d.ts +44 -0
  154. package/dist/src/gsd/plan-council.js +251 -0
  155. package/dist/src/gsd/plan-gate-vocabulary.d.ts +40 -0
  156. package/dist/src/gsd/plan-gate-vocabulary.js +64 -0
  157. package/dist/src/gsd/product-workspace.d.ts +13 -0
  158. package/dist/src/gsd/product-workspace.js +124 -0
  159. package/dist/src/gsd/ship-bridge.d.ts +25 -0
  160. package/dist/src/gsd/ship-bridge.js +65 -0
  161. package/dist/src/gsd/state-document.d.ts +40 -0
  162. package/dist/src/gsd/state-document.js +163 -0
  163. package/dist/src/gsd/verdict-schema.d.ts +39 -0
  164. package/dist/src/gsd/verdict-schema.js +144 -0
  165. package/dist/src/gsd/verify-context.d.ts +22 -0
  166. package/dist/src/gsd/verify-context.js +27 -0
  167. package/dist/src/gsd/verify-council-prompts.d.ts +19 -0
  168. package/dist/src/gsd/verify-council-prompts.js +85 -0
  169. package/dist/src/gsd/verify-council.d.ts +25 -0
  170. package/dist/src/gsd/verify-council.js +119 -0
  171. package/dist/src/gsd/verify-gate-vocabulary.d.ts +25 -0
  172. package/dist/src/gsd/verify-gate-vocabulary.js +46 -0
  173. package/dist/src/gsd/workflow-engine.d.ts +60 -0
  174. package/dist/src/gsd/workflow-engine.js +207 -0
  175. package/dist/src/gsd/workflow-tools.d.ts +13 -0
  176. package/dist/src/gsd/workflow-tools.js +277 -0
  177. package/dist/src/hooks/index.js +1 -1
  178. package/dist/src/index.js +44 -11
  179. package/dist/src/maintain/pr-builder.js +23 -13
  180. package/dist/src/mcp/auto-setup.js +57 -32
  181. package/dist/src/mcp/client-pool.js +1 -1
  182. package/dist/src/mcp/ee-tools.js +1 -0
  183. package/dist/src/mcp/research-onboarding.js +8 -7
  184. package/dist/src/mcp/runtime.js +34 -2
  185. package/dist/src/models/catalog-client.d.ts +87 -0
  186. package/dist/src/models/catalog-client.js +105 -38
  187. package/dist/src/models/catalog.json +528 -265
  188. package/dist/src/models/registry.d.ts +22 -7
  189. package/dist/src/models/registry.js +73 -10
  190. package/dist/src/ops/doctor.js +1 -1
  191. package/dist/src/orchestrator/auto-commit.js +1 -1
  192. package/dist/src/orchestrator/batch-turn-runner.js +2 -2
  193. package/dist/src/orchestrator/cache-prefix.d.ts +67 -0
  194. package/dist/src/orchestrator/cache-prefix.js +83 -0
  195. package/dist/src/orchestrator/compact-request.d.ts +32 -0
  196. package/dist/src/orchestrator/compact-request.js +41 -0
  197. package/dist/src/orchestrator/compaction.d.ts +10 -0
  198. package/dist/src/orchestrator/compaction.js +27 -7
  199. package/dist/src/orchestrator/council-manager.d.ts +12 -3
  200. package/dist/src/orchestrator/council-manager.js +65 -24
  201. package/dist/src/orchestrator/cross-turn-dedup.d.ts +6 -0
  202. package/dist/src/orchestrator/cross-turn-dedup.js +22 -1
  203. package/dist/src/orchestrator/error-utils.d.ts +29 -0
  204. package/dist/src/orchestrator/error-utils.js +132 -24
  205. package/dist/src/orchestrator/grounding-check.js +39 -1
  206. package/dist/src/orchestrator/message-processor.js +242 -33
  207. package/dist/src/orchestrator/orchestrator.d.ts +39 -3
  208. package/dist/src/orchestrator/orchestrator.js +651 -102
  209. package/dist/src/orchestrator/preprocessor.js +1 -1
  210. package/dist/src/orchestrator/proactive-compact-detector.d.ts +26 -0
  211. package/dist/src/orchestrator/proactive-compact-detector.js +36 -0
  212. package/dist/src/orchestrator/prompts.js +17 -17
  213. package/dist/src/orchestrator/reactive-delegation.d.ts +39 -0
  214. package/dist/src/orchestrator/reactive-delegation.js +59 -0
  215. package/dist/src/orchestrator/retry-classifier.d.ts +2 -1
  216. package/dist/src/orchestrator/retry-classifier.js +46 -2
  217. package/dist/src/orchestrator/safety-intercept.d.ts +45 -0
  218. package/dist/src/orchestrator/safety-intercept.js +55 -0
  219. package/dist/src/orchestrator/scope-reminder.js +1 -1
  220. package/dist/src/orchestrator/session-experience.d.ts +2 -1
  221. package/dist/src/orchestrator/session-experience.js +2 -1
  222. package/dist/src/orchestrator/should-run-gate.d.ts +5 -0
  223. package/dist/src/orchestrator/should-run-gate.js +18 -0
  224. package/dist/src/orchestrator/stall-watchdog.d.ts +24 -3
  225. package/dist/src/orchestrator/stall-watchdog.js +47 -13
  226. package/dist/src/orchestrator/stream-runner.js +62 -29
  227. package/dist/src/orchestrator/sub-agent-cap.d.ts +13 -1
  228. package/dist/src/orchestrator/sub-agent-cap.js +16 -1
  229. package/dist/src/orchestrator/sub-agent-model-tier.d.ts +13 -1
  230. package/dist/src/orchestrator/sub-agent-model-tier.js +16 -2
  231. package/dist/src/orchestrator/subagent-compactor.d.ts +53 -1
  232. package/dist/src/orchestrator/subagent-compactor.js +126 -15
  233. package/dist/src/orchestrator/tool-engine.d.ts +22 -0
  234. package/dist/src/orchestrator/tool-engine.js +620 -56
  235. package/dist/src/orchestrator/tool-limit-auto-recover.d.ts +22 -0
  236. package/dist/src/orchestrator/tool-limit-auto-recover.js +30 -0
  237. package/dist/src/orchestrator/turn-runner-deps.d.ts +19 -0
  238. package/dist/src/orchestrator/turn-watchdog.d.ts +37 -0
  239. package/dist/src/orchestrator/turn-watchdog.js +55 -0
  240. package/dist/src/pil/agent-operating-contract.d.ts +1 -1
  241. package/dist/src/pil/agent-operating-contract.js +1 -1
  242. package/dist/src/pil/cheap-model-playbook.d.ts +1 -1
  243. package/dist/src/pil/cheap-model-playbook.js +5 -1
  244. package/dist/src/pil/cheap-model-workbooks.d.ts +1 -1
  245. package/dist/src/pil/cheap-model-workbooks.js +1 -1
  246. package/dist/src/pil/discovery-types.d.ts +1 -0
  247. package/dist/src/pil/discovery.js +16 -11
  248. package/dist/src/pil/layer1-intent.d.ts +18 -6
  249. package/dist/src/pil/layer1-intent.js +66 -757
  250. package/dist/src/pil/layer15-context-scan.js +15 -1
  251. package/dist/src/pil/layer3-ee-injection.js +23 -8
  252. package/dist/src/pil/layer4-gsd.js +69 -16
  253. package/dist/src/pil/layer5-context.js +7 -3
  254. package/dist/src/pil/layer6-output.d.ts +23 -0
  255. package/dist/src/pil/layer6-output.js +5 -1
  256. package/dist/src/pil/llm-classify.d.ts +33 -2
  257. package/dist/src/pil/llm-classify.js +123 -131
  258. package/dist/src/pil/native-capabilities-workbook.d.ts +1 -1
  259. package/dist/src/pil/native-capabilities-workbook.js +1 -0
  260. package/dist/src/pil/pipeline.js +34 -2
  261. package/dist/src/pil/response-tools.js +5 -3
  262. package/dist/src/pil/schema.d.ts +1 -0
  263. package/dist/src/pil/schema.js +2 -0
  264. package/dist/src/pil/types.d.ts +18 -0
  265. package/dist/src/playbook/directives.d.ts +4 -0
  266. package/dist/src/playbook/directives.js +17 -5
  267. package/dist/src/product-loop/backlog-builder.d.ts +14 -1
  268. package/dist/src/product-loop/backlog-builder.js +30 -6
  269. package/dist/src/product-loop/discovery-context-format.js +3 -1
  270. package/dist/src/product-loop/discovery-ecosystem.js +4 -1
  271. package/dist/src/product-loop/discovery-interview.js +32 -3
  272. package/dist/src/product-loop/discovery-schema.js +5 -1
  273. package/dist/src/product-loop/ideal-trace.d.ts +7 -0
  274. package/dist/src/product-loop/ideal-trace.js +64 -0
  275. package/dist/src/product-loop/index.d.ts +13 -1
  276. package/dist/src/product-loop/index.js +333 -52
  277. package/dist/src/product-loop/loop-driver.d.ts +7 -0
  278. package/dist/src/product-loop/loop-driver.js +310 -99
  279. package/dist/src/product-loop/phase-plan.d.ts +5 -0
  280. package/dist/src/product-loop/phase-plan.js +39 -2
  281. package/dist/src/product-loop/phase-runner.js +9 -1
  282. package/dist/src/product-loop/sprint-runner.d.ts +111 -0
  283. package/dist/src/product-loop/sprint-runner.js +559 -16
  284. package/dist/src/product-loop/types.d.ts +36 -5
  285. package/dist/src/providers/adapter.d.ts +1 -1
  286. package/dist/src/providers/adapter.js +3 -4
  287. package/dist/src/providers/auth/browser-flow.d.ts +1 -1
  288. package/dist/src/providers/auth/browser-flow.js +1 -1
  289. package/dist/src/providers/auth/openai-oauth.js +1 -1
  290. package/dist/src/providers/auth/registry.js +0 -34
  291. package/dist/src/providers/auth/token-store.js +4 -1
  292. package/dist/src/providers/auth/types.d.ts +1 -1
  293. package/dist/src/providers/auth/types.js +1 -1
  294. package/dist/src/providers/capabilities.d.ts +24 -5
  295. package/dist/src/providers/capabilities.js +42 -24
  296. package/dist/src/providers/endpoints.d.ts +2 -2
  297. package/dist/src/providers/endpoints.js +11 -10
  298. package/dist/src/providers/keychain.d.ts +1 -1
  299. package/dist/src/providers/keychain.js +7 -9
  300. package/dist/src/providers/mcp-vision-bridge.js +56 -146
  301. package/dist/src/providers/openai-compatible.js +8 -1
  302. package/dist/src/providers/pricing.d.ts +2 -2
  303. package/dist/src/providers/pricing.js +3 -13
  304. package/dist/src/providers/runtime.d.ts +27 -2
  305. package/dist/src/providers/runtime.js +78 -15
  306. package/dist/src/providers/strategies/base.strategy.d.ts +16 -0
  307. package/dist/src/providers/strategies/base.strategy.js +24 -1
  308. package/dist/src/providers/strategies/{siliconflow.strategy.d.ts → opencode-go.strategy.d.ts} +3 -3
  309. package/dist/src/providers/strategies/opencode-go.strategy.js +83 -0
  310. package/dist/src/providers/strategies/registry.js +4 -4
  311. package/dist/src/providers/strategies/thinking-mode.d.ts +109 -0
  312. package/dist/src/providers/strategies/thinking-mode.js +280 -1
  313. package/dist/src/providers/strategies/zai.strategy.d.ts +14 -0
  314. package/dist/src/providers/strategies/zai.strategy.js +44 -0
  315. package/dist/src/providers/types.d.ts +5 -6
  316. package/dist/src/providers/types.js +2 -2
  317. package/dist/src/providers/vision-backend.d.ts +47 -0
  318. package/dist/src/providers/vision-backend.js +258 -0
  319. package/dist/src/providers/vision-proxy.d.ts +22 -9
  320. package/dist/src/providers/vision-proxy.js +63 -132
  321. package/dist/src/providers/wire-debug.js +95 -0
  322. package/dist/src/router/decide.d.ts +13 -0
  323. package/dist/src/router/decide.js +138 -36
  324. package/dist/src/router/peak-hour.d.ts +38 -0
  325. package/dist/src/router/peak-hour.js +107 -0
  326. package/dist/src/router/step-router.js +3 -2
  327. package/dist/src/router/warm.js +4 -5
  328. package/dist/src/scaffold/continuation-prompt.d.ts +11 -0
  329. package/dist/src/scaffold/continuation-prompt.js +26 -0
  330. package/dist/src/scaffold/point-to-existing.d.ts +21 -0
  331. package/dist/src/scaffold/point-to-existing.js +25 -0
  332. package/dist/src/self-qa/agentic-loop.js +3 -3
  333. package/dist/src/{ui/state → state}/active-run.d.ts +19 -0
  334. package/dist/src/{ui/state → state}/active-run.js +21 -0
  335. package/dist/src/{ui/status-bar/store.d.ts → state/status-bar-store.d.ts} +4 -1
  336. package/dist/src/{ui/status-bar/store.js → state/status-bar-store.js} +12 -9
  337. package/dist/src/state/turn-trace.d.ts +43 -0
  338. package/dist/src/state/turn-trace.js +32 -0
  339. package/dist/src/storage/db.js +2 -1
  340. package/dist/src/storage/index.d.ts +1 -1
  341. package/dist/src/storage/index.js +1 -1
  342. package/dist/src/storage/interaction-log.d.ts +1 -1
  343. package/dist/src/storage/migrations.js +71 -1
  344. package/dist/src/storage/sessions.d.ts +28 -10
  345. package/dist/src/storage/sessions.js +78 -21
  346. package/dist/src/storage/transcript-view.js +1 -1
  347. package/dist/src/storage/transcript.d.ts +51 -0
  348. package/dist/src/storage/transcript.js +284 -13
  349. package/dist/src/tools/file.d.ts +15 -0
  350. package/dist/src/tools/file.js +32 -0
  351. package/dist/src/tools/native-tools.js +5 -0
  352. package/dist/src/tools/registry.d.ts +3 -0
  353. package/dist/src/tools/registry.js +460 -22
  354. package/dist/src/tools/research.d.ts +29 -0
  355. package/dist/src/tools/research.js +233 -0
  356. package/dist/src/types/index.d.ts +118 -3
  357. package/dist/src/ui/app.js +0 -0
  358. package/dist/src/ui/cards/product-status-card.js +1 -1
  359. package/dist/src/ui/components/bubble-body-guard.d.ts +27 -0
  360. package/dist/src/ui/components/bubble-body-guard.js +50 -0
  361. package/dist/src/ui/components/context-rail.d.ts +26 -0
  362. package/dist/src/ui/components/context-rail.js +33 -0
  363. package/dist/src/ui/components/council-conclusion-card.d.ts +73 -0
  364. package/dist/src/ui/components/council-conclusion-card.js +420 -0
  365. package/dist/src/ui/components/council-debate-pill.d.ts +36 -0
  366. package/dist/src/ui/components/council-debate-pill.js +34 -0
  367. package/dist/src/ui/components/council-info-card.js +2 -2
  368. package/dist/src/ui/components/council-leader-bubble.d.ts +10 -3
  369. package/dist/src/ui/components/council-leader-bubble.js +21 -11
  370. package/dist/src/ui/components/council-message-bubble.d.ts +15 -2
  371. package/dist/src/ui/components/council-message-bubble.js +16 -15
  372. package/dist/src/ui/components/council-phase-timeline.d.ts +9 -1
  373. package/dist/src/ui/components/council-phase-timeline.js +49 -15
  374. package/dist/src/ui/components/council-placeholder-bubble.d.ts +16 -9
  375. package/dist/src/ui/components/council-placeholder-bubble.js +32 -29
  376. package/dist/src/ui/components/council-question-card.js +12 -12
  377. package/dist/src/ui/components/council-rail-rounds.d.ts +26 -0
  378. package/dist/src/ui/components/council-rail-rounds.js +57 -0
  379. package/dist/src/ui/components/council-round-group.d.ts +38 -0
  380. package/dist/src/ui/components/council-round-group.js +88 -0
  381. package/dist/src/ui/components/council-status-list.d.ts +3 -1
  382. package/dist/src/ui/components/council-status-list.js +36 -24
  383. package/dist/src/ui/components/council-synthesis-banner.d.ts +7 -2
  384. package/dist/src/ui/components/council-synthesis-banner.js +20 -5
  385. package/dist/src/ui/components/halt-recovery-card.js +9 -5
  386. package/dist/src/ui/components/jump-to-latest-pill.d.ts +11 -0
  387. package/dist/src/ui/components/jump-to-latest-pill.js +14 -0
  388. package/dist/src/ui/components/prompt-box.js +18 -16
  389. package/dist/src/ui/components/session-tree-card.d.ts +14 -0
  390. package/dist/src/ui/components/session-tree-card.js +46 -0
  391. package/dist/src/ui/components/slash-inline-menu.d.ts +12 -0
  392. package/dist/src/ui/components/slash-inline-menu.js +26 -5
  393. package/dist/src/ui/components/task-list-panel.d.ts +14 -1
  394. package/dist/src/ui/components/task-list-panel.js +22 -2
  395. package/dist/src/ui/containers/modals-layer.d.ts +2 -1
  396. package/dist/src/ui/hooks/use-session-picker.d.ts +3 -3
  397. package/dist/src/ui/mcp-modal.js +2 -4
  398. package/dist/src/ui/modals/api-key-modal.js +1 -1
  399. package/dist/src/ui/modals/connect-modal.js +4 -3
  400. package/dist/src/ui/modals/session-picker-modal.d.ts +2 -2
  401. package/dist/src/ui/modals/session-picker-modal.js +3 -5
  402. package/dist/src/ui/picker-providers.d.ts +1 -1
  403. package/dist/src/ui/picker-providers.js +1 -1
  404. package/dist/src/ui/primitives/index.d.ts +1 -0
  405. package/dist/src/ui/primitives/index.js +2 -0
  406. package/dist/src/ui/primitives/semantic-primitives.d.ts +76 -0
  407. package/dist/src/ui/primitives/semantic-primitives.js +81 -0
  408. package/dist/src/ui/slash/compact.js +5 -7
  409. package/dist/src/ui/slash/cost.js +1 -1
  410. package/dist/src/ui/slash/council.js +19 -1
  411. package/dist/src/ui/slash/debug.d.ts +3 -31
  412. package/dist/src/ui/slash/debug.js +9 -20
  413. package/dist/src/ui/slash/ideal.d.ts +6 -2
  414. package/dist/src/ui/slash/ideal.js +97 -7
  415. package/dist/src/ui/slash/menu-items.d.ts +7 -0
  416. package/dist/src/ui/slash/menu-items.js +12 -18
  417. package/dist/src/ui/slash/registry.d.ts +2 -0
  418. package/dist/src/ui/slash/registry.js +4 -0
  419. package/dist/src/ui/status-bar/cache-hit.d.ts +6 -0
  420. package/dist/src/ui/status-bar/cache-hit.js +9 -0
  421. package/dist/src/ui/status-bar/index.d.ts +1 -1
  422. package/dist/src/ui/status-bar/index.js +7 -3
  423. package/dist/src/ui/status-bar/usd-meter.d.ts +5 -4
  424. package/dist/src/ui/status-bar/usd-meter.js +6 -4
  425. package/dist/src/ui/theme.d.ts +1 -0
  426. package/dist/src/ui/theme.js +2 -0
  427. package/dist/src/ui/types.d.ts +7 -0
  428. package/dist/src/ui/use-app-logic.js +0 -0
  429. package/dist/src/ui/utils/format.d.ts +14 -0
  430. package/dist/src/ui/utils/format.js +23 -3
  431. package/dist/src/usage/downgrade.js +2 -2
  432. package/dist/src/usage/product-ledger.js +2 -2
  433. package/dist/src/utils/install-manager.js +2 -1
  434. package/dist/src/utils/logger.js +2 -2
  435. package/dist/src/utils/permission-mode.js +5 -3
  436. package/dist/src/utils/redactor.js +1 -1
  437. package/dist/src/utils/settings.d.ts +153 -5
  438. package/dist/src/utils/settings.js +233 -29
  439. package/dist/src/utils/visible-retry.d.ts +11 -0
  440. package/dist/src/utils/visible-retry.js +10 -1
  441. package/dist/src/verify/entrypoint.d.ts +1 -1
  442. package/dist/src/verify/entrypoint.js +1 -1
  443. package/dist/src/verify/recipes.d.ts +13 -0
  444. package/dist/src/verify/recipes.js +15 -0
  445. package/package.json +135 -132
  446. package/dist/src/providers/auth/gcloud.d.ts +0 -28
  447. package/dist/src/providers/auth/gcloud.js +0 -102
  448. package/dist/src/providers/auth/gemini-oauth.d.ts +0 -82
  449. package/dist/src/providers/auth/gemini-oauth.js +0 -472
  450. package/dist/src/providers/gemini.d.ts +0 -11
  451. package/dist/src/providers/gemini.js +0 -45
  452. package/dist/src/providers/siliconflow-sse-repair.d.ts +0 -58
  453. package/dist/src/providers/siliconflow-sse-repair.js +0 -177
  454. package/dist/src/providers/strategies/google.strategy.d.ts +0 -22
  455. package/dist/src/providers/strategies/google.strategy.js +0 -174
  456. package/dist/src/providers/strategies/siliconflow.strategy.js +0 -29
  457. package/dist/src/ui/containers/chat-feed.d.ts +0 -40
  458. package/dist/src/ui/containers/chat-feed.js +0 -66
@@ -21,11 +21,17 @@
21
21
  * projection check, not a retroactive one.
22
22
  * - CB-2 (oscillation) is checked AFTER this sprint's score is known.
23
23
  */
24
+ import { existsSync } from "node:fs";
25
+ import { readFile, writeFile } from "node:fs/promises";
24
26
  import * as path from "node:path";
25
27
  import { prependDecisionsLock, readDecisionsLock } from "../council/decisions-lock.js";
26
28
  import { runCouncil } from "../council/index.js";
27
29
  import { phaseDone, phaseError, phaseStart } from "../council/phase-events.js";
30
+ import { fireAndForgetWorkflowEvent } from "../ee/workflow-event.js";
28
31
  import { readArtifact, writeArtifact } from "../flow/artifact-io.js";
32
+ import { renderResumeDigest, writeSprintOutcome, writeSprintVerify } from "../flow/run-artifacts.js";
33
+ import { isContextRailEnabled } from "../gsd/flags.js";
34
+ import { SPRINT_EXECUTION_MARKER } from "../pil/layer6-output.js";
29
35
  import { detectProviderForModel } from "../providers/runtime.js";
30
36
  import { logUIInteraction } from "../storage/index.js";
31
37
  import { commitToProduct, release } from "../usage/ledger.js";
@@ -40,19 +46,214 @@ import { formatProjectContextForPrompt } from "./discovery-context-format.js";
40
46
  import { readProjectContext } from "./discovery-persistence.js";
41
47
  import { evaluateDoneGate } from "./done-gate.js";
42
48
  import { buildContinueFeedback } from "./feedback-routing.js";
49
+ import { idealTrace } from "./ideal-trace.js";
43
50
  import { postSprintBoundary } from "./phase-tracker-bridge.js";
44
51
  import { computeProgressSnapshot, renderSnapshotMarkdown } from "./progress-snapshot.js";
45
52
  import { appendRoleMemory } from "./role-memory.js";
46
53
  import { loadVerifyFailureSignatures, recordVerifyFailureAndMaybePush } from "./verify-failure-tracking.js";
47
- import { parseVerifyResult } from "./verify-result.js";
54
+ import { parseVerifyResult, VERIFY_PASS_MARKER } from "./verify-result.js";
48
55
  // P3.7: track one-shot CB-2 retry bonus per run (keyed by runId).
49
56
  // The Map is module-scoped so multiple sprints within the same run share state
50
57
  // without touching DriverContext / IterationState shapes.
51
58
  const _cb2RetryUsed = new Map();
59
+ /** Watchdog ceiling for the verify stage (ms). Override with MUONROI_SPRINT_VERIFY_TIMEOUT_MS. */
60
+ function getVerifyWatchdogTimeoutMs() {
61
+ const raw = process.env.MUONROI_SPRINT_VERIFY_TIMEOUT_MS;
62
+ const n = raw ? Number.parseInt(raw, 10) : Number.NaN;
63
+ if (Number.isFinite(n) && n > 0)
64
+ return n;
65
+ return 10 * 60 * 1000; // 10 min default
66
+ }
67
+ /**
68
+ * Bound the verify stage with a watchdog timeout.
69
+ *
70
+ * `runVerifyOrchestration` can hang indefinitely with no visible signal:
71
+ * `prepareVerifyRun` → `ensureVerifyCheckpoint` spawns the `shuru` sandbox
72
+ * (`spawnWithProgress("shuru", …)`) which stalls on hosts where shuru is
73
+ * unavailable/misconfigured (e.g. Windows), and the verify sub-agent itself has
74
+ * no TTFB timeout. Because sprint-runner previously called it as a bare
75
+ * `await runVerifyOrchestration(agent)` with NO abortSignal and NO timeout, a
76
+ * single hung verify BRICKED the whole /ideal run silently — no error, no
77
+ * recovery card — observed live as a 30+ min dead stall right after
78
+ * "Committed: N sprints planned" (the impl turn finished, verify never returned).
79
+ *
80
+ * On timeout we abort the sub-agent, log with context (No-Silent-Catch), and
81
+ * return an ERROR ToolResult so the sprint loop treats it as a failed verify
82
+ * (Step 5 → verifyVerdict FAIL/ERROR → feedback-routing) instead of hanging
83
+ * forever. The hung sandbox op may leak in the background, but the run recovers
84
+ * and the failure is surfaced + resumable. `onProgress` is forwarded to console
85
+ * so a future hang is diagnosable (e.g. "Creating checkpoint: <name>").
86
+ */
87
+ async function runVerifyWithWatchdog(verifyAgent, runId, sprintN) {
88
+ const timeoutMs = getVerifyWatchdogTimeoutMs();
89
+ const controller = new AbortController();
90
+ let timer;
91
+ const onProgress = (detail) => {
92
+ if (process.env.MUONROI_DEBUG_VERIFY === "1")
93
+ console.error(`[verify:sprint-${sprintN}] ${detail}`);
94
+ };
95
+ const timeout = new Promise((resolve) => {
96
+ timer = setTimeout(() => {
97
+ controller.abort();
98
+ const msg = `verify stage exceeded ${Math.round(timeoutMs / 1000)}s watchdog and was aborted ` +
99
+ `(sprint ${sprintN}, run ${runId}) — likely a hung sandbox checkpoint (shuru) or a ` +
100
+ `verify sub-agent LLM call with no TTFB timeout`;
101
+ console.error(`[sprint-runner] ${msg}`);
102
+ resolve({ success: false, output: "", error: `verify-timeout: ${msg}` });
103
+ }, timeoutMs);
104
+ });
105
+ try {
106
+ return await Promise.race([
107
+ runVerifyOrchestration(verifyAgent, { abortSignal: controller.signal, onProgress }),
108
+ timeout,
109
+ ]);
110
+ }
111
+ catch (err) {
112
+ const message = err instanceof Error ? err.message : String(err);
113
+ console.error(`[sprint-runner] verify stage threw (sprint ${sprintN}, run ${runId}): ${message}`);
114
+ return { success: false, output: "", error: `verify-error: ${message}` };
115
+ }
116
+ finally {
117
+ if (timer)
118
+ clearTimeout(timer);
119
+ }
120
+ }
52
121
  /** @internal Test-only: reset CB-2 retry state for a given runId. */
53
122
  export function _resetCb2RetryUsed(runId) {
54
123
  _cb2RetryUsed.delete(runId);
55
124
  }
125
+ /**
126
+ * Idle-chunk ceiling for the implementation stage (ms). Override with
127
+ * MUONROI_SPRINT_IMPL_IDLE_MS. This is a TIME-SINCE-LAST-CHUNK budget, not a
128
+ * total-turn cap — a legitimately long implementation streams progress the
129
+ * whole way, so it may run for many minutes, but it must never go completely
130
+ * silent (no chunk at all) for this long.
131
+ */
132
+ export function getImplIdleTimeoutMs() {
133
+ const raw = process.env.MUONROI_SPRINT_IMPL_IDLE_MS;
134
+ const n = raw ? Number.parseInt(raw, 10) : Number.NaN;
135
+ if (Number.isFinite(n) && n > 0)
136
+ return n;
137
+ return 4 * 60 * 1000; // 4 min of total silence → treat the impl turn as stalled
138
+ }
139
+ /**
140
+ * Hard total-elapsed ceiling for the implementation stage (ms). Override with
141
+ * MUONROI_SPRINT_IMPL_TOTAL_MS. Unlike the idle budget this is armed once and is
142
+ * NOT reset by chunks, so it catches a hang that keeps the idle guard alive with
143
+ * heartbeat/status chunks. Generous by default so a legitimately large sprint is
144
+ * not cut short; a genuine hang still terminates within this ceiling.
145
+ */
146
+ export function getImplTotalTimeoutMs() {
147
+ const raw = process.env.MUONROI_SPRINT_IMPL_TOTAL_MS;
148
+ const n = raw ? Number.parseInt(raw, 10) : Number.NaN;
149
+ if (Number.isFinite(n) && n > 0)
150
+ return n;
151
+ return 15 * 60 * 1000; // 15 min hard ceiling on a single impl turn
152
+ }
153
+ /**
154
+ * Whether the implement stage runs in an ISOLATED bounded sub-agent context
155
+ * (ctx.runIsolatedTask) instead of the shared top-level turn (processMessageFn).
156
+ * Default ON. Disable with MUONROI_SPRINT_ISOLATED_IMPL=0.
157
+ *
158
+ * The isolated path is the fix for the live ctx-overflow wedge: the flat
159
+ * processMessageFn turn inherited the full council-debate history (~5.9M tokens
160
+ * observed), started implementation already at ~94% context, then wedged after a
161
+ * mid-turn compaction. A fresh child context (getSubAgentBudgetChars cap +
162
+ * independent in-loop compaction) never inherits the debate, so it starts near
163
+ * empty and its clutter is absorbed as one compact ToolResult.
164
+ */
165
+ export function getSprintIsolatedImplEnabled() {
166
+ return process.env.MUONROI_SPRINT_ISOLATED_IMPL !== "0";
167
+ }
168
+ /**
169
+ * Pure decision: use the isolated sub-agent path for the implement stage?
170
+ * True only when the flag is on AND the driver actually provides the bridge
171
+ * (legacy/test drivers omit runIsolatedTask → fall back to processMessageFn).
172
+ * Extracted for unit testing without spinning up a full runSprint.
173
+ */
174
+ export function shouldUseIsolatedImpl(hasBridge, enabled = getSprintIsolatedImplEnabled()) {
175
+ return enabled && hasBridge;
176
+ }
177
+ /**
178
+ * Imperative execution directive prepended to the sprint plan before it is
179
+ * handed to the orchestrator. The raw plan synthesis is a declarative design
180
+ * document; without this prefix the impl turn narrates it back instead of
181
+ * applying edits. Exported for test assertion. @internal
182
+ */
183
+ export const IMPL_EXECUTION_DIRECTIVE = `${SPRINT_EXECUTION_MARKER}\n\n` +
184
+ "You are the sprint IMPLEMENTER. EXECUTE the sprint plan below as an implementation task. Make the " +
185
+ "actual code changes NOW using your file-edit tools — read the target files, then edit/write them to " +
186
+ "apply every action item. Do NOT merely restate, summarize, or re-plan the design; apply the edits to " +
187
+ "the repository. Run the plan's own verification commands where given. Before you finish, self-verify " +
188
+ "as a reviewer would: confirm every target file named in the plan actually exists on disk with the " +
189
+ "intended change — do not stop with action items unaddressed. Stop only when the action items are " +
190
+ "implemented.\n\n" +
191
+ "--- SPRINT PLAN TO IMPLEMENT ---\n\n";
192
+ /**
193
+ * Wrap the implementation `processMessageFn` stream with an idle-chunk watchdog.
194
+ *
195
+ * Root cause it addresses (observed live 2026-07-08, /ideal resume of the
196
+ * gsd-core migration): the implementation stage delegates to the host
197
+ * orchestrator turn via `ctx.processMessageFn(implPrompt)` and consumes it with
198
+ * `for await (const chunk of implGen)`. The orchestrator turn finished its final
199
+ * LLM response cleanly (finishReason "stop", text-only) but the generator then
200
+ * suspended post-finish and never completed — the `for await` blocked for 17+
201
+ * minutes with NO chunk, NO phaseDone, NO advance to Verify, NO error. Because
202
+ * the LLM STREAM had already finished, the orchestrator's mid-stream
203
+ * time-to-next-chunk stall-watchdog does not fire — the hang is on the JS side
204
+ * after the stream terminator.
205
+ *
206
+ * TWO complementary guards (a single idle guard was observed live to be
207
+ * defeated: the impl created 2 files then emitted only non-progress heartbeat
208
+ * chunks for 9+ min, resetting a per-chunk idle timer without ever completing):
209
+ * - `idleMs` — resets on every yielded chunk; catches a TOTALLY silent stall
210
+ * (the post-finish hang above, zero chunks) quickly.
211
+ * - `totalMs` — armed ONCE at entry, NOT reset by chunks; a hard ceiling that
212
+ * fires even when heartbeat/status chunks keep the idle guard alive while no
213
+ * real progress is made.
214
+ * Either firing throws so the caller's existing try/catch converts the wedge
215
+ * into a visible phaseError (the sprint then surfaces + can recover), exactly
216
+ * like `runVerifyWithWatchdog` does for the verify stage. The suspended
217
+ * orchestrator promise may leak in the background, but the run recovers.
218
+ */
219
+ export async function* withImplIdleWatchdog(gen, idleMs, sprintN, totalMs = getImplTotalTimeoutMs()) {
220
+ const it = gen[Symbol.asyncIterator]();
221
+ let totalTimer;
222
+ const total = new Promise((_, reject) => {
223
+ totalTimer = setTimeout(() => {
224
+ reject(new Error(`implementation stage exceeded ${Math.round(totalMs / 1000)}s total watchdog and was ` +
225
+ `treated as stalled (sprint ${sprintN}) — the orchestrator turn never completed ` +
226
+ `(likely hung after its final response while emitting only heartbeat chunks)`));
227
+ }, totalMs);
228
+ });
229
+ try {
230
+ while (true) {
231
+ let idleTimer;
232
+ const idle = new Promise((_, reject) => {
233
+ idleTimer = setTimeout(() => {
234
+ reject(new Error(`implementation stage produced no output for ${Math.round(idleMs / 1000)}s and was ` +
235
+ `treated as stalled (sprint ${sprintN}) — the orchestrator turn hung post-finish ` +
236
+ `(finished its LLM response but the generator never completed)`));
237
+ }, idleMs);
238
+ });
239
+ let res;
240
+ try {
241
+ res = await Promise.race([it.next(), idle, total]);
242
+ }
243
+ finally {
244
+ if (idleTimer)
245
+ clearTimeout(idleTimer);
246
+ }
247
+ if (res.done)
248
+ return;
249
+ yield res.value;
250
+ }
251
+ }
252
+ finally {
253
+ if (totalTimer)
254
+ clearTimeout(totalTimer);
255
+ }
256
+ }
56
257
  export { computeFailureSignature, loadVerifyFailureSignatures, pushFailureToEE, recordVerifyFailureAndMaybePush, saveVerifyFailureSignatures, } from "./verify-failure-tracking.js";
57
258
  /**
58
259
  * Run a single sprint. Yields StreamChunk events for the UI and returns the
@@ -61,6 +262,104 @@ export { computeFailureSignature, loadVerifyFailureSignatures, pushFailureToEE,
61
262
  * Throws on circuit-breaker halt — caller (loop driver) catches and writes
62
263
  * the appropriate halt state to manifest/state.
63
264
  */
265
+ /** Path to the persisted per-sprint plan synthesis (Wave 2). @internal */
266
+ export function sprintPlanPath(runDir, sprintN) {
267
+ return path.join(runDir, `sprint-${sprintN}-plan.md`);
268
+ }
269
+ /**
270
+ * Wave 2: read a persisted sprint plan if present. Returns "" when absent or on
271
+ * read error (caller then runs the planning council). Never throws.
272
+ *
273
+ * The planning council is non-deterministic — re-running it on a resumed/retried
274
+ * sprint produces a different design AND a different target folder, which is why
275
+ * the impl turn was observed re-scaffolding in a new location each run. Reusing
276
+ * the persisted plan makes per-sprint planning idempotent so the same target
277
+ * files are continued across resume.
278
+ */
279
+ export async function readPersistedSprintPlan(planPath) {
280
+ try {
281
+ if (!existsSync(planPath))
282
+ return "";
283
+ return (await readFile(planPath, "utf8")).trim();
284
+ }
285
+ catch (err) {
286
+ console.error(`[sprint-runner] readPersistedSprintPlan failed for ${planPath}: ${err.message}`);
287
+ return "";
288
+ }
289
+ }
290
+ /** Wave 2: persist a sprint plan synthesis for idempotent resume. Never throws. */
291
+ export async function persistSprintPlan(planPath, synthesis) {
292
+ if (!synthesis.trim())
293
+ return;
294
+ try {
295
+ await writeFile(planPath, synthesis, "utf8");
296
+ }
297
+ catch (err) {
298
+ console.error(`[sprint-runner] persistSprintPlan failed for ${planPath}: ${err.message}`);
299
+ }
300
+ }
301
+ /**
302
+ * Extract repo-relative target file paths a sprint plan names (src/…, packages/…,
303
+ * tests/…). Deduped, capped. Used by Wave 3 (existing targets → continue) and 4A
304
+ * (missing targets → completeness re-check). Never throws.
305
+ */
306
+ export function extractPlanTargetPaths(planSynthesis, cap = 40) {
307
+ try {
308
+ const tokens = new Set();
309
+ const re = /\b((?:src|packages|tests|scripts|lib|app|apps)\/[\w./@-]+\.[a-z]{1,5})\b/gi;
310
+ let m = re.exec(planSynthesis);
311
+ while (m !== null) {
312
+ tokens.add(m[1].replace(/\\/g, "/"));
313
+ if (tokens.size >= cap)
314
+ break;
315
+ m = re.exec(planSynthesis);
316
+ }
317
+ return [...tokens];
318
+ }
319
+ catch (err) {
320
+ console.error(`[sprint-runner] extractPlanTargetPaths failed: ${err.message}`);
321
+ return [];
322
+ }
323
+ }
324
+ /**
325
+ * Wave 3: plan-named target file paths that ALREADY EXIST on disk, so the impl
326
+ * turn continues them rather than re-scaffolding in a new location. Empty on a
327
+ * greenfield sprint (files don't exist yet) → no injection.
328
+ */
329
+ export async function detectExistingPlanTargets(planSynthesis, cwd, cap = 20) {
330
+ const existing = [];
331
+ for (const t of extractPlanTargetPaths(planSynthesis)) {
332
+ if (existsSync(path.resolve(cwd, t)))
333
+ existing.push(t);
334
+ if (existing.length >= cap)
335
+ break;
336
+ }
337
+ return existing;
338
+ }
339
+ /**
340
+ * 4A: plan-named target file paths that STILL DO NOT EXIST after the impl turn —
341
+ * i.e. action items the implementer left unaddressed. Drives the post-impl
342
+ * completeness re-check (spend an extra turn ONLY when there is proven-incomplete
343
+ * work, unlike an unconditional reviewer pass). Empty ⇒ every named target landed.
344
+ */
345
+ export async function computeMissingPlanTargets(planSynthesis, cwd, cap = 20) {
346
+ const missing = [];
347
+ for (const t of extractPlanTargetPaths(planSynthesis)) {
348
+ if (!existsSync(path.resolve(cwd, t)))
349
+ missing.push(t);
350
+ if (missing.length >= cap)
351
+ break;
352
+ }
353
+ return missing;
354
+ }
355
+ /**
356
+ * 4A completeness re-check toggle. Default ON; disable with
357
+ * MUONROI_SPRINT_IMPL_RECHECK=0. When on, and the impl turn left plan-named
358
+ * target files missing, ONE focused follow-up turn is spent to finish them.
359
+ */
360
+ export function getImplRecheckEnabled() {
361
+ return process.env.MUONROI_SPRINT_IMPL_RECHECK !== "0";
362
+ }
64
363
  export async function* runSprint(args) {
65
364
  const { sprintN, ctx, productSpec, roleAssignments, history, carryOver, phaseScope } = args;
66
365
  const runDir = path.join(ctx.flowDir, "runs", ctx.runId);
@@ -216,15 +515,52 @@ export async function* runSprint(args) {
216
515
  const noopProcess = async function* () {
217
516
  /* no host orchestrator wired during planning */
218
517
  };
219
- const planGen = runCouncil(councilTopic, sessionModelId, [], ctx.runId, productLlm, ctx.respondToQuestion, ctx.respondToPreflight, ctx.processMessageFn ?? noopProcess, { skipClarification: true, cwd, runDir });
220
- let planSynthesis = "";
221
- while (true) {
222
- const step = await planGen.next();
223
- if (step.done) {
224
- planSynthesis = step.value ?? "";
225
- break;
518
+ // Wave 2 (2026-07-08): reuse a persisted per-sprint plan if one exists, making
519
+ // per-sprint planning idempotent across resume/retry. Without this the
520
+ // non-deterministic planning council re-ran on every runSprint call and emitted
521
+ // a different design → a different target folder each time (run1 src/council/,
522
+ // run4 src/engine/), so the impl turn re-scaffolded instead of continuing.
523
+ const planPath = sprintPlanPath(runDir, sprintN);
524
+ let planSynthesis = await readPersistedSprintPlan(planPath);
525
+ if (planSynthesis) {
526
+ idealTrace("sprint.planCouncil.reused", { runId: ctx.runId, sprintN, planSynthesisLen: planSynthesis.length });
527
+ yield {
528
+ type: "content",
529
+ content: `\n> [sprint-plan] Reusing persisted plan for sprint ${sprintN} (${planSynthesis.length} chars) — re-planning skipped so the same target files are continued.\n`,
530
+ };
531
+ }
532
+ else {
533
+ idealTrace("sprint.planCouncil.before", { runId: ctx.runId, sprintN });
534
+ const planGen = runCouncil(councilTopic, sessionModelId, [], ctx.runId, productLlm, ctx.respondToQuestion, ctx.respondToPreflight, ctx.processMessageFn ?? noopProcess, {
535
+ skipClarification: true,
536
+ cwd,
537
+ runDir,
538
+ suppressInlineMeta: isContextRailEnabled(),
539
+ // The product plan + spec were already debated (CB-1) and approved at the
540
+ // `/ideal` preflight. Re-gating and re-researching each sprint's internal
541
+ // plan strands the loop before implementation is ever reached (the exact
542
+ // "debate great, never implements" symptom). Auto-approve the per-sprint
543
+ // plan and reuse CB-1 research; the post-sprint customer verdict still lets
544
+ // the user review each sprint's OUTPUT.
545
+ autoApprovePreflight: true,
546
+ skipResearch: true,
547
+ // Automated per-sprint planning: suppress the interactive post-debate menu
548
+ // (it stranded the sprint before implementation — blocker 4/5) and skip the
549
+ // session-scoped persistence that FK-fails on the product-run id. The plan
550
+ // is auto-locked and control returns here for the Implementation stage.
551
+ sprintPlanningMode: true,
552
+ });
553
+ while (true) {
554
+ const step = await planGen.next();
555
+ if (step.done) {
556
+ planSynthesis = step.value ?? "";
557
+ break;
558
+ }
559
+ yield step.value;
226
560
  }
227
- yield step.value;
561
+ idealTrace("sprint.planCouncil.after", { runId: ctx.runId, sprintN, planSynthesisLen: planSynthesis.length });
562
+ // Persist so a resumed/retried sprint reuses this exact plan (and target folder).
563
+ await persistSprintPlan(planPath, planSynthesis);
228
564
  }
229
565
  // P4-C: close the planning phase row before opening implementation.
230
566
  yield phaseDone({
@@ -234,6 +570,7 @@ export async function* runSprint(args) {
234
570
  startedAt: planStartedAt,
235
571
  });
236
572
  // ── Step 4: Implement stage — pipe plan through host process loop ─────────
573
+ idealTrace("sprint.implementation.enter", { runId: ctx.runId, sprintN, planSynthesisLen: planSynthesis.length });
237
574
  yield { type: "content", content: `\n## Sprint ${sprintN} — Implementation\n` };
238
575
  const implPhaseId = `sprint-${sprintN}-implementation`;
239
576
  const implStartedAt = Date.now();
@@ -262,13 +599,28 @@ export async function* runSprint(args) {
262
599
  subtype: "sprint_stage",
263
600
  data: { sprintIndex: sprintN, stage: "implementation", runId: ctx.runId },
264
601
  });
602
+ // Defect fix (2026-07-08): the raw plan synthesis is a DECLARATIVE design
603
+ // document ("## Agreed Architecture / Function Signatures / Acceptance
604
+ // Criteria"). Passed verbatim as the orchestrator message it reads as
605
+ // something to discuss, so the impl turn narrated the plan back as markdown
606
+ // (finishReason "stop", zero edits) instead of applying it — observed live on
607
+ // the gsd-core migration. Prepend an explicit execution directive (module-level
608
+ // IMPL_EXECUTION_DIRECTIVE) so the PIL classifier routes it to the
609
+ // implement/edit path, not the respond path.
265
610
  // C2: Pre-impl gate — read decisions.lock.md and prepend to implementation prompt.
266
611
  // When lock file is missing (greenfield / no council with runDir), pass-through unchanged.
267
- let implPrompt = planSynthesis;
612
+ let implPrompt = planSynthesis.trim() ? IMPL_EXECUTION_DIRECTIVE + planSynthesis : planSynthesis;
268
613
  try {
269
614
  const lockContent = await readDecisionsLock(runDir);
270
615
  if (lockContent) {
271
- implPrompt = prependDecisionsLock(planSynthesis, lockContent);
616
+ // Prepend the lock to the DIRECTIVE-carrying implPrompt, NOT the bare
617
+ // planSynthesis. Passing planSynthesis here (the original 2026-07-08 C2
618
+ // gate bug) silently dropped IMPL_EXECUTION_DIRECTIVE + its
619
+ // SPRINT_EXECUTION_MARKER, so every council-backed sprint (a lock always
620
+ // exists once the council ran) reached the orchestrator as a bare design
621
+ // doc: the impl turn narrated the plan instead of executing it, classified
622
+ // taskType=null (4_096 output cap), then wedged on finishReason:"length".
623
+ implPrompt = prependDecisionsLock(implPrompt, lockContent);
272
624
  yield {
273
625
  type: "content",
274
626
  content: "\n> [decisions.lock.md] Locked decisions prepended to implementation prompt.\n",
@@ -278,16 +630,66 @@ export async function* runSprint(args) {
278
630
  catch {
279
631
  /* fail-open — lock read failure must not block implementation */
280
632
  }
633
+ // Wave 3 (2026-07-08): the impl turn was blind to files a prior sprint/run had
634
+ // already created, so it re-created them from scratch. Tell it which of the
635
+ // plan's OWN named target files already exist on disk so it reads + continues
636
+ // them instead of re-scaffolding. Empty on greenfield (nothing exists yet).
637
+ if (planSynthesis.trim()) {
638
+ const existingTargets = await detectExistingPlanTargets(planSynthesis, cwd);
639
+ if (existingTargets.length > 0) {
640
+ implPrompt = `${implPrompt}\n\n--- FILES ALREADY PRESENT ON DISK (prior-sprint work — READ and CONTINUE these; do NOT recreate them from scratch) ---\n${existingTargets
641
+ .map((f) => `- ${f}`)
642
+ .join("\n")}\n`;
643
+ yield {
644
+ type: "content",
645
+ content: `\n> [continuation] ${existingTargets.length} plan target file(s) already exist — instructed to continue, not recreate.\n`,
646
+ };
647
+ }
648
+ }
281
649
  let implError = null;
282
650
  if (ctx.processMessageFn && implPrompt.trim()) {
651
+ const useIsolated = shouldUseIsolatedImpl(!!ctx.runIsolatedTask);
283
652
  try {
284
- const implGen = ctx.processMessageFn(implPrompt);
285
- for await (const chunk of implGen) {
286
- yield chunk;
653
+ if (useIsolated && ctx.runIsolatedTask) {
654
+ // ISOLATED path run the sprint plan in a fresh, budget-capped child
655
+ // context that does NOT inherit the council-debate history. This is the
656
+ // fix for the ctx-overflow wedge: the sub-agent starts near-empty, has
657
+ // full tool access (edit/bash), compacts independently in-loop, and
658
+ // returns a compact ToolResult (its tool clutter is absorbed, not piped
659
+ // into the parent). No stream to watchdog — the sub-agent has its own
660
+ // stall + no-forward-progress guards (stall-watchdog.ts).
661
+ yield {
662
+ type: "content",
663
+ content: "\n> [isolated impl] Executing the sprint in a fresh sub-agent context " +
664
+ "(anti-overflow: does not inherit the debate history).\n",
665
+ };
666
+ const result = await ctx.runIsolatedTask({
667
+ agent: "general",
668
+ description: `Sprint ${sprintN} implementation`,
669
+ prompt: implPrompt,
670
+ modelId: ctx.sessionModelId,
671
+ });
672
+ if (!result.success) {
673
+ implError = result.error?.trim() || "isolated implementation task failed";
674
+ }
675
+ else if (result.output?.trim()) {
676
+ yield { type: "content", content: `\n${result.output.trim()}\n` };
677
+ }
678
+ }
679
+ else {
680
+ const implGen = ctx.processMessageFn(implPrompt);
681
+ // Guard the impl turn with an idle-chunk watchdog so a post-finish
682
+ // orchestrator hang surfaces as a phaseError instead of a silent wedge.
683
+ for await (const chunk of withImplIdleWatchdog(implGen, getImplIdleTimeoutMs(), sprintN)) {
684
+ yield chunk;
685
+ }
287
686
  }
288
687
  }
289
688
  catch (e) {
290
689
  implError = e instanceof Error ? e.message : String(e);
690
+ // No-Silent-Catch: the finally below surfaces a phaseError chunk, but log
691
+ // here too so the hang/failure is diagnosable from stderr / MUONROI logs.
692
+ console.error(`[sprint-runner] implementation stage failed (sprint ${sprintN}, run ${ctx.runId}): ${implError}`);
291
693
  }
292
694
  finally {
293
695
  // A3 FIX: phaseDone for implementation MUST always fire, even when
@@ -328,6 +730,76 @@ export async function* runSprint(args) {
328
730
  if (implError) {
329
731
  throw new Error(implError);
330
732
  }
733
+ // ── Step 4b: 4A completeness re-check ─────────────────────────────────────
734
+ // The impl turn can "finish" (finishReason stop) with plan action items
735
+ // unaddressed — narrated but not applied. Rather than an unconditional
736
+ // (2-3x cost) reviewer pass, spend ONE focused follow-up turn ONLY when
737
+ // plan-named target files are provably still missing on disk. No missing
738
+ // targets ⇒ no extra turn (the resume/migration case where the targets already
739
+ // exist is a no-op). A re-check failure never fails the sprint — the primary
740
+ // impl already succeeded and verify/tests are the real gate.
741
+ if (ctx.processMessageFn && getImplRecheckEnabled() && planSynthesis.trim()) {
742
+ const missing = await computeMissingPlanTargets(planSynthesis, cwd);
743
+ if (missing.length > 0) {
744
+ idealTrace("sprint.implementation.recheck", { runId: ctx.runId, sprintN, missing: missing.length });
745
+ const recheckPhaseId = `sprint-${sprintN}-impl-recheck`;
746
+ const recheckStartedAt = Date.now();
747
+ yield phaseStart({
748
+ phaseId: recheckPhaseId,
749
+ kind: "sprint_stage",
750
+ label: `Sprint ${sprintN} — Completeness re-check`,
751
+ detail: `${missing.length} plan target(s) still missing — finishing`,
752
+ startedAt: recheckStartedAt,
753
+ });
754
+ const recheckPrompt = "The sprint plan named these target files but they DO NOT exist on disk yet — the sprint is NOT " +
755
+ "finished. Create/complete each one NOW using your file-edit tools. Do NOT explain or re-plan; " +
756
+ "make the edits.\n" +
757
+ missing.map((f) => `- ${f}`).join("\n") +
758
+ "\n";
759
+ let recheckErr = null;
760
+ try {
761
+ const recheckGen = ctx.processMessageFn(recheckPrompt);
762
+ for await (const chunk of withImplIdleWatchdog(recheckGen, getImplIdleTimeoutMs(), sprintN)) {
763
+ yield chunk;
764
+ }
765
+ }
766
+ catch (e) {
767
+ recheckErr = e instanceof Error ? e.message : String(e);
768
+ console.error(`[sprint-runner] impl completeness re-check failed (sprint ${sprintN}, run ${ctx.runId}): ${recheckErr}`);
769
+ }
770
+ finally {
771
+ if (recheckErr) {
772
+ yield phaseError({
773
+ phaseId: recheckPhaseId,
774
+ kind: "sprint_stage",
775
+ label: `Sprint ${sprintN} — Completeness re-check`,
776
+ startedAt: recheckStartedAt,
777
+ errorMessage: recheckErr,
778
+ });
779
+ }
780
+ else {
781
+ yield phaseDone({
782
+ phaseId: recheckPhaseId,
783
+ kind: "sprint_stage",
784
+ label: `Sprint ${sprintN} — Completeness re-check`,
785
+ startedAt: recheckStartedAt,
786
+ });
787
+ }
788
+ }
789
+ const stillMissing = await computeMissingPlanTargets(planSynthesis, cwd);
790
+ idealTrace("sprint.implementation.recheck.after", {
791
+ runId: ctx.runId,
792
+ sprintN,
793
+ stillMissing: stillMissing.length,
794
+ });
795
+ if (stillMissing.length > 0) {
796
+ yield {
797
+ type: "content",
798
+ content: `\n> [completeness] ${stillMissing.length} plan target(s) still missing after re-check — deferring to verify.\n`,
799
+ };
800
+ }
801
+ }
802
+ }
331
803
  // ── Step 5: Verify stage ──────────────────────────────────────────────────
332
804
  yield { type: "content", content: `\n## Sprint ${sprintN} — Verification\n` };
333
805
  const verifyPhaseId = `sprint-${sprintN}-verification`;
@@ -351,7 +823,30 @@ export async function* runSprint(args) {
351
823
  subtype: "sprint_stage",
352
824
  data: { sprintIndex: sprintN, stage: "verification", runId: ctx.runId },
353
825
  });
354
- const verifyResult = await runVerifyOrchestration(verifyAgent);
826
+ // A "Skip verify" recovery option: the user chose to bypass a broken verify
827
+ // stage (e.g. shuru sandbox unavailable on Windows that hangs the watchdog
828
+ // every sprint). Treat verify as a PASS with an explicit synthetic output so
829
+ // the done-gate is not blocked, and log loudly so the bypass is auditable.
830
+ // The env var is set by the recovery-card handler and reset on the next fresh
831
+ // `/ideal "<idea>"` start, so a new run re-enables verification.
832
+ const skipVerify = process.env.MUONROI_SPRINT_SKIP_VERIFY === "1";
833
+ let verifyResult;
834
+ if (skipVerify) {
835
+ console.error(`[sprint-runner] MUONROI_SPRINT_SKIP_VERIFY=1 — verify stage bypassed (sprint ${sprintN}, run ${ctx.runId})`);
836
+ verifyResult = {
837
+ success: true,
838
+ // Include the canonical PASS marker so parseVerifyResult → PASS (the user
839
+ // explicitly opted to treat verify as satisfied for this recovery).
840
+ output: `${VERIFY_PASS_MARKER}\nverify skipped by user recovery choice (MUONROI_SPRINT_SKIP_VERIFY=1)`,
841
+ };
842
+ yield {
843
+ type: "content",
844
+ content: `\n> [skip-verify] Verify stage bypassed for sprint ${sprintN} (user recovery choice).\n`,
845
+ };
846
+ }
847
+ else {
848
+ verifyResult = await runVerifyWithWatchdog(verifyAgent, ctx.runId, sprintN);
849
+ }
355
850
  yield phaseDone({
356
851
  phaseId: verifyPhaseId,
357
852
  kind: "sprint_stage",
@@ -524,8 +1019,39 @@ export async function* runSprint(args) {
524
1019
  await appendIteration(ctx.flowDir, ctx.runId, iter);
525
1020
  // Update Resume Digest in state.md so PIL Layer 5 + future resume can pick it up
526
1021
  const stateMap = (await readArtifact(runDir, "state.md")) ?? { preamble: "", sections: new Map() };
527
- stateMap.sections.set("Resume Digest", `Sprint: ${sprintN} | Stage: ${iter.stage} | Score: ${verdict.score.toFixed(2)} | Verify: ${verifyVerdict}`);
1022
+ stateMap.sections.set("Resume Digest", renderResumeDigest({
1023
+ stage: `sprint-${sprintN}`,
1024
+ lastCompleted: `sprint-${sprintN} ${iter.stage}`,
1025
+ nextAction: verdict.pass
1026
+ ? "Definition-of-Done met — advance to the next phase or ship"
1027
+ : `Retry sprint ${sprintN}: ${verdict.failedCondition ?? "continue toward Definition-of-Done"}`,
1028
+ sprintN,
1029
+ score: verdict.score,
1030
+ verify: verifyVerdict,
1031
+ updatedAt: new Date().toISOString(),
1032
+ }));
528
1033
  await writeArtifact(runDir, "state.md", stateMap);
1034
+ // Part A — persist a first-class per-sprint outcome record + verify report so
1035
+ // `/ideal review` and cross-run memory render real sprint history (not just
1036
+ // the fire-and-forget EE boundary event, which leaves nothing on disk).
1037
+ try {
1038
+ await writeSprintOutcome(ctx.flowDir, ctx.runId, {
1039
+ sprintN,
1040
+ pass: verdict.pass,
1041
+ score: verdict.score,
1042
+ verify: verifyVerdict,
1043
+ failedCondition: verdict.failedCondition ?? undefined,
1044
+ criteriaMet: iter.criteriaMet,
1045
+ criteriaPartial: iter.criteriaPartial,
1046
+ criteriaUnmet: iter.criteriaUnmet,
1047
+ finishedAt: new Date().toISOString(),
1048
+ });
1049
+ const verifyReport = (verifyResult.error?.trim() ? verifyResult.error : (verifyResult.output ?? "")).trim() || "(no verify output)";
1050
+ await writeSprintVerify(ctx.flowDir, ctx.runId, sprintN, `# Sprint ${sprintN} verify — ${verifyVerdict} (score ${verdict.score.toFixed(2)})\n\n\`\`\`\n${verifyReport.slice(0, 8000)}\n\`\`\`\n`);
1051
+ }
1052
+ catch {
1053
+ /* non-critical — sprint artifacts are a review surface, never derail the loop */
1054
+ }
529
1055
  // Emit ProgressSnapshot on sprint boundary so the user sees rolling progress.
530
1056
  // Wrapped in try/catch — never crash sprint-runner because the snapshot failed.
531
1057
  try {
@@ -557,6 +1083,23 @@ export async function* runSprint(args) {
557
1083
  }).catch(() => {
558
1084
  /* EE failures must not derail the loop */
559
1085
  });
1086
+ // Part C — write-during-execution: persist this sprint's outcome as a NEW
1087
+ // workflow_sprint experience (not just reinforcement) so a later sprint in the
1088
+ // SAME run — or a future run — can recall "how this kind of sprint went".
1089
+ // gate-on-outcome (Kill #4): fired here, AFTER verify+judge produced a verdict.
1090
+ fireAndForgetWorkflowEvent({
1091
+ kind: "sprint-execution",
1092
+ phaseRef: `runs/${ctx.runId}#sprint-${sprintN}`,
1093
+ sessionId: ctx.runId,
1094
+ text: `Sprint ${sprintN} ${verdict.pass ? "passed" : "failed"} (score ${verdict.score.toFixed(2)}, verify ${verifyVerdict})${verdict.failedCondition ? ` — ${verdict.failedCondition}` : ""}`,
1095
+ payload: {
1096
+ sprintN,
1097
+ pass: verdict.pass,
1098
+ score: verdict.score,
1099
+ verify: verifyVerdict,
1100
+ failedCondition: verdict.failedCondition ?? null,
1101
+ },
1102
+ });
560
1103
  // ── Step 9: If not done, surface continue-feedback to the user ───────────
561
1104
  if (!verdict.pass) {
562
1105
  const fb = buildContinueFeedback(verdict, verifyResult, currentCriteria);