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
@@ -0,0 +1,420 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "@opentui/react/jsx-runtime";
2
+ function asStringArray(v) {
3
+ if (!Array.isArray(v))
4
+ return [];
5
+ return v.filter((x) => typeof x === "string" && x.trim().length > 0).map((x) => x.trim());
6
+ }
7
+ function firstString(obj, keys) {
8
+ for (const k of keys) {
9
+ const val = obj[k];
10
+ if (typeof val === "string" && val.trim().length > 0)
11
+ return val.trim();
12
+ }
13
+ return undefined;
14
+ }
15
+ function firstArray(obj, keys) {
16
+ for (const k of keys) {
17
+ const arr = asStringArray(obj[k]);
18
+ if (arr.length > 0)
19
+ return arr;
20
+ }
21
+ return [];
22
+ }
23
+ function coverageRows(obj) {
24
+ for (const k of ["coverage_matrix", "coverage", "criteria", "coverageMatrix"]) {
25
+ const raw = obj[k];
26
+ if (!Array.isArray(raw))
27
+ continue;
28
+ const rows = [];
29
+ for (const item of raw) {
30
+ if (item && typeof item === "object") {
31
+ const cells = Object.values(item)
32
+ .filter((c) => typeof c === "string" && c.trim().length > 0)
33
+ .map((c) => c.trim());
34
+ if (cells.length > 0)
35
+ rows.push(cells);
36
+ }
37
+ else if (typeof item === "string" && item.trim().length > 0) {
38
+ rows.push([item.trim()]);
39
+ }
40
+ }
41
+ if (rows.length > 0)
42
+ return rows;
43
+ }
44
+ return [];
45
+ }
46
+ function parseDimensionScores(obj) {
47
+ const raw = obj.dimension_scores ?? obj.dimensionScores ?? obj.scores;
48
+ if (!Array.isArray(raw))
49
+ return [];
50
+ const out = [];
51
+ for (const item of raw) {
52
+ if (!item || typeof item !== "object")
53
+ continue;
54
+ const row = item;
55
+ const dimension = String(row.dimension ?? row.name ?? row.criteria ?? "").trim();
56
+ const scoreRaw = row.score ?? row.rating ?? row.value;
57
+ const score = typeof scoreRaw === "number" ? scoreRaw : Number.parseInt(String(scoreRaw), 10);
58
+ const justification = String(row.justification ?? row.reason ?? row.note ?? "").trim();
59
+ if (dimension && Number.isFinite(score)) {
60
+ out.push({ dimension, score, justification: justification || "(no justification)" });
61
+ }
62
+ }
63
+ return out;
64
+ }
65
+ function parseOperationalRisks(obj) {
66
+ const raw = obj.operational_risks ?? obj.operationalRisks ?? obj.risks;
67
+ if (!Array.isArray(raw))
68
+ return [];
69
+ const out = [];
70
+ for (const item of raw) {
71
+ if (!item || typeof item !== "object")
72
+ continue;
73
+ const row = item;
74
+ const risk = String(row.risk ?? row.name ?? row.title ?? "").trim();
75
+ const severity = String(row.severity ?? row.level ?? row.impact ?? "").trim();
76
+ const trigger = String(row.trigger ?? row.when ?? row.condition ?? "").trim();
77
+ if (risk) {
78
+ out.push({ risk, severity: severity || "Unknown", trigger: trigger || "(not specified)" });
79
+ }
80
+ }
81
+ return out;
82
+ }
83
+ function parsePriorityFixes(obj) {
84
+ const raw = obj.priority_fixes ?? obj.priorityFixes ?? obj.fixes ?? obj.action_items;
85
+ if (Array.isArray(raw)) {
86
+ const strings = asStringArray(raw);
87
+ if (strings.length > 0)
88
+ return strings;
89
+ const flat = [];
90
+ for (const item of raw) {
91
+ if (item && typeof item === "object") {
92
+ const cells = Object.entries(item)
93
+ .filter(([, cv]) => cv !== null && cv !== undefined && typeof cv !== "object")
94
+ .map(([ck, cv]) => `${ck}: ${String(cv)}`);
95
+ if (cells.length > 0)
96
+ flat.push(cells.join(" · "));
97
+ }
98
+ }
99
+ if (flat.length > 0)
100
+ return flat;
101
+ }
102
+ return [];
103
+ }
104
+ function parseNextActions(obj) {
105
+ const raw = obj.nextActions ?? obj.next_actions ?? obj.actions;
106
+ if (!Array.isArray(raw))
107
+ return [];
108
+ const out = [];
109
+ for (const item of raw) {
110
+ if (!item || typeof item !== "object")
111
+ continue;
112
+ const row = item;
113
+ const action = String(row.action ?? row.id ?? row.key ?? "").trim();
114
+ const label = String(row.label ?? row.title ?? row.summary ?? action).trim();
115
+ const reason = String(row.reason ?? row.why ?? row.explanation ?? "").trim();
116
+ if (label) {
117
+ out.push({ action: action || label, label, reason: reason || undefined });
118
+ }
119
+ }
120
+ return out;
121
+ }
122
+ /**
123
+ * Best-effort parse of possibly-truncated JSON. Providers cut synthesis output
124
+ * at maxTokens mid-array (live-verified 2026-07-06: `"nextActions":[…"action":"ask`),
125
+ * which made the whole conclusion fall back to a raw-JSON text wall.
126
+ *
127
+ * Single scan tracking string/escape state and the open-bracket stack. A "safe
128
+ * point" is the index AFTER a complete VALUE (string close, bracket close, or a
129
+ * number/true/false/null character). A closed string is only tentatively safe:
130
+ * if the next structural char is `:` it was a KEY, so we roll back to the
131
+ * previous safe point (otherwise the cut would produce a dangling `{"key"` —
132
+ * invalid JSON). The bracket stack is snapshotted at each safe point so the
133
+ * appended closers match the cut position, not the ragged end.
134
+ */
135
+ export function salvageJson(body) {
136
+ try {
137
+ const direct = JSON.parse(body);
138
+ return direct && typeof direct === "object" && !Array.isArray(direct) ? direct : null;
139
+ }
140
+ catch {
141
+ // fall through to salvage — expected branch for truncated output
142
+ }
143
+ const stack = [];
144
+ let inString = false;
145
+ let escaped = false;
146
+ let lastSafe = -1;
147
+ let stackAtSafe = [];
148
+ let prevSafe = -1;
149
+ let stackAtPrevSafe = [];
150
+ let lastStringEnd = -1; // safe point created by the most recent string close
151
+ const markSafe = (endExclusive) => {
152
+ if (endExclusive === lastSafe)
153
+ return;
154
+ prevSafe = lastSafe;
155
+ stackAtPrevSafe = stackAtSafe;
156
+ lastSafe = endExclusive;
157
+ stackAtSafe = stack.slice();
158
+ };
159
+ for (let i = 0; i < body.length; i++) {
160
+ const ch = body[i];
161
+ if (inString) {
162
+ if (escaped)
163
+ escaped = false;
164
+ else if (ch === "\\")
165
+ escaped = true;
166
+ else if (ch === '"') {
167
+ inString = false;
168
+ markSafe(i + 1);
169
+ lastStringEnd = i + 1;
170
+ }
171
+ continue;
172
+ }
173
+ if (ch === '"')
174
+ inString = true;
175
+ else if (ch === "{" || ch === "[")
176
+ stack.push(ch === "{" ? "}" : "]");
177
+ else if (ch === "}" || ch === "]") {
178
+ stack.pop();
179
+ markSafe(i + 1);
180
+ }
181
+ else if (ch === ":") {
182
+ // The string that just closed was a key, not a value — retract it.
183
+ if (lastSafe === lastStringEnd && prevSafe !== -1) {
184
+ lastSafe = prevSafe;
185
+ stackAtSafe = stackAtPrevSafe;
186
+ }
187
+ }
188
+ else if (/[0-9el]/.test(ch)) {
189
+ // Number / true / false / null terminal characters (outside strings,
190
+ // JSON only allows literals here) — cheap approximation of a value end.
191
+ markSafe(i + 1);
192
+ }
193
+ }
194
+ if (lastSafe <= 0)
195
+ return null;
196
+ const prefix = body.slice(0, lastSafe).replace(/,\s*$/, "") + stackAtSafe.reverse().join("");
197
+ try {
198
+ const parsed = JSON.parse(prefix);
199
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
200
+ }
201
+ catch {
202
+ // salvage failed — caller renders plain text; expected for hopeless input
203
+ return null;
204
+ }
205
+ }
206
+ /** "agreed_architecture" → "Agreed Architecture"; "actionItems" → "Action Items". */
207
+ function titleCase(key) {
208
+ return key
209
+ .replace(/([a-z])([A-Z])/g, "$1 $2")
210
+ .replace(/[_-]+/g, " ")
211
+ .trim()
212
+ .replace(/\b\w/g, (c) => c.toUpperCase());
213
+ }
214
+ /** Keys never worth a generic section: routing/meta fields. */
215
+ const NOISE_KEYS = new Set([
216
+ "type",
217
+ "nextActions",
218
+ "next_actions",
219
+ "sections",
220
+ "kind",
221
+ "dimension_scores",
222
+ "dimensionScores",
223
+ "dimensions",
224
+ "operational_risks",
225
+ "operationalRisks",
226
+ "risk_matrix",
227
+ "priority_fixes",
228
+ "priorityFixes",
229
+ "fixes",
230
+ "action_items",
231
+ ]);
232
+ /** Color a numeric score (1-5) by quality tier. */
233
+ function scoreColor(score, theme) {
234
+ if (score <= 2)
235
+ return theme.diffRemovedFg;
236
+ if (score === 3)
237
+ return theme.mdItalic;
238
+ return theme.diffAddedFg;
239
+ }
240
+ function severityColor(severity, theme) {
241
+ const s = severity.toLowerCase();
242
+ if (s.includes("critical") || s.includes("high"))
243
+ return theme.diffRemovedFg;
244
+ if (s.includes("medium") || s.includes("moderate"))
245
+ return theme.mdItalic;
246
+ return theme.diffAddedFg;
247
+ }
248
+ /** Compact ASCII bar for a 1-5 score: e.g. "[### ]". */
249
+ function scoreBar(score) {
250
+ const clamped = Math.max(1, Math.min(5, Math.round(score)));
251
+ const filled = "#".repeat(clamped);
252
+ const empty = " ".repeat(5 - clamped);
253
+ return `[${filled}${empty}]`;
254
+ }
255
+ /** Flatten one unknown top-level value into displayable bullet items. */
256
+ function flattenValue(v) {
257
+ if (typeof v === "string")
258
+ return v.trim().length > 0 ? [v.trim()] : [];
259
+ if (Array.isArray(v)) {
260
+ const items = [];
261
+ for (const el of v) {
262
+ if (typeof el === "string" && el.trim().length > 0)
263
+ items.push(el.trim());
264
+ else if (el && typeof el === "object") {
265
+ const cells = Object.entries(el)
266
+ .filter(([, cv]) => cv !== null && cv !== undefined && typeof cv !== "object")
267
+ .map(([ck, cv]) => `${ck}: ${String(cv)}`);
268
+ if (cells.length > 0)
269
+ items.push(cells.join(" · "));
270
+ }
271
+ }
272
+ return items;
273
+ }
274
+ return [];
275
+ }
276
+ /**
277
+ * Best-effort parse of a synthesis body into a structured conclusion. Returns
278
+ * null when the text is not a JSON object with at least one recognizable section
279
+ * — the caller then renders it as plain text.
280
+ */
281
+ export function parseConclusion(text) {
282
+ const trimmed = text.trim();
283
+ // A `---READABLE---` prose tail means the synthesizer already produced human
284
+ // copy; don't try to structure it — let the plain-text path render the prose.
285
+ if (trimmed.includes("---READABLE---"))
286
+ return null;
287
+ // Strip a leading ```json … ``` fence if present, then isolate the object.
288
+ const fenced = trimmed.match(/```(?:json)?\s*([\s\S]*?)```/);
289
+ const body = (fenced ? fenced[1] : trimmed).trim();
290
+ const start = body.indexOf("{");
291
+ if (start === -1)
292
+ return null;
293
+ const end = body.lastIndexOf("}");
294
+ // Truncated output may have NO balanced end — hand the raw tail to salvage.
295
+ const candidate = end > start ? body.slice(start, end + 1) : body.slice(start);
296
+ const parsed = salvageJson(candidate) ?? (end > start ? salvageJson(body.slice(start)) : null);
297
+ if (!parsed)
298
+ return null;
299
+ const summary = firstString(parsed, ["summary", "conclusion"]);
300
+ const recommendation = firstString(parsed, ["recommendation", "decision", "verdict"]);
301
+ const strengths = firstArray(parsed, ["strengths", "pros", "agreed"]);
302
+ const weaknesses = firstArray(parsed, ["weaknesses", "cons", "gaps"]);
303
+ const risks = firstArray(parsed, ["risks", "concerns"]);
304
+ const tradeoffs = firstArray(parsed, ["tradeoffs", "trade_offs", "trade-offs"]);
305
+ const coverage = coverageRows(parsed);
306
+ const dimensionScores = parseDimensionScores(parsed);
307
+ const operationalRisks = parseOperationalRisks(parsed);
308
+ const priorityFixes = parsePriorityFixes(parsed);
309
+ const nextActions = parseNextActions(parsed);
310
+ // Track which keys the named extractions actually consumed (a key only
311
+ // counts as consumed when it produced content — object-shaped `risks`
312
+ // yield [] above and must still reach the generic pass below).
313
+ const consumed = new Set();
314
+ if (summary)
315
+ for (const k of ["summary", "conclusion"])
316
+ if (firstString(parsed, [k]))
317
+ consumed.add(k);
318
+ if (recommendation)
319
+ for (const k of ["recommendation", "decision", "verdict"])
320
+ if (firstString(parsed, [k]))
321
+ consumed.add(k);
322
+ const arrayKeyGroups = [
323
+ [["strengths", "pros", "agreed"], strengths],
324
+ [["weaknesses", "cons", "gaps"], weaknesses],
325
+ [["risks", "concerns"], risks],
326
+ [["tradeoffs", "trade_offs", "trade-offs"], tradeoffs],
327
+ ];
328
+ for (const [keys, extracted] of arrayKeyGroups) {
329
+ if (extracted.length > 0)
330
+ for (const k of keys)
331
+ if (asStringArray(parsed[k]).length > 0)
332
+ consumed.add(k);
333
+ }
334
+ if (coverage.length > 0)
335
+ for (const k of ["coverage_matrix", "coverage", "criteria", "coverageMatrix"])
336
+ if (Array.isArray(parsed[k]))
337
+ consumed.add(k);
338
+ if (dimensionScores.length > 0)
339
+ for (const k of ["dimension_scores", "dimensionScores", "dimensions", "scores"])
340
+ if (Array.isArray(parsed[k]))
341
+ consumed.add(k);
342
+ if (operationalRisks.length > 0)
343
+ for (const k of ["operational_risks", "operationalRisks", "risk_matrix"])
344
+ if (Array.isArray(parsed[k]))
345
+ consumed.add(k);
346
+ if (priorityFixes.length > 0)
347
+ for (const k of ["priority_fixes", "priorityFixes", "fixes", "action_items"])
348
+ if (Array.isArray(parsed[k]))
349
+ consumed.add(k);
350
+ if (nextActions.length > 0)
351
+ for (const k of ["nextActions", "next_actions"])
352
+ if (Array.isArray(parsed[k]))
353
+ consumed.add(k);
354
+ const sections = [];
355
+ for (const [key, value] of Object.entries(parsed)) {
356
+ if (consumed.has(key) || NOISE_KEYS.has(key))
357
+ continue;
358
+ const items = flattenValue(value);
359
+ if (items.length > 0)
360
+ sections.push({ title: titleCase(key), items });
361
+ }
362
+ const hasContent = !!summary ||
363
+ !!recommendation ||
364
+ strengths.length > 0 ||
365
+ weaknesses.length > 0 ||
366
+ risks.length > 0 ||
367
+ tradeoffs.length > 0 ||
368
+ coverage.length > 0 ||
369
+ dimensionScores.length > 0 ||
370
+ operationalRisks.length > 0 ||
371
+ priorityFixes.length > 0 ||
372
+ nextActions.length > 0 ||
373
+ sections.length > 0;
374
+ if (!hasContent)
375
+ return null;
376
+ return {
377
+ summary,
378
+ recommendation,
379
+ strengths,
380
+ weaknesses,
381
+ risks,
382
+ tradeoffs,
383
+ coverage,
384
+ dimensionScores,
385
+ operationalRisks,
386
+ priorityFixes,
387
+ nextActions,
388
+ sections,
389
+ };
390
+ }
391
+ function BulletSection({ title, items, color, theme: t, marker = "•" }) {
392
+ if (items.length === 0)
393
+ return null;
394
+ return (_jsxs("box", { flexDirection: "column", marginTop: 1, children: [_jsx("text", { fg: color, attributes: 1, children: title }), items.map((it, i) => (_jsxs("box", { flexDirection: "row", children: [_jsx("text", { fg: t.textMuted, children: ` ${marker} ` }), _jsx("text", { fg: t.text, children: it })] }, `${title}-${i}`)))] }));
395
+ }
396
+ function DimensionScoreTable({ scores, theme: t }) {
397
+ if (scores.length === 0)
398
+ return null;
399
+ return (_jsxs("box", { flexDirection: "column", marginTop: 1, children: [_jsx("text", { fg: t.accent, attributes: 1, children: "Dimension Scores" }), scores.map((s, i) => (_jsxs("box", { flexDirection: "column", marginTop: 1, children: [_jsxs("box", { flexDirection: "row", children: [_jsx("text", { fg: t.text, children: s.dimension }), _jsx("box", { flexGrow: 1 }), _jsx("text", { fg: scoreColor(s.score, t), attributes: 1, children: `${s.score}/5 ${scoreBar(s.score)}` })] }), _jsx("text", { fg: t.textMuted, children: ` ${s.justification}` })] }, `dim-${i}`)))] }));
400
+ }
401
+ function RiskTable({ risks, theme: t }) {
402
+ if (risks.length === 0)
403
+ return null;
404
+ return (_jsxs("box", { flexDirection: "column", marginTop: 1, children: [_jsx("text", { fg: t.diffRemovedFg, attributes: 1, children: "Operational Risks" }), risks.map((r, i) => (_jsxs("box", { flexDirection: "column", marginTop: 1, children: [_jsxs("box", { flexDirection: "row", children: [_jsx("text", { fg: t.text, attributes: 1, children: r.risk }), _jsx("box", { flexGrow: 1 }), _jsx("text", { fg: severityColor(r.severity, t), children: r.severity })] }), _jsx("text", { fg: t.textMuted, children: ` Trigger: ${r.trigger}` })] }, `risk-${i}`)))] }));
405
+ }
406
+ function PriorityFixList({ fixes, theme: t }) {
407
+ if (fixes.length === 0)
408
+ return null;
409
+ return (_jsxs("box", { flexDirection: "column", marginTop: 1, children: [_jsx("text", { fg: t.mdItalic, attributes: 1, children: "Priority Fixes" }), fixes.map((fix, i) => (_jsxs("box", { flexDirection: "row", children: [_jsx("text", { fg: t.textMuted, children: ` ${i + 1}. ` }), _jsx("text", { fg: t.text, children: fix })] }, `fix-${i}`)))] }));
410
+ }
411
+ function NextActionList({ actions, theme: t }) {
412
+ if (actions.length === 0)
413
+ return null;
414
+ return (_jsxs("box", { flexDirection: "column", marginTop: 1, children: [_jsx("text", { fg: t.planStepNum, attributes: 1, children: "Next Actions" }), actions.map((a, i) => (_jsxs("box", { flexDirection: "column", marginTop: 1, children: [_jsxs("box", { flexDirection: "row", children: [_jsx("text", { fg: t.textMuted, children: ` ${i + 1}. ` }), _jsx("text", { fg: t.text, attributes: 1, children: a.label })] }), a.reason && _jsx("text", { fg: t.textMuted, children: ` ${a.reason}` })] }, `act-${i}`)))] }));
415
+ }
416
+ export function CouncilConclusionCard({ conclusion, round, theme: t }) {
417
+ const title = round === undefined ? "Final Conclusion" : `Round ${round} Conclusion`;
418
+ return (_jsxs("box", { flexDirection: "column", marginBottom: 1, border: ["left"], borderColor: t.councilSynthesisBorder, paddingLeft: 2, children: [_jsx("text", { fg: t.councilSynthesisBorder, attributes: 1, children: title }), conclusion.summary && (_jsx("box", { marginTop: 1, children: _jsx("text", { fg: t.text, children: conclusion.summary }) })), conclusion.recommendation && (_jsxs("box", { flexDirection: "column", marginTop: 1, children: [_jsx("text", { fg: t.accent, attributes: 1, children: "Recommendation" }), _jsx("text", { fg: t.text, children: conclusion.recommendation })] })), _jsx(DimensionScoreTable, { scores: conclusion.dimensionScores, theme: t }), _jsx(BulletSection, { title: "Strengths", items: conclusion.strengths, color: t.diffAddedFg, theme: t }), _jsx(BulletSection, { title: "Weaknesses", items: conclusion.weaknesses, color: t.diffRemovedFg, theme: t }), _jsx(RiskTable, { risks: conclusion.operationalRisks, theme: t }), _jsx(BulletSection, { title: "Risks", items: conclusion.risks, color: t.diffRemovedFg, theme: t }), _jsx(BulletSection, { title: "Trade-offs", items: conclusion.tradeoffs, color: t.mdItalic, theme: t }), _jsx(PriorityFixList, { fixes: conclusion.priorityFixes, theme: t }), _jsx(NextActionList, { actions: conclusion.nextActions, theme: t }), conclusion.coverage.length > 0 && (_jsxs("box", { flexDirection: "column", marginTop: 1, children: [_jsx("text", { fg: t.textMuted, attributes: 1, children: "Coverage" }), conclusion.coverage.map((row, i) => (_jsxs("box", { flexDirection: "row", children: [_jsx("text", { fg: t.textMuted, children: " – " }), _jsx("text", { fg: t.text, children: row.join(" · ") })] }, `cov-${i}`)))] })), conclusion.sections.map((sec) => (_jsx(BulletSection, { title: sec.title, items: sec.items, color: t.accent, theme: t }, sec.title)))] }));
419
+ }
420
+ //# sourceMappingURL=council-conclusion-card.js.map
@@ -0,0 +1,36 @@
1
+ import type { ReactNode } from "react";
2
+ import type { Theme } from "../theme.js";
3
+ export interface CouncilDebatePillProps {
4
+ /** Number of debate turns folded into the pill (leader + debate + research). */
5
+ count: number;
6
+ /** Debate still running — show a spinner + live tail; false → done summary. */
7
+ active: boolean;
8
+ /** Expanded → render full transcript (children); collapsed → header + tail only. */
9
+ expanded: boolean;
10
+ /**
11
+ * Last few non-empty lines of the most recent debate turn, joined with " · ".
12
+ * Only shown while active + collapsed to mimic the "thinking" pill. Empty
13
+ * string = nothing to show yet.
14
+ */
15
+ tailText: string;
16
+ theme: Theme;
17
+ /** Full debate bubbles, rendered only when `expanded` is true. */
18
+ children?: ReactNode;
19
+ }
20
+ /**
21
+ * Collapsible debate transcript, styled after the reasoning ("[Thought]") pill.
22
+ *
23
+ * The council debate can emit dozens of tall bubbles. Rendering them all inline
24
+ * buries the synthesis/deliverable and floods the scrollback. This pill folds
25
+ * the back-and-forth into a single line:
26
+ * - active + collapsed → spinner + "Debating… (N turns)" + a live tail of the
27
+ * latest turn (like the reasoning pill's last-3-lines preview).
28
+ * - done + collapsed → "Debated N turns" summary; detail is hidden.
29
+ * - expanded → full transcript in a left-bordered box.
30
+ * Toggle via Ctrl+O (wired in use-app-logic handleKey). Synthesis is rendered
31
+ * OUTSIDE this pill by the caller so the deliverable is always visible.
32
+ *
33
+ * ASCII-only strings on purpose: this file's siblings mangle non-ASCII glyphs
34
+ * to mojibake under the repo's encoding, so we mirror the "[Thought]" pill idiom.
35
+ */
36
+ export declare function CouncilDebatePill({ count, active, expanded, tailText, theme: t, children }: CouncilDebatePillProps): ReactNode;
@@ -0,0 +1,34 @@
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "@opentui/react/jsx-runtime";
2
+ import { useEffect, useState } from "react";
3
+ const SPINNER_FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
4
+ function Spinner() {
5
+ const [frame, setFrame] = useState(0);
6
+ useEffect(() => {
7
+ const id = setInterval(() => setFrame((n) => (n + 1) % SPINNER_FRAMES.length), 100);
8
+ return () => clearInterval(id);
9
+ }, []);
10
+ return _jsx(_Fragment, { children: SPINNER_FRAMES[frame] });
11
+ }
12
+ /**
13
+ * Collapsible debate transcript, styled after the reasoning ("[Thought]") pill.
14
+ *
15
+ * The council debate can emit dozens of tall bubbles. Rendering them all inline
16
+ * buries the synthesis/deliverable and floods the scrollback. This pill folds
17
+ * the back-and-forth into a single line:
18
+ * - active + collapsed → spinner + "Debating… (N turns)" + a live tail of the
19
+ * latest turn (like the reasoning pill's last-3-lines preview).
20
+ * - done + collapsed → "Debated N turns" summary; detail is hidden.
21
+ * - expanded → full transcript in a left-bordered box.
22
+ * Toggle via Ctrl+O (wired in use-app-logic handleKey). Synthesis is rendered
23
+ * OUTSIDE this pill by the caller so the deliverable is always visible.
24
+ *
25
+ * ASCII-only strings on purpose: this file's siblings mangle non-ASCII glyphs
26
+ * to mojibake under the repo's encoding, so we mirror the "[Thought]" pill idiom.
27
+ */
28
+ export function CouncilDebatePill({ count, active, expanded, tailText, theme: t, children }) {
29
+ const turnLabel = count === 1 ? "turn" : "turns";
30
+ const header = active ? `[Council] Debating... (${count} ${turnLabel})` : `[Council] Debated ${count} ${turnLabel}`;
31
+ const hint = expanded ? "Ctrl+O to collapse" : "Ctrl+O to expand";
32
+ return (_jsxs("box", { paddingLeft: 3, marginTop: 1, flexShrink: 0, flexDirection: "column", children: [_jsxs("box", { children: [active ? (_jsx("text", { fg: t.accent, children: _jsx(Spinner, {}) })) : null, _jsx("text", { fg: t.textMuted, children: `${active ? " " : ""}${header} · ${hint}` })] }), expanded ? (_jsx("box", { border: ["left"], borderColor: t.textMuted, paddingLeft: 2, marginTop: 1, flexDirection: "column", children: children })) : active && tailText ? (_jsx("box", { border: ["left"], borderColor: t.textMuted, paddingLeft: 2, marginTop: 1, children: _jsx("text", { fg: t.textMuted, children: tailText }) })) : null] }));
33
+ }
34
+ //# sourceMappingURL=council-debate-pill.js.map
@@ -1,10 +1,10 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "@opentui/react/jsx-runtime";
2
- import { Semantic } from "@muonroi/agent-harness-opentui";
2
+ import { ListItem } from "../primitives/index.js";
3
3
  const MAX_CARD_COLS = 100;
4
4
  const FALLBACK_THRESHOLD = 70;
5
5
  export function CouncilInfoCardView({ card, terminalCols, theme }) {
6
6
  const fallback = terminalCols < FALLBACK_THRESHOLD;
7
7
  const width = fallback ? terminalCols : Math.min(terminalCols - 2, MAX_CARD_COLS);
8
- return (_jsx(Semantic, { id: "info-card", role: "listitem", name: card.title, children: _jsx("box", { flexDirection: "column", marginBottom: 1, children: _jsxs("box", { width: width, borderStyle: "single", borderColor: theme.councilInfoCardBorder, flexDirection: "column", paddingLeft: 1, paddingRight: 1, children: [_jsx("text", { fg: theme.councilInfoCardTitle, attributes: 1, children: card.title }), card.sections.map((section, i) => (_jsxs("box", { flexDirection: "column", marginTop: 1, children: [_jsx("text", { fg: theme.councilInfoCardHeading, attributes: 1, children: section.heading }), _jsx("text", { fg: theme.text, children: section.body })] }, `${section.heading}-${i}`)))] }) }) }));
8
+ return (_jsx(ListItem, { id: "info-card", name: card.title, children: _jsx("box", { flexDirection: "column", marginBottom: 1, children: _jsxs("box", { width: width, borderStyle: "single", borderColor: theme.councilInfoCardBorder, flexDirection: "column", paddingLeft: 1, paddingRight: 1, children: [_jsx("text", { fg: theme.councilInfoCardTitle, attributes: 1, children: card.title }), card.sections.map((section, i) => (_jsxs("box", { flexDirection: "column", marginTop: 1, children: [_jsx("text", { fg: theme.councilInfoCardHeading, attributes: 1, children: section.heading }), _jsx("text", { fg: theme.text, children: section.body })] }, `${section.heading}-${i}`)))] }) }) }));
9
9
  }
10
10
  //# sourceMappingURL=council-info-card.js.map
@@ -1,10 +1,17 @@
1
1
  import type { CouncilMessage } from "../../types/index.js";
2
+ import type { Theme } from "../theme.js";
2
3
  export interface CouncilLeaderBubbleProps {
3
4
  msg: CouncilMessage;
4
5
  terminalCols: number;
6
+ theme: Theme;
5
7
  }
6
- export declare function buildLeaderHeader(round: number | undefined): string;
8
+ export declare function buildLeaderHeader(round: number | undefined, phase?: CouncilMessage["phase"]): string;
7
9
  /**
8
- * Centered, narrow (40% width), gray-bordered bubble for leader evaluations.
10
+ * Leader evaluation, rendered as a linear group-chat row (matching the debate
11
+ * speakers) instead of a centered narrow bubble — a muted gray left bar marks
12
+ * it as the moderator's turn while keeping the single downward reading flow.
13
+ *
14
+ * B5: a pre-round `directive` steers the debate and is rendered with the accent
15
+ * color so the leader visibly LEADS each round; `verdict`/`eval` stay muted.
9
16
  */
10
- export declare function CouncilLeaderBubble({ msg, terminalCols }: CouncilLeaderBubbleProps): import("react").ReactNode;
17
+ export declare function CouncilLeaderBubble({ msg, terminalCols, theme: t }: CouncilLeaderBubbleProps): import("react").ReactNode;
@@ -1,17 +1,27 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "@opentui/react/jsx-runtime";
2
- import { dark } from "../theme.js";
3
- import { computeBubbleLayout } from "./bubble-layout.js";
4
- export function buildLeaderHeader(round) {
5
- return round !== undefined ? `Leader · round ${round} eval` : "Leader";
2
+ import { capBubbleBody } from "./bubble-body-guard.js";
3
+ export function buildLeaderHeader(round, phase) {
4
+ // B5: distinguish the leader's pre-round steering from its post-round grading
5
+ // so the conductor role reads clearly in the transcript (not a faint "eval").
6
+ const suffix = phase === "directive" ? "directive" : phase === "verdict" ? "verdict" : "eval";
7
+ const label = phase === "directive" ? "▶ Leader" : "Leader";
8
+ return round !== undefined ? `${label} · round ${round} ${suffix}` : label;
6
9
  }
7
10
  /**
8
- * Centered, narrow (40% width), gray-bordered bubble for leader evaluations.
11
+ * Leader evaluation, rendered as a linear group-chat row (matching the debate
12
+ * speakers) instead of a centered narrow bubble — a muted gray left bar marks
13
+ * it as the moderator's turn while keeping the single downward reading flow.
14
+ *
15
+ * B5: a pre-round `directive` steers the debate and is rendered with the accent
16
+ * color so the leader visibly LEADS each round; `verdict`/`eval` stay muted.
9
17
  */
10
- export function CouncilLeaderBubble({ msg, terminalCols }) {
11
- const layout = computeBubbleLayout(terminalCols);
12
- const width = layout.leaderCols;
13
- const centerIndent = Math.max(0, Math.floor((terminalCols - width) / 2));
14
- const header = buildLeaderHeader(msg.round);
15
- return (_jsx("box", { flexDirection: "column", marginBottom: 1, marginLeft: centerIndent, children: _jsxs("box", { width: width, borderStyle: "single", borderColor: dark.councilLeaderBorder, flexDirection: "column", paddingLeft: 1, paddingRight: 1, children: [_jsx("text", { fg: dark.textMuted, attributes: 1, children: header }), _jsx("text", { fg: dark.textMuted, children: msg.text.trim() })] }) }));
18
+ export function CouncilLeaderBubble({ msg, terminalCols, theme: t }) {
19
+ const header = buildLeaderHeader(msg.round, msg.phase);
20
+ const isDirective = msg.phase === "directive";
21
+ const headerColor = isDirective ? t.accent : t.textMuted;
22
+ const borderColor = isDirective ? t.accent : t.councilLeaderBorder;
23
+ // Same unbounded-<text> guard as the speaker bubble (see bubble-body-guard.ts).
24
+ const bodyText = capBubbleBody(msg.text.trim(), terminalCols);
25
+ return (_jsxs("box", { flexDirection: "column", marginBottom: 1, border: ["left"], borderColor: borderColor, paddingLeft: 2, children: [_jsx("text", { fg: headerColor, attributes: 1, children: header }), _jsx("text", { fg: t.textMuted, children: bodyText })] }));
16
26
  }
17
27
  //# sourceMappingURL=council-leader-bubble.js.map
@@ -4,7 +4,11 @@ import type { RoleStyle } from "./role-palette.js";
4
4
  export interface CouncilMessageBubbleProps {
5
5
  msg: CouncilMessage;
6
6
  terminalCols: number;
7
- /** "left" | "right" — computed by usePairSideMap in container, NOT on the message */
7
+ /**
8
+ * Legacy left/right pairing hint. The debate now renders as a single linear
9
+ * group-chat stream (WhatsApp-style), so this is ignored — kept only for
10
+ * call-site/back-compat. Do not reintroduce side-based alignment.
11
+ */
8
12
  side: "left" | "right";
9
13
  /** Stable role → style resolver from useRolePalette */
10
14
  resolveStyle: (role: string) => RoleStyle;
@@ -17,4 +21,13 @@ export interface CouncilMessageBubbleProps {
17
21
  export declare function buildFooter(msg: CouncilMessage): string;
18
22
  export declare function buildHeader(msg: CouncilMessage, style: RoleStyle): string;
19
23
  export declare function buildQuoteLine(partnerLastText: string, partnerRole: string): string;
20
- export declare function CouncilMessageBubble({ msg, terminalCols, side, resolveStyle, partnerLastText, partnerRole, theme, }: CouncilMessageBubbleProps): import("react").ReactNode;
24
+ /**
25
+ * Linear group-chat message row. Every speaker renders the same way — a
26
+ * role-colored left bar + a bold role-colored header (`● Role · model`), the
27
+ * body, and a muted footer — appended in chronological order like a WhatsApp
28
+ * group chat. No left/right/bubble alignment: the reader follows one downward
29
+ * stream instead of a two-column ping-pong. The role color (from the shared
30
+ * palette) is the sole visual identity per speaker, so a long debate stays
31
+ * easy to track.
32
+ */
33
+ export declare function CouncilMessageBubble({ msg, terminalCols, resolveStyle, partnerLastText, partnerRole, theme, }: CouncilMessageBubbleProps): import("react").ReactNode;
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "@opentui/react/jsx-runtime";
2
- import { computeBubbleLayout } from "./bubble-layout.js";
2
+ import { capBubbleBody } from "./bubble-body-guard.js";
3
3
  import { truncateCodeBlocks } from "./code-block-truncate.js";
4
4
  const MAX_QUOTE_CHARS = 80;
5
5
  export function buildFooter(msg) {
@@ -25,23 +25,24 @@ export function buildQuoteLine(partnerLastText, partnerRole) {
25
25
  const ellipsis = flat.length > MAX_QUOTE_CHARS ? "…" : "";
26
26
  return `↪ ${partnerRole}: "${excerpt}${ellipsis}"`;
27
27
  }
28
- function FlatDebateBubble({ msg, style, theme }) {
29
- const header = buildHeader(msg, style);
30
- const footer = buildFooter(msg);
31
- return (_jsxs("box", { flexDirection: "column", marginBottom: 1, children: [_jsx("text", { fg: style.color, attributes: 1, children: header }), _jsx("text", { fg: theme.text, children: msg.text.trim() }), _jsx("text", { fg: theme.textMuted, children: footer })] }));
32
- }
33
- export function CouncilMessageBubble({ msg, terminalCols, side, resolveStyle, partnerLastText, partnerRole, theme, }) {
34
- const layout = computeBubbleLayout(terminalCols);
28
+ /**
29
+ * Linear group-chat message row. Every speaker renders the same way — a
30
+ * role-colored left bar + a bold role-colored header (`● Role · model`), the
31
+ * body, and a muted footer appended in chronological order like a WhatsApp
32
+ * group chat. No left/right/bubble alignment: the reader follows one downward
33
+ * stream instead of a two-column ping-pong. The role color (from the shared
34
+ * palette) is the sole visual identity per speaker, so a long debate stays
35
+ * easy to track.
36
+ */
37
+ export function CouncilMessageBubble({ msg, terminalCols, resolveStyle, partnerLastText, partnerRole, theme, }) {
35
38
  const style = resolveStyle(msg.speaker.role);
36
- if (layout.fallback) {
37
- return _jsx(FlatDebateBubble, { msg: msg, style: style, theme: theme });
38
- }
39
- const isRight = side === "right";
40
- const indent = isRight ? layout.rightIndent : 0;
41
39
  const header = buildHeader(msg, style);
42
40
  const footer = buildFooter(msg);
43
- const bodyText = truncateCodeBlocks(msg.text.trim());
41
+ // Guard the terminal wrapper against a pathological body (mega single-line /
42
+ // 100KB+ blob) that hard-freezes the shared render+loop thread. See
43
+ // bubble-body-guard.ts for the live root-cause trace.
44
+ const bodyText = capBubbleBody(truncateCodeBlocks(msg.text.trim()), terminalCols);
44
45
  const roundLabel = msg.round !== undefined ? `Round ${msg.round} · ` : "";
45
- return (_jsxs("box", { flexDirection: "column", marginBottom: 1, children: [partnerLastText && partnerRole && (_jsx("box", { marginLeft: indent, children: _jsx("text", { fg: theme.textMuted, children: buildQuoteLine(partnerLastText, partnerRole) }) })), _jsxs("box", { marginLeft: indent, width: layout.bubbleCols, borderStyle: "single", borderColor: style.color, flexDirection: "column", paddingLeft: 1, paddingRight: 1, children: [_jsx("text", { fg: style.color, attributes: 1, children: header }), _jsx("text", { fg: theme.text, children: bodyText }), _jsx("text", { fg: theme.textMuted, children: `${roundLabel}${footer}` })] })] }));
46
+ return (_jsxs("box", { flexDirection: "column", marginBottom: 1, border: ["left"], borderColor: style.color, paddingLeft: 2, children: [partnerLastText && partnerRole && (_jsx("text", { fg: theme.textMuted, children: buildQuoteLine(partnerLastText, partnerRole) })), _jsx("text", { fg: style.color, attributes: 1, children: header }), _jsx("text", { fg: theme.text, children: bodyText }), _jsx("text", { fg: theme.textMuted, children: `${roundLabel}${footer}` })] }));
46
47
  }
47
48
  //# sourceMappingURL=council-message-bubble.js.map