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
@@ -1,21 +1,23 @@
1
1
  import { promises as fs } from "node:fs";
2
2
  import * as path from "node:path";
3
+ import { readDebateCheckpoint } from "../council/debate-checkpoint.js";
3
4
  import { resolveLeaderModel } from "../council/leader.js";
4
5
  import { routeModel as eeRouteModel } from "../ee/bridge.js";
5
6
  import { fireAndForgetPhaseOutcome } from "../ee/phase-outcome.js";
6
7
  import { readArtifact } from "../flow/artifact-io.js";
8
+ import { parseResumeDigest, readSprintOutcomes } from "../flow/run-artifacts.js";
7
9
  import { createRun, loadRun } from "../flow/run-manager.js";
8
10
  import { getModelsForProvider } from "../models/registry.js";
9
11
  import { loadKeyForProvider } from "../providers/keychain.js";
10
12
  import { ALL_PROVIDER_IDS } from "../providers/types.js";
11
13
  import { defaultResolveChannelId, maybeAutoFire } from "../reporter/auto-fire.js";
14
+ import { clearWorkspaceFocus, setWorkspaceFocus } from "../state/active-run.js";
12
15
  import { logInteraction, logUIInteraction } from "../storage/index.js";
13
- import { activeRunStore } from "../ui/state/active-run.js";
14
16
  import { markIterationCrashed, readIterations, readManifest, writeManifest } from "./artifact-io.js";
15
17
  import { buildBacklog } from "./backlog-builder.js";
16
18
  import { readBacklog, writeBacklog } from "./backlog-store.js";
17
19
  import { formatCostPreview, previewRunCost } from "./cost-preview.js";
18
- import { extractRunToEE } from "./cross-run-memory.js";
20
+ import { composeRunTranscript, extractRunToEE } from "./cross-run-memory.js";
19
21
  import { buildContinueFeedback } from "./feedback-routing.js";
20
22
  import { runLoopDriver } from "./loop-driver.js";
21
23
  import { resolveRoles } from "./role-registry.js";
@@ -38,6 +40,8 @@ export async function* runProductLoop(opts) {
38
40
  switch (sub) {
39
41
  case "status":
40
42
  return yield* runStatus(opts);
43
+ case "review":
44
+ return yield* runReview(opts);
41
45
  case "resume":
42
46
  return yield* runResume(opts);
43
47
  case "abort":
@@ -46,14 +50,30 @@ export async function* runProductLoop(opts) {
46
50
  return yield* runShip(opts);
47
51
  default: {
48
52
  // Mode C dispatch — see .planning/MAINTAIN-MODE.md "Trigger mechanism".
49
- // 1. Explicit --maintain → Mode C
50
- // 2. Explicit --new → Mode A (current behavior, skip detection)
51
- // 3. Auto-detect: verify recipe present in cwd Mode C
52
- // 4. Otherwise → Mode A
53
+ // 1. Explicit --maintain → Mode C (strongest signal; wins over --force-council)
54
+ // 2. Explicit --new → Mode A (skip recipe detection)
55
+ // 3. --force-council → Mode A (user explicitly wants the full Council/loop)
56
+ // 4. Auto-detect: verify recipe present in cwd → Mode C
57
+ // 5. Otherwise → Mode A
53
58
  if (opts.mode === "maintain") {
54
59
  return yield* runMaintain(opts);
55
60
  }
56
- if (opts.mode !== "new" && opts.detectVerifyRecipe) {
61
+ // `--force-council` must bypass the recipe auto-detect. Without this,
62
+ // ANY recipe-bearing repo (package.json/*.csproj/…) routes to runMaintain
63
+ // here — BEFORE the forceCouncil checks below (:189 / :197) are ever
64
+ // reached — so `/ideal --force-council` in an existing project was silently
65
+ // downgraded to maint-edit (observed: route-decision forceCouncil:false,
66
+ // path:maintain). Explicit --maintain above still wins over --force-council.
67
+ //
68
+ // complexity==="high" ALSO bypasses the recipe auto-detect. An
69
+ // architectural change (migration, SDK removal, subsystem rewrite) in a
70
+ // recipe-bearing repo must still earn the full Council — the very intent
71
+ // the complexity gate at :196-207 (and comment :188-195) documents. Before
72
+ // this guard, that gate was dead code for any repo with a verify recipe
73
+ // (real orchestrator ALWAYS wires detectVerifyRecipe), so a high-complexity
74
+ // /ideal was silently downgraded to maint-edit and jumped straight to Edit
75
+ // with no debate (observed: route-decision complexity:high path:maintain).
76
+ if (opts.mode !== "new" && !opts.flags.forceCouncil && opts.complexity !== "high" && opts.detectVerifyRecipe) {
57
77
  try {
58
78
  const recipe = await opts.detectVerifyRecipe();
59
79
  if (recipe) {
@@ -86,10 +106,18 @@ export async function* runProductLoop(opts) {
86
106
  };
87
107
  return yield* runStart(forcedOpts);
88
108
  }
89
- // Existing repo + complexity≠high → hot-path. The leader can grep
90
- // the source instead of interviewing the user. Only architectural
91
- // changes (complexity=high) still warrant the full Council debate.
92
- if (existingRepoBypass && opts.complexity !== "high" && !opts.flags.forceCouncil) {
109
+ // Existing repo + complexity≠high + well-specified → hot-path. The leader
110
+ // can grep the source instead of interviewing the user. Two things still
111
+ // warrant the full Council/interview path: an architectural change
112
+ // (complexity=high / heavy), OR a request the model flagged as
113
+ // UNDERSPECIFIED (needsClarification) — a standard task missing a target
114
+ // or design decision must be clarified before code. A `quick`
115
+ // (complexity=low) task always hot-paths (handled below) even when
116
+ // underspecified: a trivial ask never earns an interview.
117
+ if (existingRepoBypass &&
118
+ opts.complexity !== "high" &&
119
+ !(opts.needsClarification && opts.complexity !== "low") &&
120
+ !opts.flags.forceCouncil) {
93
121
  return yield* runHotPath(opts);
94
122
  }
95
123
  if (opts.complexity === "low" && !opts.flags.forceCouncil) {
@@ -148,6 +176,22 @@ async function* runHotPath(opts) {
148
176
  stack: flags.stack,
149
177
  createdAt: new Date(),
150
178
  });
179
+ if (opts.cwd) {
180
+ try {
181
+ const { isGsdNativeEnabled } = await import("../gsd/flags.js");
182
+ if (isGsdNativeEnabled()) {
183
+ const { ensureProductPlanningWorkspace } = await import("../gsd/product-workspace.js");
184
+ ensureProductPlanningWorkspace(opts.cwd, {
185
+ idea,
186
+ sessionModelId: opts.sessionModelId,
187
+ runId,
188
+ });
189
+ }
190
+ }
191
+ catch (err) {
192
+ console.error(`[ideal/hot-path] gsd product workspace bootstrap failed: ${err.message}`);
193
+ }
194
+ }
151
195
  yield {
152
196
  type: "content",
153
197
  content: "\n> hot-path: complexity=low → single sprint, no council debate\n",
@@ -160,6 +204,7 @@ async function* runHotPath(opts) {
160
204
  kind: "route-decision",
161
205
  path: "hot-path",
162
206
  complexity: opts.complexity ?? "low",
207
+ underspecified: !!opts.needsClarification,
163
208
  forceCouncil: false,
164
209
  runId,
165
210
  });
@@ -201,7 +246,7 @@ async function* runHotPath(opts) {
201
246
  try {
202
247
  const { productSlug: deriveSlug } = await import("./product-identity.js");
203
248
  const slug = deriveSlug(idea);
204
- activeRunStore.setActiveRun(runId, flowDir, slug);
249
+ await setWorkspaceFocus(flowDir, { runId, productSlug: slug, reason: "sprint-plan-committed" });
205
250
  fireAutoReport("sprint-plan-committed", { runId, flowDir, productSlug: slug, sprintCount: 1 });
206
251
  }
207
252
  catch {
@@ -233,6 +278,7 @@ async function* runHotPath(opts) {
233
278
  cwd: opts.cwd,
234
279
  sessionId: opts.sessionId,
235
280
  processMessageFn: opts.processMessageFn,
281
+ runIsolatedTask: opts.runIsolatedTask,
236
282
  detectVerifyRecipe: opts.detectVerifyRecipe,
237
283
  skipPriorContext: opts.skipPriorContext,
238
284
  sufficiencyMissing: opts.sufficiencyMissing,
@@ -556,6 +602,22 @@ async function* runStart(opts) {
556
602
  stack: flags.stack,
557
603
  createdAt: new Date(),
558
604
  });
605
+ if (opts.cwd) {
606
+ try {
607
+ const { isGsdNativeEnabled } = await import("../gsd/flags.js");
608
+ if (isGsdNativeEnabled()) {
609
+ const { ensureProductPlanningWorkspace } = await import("../gsd/product-workspace.js");
610
+ ensureProductPlanningWorkspace(opts.cwd, {
611
+ idea,
612
+ sessionModelId: opts.sessionModelId,
613
+ runId,
614
+ });
615
+ }
616
+ }
617
+ catch (err) {
618
+ console.error(`[ideal] gsd product workspace bootstrap failed: ${err.message}`);
619
+ }
620
+ }
559
621
  // Surface a cost-vs-cap preview before the loop kicks off so $50 isn't
560
622
  // an arbitrary number — show predicted spend per sprint × max-sprints
561
623
  // against the configured cap, with a recommended max-sprints if it
@@ -574,6 +636,7 @@ async function* runStart(opts) {
574
636
  kind: "route-decision",
575
637
  path: "council",
576
638
  complexity: opts.complexity ?? "unknown",
639
+ underspecified: !!opts.needsClarification,
577
640
  forceCouncil: !!opts.flags.forceCouncil,
578
641
  sufficiencyMissing: opts.sufficiencyMissing ?? [],
579
642
  runId,
@@ -604,6 +667,7 @@ async function* runStart(opts) {
604
667
  cwd: opts.cwd,
605
668
  sessionId: opts.sessionId,
606
669
  processMessageFn: opts.processMessageFn,
670
+ runIsolatedTask: opts.runIsolatedTask,
607
671
  detectVerifyRecipe: opts.detectVerifyRecipe,
608
672
  skipPriorContext: opts.skipPriorContext,
609
673
  sufficiencyMissing: opts.sufficiencyMissing,
@@ -688,7 +752,7 @@ async function* runStart(opts) {
688
752
  try {
689
753
  const { productSlug: deriveSlug } = await import("./product-identity.js");
690
754
  const slug = deriveSlug(idea);
691
- activeRunStore.setActiveRun(runId, flowDir, slug);
755
+ await setWorkspaceFocus(flowDir, { runId, productSlug: slug, reason: "sprint-plan-committed" });
692
756
  fireAutoReport("sprint-plan-committed", { runId, flowDir, productSlug: slug, sprintCount });
693
757
  }
694
758
  catch {
@@ -880,7 +944,7 @@ async function* drainSprints(args) {
880
944
  const { productSlug: deriveSlug } = await import("./product-identity.js");
881
945
  const slug = deriveSlug(productSpec.idea);
882
946
  fireAutoReport("sprint-halt", { runId: ctx.runId, flowDir: ctx.flowDir, productSlug: slug, haltReason });
883
- activeRunStore.clearActiveRun();
947
+ clearWorkspaceFocus();
884
948
  }
885
949
  catch {
886
950
  /* best-effort */
@@ -934,7 +998,7 @@ async function* drainSprints(args) {
934
998
  const { productSlug: deriveSlug } = await import("./product-identity.js");
935
999
  const slug = deriveSlug(productSpec.idea);
936
1000
  fireAutoReport("sprint-halt", { runId: ctx.runId, flowDir: ctx.flowDir, productSlug: slug, haltReason: msg });
937
- activeRunStore.clearActiveRun();
1001
+ clearWorkspaceFocus();
938
1002
  }
939
1003
  catch {
940
1004
  /* best-effort */
@@ -1028,7 +1092,7 @@ async function* drainSprints(args) {
1028
1092
  }
1029
1093
  }
1030
1094
  // B1: clear active-run on successful ship.
1031
- activeRunStore.clearActiveRun();
1095
+ clearWorkspaceFocus();
1032
1096
  return {
1033
1097
  runId: ctx.runId,
1034
1098
  stage: "approved",
@@ -1052,7 +1116,7 @@ async function* drainSprints(args) {
1052
1116
  content: `\n> Reached max-sprints (${flags.maxSprints}) without satisfying Definition-of-Done.\n`,
1053
1117
  };
1054
1118
  // B1: clear active-run when max-sprints reached.
1055
- activeRunStore.clearActiveRun();
1119
+ clearWorkspaceFocus();
1056
1120
  return {
1057
1121
  runId: ctx.runId,
1058
1122
  stage: "halted",
@@ -1247,6 +1311,8 @@ async function* runPhasesPath(args) {
1247
1311
  remainingUsd: async () => Math.max(0, manifest.capUsd - (await getProductSpentUsd(ctx.runId))),
1248
1312
  awaitCustomerVerdict,
1249
1313
  sprintRunner,
1314
+ projectCwd: ctx.cwd,
1315
+ idea: ctx.idea,
1250
1316
  });
1251
1317
  let phaseOutcome = { pass: false };
1252
1318
  while (true) {
@@ -1384,12 +1450,27 @@ async function* runStatus(opts) {
1384
1450
  return { runId: opts.runId, stage: "error", success: false, reason: "not_found" };
1385
1451
  }
1386
1452
  const iters = await readIterations(opts.flowDir, opts.runId);
1387
- yield {
1388
- type: "content",
1389
- content: `Run ${opts.runId}: ${m.idea}\n` +
1390
- `Cap: $${m.capUsd} MaxSprints: ${m.maxSprints} DoneThreshold: ${m.doneThreshold}\n` +
1391
- `Iterations: ${iters.length} Aborted: ${m.aborted ?? false} DoneAt: ${m.doneAt?.toISOString() ?? "—"}\n`,
1392
- };
1453
+ const digest = await readResumeDigest(opts.flowDir, opts.runId);
1454
+ const outcomes = await readSprintOutcomes(opts.flowDir, opts.runId).catch(() => []);
1455
+ const lines = [
1456
+ `Run ${opts.runId}: ${m.idea}`,
1457
+ `Cap: $${m.capUsd} MaxSprints: ${m.maxSprints} DoneThreshold: ${m.doneThreshold}`,
1458
+ `Iterations: ${iters.length} Aborted: ${m.aborted ?? false} DoneAt: ${m.doneAt?.toISOString() ?? "—"}`,
1459
+ ];
1460
+ if (digest) {
1461
+ lines.push("", "Resume Digest:", ` Stage: ${digest.stage}` +
1462
+ (typeof digest.sprintN === "number" ? ` Sprint: ${digest.sprintN}` : "") +
1463
+ (typeof digest.score === "number" ? ` Score: ${digest.score.toFixed(2)}` : "") +
1464
+ (digest.verify ? ` Verify: ${digest.verify}` : ""), ` Next: ${digest.nextAction || "—"}`);
1465
+ }
1466
+ if (outcomes.length > 0) {
1467
+ lines.push("", "Sprints:");
1468
+ for (const o of outcomes) {
1469
+ lines.push(` #${o.sprintN} ${o.pass ? "✓ pass" : "✗ fail"} score=${o.score.toFixed(2)} verify=${o.verify}` +
1470
+ (o.failedCondition ? ` (${o.failedCondition})` : ""));
1471
+ }
1472
+ }
1473
+ yield { type: "content", content: `${lines.join("\n")}\n` };
1393
1474
  return { runId: opts.runId, stage: "approved", success: true };
1394
1475
  }
1395
1476
  const lines = [`Active runs (${entries.length}):`];
@@ -1398,26 +1479,108 @@ async function* runStatus(opts) {
1398
1479
  const iters = await readIterations(opts.flowDir, id).catch(() => []);
1399
1480
  if (!m)
1400
1481
  continue;
1401
- lines.push(` ${id} ${m.idea.slice(0, 60)} sprints=${iters.length} aborted=${m.aborted ?? false}`);
1482
+ const digest = await readResumeDigest(opts.flowDir, id).catch(() => null);
1483
+ const stagePart = digest ? ` stage=${digest.stage}` : "";
1484
+ lines.push(` ${id} ${m.idea.slice(0, 60)} sprints=${iters.length}${stagePart} aborted=${m.aborted ?? false}`);
1402
1485
  }
1403
1486
  yield { type: "content", content: `${lines.join("\n")}\n` };
1404
1487
  return { runId: "", stage: "approved", success: true };
1405
1488
  }
1489
+ /**
1490
+ * Read + parse the structured Resume Digest from a run's top-level state.md.
1491
+ * Returns null when the run has no digest yet (or only a legacy one-liner).
1492
+ */
1493
+ async function readResumeDigest(flowDir, runId) {
1494
+ const run = await loadRun(flowDir, runId).catch(() => null);
1495
+ if (!run)
1496
+ return null;
1497
+ return parseResumeDigest(run.state.sections.get("Resume Digest"));
1498
+ }
1499
+ /**
1500
+ * `/ideal review [runId]` — render a run's composed transcript plus a scored
1501
+ * sprint table. Read-only. With no runId, reviews the most recent run (any
1502
+ * status — review is a post-hoc lens, not restricted to incomplete runs).
1503
+ */
1504
+ async function* runReview(opts) {
1505
+ let resolvedRunId = opts.runId;
1506
+ if (!resolvedRunId) {
1507
+ const runsRoot = path.join(opts.flowDir, "runs");
1508
+ let entries = [];
1509
+ try {
1510
+ entries = await fs.readdir(runsRoot);
1511
+ }
1512
+ catch {
1513
+ yield { type: "content", content: "No runs to review.\n" };
1514
+ return { runId: "", stage: "error", success: false, reason: "no_runs" };
1515
+ }
1516
+ const dated = [];
1517
+ for (const id of entries) {
1518
+ const m = await readManifest(opts.flowDir, id).catch(() => null);
1519
+ if (!m)
1520
+ continue;
1521
+ const createdAt = m.createdAt instanceof Date && !Number.isNaN(m.createdAt.getTime()) ? m.createdAt.getTime() : 0;
1522
+ dated.push({ id, createdAt });
1523
+ }
1524
+ if (dated.length === 0) {
1525
+ yield { type: "content", content: "No runs to review.\n" };
1526
+ return { runId: "", stage: "error", success: false, reason: "no_runs" };
1527
+ }
1528
+ dated.sort((a, b) => b.createdAt - a.createdAt);
1529
+ resolvedRunId = dated[0].id;
1530
+ }
1531
+ const manifest = await readManifest(opts.flowDir, resolvedRunId);
1532
+ if (!manifest) {
1533
+ yield { type: "content", content: `Run not found: ${resolvedRunId}\n` };
1534
+ return { runId: resolvedRunId, stage: "error", success: false, reason: "not_found" };
1535
+ }
1536
+ const header = [
1537
+ `# Review — run ${resolvedRunId}`,
1538
+ "",
1539
+ `Idea: ${manifest.idea}`,
1540
+ `Aborted: ${manifest.aborted ?? false} DoneAt: ${manifest.doneAt?.toISOString() ?? "—"}`,
1541
+ ];
1542
+ const digest = await readResumeDigest(opts.flowDir, resolvedRunId);
1543
+ if (digest) {
1544
+ header.push(`Last stage: ${digest.stage} — ${digest.nextAction || "—"}`);
1545
+ }
1546
+ const outcomes = await readSprintOutcomes(opts.flowDir, resolvedRunId).catch(() => []);
1547
+ if (outcomes.length > 0) {
1548
+ header.push("", "## Sprint scores", "", "| Sprint | Result | Score | Verify | Failed condition |", "|---|---|---|---|---|");
1549
+ for (const o of outcomes) {
1550
+ header.push(`| ${o.sprintN} | ${o.pass ? "pass" : "fail"} | ${o.score.toFixed(2)} | ${o.verify} | ${o.failedCondition ?? "—"} |`);
1551
+ }
1552
+ }
1553
+ yield { type: "content", content: `${header.join("\n")}\n` };
1554
+ // The composed transcript (manifest/roadmap/delegations/gray-areas) rounds out
1555
+ // the review with the actual debate + spec text. Bounded to 32KB by the composer.
1556
+ const transcript = await composeRunTranscript(opts.flowDir, resolvedRunId).catch(() => "");
1557
+ if (transcript.trim()) {
1558
+ yield { type: "content", content: `\n## Transcript\n${transcript}\n` };
1559
+ }
1560
+ return { runId: resolvedRunId, stage: "approved", success: true };
1561
+ }
1406
1562
  async function* runAbort(opts) {
1407
- if (!opts.runId) {
1408
- yield { type: "content", content: "error: abort requires a runId\n" };
1409
- return { runId: "", stage: "error", success: false, reason: "missing_runId" };
1563
+ // A/B — bare `/ideal abort` (no runId, e.g. the recovery card's Abort option):
1564
+ // auto-detect the newest incomplete run, mirroring resume.
1565
+ let resolvedRunId = opts.runId;
1566
+ if (!resolvedRunId) {
1567
+ const latest = await findLatestIncompleteRun(opts.flowDir);
1568
+ if (!latest) {
1569
+ yield { type: "content", content: "No incomplete run to abort.\n" };
1570
+ return { runId: "", stage: "error", success: false, reason: "no_incomplete_run" };
1571
+ }
1572
+ resolvedRunId = latest.id;
1410
1573
  }
1411
- const m = await readManifest(opts.flowDir, opts.runId);
1574
+ const m = await readManifest(opts.flowDir, resolvedRunId);
1412
1575
  if (!m) {
1413
- yield { type: "content", content: `Run not found: ${opts.runId}\n` };
1414
- return { runId: opts.runId, stage: "error", success: false, reason: "not_found" };
1576
+ yield { type: "content", content: `Run not found: ${resolvedRunId}\n` };
1577
+ return { runId: resolvedRunId, stage: "error", success: false, reason: "not_found" };
1415
1578
  }
1416
- await writeManifest(opts.flowDir, opts.runId, { ...m, aborted: true, doneAt: new Date() });
1579
+ await writeManifest(opts.flowDir, resolvedRunId, { ...m, aborted: true, doneAt: new Date() });
1417
1580
  // Fire-and-forget EE phase-outcome=aborted (extension landed in 13-05).
1418
1581
  try {
1419
1582
  fireAndForgetPhaseOutcome({
1420
- sessionId: opts.runId,
1583
+ sessionId: resolvedRunId,
1421
1584
  phaseName: "product-loop",
1422
1585
  outcome: "aborted",
1423
1586
  });
@@ -1431,9 +1594,9 @@ async function* runAbort(opts) {
1431
1594
  // EE client is non-fatal (offline queue absorbs transport failures).
1432
1595
  // P1.6: log telemetry for the extract outcome.
1433
1596
  {
1434
- const eeResult = await extractRunToEE(opts.flowDir, opts.runId, opts.cwd ?? process.cwd());
1597
+ const eeResult = await extractRunToEE(opts.flowDir, resolvedRunId, opts.cwd ?? process.cwd());
1435
1598
  try {
1436
- logInteraction(opts.sessionId ?? opts.runId ?? "abort", "ee_injection", {
1599
+ logInteraction(opts.sessionId ?? resolvedRunId ?? "abort", "ee_injection", {
1437
1600
  eventSubtype: "extract",
1438
1601
  durationMs: Math.round(eeResult.durationMs),
1439
1602
  data: {
@@ -1447,39 +1610,106 @@ async function* runAbort(opts) {
1447
1610
  // DB errors must not break /ideal
1448
1611
  }
1449
1612
  }
1450
- yield { type: "content", content: `Aborted run ${opts.runId}.\n` };
1451
- return { runId: opts.runId, stage: "halted", success: false, reason: "aborted" };
1613
+ yield { type: "content", content: `Aborted run ${resolvedRunId}.\n` };
1614
+ return { runId: resolvedRunId, stage: "halted", success: false, reason: "aborted" };
1615
+ }
1616
+ /**
1617
+ * B — Auto-detect the newest resumable run.
1618
+ *
1619
+ * "Resumable" = a run that has a manifest (early pre-manifest crashes are not
1620
+ * replayable) AND is neither aborted nor terminal (`doneAt` is set on done-gate
1621
+ * pass / ship / abort). Sorted by manifest `createdAt` descending so a bare
1622
+ * `/ideal resume` continues the most recent incomplete run without the user
1623
+ * having to remember (or type) the runId.
1624
+ */
1625
+ async function findLatestIncompleteRun(flowDir) {
1626
+ const runsRoot = path.join(flowDir, "runs");
1627
+ let entries;
1628
+ try {
1629
+ entries = await fs.readdir(runsRoot);
1630
+ }
1631
+ catch (err) {
1632
+ // No runs directory yet → nothing to resume. Not an error worth surfacing.
1633
+ if (err?.code !== "ENOENT") {
1634
+ console.error(`[product-loop] findLatestIncompleteRun: readdir failed: ${err?.message}`);
1635
+ }
1636
+ return null;
1637
+ }
1638
+ const candidates = [];
1639
+ for (const id of entries) {
1640
+ const m = await readManifest(flowDir, id).catch((e) => {
1641
+ console.error(`[product-loop] findLatestIncompleteRun: manifest read failed for ${id}: ${e?.message}`);
1642
+ return null;
1643
+ });
1644
+ if (!m)
1645
+ continue; // no manifest → not resumable
1646
+ if (m.aborted)
1647
+ continue; // hard-killed
1648
+ if (m.doneAt)
1649
+ continue; // terminal (done / shipped)
1650
+ const createdAt = m.createdAt instanceof Date && !Number.isNaN(m.createdAt.getTime()) ? m.createdAt.getTime() : 0;
1651
+ candidates.push({ id, idea: m.idea, createdAt });
1652
+ }
1653
+ if (candidates.length === 0)
1654
+ return null;
1655
+ candidates.sort((a, b) => b.createdAt - a.createdAt);
1656
+ const top = candidates[0];
1657
+ return { id: top.id, idea: top.idea };
1452
1658
  }
1453
1659
  async function* runResume(opts) {
1454
- if (!opts.runId) {
1455
- yield { type: "content", content: "error: resume requires a runId\n" };
1456
- return { runId: "", stage: "error", success: false, reason: "missing_runId" };
1660
+ // B — bare `/ideal resume` (no runId): auto-detect the newest incomplete run.
1661
+ let resolvedRunId = opts.runId;
1662
+ if (!resolvedRunId) {
1663
+ const latest = await findLatestIncompleteRun(opts.flowDir);
1664
+ if (!latest) {
1665
+ yield {
1666
+ type: "content",
1667
+ content: 'No incomplete run to resume. Start one with /ideal "<idea>".\n',
1668
+ };
1669
+ return { runId: "", stage: "error", success: false, reason: "no_incomplete_run" };
1670
+ }
1671
+ resolvedRunId = latest.id;
1672
+ yield {
1673
+ type: "content",
1674
+ content: `Resuming latest incomplete run ${resolvedRunId}: ${latest.idea.slice(0, 60)}\n`,
1675
+ };
1457
1676
  }
1458
- const run = await loadRun(opts.flowDir, opts.runId);
1677
+ const run = await loadRun(opts.flowDir, resolvedRunId);
1459
1678
  if (!run) {
1460
- yield { type: "content", content: `Run not found: ${opts.runId}\n` };
1461
- return { runId: opts.runId, stage: "error", success: false, reason: "not_found" };
1679
+ yield { type: "content", content: `Run not found: ${resolvedRunId}\n` };
1680
+ return { runId: resolvedRunId, stage: "error", success: false, reason: "not_found" };
1462
1681
  }
1463
- const manifest = await readManifest(opts.flowDir, opts.runId);
1682
+ const manifest = await readManifest(opts.flowDir, resolvedRunId);
1464
1683
  if (!manifest) {
1465
- yield { type: "content", content: `Manifest missing for ${opts.runId}\n` };
1466
- return { runId: opts.runId, stage: "error", success: false, reason: "manifest_missing" };
1684
+ yield { type: "content", content: `Manifest missing for ${resolvedRunId}\n` };
1685
+ return { runId: resolvedRunId, stage: "error", success: false, reason: "manifest_missing" };
1467
1686
  }
1468
1687
  if (manifest.aborted) {
1469
- yield { type: "content", content: `Run ${opts.runId} was aborted; cannot resume.\n` };
1470
- return { runId: opts.runId, stage: "halted", success: false, reason: "aborted" };
1688
+ yield { type: "content", content: `Run ${resolvedRunId} was aborted; cannot resume.\n` };
1689
+ return { runId: resolvedRunId, stage: "halted", success: false, reason: "aborted" };
1690
+ }
1691
+ // Surface the Resume Digest so the user sees where the run stopped and what
1692
+ // resuming will do — the whole point of giving the digest real content.
1693
+ {
1694
+ const digest = parseResumeDigest(run.state.sections.get("Resume Digest"));
1695
+ if (digest) {
1696
+ yield {
1697
+ type: "content",
1698
+ content: `> Resume Digest — stage: ${digest.stage}${typeof digest.sprintN === "number" ? ` (sprint ${digest.sprintN})` : ""} · next: ${digest.nextAction || "—"}\n`,
1699
+ };
1700
+ }
1471
1701
  }
1472
1702
  // Detect crashed in-flight sprint: an iterations.md entry without a closing
1473
1703
  // Verify line is treated as crashed. Our schema always writes the Verify line
1474
1704
  // before returning, so an iteration is "in-flight" iff the file has a Sprint
1475
1705
  // heading but no matching Verify field. readIterations skips malformed
1476
1706
  // entries — so we mark the highest sprint number as crashed regardless.
1477
- const iters = await readIterations(opts.flowDir, opts.runId);
1707
+ const iters = await readIterations(opts.flowDir, resolvedRunId);
1478
1708
  let nextSprint = iters.length + 1;
1479
1709
  if (iters.length > 0) {
1480
1710
  const last = iters[iters.length - 1];
1481
1711
  if (!last.lastVerifyResult || last.lastVerifyResult === "UNKNOWN") {
1482
- await markIterationCrashed(opts.flowDir, opts.runId, last.sprintN);
1712
+ await markIterationCrashed(opts.flowDir, resolvedRunId, last.sprintN);
1483
1713
  nextSprint = last.sprintN; // retry with retryOf metadata
1484
1714
  yield {
1485
1715
  type: "content",
@@ -1490,7 +1720,7 @@ async function* runResume(opts) {
1490
1720
  // Fire EE phase-outcome=resumed (extension landed in 13-05).
1491
1721
  try {
1492
1722
  fireAndForgetPhaseOutcome({
1493
- sessionId: opts.runId,
1723
+ sessionId: resolvedRunId,
1494
1724
  phaseName: `sprint-${Math.max(1, nextSprint - 1)}`,
1495
1725
  outcome: "resumed",
1496
1726
  });
@@ -1499,9 +1729,8 @@ async function* runResume(opts) {
1499
1729
  /* non-fatal */
1500
1730
  }
1501
1731
  // Resume into sprint loop with reconstructed history + manifest flags.
1502
- const productSpec = await loadProductSpec(opts.flowDir, opts.runId, manifest.idea, manifest.stack);
1503
1732
  const ctx = {
1504
- runId: opts.runId,
1733
+ runId: resolvedRunId,
1505
1734
  flowDir: opts.flowDir,
1506
1735
  idea: manifest.idea,
1507
1736
  sessionModelId: opts.sessionModelId,
@@ -1512,8 +1741,60 @@ async function* runResume(opts) {
1512
1741
  cwd: opts.cwd,
1513
1742
  sessionId: opts.sessionId,
1514
1743
  processMessageFn: opts.processMessageFn,
1744
+ runIsolatedTask: opts.runIsolatedTask,
1515
1745
  detectVerifyRecipe: opts.detectVerifyRecipe,
1516
1746
  };
1747
+ // C-v2 cross-session debate resume — a persisted debate checkpoint means the
1748
+ // council debate was interrupted before it ever produced a spec, so the run
1749
+ // cannot go straight to sprints (loadProductSpec would return an empty stub).
1750
+ // Re-run the council FSM: loop-driver's resume entry skips discovery + the
1751
+ // interview and restores the debate from its checkpoint, then scoping writes
1752
+ // the spec. This mirrors runStart's phase-1 → phase-2 handoff.
1753
+ const runDir = path.join(opts.flowDir, "runs", resolvedRunId);
1754
+ const interruptedDebate = await readDebateCheckpoint(runDir);
1755
+ if (interruptedDebate) {
1756
+ yield {
1757
+ type: "content",
1758
+ content: `\n> Detected an interrupted council debate (round ${interruptedDebate.roundCount + 1}); resuming it before sprints.\n`,
1759
+ };
1760
+ const driverGen = runLoopDriver(ctx);
1761
+ let driverResult;
1762
+ try {
1763
+ while (true) {
1764
+ const { value, done } = await driverGen.next();
1765
+ if (done) {
1766
+ driverResult = value;
1767
+ break;
1768
+ }
1769
+ yield value;
1770
+ }
1771
+ }
1772
+ catch (err) {
1773
+ const msg = err instanceof Error ? err.message : String(err);
1774
+ yield { type: "error", error: true, content: msg };
1775
+ return { runId: resolvedRunId, stage: "error", success: false, reason: msg };
1776
+ }
1777
+ if (!driverResult?.success || driverResult.stage !== "approved") {
1778
+ return { ...driverResult, runId: resolvedRunId };
1779
+ }
1780
+ // Build the sprint plan now that the spec exists (idempotent — skips when
1781
+ // backlog.json / sprint-plan.json already exist).
1782
+ const resumedSpec = await loadProductSpec(opts.flowDir, resolvedRunId, manifest.idea, manifest.stack);
1783
+ const { sprintCount } = await buildBacklogAndSprintPlan({
1784
+ flowDir: opts.flowDir,
1785
+ runId: resolvedRunId,
1786
+ productSpec: resumedSpec,
1787
+ ctx,
1788
+ sessionModelId: opts.sessionModelId,
1789
+ maxSprints: opts.flags.maxSprints,
1790
+ onChunk: (chunk) => void chunk,
1791
+ });
1792
+ yield {
1793
+ type: "content",
1794
+ content: `\n> Committed: ${sprintCount} sprint${sprintCount === 1 ? "" : "s"} planned. Sprint 1 active.\n`,
1795
+ };
1796
+ }
1797
+ const productSpec = await loadProductSpec(opts.flowDir, resolvedRunId, manifest.idea, manifest.stack);
1517
1798
  const roleAssignments = opts.roleAssignments ?? (await resolveRoleAssignments(opts.sessionModelId));
1518
1799
  // Subsystem E: phase-orchestrated path (default ON; set MUONROI_PHASE_MODE=0 for legacy).
1519
1800
  if (process.env.MUONROI_PHASE_MODE !== "0") {
@@ -1,4 +1,11 @@
1
1
  import type { StreamChunk } from "../types/index.js";
2
2
  import type { DriverContext, DriverResult, Stage } from "./types.js";
3
+ /**
4
+ * Clamp a title for the milestone/phase index (F12): truncate at a word
5
+ * boundary when possible and strip trailing punctuation/whitespace so a raw
6
+ * slice can't leave a dangling "(" or a half word. Falls back to a hard slice
7
+ * for a single long token.
8
+ */
9
+ export declare function clampTitle(raw: string, max: number): string;
3
10
  export declare function runLoopDriver(ctx: DriverContext): AsyncGenerator<StreamChunk, DriverResult, unknown>;
4
11
  export type { DriverContext, DriverResult, Stage };