muonroi-cli 1.8.4 → 1.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (562) 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-filter.js +11 -0
  5. package/dist/packages/agent-harness-core/src/event-redact.js +7 -0
  6. package/dist/packages/agent-harness-core/src/event-tee.d.ts +64 -0
  7. package/dist/packages/agent-harness-core/src/event-tee.js +104 -0
  8. package/dist/packages/agent-harness-core/src/mcp-server.d.ts +25 -0
  9. package/dist/packages/agent-harness-core/src/mcp-server.js +169 -21
  10. package/dist/packages/agent-harness-core/src/predicate.d.ts +1 -1
  11. package/dist/packages/agent-harness-core/src/protocol.d.ts +90 -4
  12. package/dist/packages/agent-harness-core/src/protocol.js +15 -0
  13. package/dist/packages/agent-harness-core/src/visual-quality.d.ts +58 -0
  14. package/dist/packages/agent-harness-core/src/visual-quality.js +141 -0
  15. package/dist/packages/agent-harness-opentui/src/agent-mode.d.ts +6 -0
  16. package/dist/packages/agent-harness-opentui/src/agent-mode.js +14 -1
  17. package/dist/packages/agent-harness-opentui/src/input-bridge.d.ts +2 -10
  18. package/dist/packages/agent-harness-opentui/src/input-bridge.js +103 -16
  19. package/dist/packages/agent-harness-opentui/src/install.d.ts +8 -0
  20. package/dist/packages/agent-harness-opentui/src/install.js +10 -0
  21. package/dist/packages/agent-harness-opentui/src/semantic.js +12 -10
  22. package/dist/packages/agent-harness-opentui/src/visual-capture.d.ts +56 -0
  23. package/dist/packages/agent-harness-opentui/src/visual-capture.js +103 -0
  24. package/dist/src/agent-harness/mock-model.d.ts +38 -0
  25. package/dist/src/agent-harness/mock-model.js +69 -3
  26. package/dist/src/agent-harness/test-spawn.js +31 -0
  27. package/dist/src/chat/chat-keychain.d.ts +7 -12
  28. package/dist/src/chat/chat-keychain.js +19 -86
  29. package/dist/src/cli/config/screen-providers.js +1 -1
  30. package/dist/src/cli/cost-forensics.d.ts +10 -0
  31. package/dist/src/cli/cost-forensics.js +18 -3
  32. package/dist/src/cli/keys-bundle.d.ts +1 -1
  33. package/dist/src/cli/keys-bundle.js +1 -1
  34. package/dist/src/cli/keys.d.ts +10 -47
  35. package/dist/src/cli/keys.js +31 -399
  36. package/dist/src/council/clarifier.d.ts +31 -3
  37. package/dist/src/council/clarifier.js +220 -32
  38. package/dist/src/council/context.js +49 -15
  39. package/dist/src/council/debate-checkpoint.d.ts +129 -0
  40. package/dist/src/council/debate-checkpoint.js +176 -0
  41. package/dist/src/council/debate-planner.js +54 -5
  42. package/dist/src/council/debate-summary.d.ts +25 -0
  43. package/dist/src/council/debate-summary.js +85 -0
  44. package/dist/src/council/debate.d.ts +169 -2
  45. package/dist/src/council/debate.js +1265 -135
  46. package/dist/src/council/index.d.ts +108 -1
  47. package/dist/src/council/index.js +670 -197
  48. package/dist/src/council/leader.d.ts +26 -0
  49. package/dist/src/council/leader.js +150 -9
  50. package/dist/src/council/llm.d.ts +94 -0
  51. package/dist/src/council/llm.js +348 -55
  52. package/dist/src/council/panel-select.d.ts +30 -0
  53. package/dist/src/council/panel-select.js +82 -0
  54. package/dist/src/council/planner.js +40 -0
  55. package/dist/src/council/preflight.d.ts +17 -0
  56. package/dist/src/council/preflight.js +50 -2
  57. package/dist/src/council/prompts.d.ts +39 -4
  58. package/dist/src/council/prompts.js +256 -69
  59. package/dist/src/council/stance-recall.d.ts +42 -0
  60. package/dist/src/council/stance-recall.js +57 -0
  61. package/dist/src/council/strip-think.d.ts +17 -0
  62. package/dist/src/council/strip-think.js +33 -0
  63. package/dist/src/council/types.d.ts +138 -0
  64. package/dist/src/ee/artifact-cache.d.ts +16 -0
  65. package/dist/src/ee/artifact-cache.js +32 -0
  66. package/dist/src/ee/auth.d.ts +20 -0
  67. package/dist/src/ee/auth.js +54 -2
  68. package/dist/src/ee/bridge.d.ts +10 -0
  69. package/dist/src/ee/bridge.js +58 -0
  70. package/dist/src/ee/client.js +109 -21
  71. package/dist/src/ee/ee-onboarding.js +6 -26
  72. package/dist/src/ee/export-transcripts.d.ts +1 -0
  73. package/dist/src/ee/export-transcripts.js +8 -10
  74. package/dist/src/ee/extract-session.js +29 -0
  75. package/dist/src/ee/extract-style.d.ts +58 -0
  76. package/dist/src/ee/extract-style.js +270 -0
  77. package/dist/src/ee/recall-ledger.d.ts +9 -0
  78. package/dist/src/ee/recall-ledger.js +3 -0
  79. package/dist/src/ee/scope.d.ts +1 -0
  80. package/dist/src/ee/scope.js +26 -1
  81. package/dist/src/ee/search.d.ts +7 -0
  82. package/dist/src/ee/search.js +24 -0
  83. package/dist/src/ee/transcript-emit.js +2 -0
  84. package/dist/src/ee/types.d.ts +22 -0
  85. package/dist/src/ee/who-am-i-brain.d.ts +35 -0
  86. package/dist/src/ee/who-am-i-brain.js +220 -0
  87. package/dist/src/ee/who-am-i.d.ts +10 -3
  88. package/dist/src/ee/who-am-i.js +12 -0
  89. package/dist/src/ee/workflow-event.d.ts +48 -0
  90. package/dist/src/ee/workflow-event.js +81 -0
  91. package/dist/src/flow/compaction/compress.d.ts +3 -3
  92. package/dist/src/flow/compaction/compress.js +58 -8
  93. package/dist/src/flow/compaction/extract.d.ts +4 -7
  94. package/dist/src/flow/compaction/extract.js +50 -10
  95. package/dist/src/flow/compaction/index.d.ts +14 -1
  96. package/dist/src/flow/compaction/index.js +96 -3
  97. package/dist/src/flow/compaction/input-guard.d.ts +24 -0
  98. package/dist/src/flow/compaction/input-guard.js +43 -0
  99. package/dist/src/flow/compaction/progress.d.ts +35 -0
  100. package/dist/src/flow/compaction/progress.js +35 -0
  101. package/dist/src/flow/fold-planning.d.ts +36 -0
  102. package/dist/src/flow/fold-planning.js +83 -0
  103. package/dist/src/flow/hierarchy.d.ts +146 -0
  104. package/dist/src/flow/hierarchy.js +427 -0
  105. package/dist/src/flow/index.d.ts +1 -0
  106. package/dist/src/flow/index.js +2 -0
  107. package/dist/src/flow/run-artifacts.d.ts +102 -0
  108. package/dist/src/flow/run-artifacts.js +208 -0
  109. package/dist/src/generated/version.d.ts +1 -1
  110. package/dist/src/generated/version.js +1 -1
  111. package/dist/src/gsd/assessment-schema.d.ts +44 -0
  112. package/dist/src/gsd/assessment-schema.js +134 -0
  113. package/dist/src/gsd/capability-registry.d.ts +45 -0
  114. package/dist/src/gsd/capability-registry.js +337 -0
  115. package/dist/src/gsd/complexity-assessor.d.ts +39 -0
  116. package/dist/src/gsd/complexity-assessor.js +152 -0
  117. package/dist/src/gsd/config-bridge.d.ts +7 -0
  118. package/dist/src/gsd/config-bridge.js +114 -0
  119. package/dist/src/gsd/config-loader.d.ts +27 -0
  120. package/dist/src/gsd/config-loader.js +50 -0
  121. package/dist/src/gsd/council-context.d.ts +44 -0
  122. package/dist/src/gsd/council-context.js +114 -0
  123. package/dist/src/gsd/ee-closure.d.ts +28 -0
  124. package/dist/src/gsd/ee-closure.js +49 -0
  125. package/dist/src/gsd/flags.d.ts +66 -0
  126. package/dist/src/gsd/flags.js +102 -0
  127. package/dist/src/gsd/gsd-dispatch.d.ts +58 -0
  128. package/dist/src/gsd/gsd-dispatch.js +131 -0
  129. package/dist/src/gsd/gsd-runtime.d.ts +22 -0
  130. package/dist/src/gsd/gsd-runtime.js +37 -0
  131. package/dist/src/gsd/host-adapter.d.ts +11 -0
  132. package/dist/src/gsd/host-adapter.js +29 -0
  133. package/dist/src/gsd/index.d.ts +24 -1
  134. package/dist/src/gsd/index.js +27 -0
  135. package/dist/src/gsd/loop-host-contract.d.ts +21 -0
  136. package/dist/src/gsd/loop-host-contract.js +39 -0
  137. package/dist/src/gsd/loop-host.d.ts +69 -0
  138. package/dist/src/gsd/loop-host.js +245 -0
  139. package/dist/src/gsd/loop-resolver.d.ts +36 -0
  140. package/dist/src/gsd/loop-resolver.js +79 -0
  141. package/dist/src/gsd/model-tier.d.ts +13 -0
  142. package/dist/src/gsd/model-tier.js +45 -0
  143. package/dist/src/gsd/mutation-gate.d.ts +16 -0
  144. package/dist/src/gsd/mutation-gate.js +41 -0
  145. package/dist/src/gsd/native-roadmap.d.ts +89 -0
  146. package/dist/src/gsd/native-roadmap.js +343 -0
  147. package/dist/src/gsd/native-state.d.ts +47 -0
  148. package/dist/src/gsd/native-state.js +220 -0
  149. package/dist/src/gsd/paths.d.ts +23 -0
  150. package/dist/src/gsd/paths.js +66 -0
  151. package/dist/src/gsd/phase-dag.d.ts +12 -0
  152. package/dist/src/gsd/phase-dag.js +94 -0
  153. package/dist/src/gsd/phase-sync.d.ts +42 -0
  154. package/dist/src/gsd/phase-sync.js +321 -0
  155. package/dist/src/gsd/pil-gate-context.d.ts +13 -0
  156. package/dist/src/gsd/pil-gate-context.js +64 -0
  157. package/dist/src/gsd/pil-gate-critic.d.ts +19 -0
  158. package/dist/src/gsd/pil-gate-critic.js +74 -0
  159. package/dist/src/gsd/plan-council-prompts.d.ts +25 -0
  160. package/dist/src/gsd/plan-council-prompts.js +79 -0
  161. package/dist/src/gsd/plan-council.d.ts +44 -0
  162. package/dist/src/gsd/plan-council.js +283 -0
  163. package/dist/src/gsd/plan-gate-vocabulary.d.ts +40 -0
  164. package/dist/src/gsd/plan-gate-vocabulary.js +64 -0
  165. package/dist/src/gsd/product-workspace.d.ts +13 -0
  166. package/dist/src/gsd/product-workspace.js +124 -0
  167. package/dist/src/gsd/ship-bridge.d.ts +25 -0
  168. package/dist/src/gsd/ship-bridge.js +65 -0
  169. package/dist/src/gsd/state-document.d.ts +40 -0
  170. package/dist/src/gsd/state-document.js +163 -0
  171. package/dist/src/gsd/verdict-schema.d.ts +39 -0
  172. package/dist/src/gsd/verdict-schema.js +144 -0
  173. package/dist/src/gsd/verify-context.d.ts +22 -0
  174. package/dist/src/gsd/verify-context.js +27 -0
  175. package/dist/src/gsd/verify-council-prompts.d.ts +19 -0
  176. package/dist/src/gsd/verify-council-prompts.js +85 -0
  177. package/dist/src/gsd/verify-council.d.ts +25 -0
  178. package/dist/src/gsd/verify-council.js +119 -0
  179. package/dist/src/gsd/verify-gate-vocabulary.d.ts +25 -0
  180. package/dist/src/gsd/verify-gate-vocabulary.js +46 -0
  181. package/dist/src/gsd/workflow-engine.d.ts +60 -0
  182. package/dist/src/gsd/workflow-engine.js +207 -0
  183. package/dist/src/gsd/workflow-tools.d.ts +13 -0
  184. package/dist/src/gsd/workflow-tools.js +277 -0
  185. package/dist/src/headless/council-answers.js +4 -0
  186. package/dist/src/hooks/index.js +1 -1
  187. package/dist/src/index.js +172 -270
  188. package/dist/src/lsp/builtins.js +3 -1
  189. package/dist/src/lsp/manager.d.ts +5 -1
  190. package/dist/src/lsp/manager.js +249 -3
  191. package/dist/src/lsp/npm-cache.d.ts +11 -1
  192. package/dist/src/lsp/npm-cache.js +17 -1
  193. package/dist/src/lsp/runtime.d.ts +6 -1
  194. package/dist/src/lsp/runtime.js +17 -1
  195. package/dist/src/lsp/types.d.ts +83 -1
  196. package/dist/src/lsp/types.js +10 -0
  197. package/dist/src/maintain/pr-builder.js +23 -13
  198. package/dist/src/mcp/auto-setup.js +57 -32
  199. package/dist/src/mcp/client-pool.js +44 -16
  200. package/dist/src/mcp/lsp-tools.d.ts +5 -1
  201. package/dist/src/mcp/lsp-tools.js +93 -2
  202. package/dist/src/mcp/mcp-keychain.d.ts +3 -5
  203. package/dist/src/mcp/mcp-keychain.js +9 -49
  204. package/dist/src/mcp/research-onboarding.js +8 -7
  205. package/dist/src/mcp/runtime.js +34 -2
  206. package/dist/src/mcp/setup-guide-text.d.ts +1 -1
  207. package/dist/src/mcp/setup-guide-text.js +22 -2
  208. package/dist/src/mcp/tools-server.d.ts +10 -0
  209. package/dist/src/mcp/tools-server.js +10 -2
  210. package/dist/src/models/catalog-client.d.ts +87 -0
  211. package/dist/src/models/catalog-client.js +105 -38
  212. package/dist/src/models/catalog.json +528 -265
  213. package/dist/src/models/registry.d.ts +22 -7
  214. package/dist/src/models/registry.js +73 -10
  215. package/dist/src/ops/doctor.js +1 -1
  216. package/dist/src/orchestrator/ask-user.d.ts +61 -0
  217. package/dist/src/orchestrator/ask-user.js +65 -0
  218. package/dist/src/orchestrator/auto-commit.js +1 -1
  219. package/dist/src/orchestrator/batch-turn-runner.js +2 -2
  220. package/dist/src/orchestrator/cache-prefix.d.ts +67 -0
  221. package/dist/src/orchestrator/cache-prefix.js +83 -0
  222. package/dist/src/orchestrator/compact-request.d.ts +32 -0
  223. package/dist/src/orchestrator/compact-request.js +41 -0
  224. package/dist/src/orchestrator/compaction.d.ts +12 -3
  225. package/dist/src/orchestrator/compaction.js +35 -15
  226. package/dist/src/orchestrator/council-manager.d.ts +12 -3
  227. package/dist/src/orchestrator/council-manager.js +74 -32
  228. package/dist/src/orchestrator/council-request.d.ts +49 -0
  229. package/dist/src/orchestrator/council-request.js +62 -0
  230. package/dist/src/orchestrator/cross-turn-dedup.d.ts +6 -0
  231. package/dist/src/orchestrator/cross-turn-dedup.js +22 -1
  232. package/dist/src/orchestrator/error-utils.d.ts +29 -0
  233. package/dist/src/orchestrator/error-utils.js +132 -24
  234. package/dist/src/orchestrator/grounding-check.js +39 -1
  235. package/dist/src/orchestrator/interactive-pause.d.ts +26 -0
  236. package/dist/src/orchestrator/interactive-pause.js +36 -0
  237. package/dist/src/orchestrator/message-processor.d.ts +4 -0
  238. package/dist/src/orchestrator/message-processor.js +268 -41
  239. package/dist/src/orchestrator/orchestrator.d.ts +64 -3
  240. package/dist/src/orchestrator/orchestrator.js +823 -120
  241. package/dist/src/orchestrator/preprocessor.js +3 -3
  242. package/dist/src/orchestrator/proactive-compact-detector.d.ts +26 -0
  243. package/dist/src/orchestrator/proactive-compact-detector.js +36 -0
  244. package/dist/src/orchestrator/prompts.js +17 -17
  245. package/dist/src/orchestrator/reactive-delegation.d.ts +39 -0
  246. package/dist/src/orchestrator/reactive-delegation.js +59 -0
  247. package/dist/src/orchestrator/retry-classifier.d.ts +2 -1
  248. package/dist/src/orchestrator/retry-classifier.js +46 -2
  249. package/dist/src/orchestrator/safety-askcard.d.ts +1 -1
  250. package/dist/src/orchestrator/safety-askcard.js +5 -2
  251. package/dist/src/orchestrator/safety-intercept.d.ts +50 -0
  252. package/dist/src/orchestrator/safety-intercept.js +62 -0
  253. package/dist/src/orchestrator/scope-reminder.js +1 -1
  254. package/dist/src/orchestrator/session-experience.d.ts +2 -1
  255. package/dist/src/orchestrator/session-experience.js +2 -1
  256. package/dist/src/orchestrator/should-run-gate.d.ts +5 -0
  257. package/dist/src/orchestrator/should-run-gate.js +18 -0
  258. package/dist/src/orchestrator/stall-watchdog.d.ts +31 -3
  259. package/dist/src/orchestrator/stall-watchdog.js +65 -10
  260. package/dist/src/orchestrator/stream-runner.d.ts +13 -3
  261. package/dist/src/orchestrator/stream-runner.js +115 -49
  262. package/dist/src/orchestrator/sub-agent-cap.d.ts +13 -1
  263. package/dist/src/orchestrator/sub-agent-cap.js +16 -1
  264. package/dist/src/orchestrator/sub-agent-model-tier.d.ts +13 -1
  265. package/dist/src/orchestrator/sub-agent-model-tier.js +16 -2
  266. package/dist/src/orchestrator/subagent-compactor.d.ts +53 -1
  267. package/dist/src/orchestrator/subagent-compactor.js +126 -15
  268. package/dist/src/orchestrator/tool-engine.d.ts +41 -0
  269. package/dist/src/orchestrator/tool-engine.js +846 -66
  270. package/dist/src/orchestrator/tool-limit-auto-recover.d.ts +22 -0
  271. package/dist/src/orchestrator/tool-limit-auto-recover.js +30 -0
  272. package/dist/src/orchestrator/turn-runner-deps.d.ts +19 -0
  273. package/dist/src/orchestrator/turn-watchdog.d.ts +44 -0
  274. package/dist/src/orchestrator/turn-watchdog.js +84 -0
  275. package/dist/src/pil/agent-operating-contract.d.ts +1 -1
  276. package/dist/src/pil/agent-operating-contract.js +6 -4
  277. package/dist/src/pil/cheap-model-playbook.d.ts +1 -1
  278. package/dist/src/pil/cheap-model-playbook.js +5 -1
  279. package/dist/src/pil/cheap-model-workbooks.d.ts +1 -1
  280. package/dist/src/pil/cheap-model-workbooks.js +1 -1
  281. package/dist/src/pil/discovery-types.d.ts +1 -0
  282. package/dist/src/pil/discovery.d.ts +1 -1
  283. package/dist/src/pil/discovery.js +18 -13
  284. package/dist/src/pil/layer1-intent.d.ts +18 -6
  285. package/dist/src/pil/layer1-intent.js +66 -757
  286. package/dist/src/pil/layer15-context-scan.js +15 -1
  287. package/dist/src/pil/layer1_5-complexity-size.d.ts +7 -0
  288. package/dist/src/pil/layer1_5-complexity-size.js +31 -5
  289. package/dist/src/pil/layer3-ee-injection.js +23 -8
  290. package/dist/src/pil/layer4-gsd.js +69 -16
  291. package/dist/src/pil/layer5-context.js +7 -3
  292. package/dist/src/pil/layer6-output.d.ts +23 -0
  293. package/dist/src/pil/layer6-output.js +5 -1
  294. package/dist/src/pil/llm-classify.d.ts +111 -5
  295. package/dist/src/pil/llm-classify.js +421 -189
  296. package/dist/src/pil/native-capabilities-workbook.d.ts +1 -1
  297. package/dist/src/pil/native-capabilities-workbook.js +8 -0
  298. package/dist/src/pil/pipeline.js +36 -2
  299. package/dist/src/pil/repo-grounding-probe.d.ts +15 -0
  300. package/dist/src/pil/repo-grounding-probe.js +136 -0
  301. package/dist/src/pil/repo-structure-hints.d.ts +7 -0
  302. package/dist/src/pil/repo-structure-hints.js +45 -0
  303. package/dist/src/pil/response-tools.js +5 -3
  304. package/dist/src/pil/schema.d.ts +1 -0
  305. package/dist/src/pil/schema.js +2 -0
  306. package/dist/src/pil/types.d.ts +18 -0
  307. package/dist/src/playbook/directives.d.ts +4 -0
  308. package/dist/src/playbook/directives.js +17 -5
  309. package/dist/src/product-loop/artifact-io.js +4 -0
  310. package/dist/src/product-loop/backlog-builder.d.ts +14 -1
  311. package/dist/src/product-loop/backlog-builder.js +30 -6
  312. package/dist/src/product-loop/criteria-seed.d.ts +51 -0
  313. package/dist/src/product-loop/criteria-seed.js +200 -0
  314. package/dist/src/product-loop/discovery-context-format.js +3 -1
  315. package/dist/src/product-loop/discovery-ecosystem.js +4 -1
  316. package/dist/src/product-loop/discovery-interview.d.ts +9 -0
  317. package/dist/src/product-loop/discovery-interview.js +60 -12
  318. package/dist/src/product-loop/discovery-recommender.js +2 -1
  319. package/dist/src/product-loop/discovery-schema.js +19 -2
  320. package/dist/src/product-loop/discovery-triage.d.ts +23 -0
  321. package/dist/src/product-loop/discovery-triage.js +109 -0
  322. package/dist/src/product-loop/gather.js +150 -2
  323. package/dist/src/product-loop/ideal-trace.d.ts +7 -0
  324. package/dist/src/product-loop/ideal-trace.js +64 -0
  325. package/dist/src/product-loop/index.d.ts +13 -1
  326. package/dist/src/product-loop/index.js +340 -52
  327. package/dist/src/product-loop/loop-driver.d.ts +7 -0
  328. package/dist/src/product-loop/loop-driver.js +330 -106
  329. package/dist/src/product-loop/phase-plan.d.ts +21 -0
  330. package/dist/src/product-loop/phase-plan.js +81 -6
  331. package/dist/src/product-loop/phase-rituals.d.ts +3 -0
  332. package/dist/src/product-loop/phase-rituals.js +8 -3
  333. package/dist/src/product-loop/phase-runner.js +39 -12
  334. package/dist/src/product-loop/plan-adherence-review.d.ts +26 -0
  335. package/dist/src/product-loop/plan-adherence-review.js +144 -0
  336. package/dist/src/product-loop/sprint-runner.d.ts +173 -0
  337. package/dist/src/product-loop/sprint-runner.js +863 -19
  338. package/dist/src/product-loop/types.d.ts +61 -5
  339. package/dist/src/providers/adapter.d.ts +1 -1
  340. package/dist/src/providers/adapter.js +3 -4
  341. package/dist/src/providers/anthropic.d.ts +9 -8
  342. package/dist/src/providers/anthropic.js +13 -47
  343. package/dist/src/providers/auth/browser-flow.d.ts +1 -1
  344. package/dist/src/providers/auth/browser-flow.js +1 -1
  345. package/dist/src/providers/auth/grok-oauth.d.ts +1 -0
  346. package/dist/src/providers/auth/grok-oauth.js +30 -5
  347. package/dist/src/providers/auth/openai-oauth.d.ts +1 -0
  348. package/dist/src/providers/auth/openai-oauth.js +15 -1
  349. package/dist/src/providers/auth/registry.js +0 -34
  350. package/dist/src/providers/auth/token-store.d.ts +9 -9
  351. package/dist/src/providers/auth/token-store.js +8 -67
  352. package/dist/src/providers/auth/types.d.ts +9 -1
  353. package/dist/src/providers/auth/types.js +1 -1
  354. package/dist/src/providers/capabilities.d.ts +24 -5
  355. package/dist/src/providers/capabilities.js +42 -24
  356. package/dist/src/providers/endpoints.d.ts +2 -2
  357. package/dist/src/providers/endpoints.js +11 -10
  358. package/dist/src/providers/env-store.d.ts +17 -0
  359. package/dist/src/providers/env-store.js +228 -0
  360. package/dist/src/providers/keychain.d.ts +22 -18
  361. package/dist/src/providers/keychain.js +127 -140
  362. package/dist/src/providers/mcp-vision-bridge.js +56 -146
  363. package/dist/src/providers/openai-compatible.js +8 -1
  364. package/dist/src/providers/pricing.d.ts +2 -2
  365. package/dist/src/providers/pricing.js +3 -13
  366. package/dist/src/providers/runtime.d.ts +43 -3
  367. package/dist/src/providers/runtime.js +88 -14
  368. package/dist/src/providers/strategies/base.strategy.d.ts +16 -0
  369. package/dist/src/providers/strategies/base.strategy.js +24 -1
  370. package/dist/src/providers/strategies/{siliconflow.strategy.d.ts → opencode-go.strategy.d.ts} +3 -3
  371. package/dist/src/providers/strategies/opencode-go.strategy.js +83 -0
  372. package/dist/src/providers/strategies/registry.js +4 -4
  373. package/dist/src/providers/strategies/thinking-mode.d.ts +109 -0
  374. package/dist/src/providers/strategies/thinking-mode.js +288 -1
  375. package/dist/src/providers/strategies/xai.strategy.js +27 -0
  376. package/dist/src/providers/strategies/zai.strategy.d.ts +14 -0
  377. package/dist/src/providers/strategies/zai.strategy.js +44 -0
  378. package/dist/src/providers/types.d.ts +5 -6
  379. package/dist/src/providers/types.js +2 -2
  380. package/dist/src/providers/vision-backend.d.ts +47 -0
  381. package/dist/src/providers/vision-backend.js +258 -0
  382. package/dist/src/providers/vision-proxy.d.ts +22 -9
  383. package/dist/src/providers/vision-proxy.js +63 -132
  384. package/dist/src/providers/warm.d.ts +65 -0
  385. package/dist/src/providers/warm.js +145 -0
  386. package/dist/src/providers/wire-debug.js +95 -0
  387. package/dist/src/router/decide.d.ts +13 -0
  388. package/dist/src/router/decide.js +138 -36
  389. package/dist/src/router/peak-hour.d.ts +38 -0
  390. package/dist/src/router/peak-hour.js +107 -0
  391. package/dist/src/router/step-router.js +3 -2
  392. package/dist/src/router/warm.js +4 -5
  393. package/dist/src/scaffold/continuation-prompt.d.ts +11 -0
  394. package/dist/src/scaffold/continuation-prompt.js +26 -0
  395. package/dist/src/scaffold/point-to-existing.d.ts +21 -0
  396. package/dist/src/scaffold/point-to-existing.js +25 -0
  397. package/dist/src/self-qa/agentic-loop.js +6 -5
  398. package/dist/src/{ui/state → state}/active-run.d.ts +19 -0
  399. package/dist/src/{ui/state → state}/active-run.js +21 -0
  400. package/dist/src/{ui/status-bar/store.d.ts → state/status-bar-store.d.ts} +4 -1
  401. package/dist/src/{ui/status-bar/store.js → state/status-bar-store.js} +12 -9
  402. package/dist/src/state/turn-trace.d.ts +43 -0
  403. package/dist/src/state/turn-trace.js +32 -0
  404. package/dist/src/storage/db.js +2 -1
  405. package/dist/src/storage/index.d.ts +1 -1
  406. package/dist/src/storage/index.js +1 -1
  407. package/dist/src/storage/interaction-log.d.ts +1 -1
  408. package/dist/src/storage/migrations.js +71 -1
  409. package/dist/src/storage/sessions.d.ts +28 -10
  410. package/dist/src/storage/sessions.js +78 -21
  411. package/dist/src/storage/transcript-view.js +1 -1
  412. package/dist/src/storage/transcript.d.ts +51 -0
  413. package/dist/src/storage/transcript.js +340 -15
  414. package/dist/src/tools/file.d.ts +15 -0
  415. package/dist/src/tools/file.js +32 -0
  416. package/dist/src/tools/git-safety.d.ts +19 -0
  417. package/dist/src/tools/git-safety.js +168 -0
  418. package/dist/src/tools/native-tools.d.ts +1 -1
  419. package/dist/src/tools/native-tools.js +81 -1
  420. package/dist/src/tools/registry.d.ts +20 -0
  421. package/dist/src/tools/registry.js +576 -23
  422. package/dist/src/tools/research.d.ts +29 -0
  423. package/dist/src/tools/research.js +233 -0
  424. package/dist/src/types/index.d.ts +147 -4
  425. package/dist/src/ui/app.js +0 -0
  426. package/dist/src/ui/cards/product-status-card.js +1 -1
  427. package/dist/src/ui/components/agent-rail-activities.d.ts +26 -0
  428. package/dist/src/ui/components/agent-rail-activities.js +47 -0
  429. package/dist/src/ui/components/bubble-body-guard.d.ts +27 -0
  430. package/dist/src/ui/components/bubble-body-guard.js +50 -0
  431. package/dist/src/ui/components/compact-progress-card.d.ts +24 -0
  432. package/dist/src/ui/components/compact-progress-card.js +42 -0
  433. package/dist/src/ui/components/context-rail.d.ts +26 -0
  434. package/dist/src/ui/components/context-rail.js +33 -0
  435. package/dist/src/ui/components/council-conclusion-card.d.ts +73 -0
  436. package/dist/src/ui/components/council-conclusion-card.js +420 -0
  437. package/dist/src/ui/components/council-debate-pill.d.ts +36 -0
  438. package/dist/src/ui/components/council-debate-pill.js +34 -0
  439. package/dist/src/ui/components/council-info-card.js +2 -2
  440. package/dist/src/ui/components/council-leader-bubble.d.ts +10 -3
  441. package/dist/src/ui/components/council-leader-bubble.js +21 -11
  442. package/dist/src/ui/components/council-message-bubble.d.ts +15 -2
  443. package/dist/src/ui/components/council-message-bubble.js +16 -15
  444. package/dist/src/ui/components/council-phase-timeline.d.ts +9 -1
  445. package/dist/src/ui/components/council-phase-timeline.js +66 -17
  446. package/dist/src/ui/components/council-placeholder-bubble.d.ts +16 -9
  447. package/dist/src/ui/components/council-placeholder-bubble.js +32 -29
  448. package/dist/src/ui/components/council-question-card.js +13 -12
  449. package/dist/src/ui/components/council-rail-rounds.d.ts +26 -0
  450. package/dist/src/ui/components/council-rail-rounds.js +57 -0
  451. package/dist/src/ui/components/council-round-group.d.ts +38 -0
  452. package/dist/src/ui/components/council-round-group.js +88 -0
  453. package/dist/src/ui/components/council-status-list.d.ts +3 -1
  454. package/dist/src/ui/components/council-status-list.js +36 -24
  455. package/dist/src/ui/components/council-synthesis-banner.d.ts +7 -2
  456. package/dist/src/ui/components/council-synthesis-banner.js +20 -5
  457. package/dist/src/ui/components/halt-recovery-card.js +9 -5
  458. package/dist/src/ui/components/jump-to-latest-pill.d.ts +11 -0
  459. package/dist/src/ui/components/jump-to-latest-pill.js +14 -0
  460. package/dist/src/ui/components/message-view.d.ts +15 -0
  461. package/dist/src/ui/components/message-view.js +50 -1
  462. package/dist/src/ui/components/prompt-box.js +18 -16
  463. package/dist/src/ui/components/session-tree-card.d.ts +14 -0
  464. package/dist/src/ui/components/session-tree-card.js +46 -0
  465. package/dist/src/ui/components/slash-inline-menu.d.ts +12 -0
  466. package/dist/src/ui/components/slash-inline-menu.js +26 -5
  467. package/dist/src/ui/components/task-list-panel.d.ts +14 -1
  468. package/dist/src/ui/components/task-list-panel.js +22 -2
  469. package/dist/src/ui/components/tool-group.d.ts +15 -3
  470. package/dist/src/ui/components/tool-group.js +69 -11
  471. package/dist/src/ui/containers/modals-layer.d.ts +4 -2
  472. package/dist/src/ui/containers/modals-layer.js +2 -2
  473. package/dist/src/ui/council-harness-event.d.ts +57 -0
  474. package/dist/src/ui/council-harness-event.js +46 -0
  475. package/dist/src/ui/heartbeat-debug.d.ts +29 -0
  476. package/dist/src/ui/heartbeat-debug.js +45 -0
  477. package/dist/src/ui/hooks/use-session-picker.d.ts +3 -3
  478. package/dist/src/ui/mcp-modal.js +2 -4
  479. package/dist/src/ui/modals/api-key-modal.js +1 -1
  480. package/dist/src/ui/modals/connect-modal.js +4 -3
  481. package/dist/src/ui/modals/model-picker-modal.d.ts +8 -18
  482. package/dist/src/ui/modals/model-picker-modal.js +8 -10
  483. package/dist/src/ui/modals/session-picker-modal.d.ts +2 -2
  484. package/dist/src/ui/modals/session-picker-modal.js +3 -5
  485. package/dist/src/ui/picker-providers.d.ts +1 -1
  486. package/dist/src/ui/picker-providers.js +1 -1
  487. package/dist/src/ui/primitives/index.d.ts +1 -0
  488. package/dist/src/ui/primitives/index.js +2 -0
  489. package/dist/src/ui/primitives/semantic-primitives.d.ts +76 -0
  490. package/dist/src/ui/primitives/semantic-primitives.js +81 -0
  491. package/dist/src/ui/slash/compact.js +5 -7
  492. package/dist/src/ui/slash/cost.js +1 -1
  493. package/dist/src/ui/slash/council.js +19 -1
  494. package/dist/src/ui/slash/debug.d.ts +3 -31
  495. package/dist/src/ui/slash/debug.js +9 -20
  496. package/dist/src/ui/slash/ee.js +81 -0
  497. package/dist/src/ui/slash/ideal.d.ts +6 -2
  498. package/dist/src/ui/slash/ideal.js +97 -7
  499. package/dist/src/ui/slash/menu-items.d.ts +7 -0
  500. package/dist/src/ui/slash/menu-items.js +23 -20
  501. package/dist/src/ui/slash/registry.d.ts +2 -0
  502. package/dist/src/ui/slash/registry.js +4 -0
  503. package/dist/src/ui/status-bar/cache-hit.d.ts +6 -0
  504. package/dist/src/ui/status-bar/cache-hit.js +9 -0
  505. package/dist/src/ui/status-bar/index.d.ts +1 -1
  506. package/dist/src/ui/status-bar/index.js +7 -3
  507. package/dist/src/ui/status-bar/usd-meter.d.ts +5 -4
  508. package/dist/src/ui/status-bar/usd-meter.js +6 -4
  509. package/dist/src/ui/theme.d.ts +1 -0
  510. package/dist/src/ui/theme.js +2 -0
  511. package/dist/src/ui/types.d.ts +7 -0
  512. package/dist/src/ui/use-app-logic.js +0 -0
  513. package/dist/src/ui/utils/agent-activities.d.ts +39 -0
  514. package/dist/src/ui/utils/agent-activities.js +96 -0
  515. package/dist/src/ui/utils/format.d.ts +14 -0
  516. package/dist/src/ui/utils/format.js +23 -3
  517. package/dist/src/ui/utils/group-tool-entries.d.ts +26 -0
  518. package/dist/src/ui/utils/group-tool-entries.js +111 -0
  519. package/dist/src/ui/utils/tool-summary.d.ts +21 -0
  520. package/dist/src/ui/utils/tool-summary.js +91 -0
  521. package/dist/src/usage/downgrade.js +2 -2
  522. package/dist/src/usage/product-ledger.js +2 -2
  523. package/dist/src/utils/event-loop-monitor.d.ts +85 -0
  524. package/dist/src/utils/event-loop-monitor.js +107 -0
  525. package/dist/src/utils/install-manager.js +2 -1
  526. package/dist/src/utils/llm-deadline.d.ts +14 -0
  527. package/dist/src/utils/llm-deadline.js +19 -0
  528. package/dist/src/utils/logger.js +2 -2
  529. package/dist/src/utils/loop-profiler.d.ts +102 -0
  530. package/dist/src/utils/loop-profiler.js +202 -0
  531. package/dist/src/utils/permission-mode.js +5 -3
  532. package/dist/src/utils/redactor.js +1 -1
  533. package/dist/src/utils/settings.d.ts +180 -5
  534. package/dist/src/utils/settings.js +271 -31
  535. package/dist/src/utils/side-question.d.ts +1 -2
  536. package/dist/src/utils/side-question.js +2 -2
  537. package/dist/src/utils/visible-retry.d.ts +11 -0
  538. package/dist/src/utils/visible-retry.js +10 -1
  539. package/dist/src/verify/entrypoint.d.ts +1 -1
  540. package/dist/src/verify/entrypoint.js +52 -17
  541. package/dist/src/verify/orchestrator.d.ts +1 -1
  542. package/dist/src/verify/orchestrator.js +20 -3
  543. package/dist/src/verify/recipes.d.ts +13 -0
  544. package/dist/src/verify/recipes.js +15 -0
  545. package/package.json +134 -132
  546. package/dist/src/cli/bw-vault.d.ts +0 -55
  547. package/dist/src/cli/bw-vault.js +0 -133
  548. package/dist/src/mcp/ee-tools.d.ts +0 -46
  549. package/dist/src/mcp/ee-tools.js +0 -193
  550. package/dist/src/providers/auth/gcloud.d.ts +0 -28
  551. package/dist/src/providers/auth/gcloud.js +0 -102
  552. package/dist/src/providers/auth/gemini-oauth.d.ts +0 -82
  553. package/dist/src/providers/auth/gemini-oauth.js +0 -472
  554. package/dist/src/providers/gemini.d.ts +0 -11
  555. package/dist/src/providers/gemini.js +0 -45
  556. package/dist/src/providers/siliconflow-sse-repair.d.ts +0 -58
  557. package/dist/src/providers/siliconflow-sse-repair.js +0 -177
  558. package/dist/src/providers/strategies/google.strategy.d.ts +0 -22
  559. package/dist/src/providers/strategies/google.strategy.js +0 -174
  560. package/dist/src/providers/strategies/siliconflow.strategy.js +0 -29
  561. package/dist/src/ui/containers/chat-feed.d.ts +0 -40
  562. package/dist/src/ui/containers/chat-feed.js +0 -66
@@ -1,5 +1,8 @@
1
+ import { getMcpKey } from "../mcp/mcp-keychain.js";
2
+ import { getWebResearchModel } from "../models/registry.js";
3
+ import { getCouncilLanguage } from "../utils/settings.js";
1
4
  import { pickCouncilTaskModel } from "./leader.js";
2
- import { tracedGenerate } from "./llm.js";
5
+ import { tracedAsync, tracedGenerate, tracedGenerateWithFallback } from "./llm.js";
3
6
  import { phaseDone, phaseError, phaseStart } from "./phase-events.js";
4
7
  import { buildClarificationPrompt, buildReadinessJudgePrompt, buildSpecSynthesisPrompt } from "./prompts.js";
5
8
  /** P5: Hard cap on clarification rounds regardless of judge verdict. */
@@ -97,6 +100,51 @@ function grayAreaToRoundQuestion(g) {
97
100
  isRequired: true,
98
101
  };
99
102
  }
103
+ /**
104
+ * Resolve the concrete interview language from the council language setting +
105
+ * the topic. Pinned locale → that locale; "english" → English; "auto" (default)
106
+ * → detect from the topic (Vietnamese diacritics, mirroring
107
+ * `detectReplyLanguageHint`). Returned as a concrete name so the clarify prompt
108
+ * FORCES it (immune to an English "## Scope Research" block) and the escape-hatch
109
+ * labels can be localized.
110
+ */
111
+ const VI_DIACRITIC_RE = /[à-ỹÀ-Ỹ]/;
112
+ export function resolveInterviewLanguage(topic) {
113
+ const setting = getCouncilLanguage();
114
+ if (setting && setting !== "auto" && setting !== "english")
115
+ return setting;
116
+ if (setting === "english")
117
+ return "english";
118
+ return VI_DIACRITIC_RE.test(topic ?? "") ? "vietnamese" : "english";
119
+ }
120
+ /**
121
+ * The two escape-hatch options appended to every clarification card, localized to
122
+ * the interview language so a Vietnamese interview doesn't show English buttons.
123
+ * `lang` is a concrete language name; anything not recognized as Vietnamese falls
124
+ * back to English labels (the LLM-authored question itself is still localized).
125
+ * When `lang` is undefined the historical English-label pair is kept byte-
126
+ * identical so existing callers/tests are unaffected.
127
+ */
128
+ function escapeHatchOptions(lang) {
129
+ const isVi = typeof lang === "string" && /vietnamese|tiếng việt/i.test(lang.trim());
130
+ if (isVi) {
131
+ return [
132
+ { label: "Nhập câu trả lời", description: "Nhập câu trả lời tự do", value: "", kind: "freetext" },
133
+ { label: "Thảo luận thêm", description: "Thảo luận thêm trước khi trả lời", value: "", kind: "chat" },
134
+ ];
135
+ }
136
+ if (lang === undefined) {
137
+ // Historical default preserved byte-identical (EN label + VN description).
138
+ return [
139
+ { label: "Type something", description: "Nhập câu trả lời tự do", value: "", kind: "freetext" },
140
+ { label: "Chat about this", description: "Thảo luận thêm trước khi trả lời", value: "", kind: "chat" },
141
+ ];
142
+ }
143
+ return [
144
+ { label: "Type something", description: "Type a free-form answer", value: "", kind: "freetext" },
145
+ { label: "Chat about this", description: "Discuss before answering", value: "", kind: "chat" },
146
+ ];
147
+ }
100
148
  /**
101
149
  * Convert legacy `suggestions: string[]` into the new options schema with
102
150
  * standard "Type something" / "Chat about this" escape-hatches appended.
@@ -110,25 +158,11 @@ function grayAreaToRoundQuestion(g) {
110
158
  * returned `defaultIndex` points to it. Otherwise `defaultIndex` is omitted
111
159
  * so the UI knows to suppress the "(Recommended)" tag.
112
160
  */
113
- export function buildClarifyOptions(suggestions, recommended) {
161
+ export function buildClarifyOptions(suggestions, recommended, lang) {
114
162
  const choices = (suggestions ?? [])
115
163
  .filter((s) => typeof s === "string" && s.trim().length > 0)
116
164
  .map((s) => ({ label: s.trim(), value: s.trim(), kind: "choice" }));
117
- const options = [
118
- ...choices,
119
- {
120
- label: "Type something",
121
- description: "Nhập câu trả lời tự do",
122
- value: "",
123
- kind: "freetext",
124
- },
125
- {
126
- label: "Chat about this",
127
- description: "Thảo luận thêm trước khi trả lời",
128
- value: "",
129
- kind: "chat",
130
- },
131
- ];
165
+ const options = [...choices, ...escapeHatchOptions(lang)];
132
166
  let defaultIndex;
133
167
  if (typeof recommended === "string" && recommended.trim().length > 0) {
134
168
  const target = recommended.trim().toLowerCase();
@@ -138,6 +172,123 @@ export function buildClarifyOptions(suggestions, recommended) {
138
172
  }
139
173
  return { options, defaultIndex };
140
174
  }
175
+ /**
176
+ * Build council options from the model's richer `{label, description,
177
+ * recommended}` objects, preserving each choice's explanation as `description`
178
+ * and pointing `defaultIndex` at the option the model flagged `recommended`
179
+ * (falling back to the first when none is flagged). The same "Type something" /
180
+ * "Chat about this" escape-hatches are appended as in `buildClarifyOptions`.
181
+ * Pure + exported for unit testing.
182
+ */
183
+ export function buildClarifyOptionsRich(specs, lang) {
184
+ const cleaned = (specs ?? []).filter((s) => !!s && typeof s.label === "string" && s.label.trim().length > 0);
185
+ const choices = cleaned.map((s) => ({
186
+ label: s.label.trim(),
187
+ value: s.label.trim(),
188
+ kind: "choice",
189
+ ...(typeof s.description === "string" && s.description.trim().length > 0
190
+ ? { description: s.description.trim() }
191
+ : {}),
192
+ }));
193
+ const options = [...choices, ...escapeHatchOptions(lang)];
194
+ let defaultIndex;
195
+ const recIdx = cleaned.findIndex((s) => s.recommended === true);
196
+ if (recIdx !== -1)
197
+ defaultIndex = recIdx;
198
+ return { options, defaultIndex };
199
+ }
200
+ /**
201
+ * Pre-clarify scope research (research-first grounding).
202
+ *
203
+ * Before asking ANY clarification question, research the topic — codebase for an
204
+ * existing repo (the research method reads the tree) plus web — so the
205
+ * question-generator surfaces the REAL gray areas the evidence exposes instead
206
+ * of guessing blind ("hỏi tào lao"). The returned brief is appended to the
207
+ * `conversationContext` that `buildClarificationPrompt` already reads, so both
208
+ * `/council` and `/ideal` (which reuses this clarifier as its gather engine)
209
+ * inherit evidence-grounded questions from one shared code path.
210
+ *
211
+ * Web-capability policy (owner's Part E rule): PREFER a model with native web
212
+ * research integrated (catalog `nativeWebResearch`), switching the research call
213
+ * to it when one is reachable. Only when no native-web model is reachable fall
214
+ * back to Tavily (via the research method's builtin web tools). When NEITHER a
215
+ * native-web model NOR a Tavily key exists, warn the user before continuing —
216
+ * research proceeds on the codebase + model knowledge only, never silently blind.
217
+ * (Codebase evidence is always gathered by the research tool regardless of the
218
+ * web tier, so an existing repo is still grounded.)
219
+ *
220
+ * Never throws and never blocks the interview: if the flag is off, the llm has
221
+ * no `research` method (most unit-test mocks), the run is aborted, or the call
222
+ * fails, it yields nothing and returns "". Default ON; opt out with
223
+ * MUONROI_CLARIFY_RESEARCH_FIRST=0.
224
+ */
225
+ async function hasTavilyKey() {
226
+ try {
227
+ const k = ((await getMcpKey("tavily")) || process.env.TAVILY_API_KEY || "").trim();
228
+ return k.length >= 10;
229
+ }
230
+ catch {
231
+ return (process.env.TAVILY_API_KEY ?? "").trim().length >= 10;
232
+ }
233
+ }
234
+ export async function* researchScopeForClarification(topic, conversationContext, leaderModelId, llm, signal, reachableModels) {
235
+ if (process.env.MUONROI_CLARIFY_RESEARCH_FIRST === "0")
236
+ return "";
237
+ if (signal?.aborted)
238
+ return "";
239
+ // Skip cleanly when the injected llm can't research (generate-only test mocks)
240
+ // — keeps every existing clarifier test on its current, research-free path.
241
+ if (typeof llm.research !== "function")
242
+ return "";
243
+ // Choose the research model + web tier. Prefer a reachable native-web model.
244
+ const reachable = new Set([leaderModelId, ...reachableModels].filter(Boolean));
245
+ const nativeModel = getWebResearchModel(reachable);
246
+ let researchModel = leaderModelId;
247
+ let webTier;
248
+ if (nativeModel) {
249
+ researchModel = nativeModel.id;
250
+ webTier = "native";
251
+ }
252
+ else {
253
+ webTier = (await hasTavilyKey()) ? "tavily" : "none";
254
+ }
255
+ const phaseId = "phase:clarification-scope-research";
256
+ const startedAt = Date.now();
257
+ yield phaseStart({ phaseId, kind: "clarification", label: "Scope research" });
258
+ // Owner's Part E principle: never research the web fully blind without telling
259
+ // the user. Codebase + model-knowledge research still runs, but web findings
260
+ // will be absent — surface that so they can wire a native-web model or Tavily.
261
+ if (webTier === "none") {
262
+ yield {
263
+ type: "content",
264
+ content: `\n> ⚠ Scope research: no web-research-native model is reachable and no Tavily key is configured. ` +
265
+ `Researching from the codebase + model knowledge only — no live web findings. ` +
266
+ `Configure a native-web model or a Tavily API key for grounded web research.\n`,
267
+ };
268
+ }
269
+ try {
270
+ const goal = `${topic}\n\n(Research goal: narrow the scope of this request. Report verified findings, and — ` +
271
+ `critically — END with an explicit "## Open Questions / Assumptions" section listing what you could ` +
272
+ `NOT verify and had to ASSUME (the real goal/pain, the concrete task, the system of record, the ` +
273
+ `target user, hard constraints). Those unresolved items are exactly what the user must clarify next, ` +
274
+ `so name them plainly rather than papering over them with a plausible guess.)`;
275
+ const brief = yield* tracedAsync(() => llm.research(researchModel, goal, conversationContext, signal, undefined, {
276
+ internetFirst: webTier !== "none",
277
+ }), { phase: "clarify", label: "Scope research" });
278
+ yield phaseDone({ phaseId, kind: "clarification", label: "Scope research", startedAt });
279
+ return typeof brief === "string" ? brief.trim() : "";
280
+ }
281
+ catch (err) {
282
+ yield phaseError({
283
+ phaseId,
284
+ kind: "clarification",
285
+ label: "Scope research",
286
+ startedAt,
287
+ errorMessage: err instanceof Error ? err.message : String(err),
288
+ });
289
+ return "";
290
+ }
291
+ }
141
292
  export async function* runClarification(topic, leaderModelId, conversationContext, respondToQuestion, llm, signal, seedQuestions, maxRounds,
142
293
  /**
143
294
  * Optional pre-filled answers keyed by seed-question id. When the loop's
@@ -152,16 +303,32 @@ prefillAnswers,
152
303
  * a cheaper tier model on the same provider as the leader. Falls back to
153
304
  * the leader model if no cheaper model is cataloged. Default false.
154
305
  */
155
- costAware = false) {
306
+ costAware = false,
307
+ /**
308
+ * Healthy panel models to fall back to when the leader's cost-tier spec-synth
309
+ * model is on a failing proxy — keeps the spec's ≥3 observable criteria (and
310
+ * thus a meaningful leader eval) instead of degrading to one generic criterion.
311
+ */
312
+ fallbackModels = []) {
156
313
  // P5: use MAX_CLARIFY_ROUNDS (12) as the hard cap; respect explicit override
157
314
  // from callers that pass maxRounds (e.g. tests that want old 3-round behavior).
158
315
  const max = typeof maxRounds === "number" && maxRounds > 0 ? maxRounds : MAX_CLARIFY_ROUNDS;
316
+ // Interview language (the user's conversation language, not English-by-default).
317
+ // Resolved once and forced into the clarify prompt + escape-hatch labels.
318
+ const uiLang = resolveInterviewLanguage(topic);
159
319
  const allQA = [];
160
320
  // P5: full Q&A history with timestamps for clarifyHistory field
161
321
  const clarifyHistory = [];
162
322
  const phaseStartedAt = Date.now();
163
323
  yield phaseStart({ phaseId: "phase:clarification", kind: "clarification", label: "Clarification" });
164
324
  const seeded = (seedQuestions ?? []).map(grayAreaToRoundQuestion);
325
+ // Research-first: ground the interview in evidence BEFORE asking anything, so
326
+ // the question-generator targets the real gray areas the research surfaced
327
+ // rather than guessing. Appended to the context every round's prompt reads.
328
+ const scopeBrief = yield* researchScopeForClarification(topic, conversationContext, leaderModelId, llm, signal, fallbackModels);
329
+ if (scopeBrief) {
330
+ conversationContext = `${conversationContext}${conversationContext ? "\n\n" : ""}## Scope Research\n${scopeBrief}`;
331
+ }
165
332
  // P5: track ready-gate state across rounds
166
333
  let gateReady = false;
167
334
  let gateConfidence = 0;
@@ -195,7 +362,7 @@ costAware = false) {
195
362
  const gapHint = pendingGaps.length > 0
196
363
  ? `\n\n## Known Gaps (target these with follow-up questions)\n${pendingGaps.map((g) => `- ${g}`).join("\n")}`
197
364
  : "";
198
- const { system, prompt } = buildClarificationPrompt(topic, conversationContext, allQA.length > 0 ? allQA : undefined);
365
+ const { system, prompt } = buildClarificationPrompt(topic, conversationContext, allQA.length > 0 ? allQA : undefined, uiLang);
199
366
  let questionsRaw;
200
367
  try {
201
368
  const clarifyModel = pickCouncilTaskModel("clarify_questions", leaderModelId, costAware);
@@ -284,7 +451,16 @@ costAware = false) {
284
451
  continue;
285
452
  }
286
453
  const questionId = crypto.randomUUID();
287
- const { options, defaultIndex } = buildClarifyOptions(q.suggestions, q.recommended);
454
+ // Prefer the model's richer {label, description, recommended} options so
455
+ // every choice shows its own explanation + the recommended default is
456
+ // pre-selected. Fall back to the legacy string `suggestions` shape (PIL
457
+ // gray-area seeds and any model still emitting the old format).
458
+ const { options, defaultIndex } = q.options && q.options.length > 0
459
+ ? buildClarifyOptionsRich(q.options, uiLang)
460
+ : buildClarifyOptions(q.suggestions, q.recommended, uiLang);
461
+ // Keep the deprecated `suggestions` mirror populated for consumers that
462
+ // still read it (audit/replay), deriving labels from rich options.
463
+ const suggestionLabels = q.suggestions ?? (q.options ? q.options.map((o) => o.label).filter((l) => typeof l === "string") : undefined);
288
464
  yield {
289
465
  type: "council_question",
290
466
  content: `**${q.question}**\n${q.why ? `> ${q.why}` : ""}`,
@@ -293,7 +469,7 @@ costAware = false) {
293
469
  phase: "clarify",
294
470
  question: q.question,
295
471
  context: q.why,
296
- suggestions: q.suggestions,
472
+ suggestions: suggestionLabels,
297
473
  options,
298
474
  isRequired: q.isRequired,
299
475
  defaultIndex,
@@ -329,7 +505,7 @@ costAware = false) {
329
505
  startedAt: phaseStartedAt,
330
506
  detail: allQA.length > 0 ? `${allQA.length} Q&A` : "no clarification needed",
331
507
  });
332
- const spec = yield* synthesizeSpec(topic, conversationContext, allQA, leaderModelId, llm, costAware);
508
+ const spec = yield* synthesizeSpec(topic, conversationContext, allQA, leaderModelId, llm, costAware, fallbackModels);
333
509
  // P5: attach ready-gate metadata to the returned spec
334
510
  spec.confidenceScore = gateConfidence;
335
511
  spec.remainingGaps = gateGaps;
@@ -355,13 +531,18 @@ costAware = false) {
355
531
  };
356
532
  return spec;
357
533
  }
358
- export function buildSpecFromTopic(topic, _conversationContext) {
534
+ export function buildSpecFromTopic(topic, conversationContext) {
359
535
  return {
360
536
  problemStatement: topic,
361
537
  constraints: [],
362
538
  successCriteria: [`Address the topic: ${topic.slice(0, 100)}`],
363
539
  scope: "Determined by conversation context",
364
540
  rawQA: [],
541
+ // Carry the session/task context onto the spec so every debate stage (not
542
+ // just the opening) can stay anchored to the parent task. Previously this
543
+ // argument was dropped (prefixed `_`), which is why auto-council debates saw
544
+ // only the isolated sub-task and drifted off-topic.
545
+ parentContext: conversationContext?.trim() || undefined,
365
546
  };
366
547
  }
367
548
  /**
@@ -374,7 +555,7 @@ export function buildSpecFromTopic(topic, _conversationContext) {
374
555
  * We LLM-extract criteria/constraints/scope from the topic when QA is empty.
375
556
  * Falls back to the original buildSpecFromTopic if the LLM call fails.
376
557
  */
377
- async function* inferSpecFromTopicOnly(topic, conversationContext, leaderModelId, llm, costAware) {
558
+ async function* inferSpecFromTopicOnly(topic, conversationContext, leaderModelId, llm, costAware, fallbackModels = []) {
378
559
  const system = `You are extracting an implicit specification from a short topic statement. ` +
379
560
  `The user did not answer clarification questions, but the topic itself often ` +
380
561
  `implies scope, criteria, and constraints. Tease them out.\n\n` +
@@ -396,16 +577,21 @@ async function* inferSpecFromTopicOnly(topic, conversationContext, leaderModelId
396
577
  `- Write all fields in the user's language (detected from the topic).`;
397
578
  const prompt = `## Topic\n${topic}\n\n${conversationContext ? `## Context\n${conversationContext}\n` : ""}`;
398
579
  try {
580
+ // Model-fallback: the cost-tier synth model can sit on a flaky proxy
581
+ // (Console Go glm/kimi → "Upstream request failed"). Falling back to
582
+ // buildSpecFromTopic yields a single generic criterion, which makes the
583
+ // leader eval read a vague "1/1 criteria met". Retry on healthy panel models
584
+ // first so the spec keeps its ≥3 observable criteria.
399
585
  const synthModel = pickCouncilTaskModel("spec_synthesis", leaderModelId, costAware);
400
- const raw = yield* tracedGenerate(llm, {
586
+ const raw = yield* tracedGenerateWithFallback(llm, {
401
587
  phase: "synthesis",
402
588
  label: "Inferring spec from topic (no clarification answers)",
403
- modelId: synthModel,
589
+ models: [synthModel, ...fallbackModels],
404
590
  system,
405
591
  prompt,
406
592
  maxTokens: 1024,
407
593
  });
408
- const match = raw.match(/\{[\s\S]*\}/);
594
+ const match = raw?.match(/\{[\s\S]*\}/);
409
595
  if (match) {
410
596
  const parsed = JSON.parse(match[0]);
411
597
  const criteria = Array.isArray(parsed.successCriteria) && parsed.successCriteria.length >= 1
@@ -429,12 +615,12 @@ async function* inferSpecFromTopicOnly(topic, conversationContext, leaderModelId
429
615
  }
430
616
  return buildSpecFromTopic(topic, conversationContext);
431
617
  }
432
- async function* synthesizeSpec(topic, conversationContext, qa, leaderModelId, llm, costAware = false) {
618
+ async function* synthesizeSpec(topic, conversationContext, qa, leaderModelId, llm, costAware = false, fallbackModels = []) {
433
619
  if (qa.length === 0) {
434
620
  // Clarifier asked 0 questions OR user skipped all of them. Use the LLM to
435
621
  // pull implicit criteria/constraints/scope from the topic alone instead of
436
622
  // returning the single-criterion fallback that makes leader-eval trivial.
437
- return yield* inferSpecFromTopicOnly(topic, conversationContext, leaderModelId, llm, costAware);
623
+ return yield* inferSpecFromTopicOnly(topic, conversationContext, leaderModelId, llm, costAware, fallbackModels);
438
624
  }
439
625
  const { system, prompt } = buildSpecSynthesisPrompt(topic, conversationContext, qa);
440
626
  const resolved = {};
@@ -444,16 +630,18 @@ async function* synthesizeSpec(topic, conversationContext, qa, leaderModelId, ll
444
630
  }
445
631
  }
446
632
  try {
633
+ // Model-fallback (see inferSpecFromTopicOnly): keep the ≥3-criteria spec even
634
+ // when the leader's cost-tier synth model is on a failing proxy.
447
635
  const synthModel = pickCouncilTaskModel("spec_synthesis", leaderModelId, costAware);
448
- const raw = yield* tracedGenerate(llm, {
636
+ const raw = yield* tracedGenerateWithFallback(llm, {
449
637
  phase: "synthesis",
450
638
  label: "Synthesizing clarified spec",
451
- modelId: synthModel,
639
+ models: [synthModel, ...fallbackModels],
452
640
  system,
453
641
  prompt,
454
642
  maxTokens: 2048,
455
643
  });
456
- const match = raw.match(/\{[\s\S]*\}/);
644
+ const match = raw?.match(/\{[\s\S]*\}/);
457
645
  if (match) {
458
646
  const parsed = JSON.parse(match[0]);
459
647
  return {
@@ -98,7 +98,7 @@ function getCompactionText(msg) {
98
98
  return null;
99
99
  return msg.content;
100
100
  }
101
- function extractUserText(content) {
101
+ function extractText(content) {
102
102
  if (typeof content === "string")
103
103
  return content;
104
104
  if (Array.isArray(content)) {
@@ -109,40 +109,74 @@ function extractUserText(content) {
109
109
  }
110
110
  return "";
111
111
  }
112
+ /** Filter assistant messages to exclude tool-call-only turns (tool_use + tool_result
113
+ * pairs that carry no analytical text). An assistant turn with ≥80 chars of text
114
+ * content is considered "analytical" (contains decisions, analysis, code, or plans). */
115
+ function isAnalyticalAssistant(content) {
116
+ const text = extractText(content);
117
+ return text.trim().length >= 80;
118
+ }
119
+ /** Maximum total characters for the built context string. Raised from 12K to 32K
120
+ * (~8K tokens) so council participants get meaningful session history rather than
121
+ * only 5 user-message snippets. */
122
+ const MAX_CONTEXT_CHARS = 32_000;
112
123
  export function buildCouncilContext(messages) {
113
124
  const parts = [];
125
+ // 1. Compaction summary (first message if it's a system compaction)
114
126
  if (messages.length > 0 && isCompactionSummary(messages[0])) {
115
127
  const summary = getCompactionText(messages[0]);
116
128
  if (summary) {
117
129
  parts.push(`## Session Context (from compaction summary)\n${summary}`);
118
130
  }
119
131
  }
120
- const userMessages = [];
121
- for (let i = messages.length - 1; i >= 0 && userMessages.length < 5; i--) {
132
+ // 2. Recent conversation turns — scan BOTH user + analytical assistant messages
133
+ // from the tail, capturing at most 8 meaningful entries.
134
+ // Previously only captured 5 user messages — lost ALL assistant analysis,
135
+ // code changes, and decisions made during the session.
136
+ const conversationTurns = [];
137
+ for (let i = messages.length - 1; i >= 0 && conversationTurns.length < 8; i--) {
122
138
  const msg = messages[i];
123
139
  if (msg.role === "user") {
124
- const text = extractUserText(msg.content);
140
+ const text = extractText(msg.content);
141
+ if (text.trim()) {
142
+ conversationTurns.unshift(`[User] ${text.slice(0, 3000).trim()}`);
143
+ }
144
+ }
145
+ else if (msg.role === "assistant" && isAnalyticalAssistant(msg.content)) {
146
+ const text = extractText(msg.content);
125
147
  if (text.trim()) {
126
- userMessages.unshift(`- ${text.slice(0, 2000).trim()}`);
148
+ // Cap assistant text to 1500 chars — enough to convey analysis/decisions
149
+ // without blowing the context budget on long code outputs.
150
+ conversationTurns.unshift(`[Assistant] ${text.slice(0, 1500).trim()}`);
127
151
  }
128
152
  }
129
153
  }
130
- if (userMessages.length > 0) {
131
- parts.push(`## Recent User Messages\n${userMessages.join("\n")}`);
154
+ if (conversationTurns.length > 0) {
155
+ parts.push(`## Recent Conversation\n${conversationTurns.join("\n\n")}`);
132
156
  }
133
- const councilMemories = [];
157
+ // 3. Key decisions from system messages (task outcomes, decisions, plans)
158
+ const decisionMsgs = [];
134
159
  for (const msg of messages) {
135
- if (msg.role === "system" && typeof msg.content === "string" && msg.content.includes("[Council Memory]")) {
136
- councilMemories.push(msg.content);
160
+ if (msg.role !== "system" || typeof msg.content !== "string")
161
+ continue;
162
+ const c = msg.content;
163
+ if (c.includes("[Council Memory]") ||
164
+ c.includes("[Council Decision]") ||
165
+ c.includes("[Council Action Items]") ||
166
+ c.includes("[Council Plan Update]") ||
167
+ c.includes("[Decision]") ||
168
+ c.includes("[Task Completed]") ||
169
+ c.includes("[NEEDS HUMAN REVIEW]")) {
170
+ decisionMsgs.push(c);
137
171
  }
138
172
  }
139
- if (councilMemories.length > 0) {
140
- const digests = councilMemories.slice(-2).map(formatCouncilMemoryDigest);
141
- parts.push(`## Previous Council Outcomes (cite by role/round)\n${digests.join("\n\n")}`);
173
+ if (decisionMsgs.length > 0) {
174
+ const digests = decisionMsgs.slice(-4).map(formatCouncilMemoryDigest);
175
+ parts.push(`## Key Decisions\n${digests.join("\n\n")}`);
142
176
  }
143
177
  const combined = parts.join("\n\n---\n\n");
144
- if (combined.length > 12000) {
145
- return `${combined.slice(0, 12000)}\n\n[... context truncated to fit token budget]`;
178
+ if (combined.length > MAX_CONTEXT_CHARS) {
179
+ return `${combined.slice(0, MAX_CONTEXT_CHARS)}\n\n[... context truncated to fit token budget]`;
146
180
  }
147
181
  return combined;
148
182
  }
@@ -0,0 +1,129 @@
1
+ /**
2
+ * src/council/debate-checkpoint.ts
3
+ *
4
+ * C (mid-debate checkpoint) — persist the CB-1 council debate's per-round state
5
+ * so a break mid-debate (provider 5xx on round 5, host crash, cap breach) can
6
+ * resume from the last completed round instead of re-running the whole debate.
7
+ *
8
+ * The debate accumulates all state in RAM (`exchangeLogs`, `active`,
9
+ * `runningSummary`, `archive`, convergence trackers). Without a checkpoint a
10
+ * break loses every round — a 5-round multi-provider debate must restart from
11
+ * round 1. This module owns the on-disk snapshot: `runDebate` writes it after
12
+ * each completed round and deletes it on normal completion; the resume path
13
+ * reads it and seeds `runDebate` so it skips research + openings + completed
14
+ * rounds.
15
+ *
16
+ * File: `<checkpointDir>/debate-checkpoint.json` (checkpointDir = the run dir,
17
+ * `.muonroi-flow/runs/<runId>`). Written atomically (tmp + rename) so a crash
18
+ * mid-write can never leave a half-JSON file.
19
+ */
20
+ import type { ClarifiedSpec, CouncilParticipant, DebateArchiveEntry } from "./types.js";
21
+ /** Bump when the checkpoint shape changes incompatibly so stale files are ignored. */
22
+ export declare const DEBATE_CHECKPOINT_VERSION: 1;
23
+ export declare const DEBATE_CHECKPOINT_FILE = "debate-checkpoint.json";
24
+ /**
25
+ * Serializable snapshot of an in-flight debate, written after each completed
26
+ * discussion round. `exchangeLogs` (a `Map`) is stored as entry tuples since
27
+ * JSON has no Map; everything else in the payload is already JSON-native.
28
+ */
29
+ export interface DebateCheckpoint {
30
+ version: typeof DEBATE_CHECKPOINT_VERSION;
31
+ /**
32
+ * Identity guard — the checkpoint is only restored when it matches the debate
33
+ * about to run. `problemStatement` pins the spec; `participantModels` pins the
34
+ * panel. A mismatch (spec changed, panel re-resolved differently) => ignore
35
+ * the stale checkpoint and run the debate fresh rather than splice wrong state.
36
+ */
37
+ problemStatement: string;
38
+ participantModels: string[];
39
+ /** Rounds fully completed (transcript + summary persisted). Resume starts at roundCount+1. */
40
+ roundCount: number;
41
+ /** Current round budget after any leader/user extensions. */
42
+ maxRounds: number;
43
+ /** Accumulated per-pair transcript (Map<pairKey, turns[]> serialized as entries). */
44
+ exchangeLogs: Array<[string, string[]]>;
45
+ /** Latest inter-round summary. */
46
+ runningSummary: string;
47
+ /** Research findings (so the research phase is not re-run on resume). */
48
+ researchFindings?: string;
49
+ /** Surviving participants with their latest position + stance (so openings are not re-run). */
50
+ active: CouncilParticipant[];
51
+ /** Citation archive accumulated so far. */
52
+ archive: DebateArchiveEntry[];
53
+ /** Convergence continuity: last round's per-criterion met flags. */
54
+ lastCriteriaMet: boolean[];
55
+ /** B4 auto-remedy high-water mark of pinned criteria met. */
56
+ bestCriteriaMetCount: number;
57
+ /** B4 consecutive evaluated rounds with no new met criterion. */
58
+ roundsSinceProgress: number;
59
+ /** Topic carried into the next round from the prior leader nextRoundFocus. */
60
+ nextTopic?: string;
61
+ /** Wall-clock the checkpoint was written (ISO). Diagnostics only. */
62
+ savedAt: string;
63
+ }
64
+ /** Input to {@link buildDebateCheckpoint} — the live round-loop locals. */
65
+ export interface DebateCheckpointInput {
66
+ problemStatement: string;
67
+ roundCount: number;
68
+ maxRounds: number;
69
+ exchangeLogs: Map<string, string[]>;
70
+ runningSummary: string;
71
+ researchFindings?: string;
72
+ active: CouncilParticipant[];
73
+ archive: DebateArchiveEntry[];
74
+ lastCriteriaMet: boolean[];
75
+ bestCriteriaMetCount: number;
76
+ roundsSinceProgress: number;
77
+ nextTopic?: string;
78
+ /** ISO timestamp; the caller supplies it (Date.now is unavailable in some sandboxes). */
79
+ savedAt: string;
80
+ }
81
+ /** Build the serializable checkpoint payload from live debate state. */
82
+ export declare function buildDebateCheckpoint(input: DebateCheckpointInput): DebateCheckpoint;
83
+ /** Rehydrate `exchangeLogs` from the serialized entry tuples. */
84
+ export declare function restoreExchangeLogs(cp: DebateCheckpoint): Map<string, string[]>;
85
+ /**
86
+ * Whether `cp` describes the debate that is about to run. Guards against
87
+ * splicing a stale checkpoint (different question, re-resolved panel) into a
88
+ * fresh debate. Participant order is not significant; the model SET must match.
89
+ */
90
+ export declare function checkpointMatches(cp: DebateCheckpoint, problemStatement: string, participantModels: string[]): boolean;
91
+ /**
92
+ * Atomically write the checkpoint to `<dir>/debate-checkpoint.json`.
93
+ * Non-fatal: a checkpoint write failure must never break the live debate — it
94
+ * only forfeits resumability for that round. Logs with context (No-Silent-Catch).
95
+ */
96
+ export declare function writeDebateCheckpoint(dir: string, cp: DebateCheckpoint): Promise<void>;
97
+ /**
98
+ * Read + parse the checkpoint. Returns null when absent or unparseable (a
99
+ * corrupt checkpoint must not crash resume — the debate just runs fresh).
100
+ */
101
+ export declare function readDebateCheckpoint(dir: string): Promise<DebateCheckpoint | null>;
102
+ /**
103
+ * Delete the checkpoint (debate completed normally, or the run was aborted).
104
+ * Non-fatal — a leftover checkpoint is only re-validated (and discarded on
105
+ * mismatch) on the next resume, never silently mis-applied.
106
+ */
107
+ export declare function deleteDebateCheckpoint(dir: string): Promise<void>;
108
+ export declare const DEBATE_INPUTS_FILE = "debate-inputs.json";
109
+ /**
110
+ * C-v2 — the minimal gather-stage outputs needed to re-enter the council debate
111
+ * on a fresh session (cross-process resume) WITHOUT re-running the interactive
112
+ * discovery + interview. Persisted once at debate start; the loop-driver resume
113
+ * entry restores `clarifiedSpec` + `conversationContext` and jumps straight to
114
+ * the research/debate stage (participants + leader are re-resolved from the
115
+ * session model deterministically, then matched against the checkpoint panel).
116
+ */
117
+ export interface DebateInputs {
118
+ version: typeof DEBATE_CHECKPOINT_VERSION;
119
+ problemStatement: string;
120
+ clarifiedSpec: ClarifiedSpec;
121
+ conversationContext: string;
122
+ savedAt: string;
123
+ }
124
+ /** Atomically persist the debate inputs. Non-fatal on failure (forfeits cross-session resume only). */
125
+ export declare function writeDebateInputs(dir: string, inputs: DebateInputs): Promise<void>;
126
+ /** Read the debate inputs. Returns null when absent/unparseable/version-mismatched. */
127
+ export declare function readDebateInputs(dir: string): Promise<DebateInputs | null>;
128
+ /** Delete the debate inputs (debate + scoping finished, or run aborted). Non-fatal. */
129
+ export declare function deleteDebateInputs(dir: string): Promise<void>;