muonroi-cli 1.8.3 → 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 (477) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +133 -122
  3. package/dist/packages/agent-harness-core/src/driver.d.ts +27 -1
  4. package/dist/packages/agent-harness-core/src/driver.js +46 -0
  5. package/dist/packages/agent-harness-core/src/event-tee.d.ts +48 -0
  6. package/dist/packages/agent-harness-core/src/event-tee.js +77 -0
  7. package/dist/packages/agent-harness-core/src/mcp-server.d.ts +11 -0
  8. package/dist/packages/agent-harness-core/src/mcp-server.js +87 -15
  9. package/dist/packages/agent-harness-core/src/protocol.d.ts +66 -2
  10. package/dist/packages/agent-harness-core/src/protocol.js +15 -0
  11. package/dist/packages/agent-harness-core/src/visual-quality.d.ts +58 -0
  12. package/dist/packages/agent-harness-core/src/visual-quality.js +141 -0
  13. package/dist/packages/agent-harness-opentui/src/agent-mode.d.ts +6 -0
  14. package/dist/packages/agent-harness-opentui/src/agent-mode.js +14 -1
  15. package/dist/packages/agent-harness-opentui/src/input-bridge.d.ts +2 -10
  16. package/dist/packages/agent-harness-opentui/src/input-bridge.js +103 -16
  17. package/dist/packages/agent-harness-opentui/src/install.d.ts +8 -0
  18. package/dist/packages/agent-harness-opentui/src/install.js +10 -0
  19. package/dist/packages/agent-harness-opentui/src/semantic.js +12 -10
  20. package/dist/packages/agent-harness-opentui/src/visual-capture.d.ts +56 -0
  21. package/dist/packages/agent-harness-opentui/src/visual-capture.js +103 -0
  22. package/dist/src/agent-harness/mock-model.d.ts +28 -0
  23. package/dist/src/agent-harness/mock-model.js +63 -1
  24. package/dist/src/agent-harness/test-spawn.js +31 -0
  25. package/dist/src/cli/config/screen-providers.js +1 -1
  26. package/dist/src/cli/cost-forensics.d.ts +10 -0
  27. package/dist/src/cli/cost-forensics.js +30 -15
  28. package/dist/src/cli/keys-bundle.d.ts +1 -1
  29. package/dist/src/cli/keys-bundle.js +1 -1
  30. package/dist/src/cli/keys.d.ts +2 -2
  31. package/dist/src/cli/keys.js +19 -81
  32. package/dist/src/council/clarifier.d.ts +28 -2
  33. package/dist/src/council/clarifier.js +81 -15
  34. package/dist/src/council/context.js +49 -15
  35. package/dist/src/council/debate-checkpoint.d.ts +129 -0
  36. package/dist/src/council/debate-checkpoint.js +176 -0
  37. package/dist/src/council/debate-planner.js +51 -3
  38. package/dist/src/council/debate-summary.d.ts +25 -0
  39. package/dist/src/council/debate-summary.js +85 -0
  40. package/dist/src/council/debate.d.ts +169 -2
  41. package/dist/src/council/debate.js +1210 -134
  42. package/dist/src/council/index.d.ts +85 -1
  43. package/dist/src/council/index.js +634 -196
  44. package/dist/src/council/leader.d.ts +26 -0
  45. package/dist/src/council/leader.js +150 -9
  46. package/dist/src/council/llm.d.ts +32 -0
  47. package/dist/src/council/llm.js +231 -38
  48. package/dist/src/council/panel-select.d.ts +30 -0
  49. package/dist/src/council/panel-select.js +72 -0
  50. package/dist/src/council/planner.js +23 -0
  51. package/dist/src/council/preflight.d.ts +7 -0
  52. package/dist/src/council/preflight.js +14 -2
  53. package/dist/src/council/prompts.d.ts +30 -3
  54. package/dist/src/council/prompts.js +254 -84
  55. package/dist/src/council/stance-recall.d.ts +42 -0
  56. package/dist/src/council/stance-recall.js +57 -0
  57. package/dist/src/council/strip-think.d.ts +17 -0
  58. package/dist/src/council/strip-think.js +33 -0
  59. package/dist/src/council/types.d.ts +128 -0
  60. package/dist/src/ee/artifact-cache.d.ts +16 -0
  61. package/dist/src/ee/artifact-cache.js +32 -0
  62. package/dist/src/ee/auth.d.ts +1 -0
  63. package/dist/src/ee/auth.js +15 -2
  64. package/dist/src/ee/bridge.d.ts +10 -0
  65. package/dist/src/ee/bridge.js +58 -0
  66. package/dist/src/ee/client.js +81 -18
  67. package/dist/src/ee/export-transcripts.d.ts +1 -0
  68. package/dist/src/ee/export-transcripts.js +8 -10
  69. package/dist/src/ee/extract-session.js +29 -0
  70. package/dist/src/ee/extract-style.d.ts +58 -0
  71. package/dist/src/ee/extract-style.js +270 -0
  72. package/dist/src/ee/recall-ledger.d.ts +9 -0
  73. package/dist/src/ee/recall-ledger.js +3 -0
  74. package/dist/src/ee/scope.d.ts +1 -0
  75. package/dist/src/ee/scope.js +26 -1
  76. package/dist/src/ee/search.d.ts +7 -0
  77. package/dist/src/ee/search.js +24 -0
  78. package/dist/src/ee/transcript-emit.js +2 -0
  79. package/dist/src/ee/types.d.ts +22 -0
  80. package/dist/src/ee/who-am-i-brain.d.ts +35 -0
  81. package/dist/src/ee/who-am-i-brain.js +220 -0
  82. package/dist/src/ee/who-am-i.d.ts +10 -3
  83. package/dist/src/ee/who-am-i.js +12 -0
  84. package/dist/src/ee/workflow-event.d.ts +48 -0
  85. package/dist/src/ee/workflow-event.js +81 -0
  86. package/dist/src/flow/compaction/compress.d.ts +3 -3
  87. package/dist/src/flow/compaction/compress.js +45 -8
  88. package/dist/src/flow/compaction/extract.d.ts +4 -7
  89. package/dist/src/flow/compaction/extract.js +50 -10
  90. package/dist/src/flow/compaction/index.d.ts +13 -1
  91. package/dist/src/flow/compaction/index.js +70 -3
  92. package/dist/src/flow/compaction/input-guard.d.ts +24 -0
  93. package/dist/src/flow/compaction/input-guard.js +43 -0
  94. package/dist/src/flow/fold-planning.d.ts +36 -0
  95. package/dist/src/flow/fold-planning.js +83 -0
  96. package/dist/src/flow/hierarchy.d.ts +146 -0
  97. package/dist/src/flow/hierarchy.js +427 -0
  98. package/dist/src/flow/index.d.ts +1 -0
  99. package/dist/src/flow/index.js +2 -0
  100. package/dist/src/flow/run-artifacts.d.ts +102 -0
  101. package/dist/src/flow/run-artifacts.js +208 -0
  102. package/dist/src/generated/version.d.ts +1 -1
  103. package/dist/src/generated/version.js +1 -1
  104. package/dist/src/gsd/assessment-schema.d.ts +44 -0
  105. package/dist/src/gsd/assessment-schema.js +134 -0
  106. package/dist/src/gsd/capability-registry.d.ts +45 -0
  107. package/dist/src/gsd/capability-registry.js +337 -0
  108. package/dist/src/gsd/complexity-assessor.d.ts +39 -0
  109. package/dist/src/gsd/complexity-assessor.js +152 -0
  110. package/dist/src/gsd/config-bridge.d.ts +7 -0
  111. package/dist/src/gsd/config-bridge.js +114 -0
  112. package/dist/src/gsd/config-loader.d.ts +27 -0
  113. package/dist/src/gsd/config-loader.js +50 -0
  114. package/dist/src/gsd/council-context.d.ts +44 -0
  115. package/dist/src/gsd/council-context.js +114 -0
  116. package/dist/src/gsd/ee-closure.d.ts +28 -0
  117. package/dist/src/gsd/ee-closure.js +49 -0
  118. package/dist/src/gsd/flags.d.ts +55 -0
  119. package/dist/src/gsd/flags.js +83 -0
  120. package/dist/src/gsd/gsd-dispatch.d.ts +58 -0
  121. package/dist/src/gsd/gsd-dispatch.js +131 -0
  122. package/dist/src/gsd/gsd-runtime.d.ts +22 -0
  123. package/dist/src/gsd/gsd-runtime.js +37 -0
  124. package/dist/src/gsd/host-adapter.d.ts +11 -0
  125. package/dist/src/gsd/host-adapter.js +29 -0
  126. package/dist/src/gsd/index.d.ts +24 -1
  127. package/dist/src/gsd/index.js +27 -0
  128. package/dist/src/gsd/loop-host-contract.d.ts +21 -0
  129. package/dist/src/gsd/loop-host-contract.js +39 -0
  130. package/dist/src/gsd/loop-host.d.ts +69 -0
  131. package/dist/src/gsd/loop-host.js +245 -0
  132. package/dist/src/gsd/loop-resolver.d.ts +36 -0
  133. package/dist/src/gsd/loop-resolver.js +79 -0
  134. package/dist/src/gsd/model-tier.d.ts +13 -0
  135. package/dist/src/gsd/model-tier.js +45 -0
  136. package/dist/src/gsd/mutation-gate.d.ts +16 -0
  137. package/dist/src/gsd/mutation-gate.js +41 -0
  138. package/dist/src/gsd/native-roadmap.d.ts +89 -0
  139. package/dist/src/gsd/native-roadmap.js +343 -0
  140. package/dist/src/gsd/native-state.d.ts +47 -0
  141. package/dist/src/gsd/native-state.js +220 -0
  142. package/dist/src/gsd/paths.d.ts +23 -0
  143. package/dist/src/gsd/paths.js +66 -0
  144. package/dist/src/gsd/phase-dag.d.ts +12 -0
  145. package/dist/src/gsd/phase-dag.js +94 -0
  146. package/dist/src/gsd/phase-sync.d.ts +42 -0
  147. package/dist/src/gsd/phase-sync.js +321 -0
  148. package/dist/src/gsd/pil-gate-context.d.ts +13 -0
  149. package/dist/src/gsd/pil-gate-context.js +64 -0
  150. package/dist/src/gsd/pil-gate-critic.d.ts +19 -0
  151. package/dist/src/gsd/pil-gate-critic.js +74 -0
  152. package/dist/src/gsd/plan-council-prompts.d.ts +25 -0
  153. package/dist/src/gsd/plan-council-prompts.js +79 -0
  154. package/dist/src/gsd/plan-council.d.ts +44 -0
  155. package/dist/src/gsd/plan-council.js +251 -0
  156. package/dist/src/gsd/plan-gate-vocabulary.d.ts +40 -0
  157. package/dist/src/gsd/plan-gate-vocabulary.js +64 -0
  158. package/dist/src/gsd/product-workspace.d.ts +13 -0
  159. package/dist/src/gsd/product-workspace.js +124 -0
  160. package/dist/src/gsd/ship-bridge.d.ts +25 -0
  161. package/dist/src/gsd/ship-bridge.js +65 -0
  162. package/dist/src/gsd/state-document.d.ts +40 -0
  163. package/dist/src/gsd/state-document.js +163 -0
  164. package/dist/src/gsd/verdict-schema.d.ts +39 -0
  165. package/dist/src/gsd/verdict-schema.js +144 -0
  166. package/dist/src/gsd/verify-context.d.ts +22 -0
  167. package/dist/src/gsd/verify-context.js +27 -0
  168. package/dist/src/gsd/verify-council-prompts.d.ts +19 -0
  169. package/dist/src/gsd/verify-council-prompts.js +85 -0
  170. package/dist/src/gsd/verify-council.d.ts +25 -0
  171. package/dist/src/gsd/verify-council.js +119 -0
  172. package/dist/src/gsd/verify-gate-vocabulary.d.ts +25 -0
  173. package/dist/src/gsd/verify-gate-vocabulary.js +46 -0
  174. package/dist/src/gsd/workflow-engine.d.ts +60 -0
  175. package/dist/src/gsd/workflow-engine.js +207 -0
  176. package/dist/src/gsd/workflow-tools.d.ts +13 -0
  177. package/dist/src/gsd/workflow-tools.js +277 -0
  178. package/dist/src/hooks/index.js +1 -1
  179. package/dist/src/index.js +44 -11
  180. package/dist/src/maintain/pr-builder.js +23 -13
  181. package/dist/src/mcp/auto-setup.js +57 -32
  182. package/dist/src/mcp/client-pool.js +1 -1
  183. package/dist/src/mcp/ee-tools.js +1 -0
  184. package/dist/src/mcp/oauth-callback.js +2 -2
  185. package/dist/src/mcp/research-onboarding.js +8 -7
  186. package/dist/src/mcp/runtime.js +34 -2
  187. package/dist/src/mcp/setup-guide-text.d.ts +1 -1
  188. package/dist/src/mcp/setup-guide-text.js +77 -76
  189. package/dist/src/models/catalog-client.d.ts +87 -0
  190. package/dist/src/models/catalog-client.js +105 -38
  191. package/dist/src/models/catalog.json +528 -265
  192. package/dist/src/models/registry.d.ts +22 -7
  193. package/dist/src/models/registry.js +73 -10
  194. package/dist/src/ops/doctor.js +8 -8
  195. package/dist/src/orchestrator/auto-commit.js +1 -1
  196. package/dist/src/orchestrator/batch-turn-runner.js +2 -2
  197. package/dist/src/orchestrator/cache-prefix.d.ts +67 -0
  198. package/dist/src/orchestrator/cache-prefix.js +83 -0
  199. package/dist/src/orchestrator/compact-request.d.ts +32 -0
  200. package/dist/src/orchestrator/compact-request.js +41 -0
  201. package/dist/src/orchestrator/compaction.d.ts +10 -0
  202. package/dist/src/orchestrator/compaction.js +27 -7
  203. package/dist/src/orchestrator/council-manager.d.ts +12 -3
  204. package/dist/src/orchestrator/council-manager.js +65 -24
  205. package/dist/src/orchestrator/cross-turn-dedup.d.ts +6 -0
  206. package/dist/src/orchestrator/cross-turn-dedup.js +22 -1
  207. package/dist/src/orchestrator/error-utils.d.ts +29 -0
  208. package/dist/src/orchestrator/error-utils.js +132 -24
  209. package/dist/src/orchestrator/grounding-check.js +39 -1
  210. package/dist/src/orchestrator/message-processor.js +242 -33
  211. package/dist/src/orchestrator/orchestrator.d.ts +39 -3
  212. package/dist/src/orchestrator/orchestrator.js +651 -102
  213. package/dist/src/orchestrator/preprocessor.js +1 -1
  214. package/dist/src/orchestrator/proactive-compact-detector.d.ts +26 -0
  215. package/dist/src/orchestrator/proactive-compact-detector.js +36 -0
  216. package/dist/src/orchestrator/prompts.js +159 -159
  217. package/dist/src/orchestrator/reactive-delegation.d.ts +39 -0
  218. package/dist/src/orchestrator/reactive-delegation.js +59 -0
  219. package/dist/src/orchestrator/retry-classifier.d.ts +2 -1
  220. package/dist/src/orchestrator/retry-classifier.js +46 -2
  221. package/dist/src/orchestrator/safety-intercept.d.ts +45 -0
  222. package/dist/src/orchestrator/safety-intercept.js +55 -0
  223. package/dist/src/orchestrator/scope-reminder.js +1 -1
  224. package/dist/src/orchestrator/session-experience.d.ts +2 -1
  225. package/dist/src/orchestrator/session-experience.js +2 -1
  226. package/dist/src/orchestrator/should-run-gate.d.ts +5 -0
  227. package/dist/src/orchestrator/should-run-gate.js +18 -0
  228. package/dist/src/orchestrator/stall-watchdog.d.ts +24 -3
  229. package/dist/src/orchestrator/stall-watchdog.js +47 -13
  230. package/dist/src/orchestrator/stream-runner.js +62 -29
  231. package/dist/src/orchestrator/sub-agent-cap.d.ts +13 -1
  232. package/dist/src/orchestrator/sub-agent-cap.js +16 -1
  233. package/dist/src/orchestrator/sub-agent-model-tier.d.ts +13 -1
  234. package/dist/src/orchestrator/sub-agent-model-tier.js +16 -2
  235. package/dist/src/orchestrator/subagent-compactor.d.ts +53 -1
  236. package/dist/src/orchestrator/subagent-compactor.js +126 -15
  237. package/dist/src/orchestrator/tool-engine.d.ts +26 -0
  238. package/dist/src/orchestrator/tool-engine.js +669 -56
  239. package/dist/src/orchestrator/tool-limit-auto-recover.d.ts +22 -0
  240. package/dist/src/orchestrator/tool-limit-auto-recover.js +30 -0
  241. package/dist/src/orchestrator/turn-runner-deps.d.ts +19 -0
  242. package/dist/src/orchestrator/turn-watchdog.d.ts +37 -0
  243. package/dist/src/orchestrator/turn-watchdog.js +55 -0
  244. package/dist/src/pil/agent-operating-contract.d.ts +1 -1
  245. package/dist/src/pil/agent-operating-contract.js +1 -1
  246. package/dist/src/pil/cheap-model-playbook.d.ts +1 -1
  247. package/dist/src/pil/cheap-model-playbook.js +5 -1
  248. package/dist/src/pil/cheap-model-workbooks.d.ts +1 -1
  249. package/dist/src/pil/cheap-model-workbooks.js +1 -1
  250. package/dist/src/pil/discovery-types.d.ts +1 -0
  251. package/dist/src/pil/discovery.js +16 -11
  252. package/dist/src/pil/layer1-intent.d.ts +18 -6
  253. package/dist/src/pil/layer1-intent.js +66 -757
  254. package/dist/src/pil/layer15-context-scan.js +15 -1
  255. package/dist/src/pil/layer2_5-ponytail.js +8 -8
  256. package/dist/src/pil/layer3-ee-injection.js +23 -8
  257. package/dist/src/pil/layer4-gsd.js +69 -16
  258. package/dist/src/pil/layer5-context.js +7 -3
  259. package/dist/src/pil/layer6-output.d.ts +23 -0
  260. package/dist/src/pil/layer6-output.js +5 -1
  261. package/dist/src/pil/llm-classify.d.ts +33 -2
  262. package/dist/src/pil/llm-classify.js +123 -131
  263. package/dist/src/pil/native-capabilities-workbook.d.ts +1 -1
  264. package/dist/src/pil/native-capabilities-workbook.js +1 -0
  265. package/dist/src/pil/pipeline.js +34 -2
  266. package/dist/src/pil/response-tools.js +5 -3
  267. package/dist/src/pil/schema.d.ts +1 -0
  268. package/dist/src/pil/schema.js +2 -0
  269. package/dist/src/pil/types.d.ts +18 -0
  270. package/dist/src/playbook/directives.d.ts +4 -0
  271. package/dist/src/playbook/directives.js +17 -5
  272. package/dist/src/product-loop/backlog-builder.d.ts +14 -1
  273. package/dist/src/product-loop/backlog-builder.js +30 -6
  274. package/dist/src/product-loop/discovery-context-format.js +3 -1
  275. package/dist/src/product-loop/discovery-ecosystem.js +4 -1
  276. package/dist/src/product-loop/discovery-interview.js +32 -3
  277. package/dist/src/product-loop/discovery-schema.js +5 -1
  278. package/dist/src/product-loop/done-gate.js +3 -3
  279. package/dist/src/product-loop/ideal-trace.d.ts +7 -0
  280. package/dist/src/product-loop/ideal-trace.js +64 -0
  281. package/dist/src/product-loop/index.d.ts +13 -1
  282. package/dist/src/product-loop/index.js +333 -52
  283. package/dist/src/product-loop/loop-driver.d.ts +7 -0
  284. package/dist/src/product-loop/loop-driver.js +327 -116
  285. package/dist/src/product-loop/phase-plan.d.ts +5 -0
  286. package/dist/src/product-loop/phase-plan.js +39 -2
  287. package/dist/src/product-loop/phase-runner.js +9 -1
  288. package/dist/src/product-loop/progress-snapshot.js +4 -4
  289. package/dist/src/product-loop/sprint-runner.d.ts +111 -0
  290. package/dist/src/product-loop/sprint-runner.js +559 -16
  291. package/dist/src/product-loop/types.d.ts +36 -5
  292. package/dist/src/providers/adapter.d.ts +1 -1
  293. package/dist/src/providers/adapter.js +3 -4
  294. package/dist/src/providers/auth/browser-flow.d.ts +1 -1
  295. package/dist/src/providers/auth/browser-flow.js +1 -1
  296. package/dist/src/providers/auth/openai-oauth.js +1 -1
  297. package/dist/src/providers/auth/registry.js +0 -34
  298. package/dist/src/providers/auth/token-store.js +4 -1
  299. package/dist/src/providers/auth/types.d.ts +1 -1
  300. package/dist/src/providers/auth/types.js +1 -1
  301. package/dist/src/providers/capabilities.d.ts +24 -5
  302. package/dist/src/providers/capabilities.js +42 -24
  303. package/dist/src/providers/endpoints.d.ts +2 -2
  304. package/dist/src/providers/endpoints.js +11 -10
  305. package/dist/src/providers/keychain.d.ts +1 -1
  306. package/dist/src/providers/keychain.js +7 -9
  307. package/dist/src/providers/mcp-vision-bridge.js +82 -172
  308. package/dist/src/providers/openai-compatible.js +8 -1
  309. package/dist/src/providers/pricing.d.ts +2 -2
  310. package/dist/src/providers/pricing.js +3 -13
  311. package/dist/src/providers/runtime.d.ts +27 -2
  312. package/dist/src/providers/runtime.js +78 -15
  313. package/dist/src/providers/strategies/base.strategy.d.ts +16 -0
  314. package/dist/src/providers/strategies/base.strategy.js +24 -1
  315. package/dist/src/providers/strategies/{siliconflow.strategy.d.ts → opencode-go.strategy.d.ts} +3 -3
  316. package/dist/src/providers/strategies/opencode-go.strategy.js +83 -0
  317. package/dist/src/providers/strategies/registry.js +4 -4
  318. package/dist/src/providers/strategies/thinking-mode.d.ts +109 -0
  319. package/dist/src/providers/strategies/thinking-mode.js +280 -1
  320. package/dist/src/providers/strategies/zai.strategy.d.ts +14 -0
  321. package/dist/src/providers/strategies/zai.strategy.js +44 -0
  322. package/dist/src/providers/types.d.ts +5 -6
  323. package/dist/src/providers/types.js +2 -2
  324. package/dist/src/providers/vision-backend.d.ts +47 -0
  325. package/dist/src/providers/vision-backend.js +258 -0
  326. package/dist/src/providers/vision-proxy.d.ts +22 -9
  327. package/dist/src/providers/vision-proxy.js +63 -132
  328. package/dist/src/providers/wire-debug.js +95 -0
  329. package/dist/src/reporter/index.js +1 -1
  330. package/dist/src/router/decide.d.ts +13 -0
  331. package/dist/src/router/decide.js +138 -36
  332. package/dist/src/router/peak-hour.d.ts +38 -0
  333. package/dist/src/router/peak-hour.js +107 -0
  334. package/dist/src/router/step-router.js +3 -2
  335. package/dist/src/router/warm.js +4 -5
  336. package/dist/src/scaffold/bb-ecosystem-apply.js +47 -47
  337. package/dist/src/scaffold/bb-quality-gate.js +5 -5
  338. package/dist/src/scaffold/continuation-prompt.d.ts +11 -0
  339. package/dist/src/scaffold/continuation-prompt.js +86 -60
  340. package/dist/src/scaffold/init-new.js +453 -453
  341. package/dist/src/scaffold/point-to-existing.d.ts +21 -0
  342. package/dist/src/scaffold/point-to-existing.js +25 -0
  343. package/dist/src/self-qa/agentic-loop.js +22 -22
  344. package/dist/src/{ui/state → state}/active-run.d.ts +19 -0
  345. package/dist/src/{ui/state → state}/active-run.js +21 -0
  346. package/dist/src/{ui/status-bar/store.d.ts → state/status-bar-store.d.ts} +4 -1
  347. package/dist/src/{ui/status-bar/store.js → state/status-bar-store.js} +12 -9
  348. package/dist/src/state/turn-trace.d.ts +43 -0
  349. package/dist/src/state/turn-trace.js +32 -0
  350. package/dist/src/storage/db.js +2 -1
  351. package/dist/src/storage/index.d.ts +1 -1
  352. package/dist/src/storage/index.js +1 -1
  353. package/dist/src/storage/interaction-log.d.ts +1 -1
  354. package/dist/src/storage/interaction-log.js +5 -5
  355. package/dist/src/storage/migrations.js +196 -126
  356. package/dist/src/storage/session-experience-store.js +4 -4
  357. package/dist/src/storage/sessions.d.ts +28 -10
  358. package/dist/src/storage/sessions.js +112 -55
  359. package/dist/src/storage/transcript-view.js +1 -1
  360. package/dist/src/storage/transcript.d.ts +51 -0
  361. package/dist/src/storage/transcript.js +383 -112
  362. package/dist/src/storage/usage.js +14 -14
  363. package/dist/src/storage/workspaces.js +12 -12
  364. package/dist/src/tools/file.d.ts +15 -0
  365. package/dist/src/tools/file.js +32 -0
  366. package/dist/src/tools/native-tools.js +5 -0
  367. package/dist/src/tools/registry.d.ts +3 -0
  368. package/dist/src/tools/registry.js +460 -22
  369. package/dist/src/tools/research.d.ts +29 -0
  370. package/dist/src/tools/research.js +233 -0
  371. package/dist/src/types/index.d.ts +118 -3
  372. package/dist/src/ui/app.js +0 -0
  373. package/dist/src/ui/cards/product-status-card.js +1 -1
  374. package/dist/src/ui/components/bubble-body-guard.d.ts +27 -0
  375. package/dist/src/ui/components/bubble-body-guard.js +50 -0
  376. package/dist/src/ui/components/context-rail.d.ts +26 -0
  377. package/dist/src/ui/components/context-rail.js +33 -0
  378. package/dist/src/ui/components/council-conclusion-card.d.ts +73 -0
  379. package/dist/src/ui/components/council-conclusion-card.js +420 -0
  380. package/dist/src/ui/components/council-debate-pill.d.ts +36 -0
  381. package/dist/src/ui/components/council-debate-pill.js +34 -0
  382. package/dist/src/ui/components/council-info-card.js +2 -2
  383. package/dist/src/ui/components/council-leader-bubble.d.ts +10 -3
  384. package/dist/src/ui/components/council-leader-bubble.js +21 -11
  385. package/dist/src/ui/components/council-message-bubble.d.ts +15 -2
  386. package/dist/src/ui/components/council-message-bubble.js +16 -15
  387. package/dist/src/ui/components/council-phase-timeline.d.ts +9 -1
  388. package/dist/src/ui/components/council-phase-timeline.js +49 -15
  389. package/dist/src/ui/components/council-placeholder-bubble.d.ts +16 -9
  390. package/dist/src/ui/components/council-placeholder-bubble.js +32 -29
  391. package/dist/src/ui/components/council-question-card.js +12 -12
  392. package/dist/src/ui/components/council-rail-rounds.d.ts +26 -0
  393. package/dist/src/ui/components/council-rail-rounds.js +57 -0
  394. package/dist/src/ui/components/council-round-group.d.ts +38 -0
  395. package/dist/src/ui/components/council-round-group.js +88 -0
  396. package/dist/src/ui/components/council-status-list.d.ts +3 -1
  397. package/dist/src/ui/components/council-status-list.js +36 -24
  398. package/dist/src/ui/components/council-synthesis-banner.d.ts +7 -2
  399. package/dist/src/ui/components/council-synthesis-banner.js +20 -5
  400. package/dist/src/ui/components/halt-recovery-card.js +9 -5
  401. package/dist/src/ui/components/jump-to-latest-pill.d.ts +11 -0
  402. package/dist/src/ui/components/jump-to-latest-pill.js +14 -0
  403. package/dist/src/ui/components/prompt-box.js +18 -16
  404. package/dist/src/ui/components/session-tree-card.d.ts +14 -0
  405. package/dist/src/ui/components/session-tree-card.js +46 -0
  406. package/dist/src/ui/components/slash-inline-menu.d.ts +12 -0
  407. package/dist/src/ui/components/slash-inline-menu.js +26 -5
  408. package/dist/src/ui/components/task-list-panel.d.ts +14 -1
  409. package/dist/src/ui/components/task-list-panel.js +22 -2
  410. package/dist/src/ui/containers/modals-layer.d.ts +2 -1
  411. package/dist/src/ui/hooks/use-session-picker.d.ts +3 -3
  412. package/dist/src/ui/mcp-modal.js +2 -4
  413. package/dist/src/ui/modals/api-key-modal.js +1 -1
  414. package/dist/src/ui/modals/connect-modal.js +4 -3
  415. package/dist/src/ui/modals/session-picker-modal.d.ts +2 -2
  416. package/dist/src/ui/modals/session-picker-modal.js +3 -5
  417. package/dist/src/ui/picker-providers.d.ts +1 -1
  418. package/dist/src/ui/picker-providers.js +1 -1
  419. package/dist/src/ui/primitives/index.d.ts +1 -0
  420. package/dist/src/ui/primitives/index.js +2 -0
  421. package/dist/src/ui/primitives/semantic-primitives.d.ts +76 -0
  422. package/dist/src/ui/primitives/semantic-primitives.js +81 -0
  423. package/dist/src/ui/slash/compact.js +5 -7
  424. package/dist/src/ui/slash/cost.js +1 -1
  425. package/dist/src/ui/slash/council-inspect.js +4 -4
  426. package/dist/src/ui/slash/council.js +19 -1
  427. package/dist/src/ui/slash/debug.d.ts +3 -31
  428. package/dist/src/ui/slash/debug.js +9 -20
  429. package/dist/src/ui/slash/ideal.d.ts +6 -2
  430. package/dist/src/ui/slash/ideal.js +97 -7
  431. package/dist/src/ui/slash/menu-items.d.ts +7 -0
  432. package/dist/src/ui/slash/menu-items.js +12 -18
  433. package/dist/src/ui/slash/registry.d.ts +2 -0
  434. package/dist/src/ui/slash/registry.js +4 -0
  435. package/dist/src/ui/status-bar/cache-hit.d.ts +6 -0
  436. package/dist/src/ui/status-bar/cache-hit.js +9 -0
  437. package/dist/src/ui/status-bar/index.d.ts +1 -1
  438. package/dist/src/ui/status-bar/index.js +7 -3
  439. package/dist/src/ui/status-bar/usd-meter.d.ts +5 -4
  440. package/dist/src/ui/status-bar/usd-meter.js +6 -4
  441. package/dist/src/ui/theme.d.ts +1 -0
  442. package/dist/src/ui/theme.js +2 -0
  443. package/dist/src/ui/types.d.ts +7 -0
  444. package/dist/src/ui/use-app-logic.js +0 -0
  445. package/dist/src/ui/utils/format.d.ts +14 -0
  446. package/dist/src/ui/utils/format.js +23 -3
  447. package/dist/src/usage/downgrade.js +2 -2
  448. package/dist/src/usage/product-ledger.js +2 -2
  449. package/dist/src/utils/clipboard-image.js +23 -23
  450. package/dist/src/utils/install-manager.js +14 -11
  451. package/dist/src/utils/logger.js +2 -2
  452. package/dist/src/utils/permission-mode.js +5 -3
  453. package/dist/src/utils/redactor.js +1 -1
  454. package/dist/src/utils/settings.d.ts +153 -5
  455. package/dist/src/utils/settings.js +233 -29
  456. package/dist/src/utils/side-question.js +2 -2
  457. package/dist/src/utils/skills.js +3 -3
  458. package/dist/src/utils/visible-retry.d.ts +11 -0
  459. package/dist/src/utils/visible-retry.js +10 -1
  460. package/dist/src/verify/entrypoint.d.ts +1 -1
  461. package/dist/src/verify/entrypoint.js +1 -1
  462. package/dist/src/verify/recipes.d.ts +13 -0
  463. package/dist/src/verify/recipes.js +15 -0
  464. package/package.json +135 -132
  465. package/dist/src/providers/auth/gcloud.d.ts +0 -28
  466. package/dist/src/providers/auth/gcloud.js +0 -102
  467. package/dist/src/providers/auth/gemini-oauth.d.ts +0 -82
  468. package/dist/src/providers/auth/gemini-oauth.js +0 -472
  469. package/dist/src/providers/gemini.d.ts +0 -11
  470. package/dist/src/providers/gemini.js +0 -45
  471. package/dist/src/providers/siliconflow-sse-repair.d.ts +0 -58
  472. package/dist/src/providers/siliconflow-sse-repair.js +0 -177
  473. package/dist/src/providers/strategies/google.strategy.d.ts +0 -22
  474. package/dist/src/providers/strategies/google.strategy.js +0 -174
  475. package/dist/src/providers/strategies/siliconflow.strategy.js +0 -29
  476. package/dist/src/ui/containers/chat-feed.d.ts +0 -40
  477. package/dist/src/ui/containers/chat-feed.js +0 -66
@@ -0,0 +1,233 @@
1
+ /**
2
+ * src/tools/research.ts
3
+ *
4
+ * Native research tools for the inner agent.
5
+ *
6
+ * These replace the previous external MCP servers (fetch, tavily, and eventually
7
+ * context7 / muonroi-docs) so that web/docs lookup and search are:
8
+ * - Always available without spawn / warmup / "Connection closed"
9
+ * - Subject to the same permission, capping, redaction and cost rules as other builtins
10
+ * - Fast and reliable on first turn
11
+ *
12
+ * memory and playwright were removed from defaults (see auto-setup.ts).
13
+ * Full browser automation (playwright) can still be added manually if needed.
14
+ */
15
+ import { dynamicTool, jsonSchema } from "ai";
16
+ import TurndownService from "turndown";
17
+ import { getMcpKey } from "../mcp/mcp-keychain.js";
18
+ const turndown = new TurndownService({
19
+ headingStyle: "atx",
20
+ codeBlockStyle: "fenced",
21
+ bulletListMarker: "-",
22
+ });
23
+ // Basic cleanup for HTML before turndown (remove scripts, styles, etc.)
24
+ function sanitizeForMarkdown(html) {
25
+ return html
26
+ .replace(/<script[\s\S]*?<\/script>/gi, "")
27
+ .replace(/<style[\s\S]*?<\/style>/gi, "")
28
+ .replace(/<noscript[\s\S]*?<\/noscript>/gi, "")
29
+ .replace(/<!--[\s\S]*?-->/g, "");
30
+ }
31
+ function extractTitle(html) {
32
+ const m = html.match(/<title[^>]*>([^<]+)<\/title>/i);
33
+ return m ? m[1].trim() : undefined;
34
+ }
35
+ export async function fetchUrl(url, opts = {}) {
36
+ const { format = "markdown", maxChars = 12000 } = opts;
37
+ const controller = new AbortController();
38
+ const timeout = setTimeout(() => controller.abort(), 15000);
39
+ try {
40
+ const res = await fetch(url, {
41
+ signal: controller.signal,
42
+ headers: {
43
+ "User-Agent": "muonroi-cli/1.0 (+https://github.com/muonroi/muonroi-cli)",
44
+ Accept: "text/html,application/xhtml+xml,application/json,text/plain,*/*",
45
+ },
46
+ redirect: "follow",
47
+ });
48
+ if (!res.ok) {
49
+ return `ERROR fetch_failed: HTTP ${res.status} ${res.statusText} for ${url}`;
50
+ }
51
+ const contentType = res.headers.get("content-type") || "";
52
+ let body = await res.text();
53
+ if (format === "html") {
54
+ return body.length > maxChars ? body.slice(0, maxChars) + "\n... [truncated]" : body;
55
+ }
56
+ if (contentType.includes("application/json")) {
57
+ try {
58
+ const obj = JSON.parse(body);
59
+ body = JSON.stringify(obj, null, 2);
60
+ }
61
+ catch { }
62
+ return body.length > maxChars ? body.slice(0, maxChars) + "\n... [truncated]" : body;
63
+ }
64
+ // Treat as HTML or plain text
65
+ const isHtml = /<\/?[a-z][\s\S]*>/i.test(body) || contentType.includes("html");
66
+ if (format === "text") {
67
+ // Very lightweight text extraction
68
+ const text = isHtml
69
+ ? body
70
+ .replace(/<[^>]+>/g, " ")
71
+ .replace(/\s+/g, " ")
72
+ .trim()
73
+ : body;
74
+ return text.length > maxChars ? text.slice(0, maxChars) + "\n... [truncated]" : text;
75
+ }
76
+ // markdown (default)
77
+ if (isHtml) {
78
+ const cleaned = sanitizeForMarkdown(body);
79
+ const title = extractTitle(body);
80
+ let md = turndown.turndown(cleaned);
81
+ if (title && !md.startsWith("# ")) {
82
+ md = `# ${title}\n\n${md}`;
83
+ }
84
+ if (md.length > maxChars) {
85
+ md = md.slice(0, maxChars) + "\n\n... [truncated — use more specific URL or smaller scope]";
86
+ }
87
+ // Add source
88
+ return `${md}\n\n_Source: ${url}_`;
89
+ }
90
+ // Plain text → code block or just return
91
+ const out = body.length > maxChars ? body.slice(0, maxChars) + "\n... [truncated]" : body;
92
+ return `\`\`\`\n${out}\n\`\`\`\n\n_Source: ${url}_`;
93
+ }
94
+ catch (err) {
95
+ if (err?.name === "AbortError") {
96
+ return `ERROR fetch_timeout: timed out after 15s fetching ${url}`;
97
+ }
98
+ return `ERROR fetch_error: ${err instanceof Error ? err.message : String(err)}`;
99
+ }
100
+ finally {
101
+ clearTimeout(timeout);
102
+ }
103
+ }
104
+ export async function webSearch(query, opts = {}) {
105
+ const maxResults = Math.max(1, Math.min(opts.maxResults ?? 8, 20));
106
+ let key = opts.apiKey;
107
+ if (!key) {
108
+ key = (await getMcpKey("tavily")) || process.env.TAVILY_API_KEY || "";
109
+ }
110
+ if (!key || key.length < 10) {
111
+ return ("ERROR no_tavily_key: Tavily API key is required for web_search. " +
112
+ "Run `muonroi-cli mcp setup-research` or set TAVILY_API_KEY. " +
113
+ "You can also use `fetch_url` for direct URLs.");
114
+ }
115
+ const controller = new AbortController();
116
+ const timeout = setTimeout(() => controller.abort(), 12000);
117
+ try {
118
+ const res = await fetch("https://api.tavily.com/search", {
119
+ method: "POST",
120
+ signal: controller.signal,
121
+ headers: {
122
+ "Content-Type": "application/json",
123
+ },
124
+ body: JSON.stringify({
125
+ api_key: key,
126
+ query,
127
+ max_results: maxResults,
128
+ include_answer: true,
129
+ include_raw_content: false,
130
+ search_depth: "basic",
131
+ }),
132
+ });
133
+ if (!res.ok) {
134
+ const text = await res.text().catch(() => "");
135
+ return `ERROR tavily_http_${res.status}: ${text.slice(0, 300)}`;
136
+ }
137
+ const data = await res.json();
138
+ const lines = [];
139
+ if (data.answer) {
140
+ lines.push("**Answer summary:**");
141
+ lines.push(data.answer);
142
+ lines.push("");
143
+ }
144
+ const results = Array.isArray(data.results) ? data.results : [];
145
+ if (results.length === 0) {
146
+ return "No web results found.";
147
+ }
148
+ lines.push(`**Web results** (top ${Math.min(results.length, maxResults)}):\n`);
149
+ for (const r of results.slice(0, maxResults)) {
150
+ const title = r.title || r.url;
151
+ const url = r.url;
152
+ const content = (r.content || r.raw_content || "").trim().slice(0, 600);
153
+ lines.push(`- **${title}**`);
154
+ lines.push(` ${url}`);
155
+ if (content)
156
+ lines.push(` ${content.replace(/\s+/g, " ")}`);
157
+ lines.push("");
158
+ }
159
+ if (data.query) {
160
+ lines.push(`_Query: ${data.query}_`);
161
+ }
162
+ return lines.join("\n");
163
+ }
164
+ catch (err) {
165
+ if (err?.name === "AbortError") {
166
+ return "ERROR web_search_timeout: Tavily request timed out.";
167
+ }
168
+ return `ERROR web_search_failed: ${err instanceof Error ? err.message : String(err)}`;
169
+ }
170
+ finally {
171
+ clearTimeout(timeout);
172
+ }
173
+ }
174
+ /** Register the native research tools into the provided ToolSet. */
175
+ export function registerNativeResearchTools(tools) {
176
+ tools.fetch_url = dynamicTool({
177
+ description: "Fetch a URL and return clean, readable content as markdown (default), plain text, or raw HTML. " +
178
+ "Ideal for documentation, articles, GitHub, blog posts, raw files, and any public web page. " +
179
+ "Use this for most 'read this URL' needs instead of external MCP fetch.",
180
+ inputSchema: jsonSchema({
181
+ type: "object",
182
+ properties: {
183
+ url: { type: "string", description: "The full http(s) URL to fetch" },
184
+ format: {
185
+ type: "string",
186
+ enum: ["markdown", "text", "html"],
187
+ description: "Output format. Default: markdown (best for agents)",
188
+ },
189
+ maxChars: {
190
+ type: "number",
191
+ description: "Maximum characters to return (500-30000). Default ~12000.",
192
+ },
193
+ },
194
+ required: ["url"],
195
+ additionalProperties: false,
196
+ }),
197
+ execute: async (input) => {
198
+ const url = String(input?.url || "").trim();
199
+ if (!url || !/^https?:\/\//i.test(url)) {
200
+ return "ERROR invalid_url: fetch_url requires a full http(s):// URL";
201
+ }
202
+ const format = (["markdown", "text", "html"].includes(input?.format) ? input.format : "markdown");
203
+ const maxChars = typeof input?.maxChars === "number" ? input.maxChars : undefined;
204
+ return fetchUrl(url, { format, maxChars });
205
+ },
206
+ });
207
+ tools.web_search = dynamicTool({
208
+ description: "Search the live web using Tavily (LLM-optimized search with summaries). " +
209
+ "Returns titles, URLs, and content snippets. Requires a Tavily API key (free tier available). " +
210
+ "Use together with fetch_url when you need deeper content from specific results.",
211
+ inputSchema: jsonSchema({
212
+ type: "object",
213
+ properties: {
214
+ query: { type: "string", description: "Search query (natural language is fine)" },
215
+ maxResults: {
216
+ type: "number",
217
+ description: "How many results to return (1-20). Default 8.",
218
+ },
219
+ },
220
+ required: ["query"],
221
+ additionalProperties: false,
222
+ }),
223
+ execute: async (input) => {
224
+ const query = String(input?.query || "").trim();
225
+ if (!query)
226
+ return "ERROR invalid_query: web_search requires a non-empty query";
227
+ const maxResults = typeof input?.maxResults === "number" ? input.maxResults : undefined;
228
+ return webSearch(query, { maxResults });
229
+ },
230
+ });
231
+ return tools;
232
+ }
233
+ //# sourceMappingURL=research.js.map
@@ -34,6 +34,8 @@ export interface TaskRequest {
34
34
  description: string;
35
35
  prompt: string;
36
36
  maxToolRounds?: number;
37
+ /** When set, bypasses parent-tier cap and uses this model for the sub-agent. */
38
+ modelId?: string;
37
39
  }
38
40
  export interface TaskRun {
39
41
  agent: string;
@@ -246,7 +248,7 @@ export interface CouncilQuestionData {
246
248
  options?: CouncilQuestionOption[];
247
249
  defaultIndex?: number;
248
250
  }
249
- export type CouncilStatusPhase = "clarify" | "plan_debate" | "research" | "opening" | "exchange" | "evaluate" | "synthesis" | "summary";
251
+ export type CouncilStatusPhase = "clarify" | "panel_select" | "plan_debate" | "research" | "opening" | "exchange" | "evaluate" | "synthesis" | "summary";
250
252
  export type CouncilStatusState = "start" | "tick" | "done" | "error";
251
253
  export interface CouncilStatusData {
252
254
  statusId: string;
@@ -256,12 +258,14 @@ export interface CouncilStatusData {
256
258
  detail?: string;
257
259
  role?: string;
258
260
  elapsedMs?: number;
261
+ /** Client-side first-seen stamp (upsertStatus), back-dated by the emitted elapsedMs. Drives live-ticking elapsed. */
262
+ startedAt?: number;
259
263
  tokensIn?: number;
260
264
  tokensOut?: number;
261
265
  errorMessage?: string;
262
266
  }
263
267
  /** High-level lifecycle event for a council phase. Drives the phase timeline UI. */
264
- export type CouncilPhaseKind = "clarification" | "clarification_round" | "preflight" | "debate_plan" | "research" | "opening" | "round" | "evaluation" | "mid_research" | "summary" | "synthesis" | "action_plan"
268
+ export type CouncilPhaseKind = "clarification" | "clarification_round" | "preflight" | "debate_plan" | "research" | "opening" | "round" | "evaluation" | "mid_research" | "grounding_verify" | "summary" | "synthesis" | "action_plan"
265
269
  /**
266
270
  * Sprint stage emitted by sprint-runner — one of planning/implementation/
267
271
  * verification/judgment. label distinguishes the stage. Used so the user
@@ -333,6 +337,84 @@ export interface CouncilInfoCard {
333
337
  title: string;
334
338
  sections: CouncilInfoCardSection[];
335
339
  }
340
+ /**
341
+ * Incremental council metadata for the context rail (P3). Emitted as one or more
342
+ * `council_meta` chunks — the leader/panel/researchMode/costAware fields come
343
+ * from the council entrypoint, the round budget/ceiling from inside runDebate
344
+ * (locals invisible to the entrypoint). The UI upsert-merges each patch into a
345
+ * single `councilMeta` object, so any subset of fields may be present.
346
+ */
347
+ /**
348
+ * One debate round's lifecycle record for the round-grouped transcript (P5/P6).
349
+ * Emitted as `council_round` chunks: a `running` record at round start, then a
350
+ * `done` record (guaranteed on every loop exit) carrying the outcome. The UI
351
+ * upsert-merges by `round` (running → done overwrite).
352
+ */
353
+ export interface CouncilRoundRecord {
354
+ round: number;
355
+ state: "running" | "done";
356
+ /** This round's focus, carried from the prior round's `nextRoundFocus`. */
357
+ topic?: string;
358
+ /** Role labels of the participants active this round. */
359
+ participants: string[];
360
+ /** Number of debate pairs exchanged this round. */
361
+ pairCount: number;
362
+ /** True when this round is beyond the leader's original planned budget. */
363
+ emergent: boolean;
364
+ /** Leader-evaluated criteria met / total (absent until the round is done). */
365
+ criteriaMet?: number;
366
+ criteriaTotal?: number;
367
+ /** Leader's one-sentence decision reason. */
368
+ leaderReason?: string;
369
+ /** What the leader / engine decided at the end of this round. */
370
+ leaderDecision?: "continue" | "stop" | "extend" | "aborted" | "circuit-break" | "eval-unavailable";
371
+ /** Topic the leader set for the NEXT round (drives the overview). */
372
+ nextRoundFocus?: string;
373
+ /**
374
+ * B5 — the leader's pre-round DIRECTIVE for this round (goal + criteria still
375
+ * unmet going in). Captured on the round record so it survives into the
376
+ * post-debate conclusion card, not only the ephemeral live directive bubble —
377
+ * otherwise a user who looks away during the debate never sees the leader
378
+ * conduct the round. Present only when the conductor is on + criteria pinned.
379
+ */
380
+ directive?: string;
381
+ }
382
+ /**
383
+ * Incremental council metadata for the context rail (P3). Emitted as one or more
384
+ * `council_meta` chunks — the leader/panel/researchMode/costAware fields come
385
+ * from the council entrypoint, the round budget/ceiling from inside runDebate
386
+ * (locals invisible to the entrypoint). The UI upsert-merges each patch into a
387
+ * single `councilMeta` object, so any subset of fields may be present.
388
+ */
389
+ export interface CouncilMetaPatch {
390
+ /** The debate topic / question under discussion (shown at the top of the rail). */
391
+ topic?: string;
392
+ /** Leader model id driving the debate. */
393
+ leader?: string;
394
+ /** Panel member role labels. */
395
+ panel?: string[];
396
+ /** Planned round budget resolved for this debate. */
397
+ roundBudget?: number;
398
+ /** Hard ceiling rounds may extend to (emergent rounds). */
399
+ roundCeiling?: number;
400
+ /** Research mode enabled for this debate. */
401
+ researchMode?: boolean;
402
+ /** Cost-aware budgeting active. */
403
+ costAware?: boolean;
404
+ /**
405
+ * The pinned outcome criteria the debate is graded against (the user-owned
406
+ * `ClarifiedSpec.successCriteria`). Emitted once after clarify so the rail can
407
+ * show the OUTCOME the debate is chasing — fixes "criteria met là gì tôi không
408
+ * biết". Stable for the whole debate.
409
+ */
410
+ successCriteria?: string[];
411
+ /**
412
+ * Per-criterion met status, index-aligned to `successCriteria`. Upsert-merged
413
+ * and refreshed after each round's leader evaluation so the rail shows live
414
+ * ✓/○ against the pinned criteria. Length matches `successCriteria`.
415
+ */
416
+ criteriaMet?: boolean[];
417
+ }
336
418
  export interface CouncilMessage {
337
419
  kind: CouncilMessageKind;
338
420
  speaker: {
@@ -343,6 +425,7 @@ export interface CouncilMessage {
343
425
  role: string;
344
426
  };
345
427
  round?: number;
428
+ phase?: "directive" | "verdict";
346
429
  text: string;
347
430
  toolCalls?: {
348
431
  name: string;
@@ -352,7 +435,7 @@ export interface CouncilMessage {
352
435
  runId?: string;
353
436
  }
354
437
  export interface StreamChunk {
355
- type: "content" | "tool_calls" | "tool_result" | "tool_approval_request" | "council_question" | "council_preflight" | "council_status" | "council_phase" | "council_message" | "council_info_card" | "done" | "error" | "reasoning" | "structured_response" | "product_status_card" | "experience_warning" | "experience_injected" | "push_notification" | "halt" | "task_list_update";
438
+ type: "content" | "tool_calls" | "tool_result" | "tool_approval_request" | "council_question" | "council_preflight" | "council_status" | "council_phase" | "council_message" | "council_info_card" | "council_meta" | "council_round" | "done" | "error" | "reasoning" | "structured_response" | "product_status_card" | "experience_warning" | "experience_injected" | "push_notification" | "halt" | "toast" | "task_list_update";
356
439
  content?: string;
357
440
  toolCalls?: ToolCall[];
358
441
  toolCall?: ToolCall;
@@ -367,12 +450,21 @@ export interface StreamChunk {
367
450
  councilPhase?: CouncilPhaseEvent;
368
451
  councilMessage?: CouncilMessage;
369
452
  councilInfoCard?: CouncilInfoCard;
453
+ councilMeta?: CouncilMetaPatch;
454
+ councilRound?: CouncilRoundRecord;
370
455
  productStatusCard?: import("../product-loop/types.js").ProductStatusCardData;
371
456
  /** Populated when type === "halt". Contains structured recovery options. */
372
457
  haltChunk?: import("../product-loop/types.js").HaltChunk;
373
458
  experienceWarning?: ExperienceWarningData;
374
459
  experienceInjected?: ExperienceInjectedData;
375
460
  taskListSnapshot?: TaskListSnapshot;
461
+ /**
462
+ * Populated when type === "toast". A transient, ephemeral notice (e.g.
463
+ * "initializing sub-session…") that the UI shows briefly then auto-dismisses
464
+ * — it is NOT appended to the persisted assistant message. `content` holds
465
+ * the text; `toastLevel` selects the style (defaults to "info").
466
+ */
467
+ toastLevel?: "info" | "warn" | "error";
376
468
  }
377
469
  export type TaskListItemStatus = "pending" | "in_progress" | "completed";
378
470
  export interface TaskListItem {
@@ -413,13 +505,28 @@ export interface ModelInfo {
413
505
  multiAgent?: boolean;
414
506
  supportsClientTools?: boolean;
415
507
  supportsMaxOutputTokens?: boolean;
508
+ /**
509
+ * When set, the provider rejects any temperature other than this exact value
510
+ * (e.g. Moonshot/Kimi: "only 1 is allowed for this model"). Callers must send
511
+ * this value verbatim rather than their preferred temperature — see
512
+ * `resolveTemperature` in src/providers/capabilities.ts.
513
+ */
514
+ fixedTemperature?: number;
416
515
  defaultReasoningEffort?: ReasoningEffort;
417
516
  supportsReasoningEffort?: boolean;
418
517
  thinkingType?: "enabled" | "adaptive";
419
518
  supportsVision?: boolean;
519
+ /** When false, excluded from getModelByTier / automatic compaction routing. Default: routable. */
520
+ tierRouting?: boolean;
521
+ /** Extra tiers this model may satisfy in getModelByTier (primary tier remains `tier`). */
522
+ routingTiers?: ModelTier[];
523
+ roles?: string[];
524
+ /** Part E — model has native online web research (its own web_search/browsing). */
525
+ nativeWebResearch?: boolean;
420
526
  }
421
527
  export type AgentMode = "agent" | "plan" | "ask";
422
528
  export type SessionStatus = "active" | "completed" | "archived" | "abandoned";
529
+ export type SessionKind = "conversation" | "rotation" | "subagent";
423
530
  export type UsageSource = "message" | "title" | "task" | "delegation" | "council" | "other";
424
531
  export interface WorkspaceInfo {
425
532
  id: string;
@@ -441,6 +548,14 @@ export interface SessionInfo {
441
548
  createdAt: Date;
442
549
  updatedAt: Date;
443
550
  }
551
+ /**
552
+ * One row in the `/sessions` resume picker: a whole conversation tree collapsed
553
+ * to a single entry. `id`/`title`/`createdAt` describe the tree root; `resumeId`
554
+ * is the latest leaf to relaunch; `model`/`updatedAt`/`status` describe that leaf.
555
+ */
556
+ export interface ResumeEntry extends SessionInfo {
557
+ resumeId: string;
558
+ }
444
559
  export interface UsageEvent {
445
560
  id: number;
446
561
  sessionId: string;
Binary file
@@ -49,7 +49,7 @@ export function ProductStatusCard({ data, theme: t }) {
49
49
  const costSpark = data.costHistory?.length
50
50
  ? sparkline(data.costHistory.map((h) => (data.costCap > 0 ? h.cumulativeUsd / data.costCap : 0)))
51
51
  : "";
52
- return (_jsx(Semantic, { id: "ideal-status", role: "region", name: "Ideal status", children: _jsxs("box", { flexDirection: "column", paddingLeft: 2, paddingTop: 0, flexShrink: 0, children: [_jsx("box", { children: _jsx("text", { fg: t.accent, children: `▶ Product Loop · ${data.currentStage}` }) }), _jsx(Semantic, { id: `ideal-phase-sprint`, role: "listitem", name: "Sprint", children: _jsxs("box", { children: [_jsx("text", { fg: t.textMuted, children: "Sprint: " }), _jsx("text", { fg: t.text, children: `${data.sprintN}/${data.totalSprints} ` }), _jsx("text", { fg: t.accent, children: bar(sprintPct) }), _jsx("text", { fg: t.textDim, children: ` ${sprintPct.toFixed(0)}%` })] }) }), _jsx(Semantic, { id: `ideal-phase-cost`, role: "listitem", name: "Cost", children: _jsxs("box", { children: [_jsx("text", { fg: t.textMuted, children: "Cost: " }), _jsx("text", { fg: t.text, children: `$${data.costSpent.toFixed(2)}/$${data.costCap.toFixed(2)} ` }), _jsx("text", { fg: costColor, children: bar(costPct) }), _jsx("text", { fg: t.textDim, children: ` ${costPct.toFixed(0)}%` })] }) }), costSpark && (_jsxs("box", { children: [_jsx("text", { fg: t.textMuted, children: "Burn: " }), _jsx("text", { fg: costColor, children: costSpark }), _jsx("text", { fg: t.textDim, children: ` (per-sprint)` })] })), _jsx(Semantic, { id: `ideal-phase-criteria`, role: "listitem", name: "Criteria", children: _jsxs("box", { children: [_jsx("text", { fg: t.textMuted, children: "Criteria: " }), _jsx("text", { fg: t.planOptionCheck, children: `✓ ${data.criteriaMet}` }), _jsx("text", { fg: t.text, children: " " }), _jsx("text", { fg: t.accent, children: `◐ ${data.criteriaPartial}` }), _jsx("text", { fg: t.text, children: " " }), _jsx("text", { fg: t.diffRemovedFg, children: `✗ ${data.criteriaUnmet}` }), _jsx("text", { fg: t.textDim, children: ` (of ${totalCriteria})` })] }) }), criteriaSpark && (_jsxs("box", { children: [_jsx("text", { fg: t.textMuted, children: "Trend: " }), _jsx("text", { fg: t.planOptionCheck, children: criteriaSpark }), _jsx("text", { fg: t.textDim, children: ` met-ratio per sprint` })] }))] }) }));
52
+ return (_jsx(Semantic, { id: "ideal-status", role: "region", name: "Ideal status", children: _jsxs("box", { flexDirection: "column", paddingLeft: 2, paddingTop: 0, flexShrink: 0, children: [_jsx("box", { children: _jsx("text", { fg: t.accent, children: `▶ Product Loop · ${data.currentStage}` }) }), _jsx(Semantic, { id: `ideal-phase-sprint`, role: "listitem", name: "Sprint", children: _jsxs("box", { children: [_jsx("text", { fg: t.textMuted, children: "Sprint: " }), _jsx("text", { fg: t.text, children: `${data.sprintN}/${data.totalSprints} ` }), _jsx("text", { fg: t.accent, children: bar(sprintPct) }), _jsx("text", { fg: t.textDim, children: ` ${sprintPct.toFixed(0)}%` })] }) }), _jsx(Semantic, { id: `ideal-phase-cost`, role: "listitem", name: "Cost", children: _jsxs("box", { children: [_jsx("text", { fg: t.textMuted, children: "Cost: " }), _jsx("text", { fg: t.text, children: `$${data.costSpent.toFixed(2)}/$${data.costCap.toFixed(2)} ` }), _jsx("text", { fg: costColor, children: bar(costPct) }), _jsx("text", { fg: t.textDim, children: ` ${costPct.toFixed(0)}%` })] }) }), costSpark && (_jsxs("box", { children: [_jsx("text", { fg: t.textMuted, children: "Burn: " }), _jsx("text", { fg: costColor, children: costSpark }), _jsx("text", { fg: t.textDim, children: ` spend per sprint` })] })), _jsx(Semantic, { id: `ideal-phase-criteria`, role: "listitem", name: "Criteria", children: _jsxs("box", { children: [_jsx("text", { fg: t.textMuted, children: "Criteria: " }), _jsx("text", { fg: t.planOptionCheck, children: `✓ ${data.criteriaMet}` }), _jsx("text", { fg: t.text, children: " " }), _jsx("text", { fg: t.accent, children: `◐ ${data.criteriaPartial}` }), _jsx("text", { fg: t.text, children: " " }), _jsx("text", { fg: t.diffRemovedFg, children: `✗ ${data.criteriaUnmet}` }), _jsx("text", { fg: t.textDim, children: ` (of ${totalCriteria})` })] }) }), criteriaSpark && (_jsxs("box", { children: [_jsx("text", { fg: t.textMuted, children: "Trend: " }), _jsx("text", { fg: t.planOptionCheck, children: criteriaSpark }), _jsx("text", { fg: t.textDim, children: ` criteria met per sprint` })] }))] }) }));
53
53
  }
54
54
  export default ProductStatusCard;
55
55
  //# sourceMappingURL=product-status-card.js.map
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Render-time guard for council message bodies.
3
+ *
4
+ * Root cause it defends against (live-diagnosed 2026-07-08, run mrbj8v6w81a3):
5
+ * a single round-1 debate turn whose body contained a very long whitespace-free
6
+ * run (an import graph / path list / blob a Flash-tier model dumped over a
7
+ * 1286-file repo). `CouncilMessageBubble` hands the raw body to a single
8
+ * OpenTUI `<text>` node with NO length or line-length bound. OpenTUI's word-wrap
9
+ * on such a mega-line pegs the main thread at 100% CPU — and because render and
10
+ * the product-loop share one JS thread, the entire `/ideal` run hard-freezes
11
+ * (render + input + debate logic all starve). Every muonroi-owned text function
12
+ * on the path (`truncateCodeBlocks`, `renderMarkdown`, `parseInline`,
13
+ * `tokenize`) was benchmarked fast on 80–130KB adversarial input, so the block
14
+ * lives in the terminal's layout of an unbounded body.
15
+ *
16
+ * This function bounds BOTH failure axes before the body reaches `<text>`:
17
+ * 1. total length — cap at `maxChars`, append a muted pointer to /export.
18
+ * 2. line length — hard-break any whitespace-free run longer than the
19
+ * terminal width so the wrapper always has a break opportunity (turns a
20
+ * pathological O(n²) single-line wrap into linear per-segment wrapping).
21
+ *
22
+ * Pure + side-effect free — safe to unit-test without a terminal.
23
+ */
24
+ /** Default ceiling on a rendered bubble body. Well above any real prose turn
25
+ * (~2–4KB) but far below the 100KB+ blobs that trigger the layout hang. */
26
+ export declare const MAX_BUBBLE_BODY_CHARS = 12000;
27
+ export declare function capBubbleBody(text: string, terminalCols: number, maxChars?: number): string;
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Render-time guard for council message bodies.
3
+ *
4
+ * Root cause it defends against (live-diagnosed 2026-07-08, run mrbj8v6w81a3):
5
+ * a single round-1 debate turn whose body contained a very long whitespace-free
6
+ * run (an import graph / path list / blob a Flash-tier model dumped over a
7
+ * 1286-file repo). `CouncilMessageBubble` hands the raw body to a single
8
+ * OpenTUI `<text>` node with NO length or line-length bound. OpenTUI's word-wrap
9
+ * on such a mega-line pegs the main thread at 100% CPU — and because render and
10
+ * the product-loop share one JS thread, the entire `/ideal` run hard-freezes
11
+ * (render + input + debate logic all starve). Every muonroi-owned text function
12
+ * on the path (`truncateCodeBlocks`, `renderMarkdown`, `parseInline`,
13
+ * `tokenize`) was benchmarked fast on 80–130KB adversarial input, so the block
14
+ * lives in the terminal's layout of an unbounded body.
15
+ *
16
+ * This function bounds BOTH failure axes before the body reaches `<text>`:
17
+ * 1. total length — cap at `maxChars`, append a muted pointer to /export.
18
+ * 2. line length — hard-break any whitespace-free run longer than the
19
+ * terminal width so the wrapper always has a break opportunity (turns a
20
+ * pathological O(n²) single-line wrap into linear per-segment wrapping).
21
+ *
22
+ * Pure + side-effect free — safe to unit-test without a terminal.
23
+ */
24
+ /** Default ceiling on a rendered bubble body. Well above any real prose turn
25
+ * (~2–4KB) but far below the 100KB+ blobs that trigger the layout hang. */
26
+ export const MAX_BUBBLE_BODY_CHARS = 12_000;
27
+ /** Lower bound on the wrap column, so a bogus `terminalCols` (0/undefined on a
28
+ * detached harness) never produces a degenerate 1-char break cadence. */
29
+ const MIN_WRAP_COLS = 20;
30
+ export function capBubbleBody(text, terminalCols, maxChars = MAX_BUBBLE_BODY_CHARS) {
31
+ // 1) Total-length cap first — bounds the work the hard-wrap below has to do.
32
+ let body = text;
33
+ let truncated = false;
34
+ if (body.length > maxChars) {
35
+ body = body.slice(0, maxChars);
36
+ truncated = true;
37
+ }
38
+ // 2) Hard-break whitespace-free runs longer than the wrap column. The lookahead
39
+ // `(?=\S)` avoids inserting a break right before an existing whitespace/EOL,
40
+ // so normal prose (which breaks on spaces) is left untouched. Linear: each
41
+ // char is visited once by the non-overlapping global match.
42
+ const cols = Math.max(MIN_WRAP_COLS, Number.isFinite(terminalCols) && terminalCols > 0 ? terminalCols : 80);
43
+ const runBreaker = new RegExp(`(\\S{${cols}})(?=\\S)`, "g");
44
+ body = body.replace(runBreaker, "$1\n");
45
+ if (truncated) {
46
+ body += "\n… truncated — see /export for the full turn";
47
+ }
48
+ return body;
49
+ }
50
+ //# sourceMappingURL=bubble-body-guard.js.map
@@ -0,0 +1,26 @@
1
+ import type { ReactNode } from "react";
2
+ /** A single label/value row shown in the rail's metadata block. */
3
+ export interface ContextRailRow {
4
+ label: string;
5
+ value: string;
6
+ }
7
+ export interface ContextRailProps {
8
+ /** Fixed column width of the rail (app.tsx decides based on terminal size). */
9
+ width: number;
10
+ /** Metadata rows (session id, mode, leader, panel, budget, …). */
11
+ rows: ContextRailRow[];
12
+ /**
13
+ * Rich content rendered below the metadata rows — info cards (Clarified Spec,
14
+ * Discussion Brief, Debate Plan), phase timeline, product-status. Wired by
15
+ * later phases; absent in the skeleton.
16
+ */
17
+ children?: ReactNode;
18
+ }
19
+ /**
20
+ * Right-hand context rail (MUONROI_CONTEXT_RAIL). Moves metadata-heavy chrome
21
+ * (session/leader/panel/budget + info cards) out of the scrolling transcript so
22
+ * the live debate stays on screen. Always renders the GLOBAL view — it never
23
+ * re-scopes to a selected round (that hides the overview and recreates the
24
+ * "empty rounds" problem). app.tsx gates visibility on width ≥ 100 and Ctrl+B.
25
+ */
26
+ export declare function ContextRail({ width, rows, children }: ContextRailProps): ReactNode;
@@ -0,0 +1,33 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "@opentui/react/jsx-runtime";
2
+ import { Semantic } from "@muonroi/agent-harness-opentui";
3
+ import { dark } from "../theme.js";
4
+ /**
5
+ * Right-hand context rail (MUONROI_CONTEXT_RAIL). Moves metadata-heavy chrome
6
+ * (session/leader/panel/budget + info cards) out of the scrolling transcript so
7
+ * the live debate stays on screen. Always renders the GLOBAL view — it never
8
+ * re-scopes to a selected round (that hides the overview and recreates the
9
+ * "empty rounds" problem). app.tsx gates visibility on width ≥ 100 and Ctrl+B.
10
+ */
11
+ export function ContextRail({ width, rows, children }) {
12
+ return (_jsx(Semantic, { id: "context-rail", role: "region", name: "Context",
13
+ // labels/values exposed for harness assertions (rail rows are plain <text>,
14
+ // not semantic nodes, so they don't otherwise show in the snapshot tree).
15
+ props: {
16
+ rowCount: rows.length,
17
+ labels: rows.map((r) => r.label).join(","),
18
+ values: rows.map((r) => r.value).join(" | "),
19
+ }, children: _jsxs("box", { flexShrink: 0, width: width, flexDirection: "column", border: ["left"], borderColor: dark.councilLeaderBorder, paddingLeft: 2, paddingRight: 1, gap: 1, children: [_jsx("text", { fg: dark.textMuted, attributes: 1, children: "Context" }), rows.length > 0 && (_jsx("box", { flexDirection: "column", flexShrink: 0, children: rows.map((r, idx) => (
20
+ // Index key: list-style rows (e.g. per-criterion outcome lines) may
21
+ // share an empty or duplicate label, which would collide on a
22
+ // label-keyed map. An empty label renders value-only (no "· : ").
23
+ //
24
+ // Label + value MUST live in one <text> node (via an inline <span>),
25
+ // not two sibling <text> in a flex-row: when a long value wraps, the
26
+ // terminal trims the trailing separator of the preceding text node,
27
+ // so "Topic: rest…" rendered as "Topicrest…" and "Progress: Round…"
28
+ // lost its space. A single text flow keeps the "Label: " prefix.
29
+ _jsx("box", { flexDirection: "column", children: _jsxs("text", { children: [r.label ? _jsx("span", { style: { fg: dark.textMuted }, children: `${r.label}: ` }) : null, r.value] }) }, idx))) })), children ? (
30
+ // biome-ignore lint/suspicious/noExplicitAny: OpenTUI stickyStart typing
31
+ _jsx("scrollbox", { flexGrow: 1, stickyScroll: false, stickyStart: "top", children: children })) : null] }) }));
32
+ }
33
+ //# sourceMappingURL=context-rail.js.map