muonroi-cli 1.8.4 → 1.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (562) hide show
  1. package/LICENSE +17 -5
  2. package/dist/packages/agent-harness-core/src/driver.d.ts +27 -1
  3. package/dist/packages/agent-harness-core/src/driver.js +46 -0
  4. package/dist/packages/agent-harness-core/src/event-filter.js +11 -0
  5. package/dist/packages/agent-harness-core/src/event-redact.js +7 -0
  6. package/dist/packages/agent-harness-core/src/event-tee.d.ts +64 -0
  7. package/dist/packages/agent-harness-core/src/event-tee.js +104 -0
  8. package/dist/packages/agent-harness-core/src/mcp-server.d.ts +25 -0
  9. package/dist/packages/agent-harness-core/src/mcp-server.js +169 -21
  10. package/dist/packages/agent-harness-core/src/predicate.d.ts +1 -1
  11. package/dist/packages/agent-harness-core/src/protocol.d.ts +90 -4
  12. package/dist/packages/agent-harness-core/src/protocol.js +15 -0
  13. package/dist/packages/agent-harness-core/src/visual-quality.d.ts +58 -0
  14. package/dist/packages/agent-harness-core/src/visual-quality.js +141 -0
  15. package/dist/packages/agent-harness-opentui/src/agent-mode.d.ts +6 -0
  16. package/dist/packages/agent-harness-opentui/src/agent-mode.js +14 -1
  17. package/dist/packages/agent-harness-opentui/src/input-bridge.d.ts +2 -10
  18. package/dist/packages/agent-harness-opentui/src/input-bridge.js +103 -16
  19. package/dist/packages/agent-harness-opentui/src/install.d.ts +8 -0
  20. package/dist/packages/agent-harness-opentui/src/install.js +10 -0
  21. package/dist/packages/agent-harness-opentui/src/semantic.js +12 -10
  22. package/dist/packages/agent-harness-opentui/src/visual-capture.d.ts +56 -0
  23. package/dist/packages/agent-harness-opentui/src/visual-capture.js +103 -0
  24. package/dist/src/agent-harness/mock-model.d.ts +38 -0
  25. package/dist/src/agent-harness/mock-model.js +69 -3
  26. package/dist/src/agent-harness/test-spawn.js +31 -0
  27. package/dist/src/chat/chat-keychain.d.ts +7 -12
  28. package/dist/src/chat/chat-keychain.js +19 -86
  29. package/dist/src/cli/config/screen-providers.js +1 -1
  30. package/dist/src/cli/cost-forensics.d.ts +10 -0
  31. package/dist/src/cli/cost-forensics.js +18 -3
  32. package/dist/src/cli/keys-bundle.d.ts +1 -1
  33. package/dist/src/cli/keys-bundle.js +1 -1
  34. package/dist/src/cli/keys.d.ts +10 -47
  35. package/dist/src/cli/keys.js +31 -399
  36. package/dist/src/council/clarifier.d.ts +31 -3
  37. package/dist/src/council/clarifier.js +220 -32
  38. package/dist/src/council/context.js +49 -15
  39. package/dist/src/council/debate-checkpoint.d.ts +129 -0
  40. package/dist/src/council/debate-checkpoint.js +176 -0
  41. package/dist/src/council/debate-planner.js +54 -5
  42. package/dist/src/council/debate-summary.d.ts +25 -0
  43. package/dist/src/council/debate-summary.js +85 -0
  44. package/dist/src/council/debate.d.ts +169 -2
  45. package/dist/src/council/debate.js +1265 -135
  46. package/dist/src/council/index.d.ts +108 -1
  47. package/dist/src/council/index.js +670 -197
  48. package/dist/src/council/leader.d.ts +26 -0
  49. package/dist/src/council/leader.js +150 -9
  50. package/dist/src/council/llm.d.ts +94 -0
  51. package/dist/src/council/llm.js +348 -55
  52. package/dist/src/council/panel-select.d.ts +30 -0
  53. package/dist/src/council/panel-select.js +82 -0
  54. package/dist/src/council/planner.js +40 -0
  55. package/dist/src/council/preflight.d.ts +17 -0
  56. package/dist/src/council/preflight.js +50 -2
  57. package/dist/src/council/prompts.d.ts +39 -4
  58. package/dist/src/council/prompts.js +256 -69
  59. package/dist/src/council/stance-recall.d.ts +42 -0
  60. package/dist/src/council/stance-recall.js +57 -0
  61. package/dist/src/council/strip-think.d.ts +17 -0
  62. package/dist/src/council/strip-think.js +33 -0
  63. package/dist/src/council/types.d.ts +138 -0
  64. package/dist/src/ee/artifact-cache.d.ts +16 -0
  65. package/dist/src/ee/artifact-cache.js +32 -0
  66. package/dist/src/ee/auth.d.ts +20 -0
  67. package/dist/src/ee/auth.js +54 -2
  68. package/dist/src/ee/bridge.d.ts +10 -0
  69. package/dist/src/ee/bridge.js +58 -0
  70. package/dist/src/ee/client.js +109 -21
  71. package/dist/src/ee/ee-onboarding.js +6 -26
  72. package/dist/src/ee/export-transcripts.d.ts +1 -0
  73. package/dist/src/ee/export-transcripts.js +8 -10
  74. package/dist/src/ee/extract-session.js +29 -0
  75. package/dist/src/ee/extract-style.d.ts +58 -0
  76. package/dist/src/ee/extract-style.js +270 -0
  77. package/dist/src/ee/recall-ledger.d.ts +9 -0
  78. package/dist/src/ee/recall-ledger.js +3 -0
  79. package/dist/src/ee/scope.d.ts +1 -0
  80. package/dist/src/ee/scope.js +26 -1
  81. package/dist/src/ee/search.d.ts +7 -0
  82. package/dist/src/ee/search.js +24 -0
  83. package/dist/src/ee/transcript-emit.js +2 -0
  84. package/dist/src/ee/types.d.ts +22 -0
  85. package/dist/src/ee/who-am-i-brain.d.ts +35 -0
  86. package/dist/src/ee/who-am-i-brain.js +220 -0
  87. package/dist/src/ee/who-am-i.d.ts +10 -3
  88. package/dist/src/ee/who-am-i.js +12 -0
  89. package/dist/src/ee/workflow-event.d.ts +48 -0
  90. package/dist/src/ee/workflow-event.js +81 -0
  91. package/dist/src/flow/compaction/compress.d.ts +3 -3
  92. package/dist/src/flow/compaction/compress.js +58 -8
  93. package/dist/src/flow/compaction/extract.d.ts +4 -7
  94. package/dist/src/flow/compaction/extract.js +50 -10
  95. package/dist/src/flow/compaction/index.d.ts +14 -1
  96. package/dist/src/flow/compaction/index.js +96 -3
  97. package/dist/src/flow/compaction/input-guard.d.ts +24 -0
  98. package/dist/src/flow/compaction/input-guard.js +43 -0
  99. package/dist/src/flow/compaction/progress.d.ts +35 -0
  100. package/dist/src/flow/compaction/progress.js +35 -0
  101. package/dist/src/flow/fold-planning.d.ts +36 -0
  102. package/dist/src/flow/fold-planning.js +83 -0
  103. package/dist/src/flow/hierarchy.d.ts +146 -0
  104. package/dist/src/flow/hierarchy.js +427 -0
  105. package/dist/src/flow/index.d.ts +1 -0
  106. package/dist/src/flow/index.js +2 -0
  107. package/dist/src/flow/run-artifacts.d.ts +102 -0
  108. package/dist/src/flow/run-artifacts.js +208 -0
  109. package/dist/src/generated/version.d.ts +1 -1
  110. package/dist/src/generated/version.js +1 -1
  111. package/dist/src/gsd/assessment-schema.d.ts +44 -0
  112. package/dist/src/gsd/assessment-schema.js +134 -0
  113. package/dist/src/gsd/capability-registry.d.ts +45 -0
  114. package/dist/src/gsd/capability-registry.js +337 -0
  115. package/dist/src/gsd/complexity-assessor.d.ts +39 -0
  116. package/dist/src/gsd/complexity-assessor.js +152 -0
  117. package/dist/src/gsd/config-bridge.d.ts +7 -0
  118. package/dist/src/gsd/config-bridge.js +114 -0
  119. package/dist/src/gsd/config-loader.d.ts +27 -0
  120. package/dist/src/gsd/config-loader.js +50 -0
  121. package/dist/src/gsd/council-context.d.ts +44 -0
  122. package/dist/src/gsd/council-context.js +114 -0
  123. package/dist/src/gsd/ee-closure.d.ts +28 -0
  124. package/dist/src/gsd/ee-closure.js +49 -0
  125. package/dist/src/gsd/flags.d.ts +66 -0
  126. package/dist/src/gsd/flags.js +102 -0
  127. package/dist/src/gsd/gsd-dispatch.d.ts +58 -0
  128. package/dist/src/gsd/gsd-dispatch.js +131 -0
  129. package/dist/src/gsd/gsd-runtime.d.ts +22 -0
  130. package/dist/src/gsd/gsd-runtime.js +37 -0
  131. package/dist/src/gsd/host-adapter.d.ts +11 -0
  132. package/dist/src/gsd/host-adapter.js +29 -0
  133. package/dist/src/gsd/index.d.ts +24 -1
  134. package/dist/src/gsd/index.js +27 -0
  135. package/dist/src/gsd/loop-host-contract.d.ts +21 -0
  136. package/dist/src/gsd/loop-host-contract.js +39 -0
  137. package/dist/src/gsd/loop-host.d.ts +69 -0
  138. package/dist/src/gsd/loop-host.js +245 -0
  139. package/dist/src/gsd/loop-resolver.d.ts +36 -0
  140. package/dist/src/gsd/loop-resolver.js +79 -0
  141. package/dist/src/gsd/model-tier.d.ts +13 -0
  142. package/dist/src/gsd/model-tier.js +45 -0
  143. package/dist/src/gsd/mutation-gate.d.ts +16 -0
  144. package/dist/src/gsd/mutation-gate.js +41 -0
  145. package/dist/src/gsd/native-roadmap.d.ts +89 -0
  146. package/dist/src/gsd/native-roadmap.js +343 -0
  147. package/dist/src/gsd/native-state.d.ts +47 -0
  148. package/dist/src/gsd/native-state.js +220 -0
  149. package/dist/src/gsd/paths.d.ts +23 -0
  150. package/dist/src/gsd/paths.js +66 -0
  151. package/dist/src/gsd/phase-dag.d.ts +12 -0
  152. package/dist/src/gsd/phase-dag.js +94 -0
  153. package/dist/src/gsd/phase-sync.d.ts +42 -0
  154. package/dist/src/gsd/phase-sync.js +321 -0
  155. package/dist/src/gsd/pil-gate-context.d.ts +13 -0
  156. package/dist/src/gsd/pil-gate-context.js +64 -0
  157. package/dist/src/gsd/pil-gate-critic.d.ts +19 -0
  158. package/dist/src/gsd/pil-gate-critic.js +74 -0
  159. package/dist/src/gsd/plan-council-prompts.d.ts +25 -0
  160. package/dist/src/gsd/plan-council-prompts.js +79 -0
  161. package/dist/src/gsd/plan-council.d.ts +44 -0
  162. package/dist/src/gsd/plan-council.js +283 -0
  163. package/dist/src/gsd/plan-gate-vocabulary.d.ts +40 -0
  164. package/dist/src/gsd/plan-gate-vocabulary.js +64 -0
  165. package/dist/src/gsd/product-workspace.d.ts +13 -0
  166. package/dist/src/gsd/product-workspace.js +124 -0
  167. package/dist/src/gsd/ship-bridge.d.ts +25 -0
  168. package/dist/src/gsd/ship-bridge.js +65 -0
  169. package/dist/src/gsd/state-document.d.ts +40 -0
  170. package/dist/src/gsd/state-document.js +163 -0
  171. package/dist/src/gsd/verdict-schema.d.ts +39 -0
  172. package/dist/src/gsd/verdict-schema.js +144 -0
  173. package/dist/src/gsd/verify-context.d.ts +22 -0
  174. package/dist/src/gsd/verify-context.js +27 -0
  175. package/dist/src/gsd/verify-council-prompts.d.ts +19 -0
  176. package/dist/src/gsd/verify-council-prompts.js +85 -0
  177. package/dist/src/gsd/verify-council.d.ts +25 -0
  178. package/dist/src/gsd/verify-council.js +119 -0
  179. package/dist/src/gsd/verify-gate-vocabulary.d.ts +25 -0
  180. package/dist/src/gsd/verify-gate-vocabulary.js +46 -0
  181. package/dist/src/gsd/workflow-engine.d.ts +60 -0
  182. package/dist/src/gsd/workflow-engine.js +207 -0
  183. package/dist/src/gsd/workflow-tools.d.ts +13 -0
  184. package/dist/src/gsd/workflow-tools.js +277 -0
  185. package/dist/src/headless/council-answers.js +4 -0
  186. package/dist/src/hooks/index.js +1 -1
  187. package/dist/src/index.js +172 -270
  188. package/dist/src/lsp/builtins.js +3 -1
  189. package/dist/src/lsp/manager.d.ts +5 -1
  190. package/dist/src/lsp/manager.js +249 -3
  191. package/dist/src/lsp/npm-cache.d.ts +11 -1
  192. package/dist/src/lsp/npm-cache.js +17 -1
  193. package/dist/src/lsp/runtime.d.ts +6 -1
  194. package/dist/src/lsp/runtime.js +17 -1
  195. package/dist/src/lsp/types.d.ts +83 -1
  196. package/dist/src/lsp/types.js +10 -0
  197. package/dist/src/maintain/pr-builder.js +23 -13
  198. package/dist/src/mcp/auto-setup.js +57 -32
  199. package/dist/src/mcp/client-pool.js +44 -16
  200. package/dist/src/mcp/lsp-tools.d.ts +5 -1
  201. package/dist/src/mcp/lsp-tools.js +93 -2
  202. package/dist/src/mcp/mcp-keychain.d.ts +3 -5
  203. package/dist/src/mcp/mcp-keychain.js +9 -49
  204. package/dist/src/mcp/research-onboarding.js +8 -7
  205. package/dist/src/mcp/runtime.js +34 -2
  206. package/dist/src/mcp/setup-guide-text.d.ts +1 -1
  207. package/dist/src/mcp/setup-guide-text.js +22 -2
  208. package/dist/src/mcp/tools-server.d.ts +10 -0
  209. package/dist/src/mcp/tools-server.js +10 -2
  210. package/dist/src/models/catalog-client.d.ts +87 -0
  211. package/dist/src/models/catalog-client.js +105 -38
  212. package/dist/src/models/catalog.json +528 -265
  213. package/dist/src/models/registry.d.ts +22 -7
  214. package/dist/src/models/registry.js +73 -10
  215. package/dist/src/ops/doctor.js +1 -1
  216. package/dist/src/orchestrator/ask-user.d.ts +61 -0
  217. package/dist/src/orchestrator/ask-user.js +65 -0
  218. package/dist/src/orchestrator/auto-commit.js +1 -1
  219. package/dist/src/orchestrator/batch-turn-runner.js +2 -2
  220. package/dist/src/orchestrator/cache-prefix.d.ts +67 -0
  221. package/dist/src/orchestrator/cache-prefix.js +83 -0
  222. package/dist/src/orchestrator/compact-request.d.ts +32 -0
  223. package/dist/src/orchestrator/compact-request.js +41 -0
  224. package/dist/src/orchestrator/compaction.d.ts +12 -3
  225. package/dist/src/orchestrator/compaction.js +35 -15
  226. package/dist/src/orchestrator/council-manager.d.ts +12 -3
  227. package/dist/src/orchestrator/council-manager.js +74 -32
  228. package/dist/src/orchestrator/council-request.d.ts +49 -0
  229. package/dist/src/orchestrator/council-request.js +62 -0
  230. package/dist/src/orchestrator/cross-turn-dedup.d.ts +6 -0
  231. package/dist/src/orchestrator/cross-turn-dedup.js +22 -1
  232. package/dist/src/orchestrator/error-utils.d.ts +29 -0
  233. package/dist/src/orchestrator/error-utils.js +132 -24
  234. package/dist/src/orchestrator/grounding-check.js +39 -1
  235. package/dist/src/orchestrator/interactive-pause.d.ts +26 -0
  236. package/dist/src/orchestrator/interactive-pause.js +36 -0
  237. package/dist/src/orchestrator/message-processor.d.ts +4 -0
  238. package/dist/src/orchestrator/message-processor.js +268 -41
  239. package/dist/src/orchestrator/orchestrator.d.ts +64 -3
  240. package/dist/src/orchestrator/orchestrator.js +823 -120
  241. package/dist/src/orchestrator/preprocessor.js +3 -3
  242. package/dist/src/orchestrator/proactive-compact-detector.d.ts +26 -0
  243. package/dist/src/orchestrator/proactive-compact-detector.js +36 -0
  244. package/dist/src/orchestrator/prompts.js +17 -17
  245. package/dist/src/orchestrator/reactive-delegation.d.ts +39 -0
  246. package/dist/src/orchestrator/reactive-delegation.js +59 -0
  247. package/dist/src/orchestrator/retry-classifier.d.ts +2 -1
  248. package/dist/src/orchestrator/retry-classifier.js +46 -2
  249. package/dist/src/orchestrator/safety-askcard.d.ts +1 -1
  250. package/dist/src/orchestrator/safety-askcard.js +5 -2
  251. package/dist/src/orchestrator/safety-intercept.d.ts +50 -0
  252. package/dist/src/orchestrator/safety-intercept.js +62 -0
  253. package/dist/src/orchestrator/scope-reminder.js +1 -1
  254. package/dist/src/orchestrator/session-experience.d.ts +2 -1
  255. package/dist/src/orchestrator/session-experience.js +2 -1
  256. package/dist/src/orchestrator/should-run-gate.d.ts +5 -0
  257. package/dist/src/orchestrator/should-run-gate.js +18 -0
  258. package/dist/src/orchestrator/stall-watchdog.d.ts +31 -3
  259. package/dist/src/orchestrator/stall-watchdog.js +65 -10
  260. package/dist/src/orchestrator/stream-runner.d.ts +13 -3
  261. package/dist/src/orchestrator/stream-runner.js +115 -49
  262. package/dist/src/orchestrator/sub-agent-cap.d.ts +13 -1
  263. package/dist/src/orchestrator/sub-agent-cap.js +16 -1
  264. package/dist/src/orchestrator/sub-agent-model-tier.d.ts +13 -1
  265. package/dist/src/orchestrator/sub-agent-model-tier.js +16 -2
  266. package/dist/src/orchestrator/subagent-compactor.d.ts +53 -1
  267. package/dist/src/orchestrator/subagent-compactor.js +126 -15
  268. package/dist/src/orchestrator/tool-engine.d.ts +41 -0
  269. package/dist/src/orchestrator/tool-engine.js +846 -66
  270. package/dist/src/orchestrator/tool-limit-auto-recover.d.ts +22 -0
  271. package/dist/src/orchestrator/tool-limit-auto-recover.js +30 -0
  272. package/dist/src/orchestrator/turn-runner-deps.d.ts +19 -0
  273. package/dist/src/orchestrator/turn-watchdog.d.ts +44 -0
  274. package/dist/src/orchestrator/turn-watchdog.js +84 -0
  275. package/dist/src/pil/agent-operating-contract.d.ts +1 -1
  276. package/dist/src/pil/agent-operating-contract.js +6 -4
  277. package/dist/src/pil/cheap-model-playbook.d.ts +1 -1
  278. package/dist/src/pil/cheap-model-playbook.js +5 -1
  279. package/dist/src/pil/cheap-model-workbooks.d.ts +1 -1
  280. package/dist/src/pil/cheap-model-workbooks.js +1 -1
  281. package/dist/src/pil/discovery-types.d.ts +1 -0
  282. package/dist/src/pil/discovery.d.ts +1 -1
  283. package/dist/src/pil/discovery.js +18 -13
  284. package/dist/src/pil/layer1-intent.d.ts +18 -6
  285. package/dist/src/pil/layer1-intent.js +66 -757
  286. package/dist/src/pil/layer15-context-scan.js +15 -1
  287. package/dist/src/pil/layer1_5-complexity-size.d.ts +7 -0
  288. package/dist/src/pil/layer1_5-complexity-size.js +31 -5
  289. package/dist/src/pil/layer3-ee-injection.js +23 -8
  290. package/dist/src/pil/layer4-gsd.js +69 -16
  291. package/dist/src/pil/layer5-context.js +7 -3
  292. package/dist/src/pil/layer6-output.d.ts +23 -0
  293. package/dist/src/pil/layer6-output.js +5 -1
  294. package/dist/src/pil/llm-classify.d.ts +111 -5
  295. package/dist/src/pil/llm-classify.js +421 -189
  296. package/dist/src/pil/native-capabilities-workbook.d.ts +1 -1
  297. package/dist/src/pil/native-capabilities-workbook.js +8 -0
  298. package/dist/src/pil/pipeline.js +36 -2
  299. package/dist/src/pil/repo-grounding-probe.d.ts +15 -0
  300. package/dist/src/pil/repo-grounding-probe.js +136 -0
  301. package/dist/src/pil/repo-structure-hints.d.ts +7 -0
  302. package/dist/src/pil/repo-structure-hints.js +45 -0
  303. package/dist/src/pil/response-tools.js +5 -3
  304. package/dist/src/pil/schema.d.ts +1 -0
  305. package/dist/src/pil/schema.js +2 -0
  306. package/dist/src/pil/types.d.ts +18 -0
  307. package/dist/src/playbook/directives.d.ts +4 -0
  308. package/dist/src/playbook/directives.js +17 -5
  309. package/dist/src/product-loop/artifact-io.js +4 -0
  310. package/dist/src/product-loop/backlog-builder.d.ts +14 -1
  311. package/dist/src/product-loop/backlog-builder.js +30 -6
  312. package/dist/src/product-loop/criteria-seed.d.ts +51 -0
  313. package/dist/src/product-loop/criteria-seed.js +200 -0
  314. package/dist/src/product-loop/discovery-context-format.js +3 -1
  315. package/dist/src/product-loop/discovery-ecosystem.js +4 -1
  316. package/dist/src/product-loop/discovery-interview.d.ts +9 -0
  317. package/dist/src/product-loop/discovery-interview.js +60 -12
  318. package/dist/src/product-loop/discovery-recommender.js +2 -1
  319. package/dist/src/product-loop/discovery-schema.js +19 -2
  320. package/dist/src/product-loop/discovery-triage.d.ts +23 -0
  321. package/dist/src/product-loop/discovery-triage.js +109 -0
  322. package/dist/src/product-loop/gather.js +150 -2
  323. package/dist/src/product-loop/ideal-trace.d.ts +7 -0
  324. package/dist/src/product-loop/ideal-trace.js +64 -0
  325. package/dist/src/product-loop/index.d.ts +13 -1
  326. package/dist/src/product-loop/index.js +340 -52
  327. package/dist/src/product-loop/loop-driver.d.ts +7 -0
  328. package/dist/src/product-loop/loop-driver.js +330 -106
  329. package/dist/src/product-loop/phase-plan.d.ts +21 -0
  330. package/dist/src/product-loop/phase-plan.js +81 -6
  331. package/dist/src/product-loop/phase-rituals.d.ts +3 -0
  332. package/dist/src/product-loop/phase-rituals.js +8 -3
  333. package/dist/src/product-loop/phase-runner.js +39 -12
  334. package/dist/src/product-loop/plan-adherence-review.d.ts +26 -0
  335. package/dist/src/product-loop/plan-adherence-review.js +144 -0
  336. package/dist/src/product-loop/sprint-runner.d.ts +173 -0
  337. package/dist/src/product-loop/sprint-runner.js +863 -19
  338. package/dist/src/product-loop/types.d.ts +61 -5
  339. package/dist/src/providers/adapter.d.ts +1 -1
  340. package/dist/src/providers/adapter.js +3 -4
  341. package/dist/src/providers/anthropic.d.ts +9 -8
  342. package/dist/src/providers/anthropic.js +13 -47
  343. package/dist/src/providers/auth/browser-flow.d.ts +1 -1
  344. package/dist/src/providers/auth/browser-flow.js +1 -1
  345. package/dist/src/providers/auth/grok-oauth.d.ts +1 -0
  346. package/dist/src/providers/auth/grok-oauth.js +30 -5
  347. package/dist/src/providers/auth/openai-oauth.d.ts +1 -0
  348. package/dist/src/providers/auth/openai-oauth.js +15 -1
  349. package/dist/src/providers/auth/registry.js +0 -34
  350. package/dist/src/providers/auth/token-store.d.ts +9 -9
  351. package/dist/src/providers/auth/token-store.js +8 -67
  352. package/dist/src/providers/auth/types.d.ts +9 -1
  353. package/dist/src/providers/auth/types.js +1 -1
  354. package/dist/src/providers/capabilities.d.ts +24 -5
  355. package/dist/src/providers/capabilities.js +42 -24
  356. package/dist/src/providers/endpoints.d.ts +2 -2
  357. package/dist/src/providers/endpoints.js +11 -10
  358. package/dist/src/providers/env-store.d.ts +17 -0
  359. package/dist/src/providers/env-store.js +228 -0
  360. package/dist/src/providers/keychain.d.ts +22 -18
  361. package/dist/src/providers/keychain.js +127 -140
  362. package/dist/src/providers/mcp-vision-bridge.js +56 -146
  363. package/dist/src/providers/openai-compatible.js +8 -1
  364. package/dist/src/providers/pricing.d.ts +2 -2
  365. package/dist/src/providers/pricing.js +3 -13
  366. package/dist/src/providers/runtime.d.ts +43 -3
  367. package/dist/src/providers/runtime.js +88 -14
  368. package/dist/src/providers/strategies/base.strategy.d.ts +16 -0
  369. package/dist/src/providers/strategies/base.strategy.js +24 -1
  370. package/dist/src/providers/strategies/{siliconflow.strategy.d.ts → opencode-go.strategy.d.ts} +3 -3
  371. package/dist/src/providers/strategies/opencode-go.strategy.js +83 -0
  372. package/dist/src/providers/strategies/registry.js +4 -4
  373. package/dist/src/providers/strategies/thinking-mode.d.ts +109 -0
  374. package/dist/src/providers/strategies/thinking-mode.js +288 -1
  375. package/dist/src/providers/strategies/xai.strategy.js +27 -0
  376. package/dist/src/providers/strategies/zai.strategy.d.ts +14 -0
  377. package/dist/src/providers/strategies/zai.strategy.js +44 -0
  378. package/dist/src/providers/types.d.ts +5 -6
  379. package/dist/src/providers/types.js +2 -2
  380. package/dist/src/providers/vision-backend.d.ts +47 -0
  381. package/dist/src/providers/vision-backend.js +258 -0
  382. package/dist/src/providers/vision-proxy.d.ts +22 -9
  383. package/dist/src/providers/vision-proxy.js +63 -132
  384. package/dist/src/providers/warm.d.ts +65 -0
  385. package/dist/src/providers/warm.js +145 -0
  386. package/dist/src/providers/wire-debug.js +95 -0
  387. package/dist/src/router/decide.d.ts +13 -0
  388. package/dist/src/router/decide.js +138 -36
  389. package/dist/src/router/peak-hour.d.ts +38 -0
  390. package/dist/src/router/peak-hour.js +107 -0
  391. package/dist/src/router/step-router.js +3 -2
  392. package/dist/src/router/warm.js +4 -5
  393. package/dist/src/scaffold/continuation-prompt.d.ts +11 -0
  394. package/dist/src/scaffold/continuation-prompt.js +26 -0
  395. package/dist/src/scaffold/point-to-existing.d.ts +21 -0
  396. package/dist/src/scaffold/point-to-existing.js +25 -0
  397. package/dist/src/self-qa/agentic-loop.js +6 -5
  398. package/dist/src/{ui/state → state}/active-run.d.ts +19 -0
  399. package/dist/src/{ui/state → state}/active-run.js +21 -0
  400. package/dist/src/{ui/status-bar/store.d.ts → state/status-bar-store.d.ts} +4 -1
  401. package/dist/src/{ui/status-bar/store.js → state/status-bar-store.js} +12 -9
  402. package/dist/src/state/turn-trace.d.ts +43 -0
  403. package/dist/src/state/turn-trace.js +32 -0
  404. package/dist/src/storage/db.js +2 -1
  405. package/dist/src/storage/index.d.ts +1 -1
  406. package/dist/src/storage/index.js +1 -1
  407. package/dist/src/storage/interaction-log.d.ts +1 -1
  408. package/dist/src/storage/migrations.js +71 -1
  409. package/dist/src/storage/sessions.d.ts +28 -10
  410. package/dist/src/storage/sessions.js +78 -21
  411. package/dist/src/storage/transcript-view.js +1 -1
  412. package/dist/src/storage/transcript.d.ts +51 -0
  413. package/dist/src/storage/transcript.js +340 -15
  414. package/dist/src/tools/file.d.ts +15 -0
  415. package/dist/src/tools/file.js +32 -0
  416. package/dist/src/tools/git-safety.d.ts +19 -0
  417. package/dist/src/tools/git-safety.js +168 -0
  418. package/dist/src/tools/native-tools.d.ts +1 -1
  419. package/dist/src/tools/native-tools.js +81 -1
  420. package/dist/src/tools/registry.d.ts +20 -0
  421. package/dist/src/tools/registry.js +576 -23
  422. package/dist/src/tools/research.d.ts +29 -0
  423. package/dist/src/tools/research.js +233 -0
  424. package/dist/src/types/index.d.ts +147 -4
  425. package/dist/src/ui/app.js +0 -0
  426. package/dist/src/ui/cards/product-status-card.js +1 -1
  427. package/dist/src/ui/components/agent-rail-activities.d.ts +26 -0
  428. package/dist/src/ui/components/agent-rail-activities.js +47 -0
  429. package/dist/src/ui/components/bubble-body-guard.d.ts +27 -0
  430. package/dist/src/ui/components/bubble-body-guard.js +50 -0
  431. package/dist/src/ui/components/compact-progress-card.d.ts +24 -0
  432. package/dist/src/ui/components/compact-progress-card.js +42 -0
  433. package/dist/src/ui/components/context-rail.d.ts +26 -0
  434. package/dist/src/ui/components/context-rail.js +33 -0
  435. package/dist/src/ui/components/council-conclusion-card.d.ts +73 -0
  436. package/dist/src/ui/components/council-conclusion-card.js +420 -0
  437. package/dist/src/ui/components/council-debate-pill.d.ts +36 -0
  438. package/dist/src/ui/components/council-debate-pill.js +34 -0
  439. package/dist/src/ui/components/council-info-card.js +2 -2
  440. package/dist/src/ui/components/council-leader-bubble.d.ts +10 -3
  441. package/dist/src/ui/components/council-leader-bubble.js +21 -11
  442. package/dist/src/ui/components/council-message-bubble.d.ts +15 -2
  443. package/dist/src/ui/components/council-message-bubble.js +16 -15
  444. package/dist/src/ui/components/council-phase-timeline.d.ts +9 -1
  445. package/dist/src/ui/components/council-phase-timeline.js +66 -17
  446. package/dist/src/ui/components/council-placeholder-bubble.d.ts +16 -9
  447. package/dist/src/ui/components/council-placeholder-bubble.js +32 -29
  448. package/dist/src/ui/components/council-question-card.js +13 -12
  449. package/dist/src/ui/components/council-rail-rounds.d.ts +26 -0
  450. package/dist/src/ui/components/council-rail-rounds.js +57 -0
  451. package/dist/src/ui/components/council-round-group.d.ts +38 -0
  452. package/dist/src/ui/components/council-round-group.js +88 -0
  453. package/dist/src/ui/components/council-status-list.d.ts +3 -1
  454. package/dist/src/ui/components/council-status-list.js +36 -24
  455. package/dist/src/ui/components/council-synthesis-banner.d.ts +7 -2
  456. package/dist/src/ui/components/council-synthesis-banner.js +20 -5
  457. package/dist/src/ui/components/halt-recovery-card.js +9 -5
  458. package/dist/src/ui/components/jump-to-latest-pill.d.ts +11 -0
  459. package/dist/src/ui/components/jump-to-latest-pill.js +14 -0
  460. package/dist/src/ui/components/message-view.d.ts +15 -0
  461. package/dist/src/ui/components/message-view.js +50 -1
  462. package/dist/src/ui/components/prompt-box.js +18 -16
  463. package/dist/src/ui/components/session-tree-card.d.ts +14 -0
  464. package/dist/src/ui/components/session-tree-card.js +46 -0
  465. package/dist/src/ui/components/slash-inline-menu.d.ts +12 -0
  466. package/dist/src/ui/components/slash-inline-menu.js +26 -5
  467. package/dist/src/ui/components/task-list-panel.d.ts +14 -1
  468. package/dist/src/ui/components/task-list-panel.js +22 -2
  469. package/dist/src/ui/components/tool-group.d.ts +15 -3
  470. package/dist/src/ui/components/tool-group.js +69 -11
  471. package/dist/src/ui/containers/modals-layer.d.ts +4 -2
  472. package/dist/src/ui/containers/modals-layer.js +2 -2
  473. package/dist/src/ui/council-harness-event.d.ts +57 -0
  474. package/dist/src/ui/council-harness-event.js +46 -0
  475. package/dist/src/ui/heartbeat-debug.d.ts +29 -0
  476. package/dist/src/ui/heartbeat-debug.js +45 -0
  477. package/dist/src/ui/hooks/use-session-picker.d.ts +3 -3
  478. package/dist/src/ui/mcp-modal.js +2 -4
  479. package/dist/src/ui/modals/api-key-modal.js +1 -1
  480. package/dist/src/ui/modals/connect-modal.js +4 -3
  481. package/dist/src/ui/modals/model-picker-modal.d.ts +8 -18
  482. package/dist/src/ui/modals/model-picker-modal.js +8 -10
  483. package/dist/src/ui/modals/session-picker-modal.d.ts +2 -2
  484. package/dist/src/ui/modals/session-picker-modal.js +3 -5
  485. package/dist/src/ui/picker-providers.d.ts +1 -1
  486. package/dist/src/ui/picker-providers.js +1 -1
  487. package/dist/src/ui/primitives/index.d.ts +1 -0
  488. package/dist/src/ui/primitives/index.js +2 -0
  489. package/dist/src/ui/primitives/semantic-primitives.d.ts +76 -0
  490. package/dist/src/ui/primitives/semantic-primitives.js +81 -0
  491. package/dist/src/ui/slash/compact.js +5 -7
  492. package/dist/src/ui/slash/cost.js +1 -1
  493. package/dist/src/ui/slash/council.js +19 -1
  494. package/dist/src/ui/slash/debug.d.ts +3 -31
  495. package/dist/src/ui/slash/debug.js +9 -20
  496. package/dist/src/ui/slash/ee.js +81 -0
  497. package/dist/src/ui/slash/ideal.d.ts +6 -2
  498. package/dist/src/ui/slash/ideal.js +97 -7
  499. package/dist/src/ui/slash/menu-items.d.ts +7 -0
  500. package/dist/src/ui/slash/menu-items.js +23 -20
  501. package/dist/src/ui/slash/registry.d.ts +2 -0
  502. package/dist/src/ui/slash/registry.js +4 -0
  503. package/dist/src/ui/status-bar/cache-hit.d.ts +6 -0
  504. package/dist/src/ui/status-bar/cache-hit.js +9 -0
  505. package/dist/src/ui/status-bar/index.d.ts +1 -1
  506. package/dist/src/ui/status-bar/index.js +7 -3
  507. package/dist/src/ui/status-bar/usd-meter.d.ts +5 -4
  508. package/dist/src/ui/status-bar/usd-meter.js +6 -4
  509. package/dist/src/ui/theme.d.ts +1 -0
  510. package/dist/src/ui/theme.js +2 -0
  511. package/dist/src/ui/types.d.ts +7 -0
  512. package/dist/src/ui/use-app-logic.js +0 -0
  513. package/dist/src/ui/utils/agent-activities.d.ts +39 -0
  514. package/dist/src/ui/utils/agent-activities.js +96 -0
  515. package/dist/src/ui/utils/format.d.ts +14 -0
  516. package/dist/src/ui/utils/format.js +23 -3
  517. package/dist/src/ui/utils/group-tool-entries.d.ts +26 -0
  518. package/dist/src/ui/utils/group-tool-entries.js +111 -0
  519. package/dist/src/ui/utils/tool-summary.d.ts +21 -0
  520. package/dist/src/ui/utils/tool-summary.js +91 -0
  521. package/dist/src/usage/downgrade.js +2 -2
  522. package/dist/src/usage/product-ledger.js +2 -2
  523. package/dist/src/utils/event-loop-monitor.d.ts +85 -0
  524. package/dist/src/utils/event-loop-monitor.js +107 -0
  525. package/dist/src/utils/install-manager.js +2 -1
  526. package/dist/src/utils/llm-deadline.d.ts +14 -0
  527. package/dist/src/utils/llm-deadline.js +19 -0
  528. package/dist/src/utils/logger.js +2 -2
  529. package/dist/src/utils/loop-profiler.d.ts +102 -0
  530. package/dist/src/utils/loop-profiler.js +202 -0
  531. package/dist/src/utils/permission-mode.js +5 -3
  532. package/dist/src/utils/redactor.js +1 -1
  533. package/dist/src/utils/settings.d.ts +180 -5
  534. package/dist/src/utils/settings.js +271 -31
  535. package/dist/src/utils/side-question.d.ts +1 -2
  536. package/dist/src/utils/side-question.js +2 -2
  537. package/dist/src/utils/visible-retry.d.ts +11 -0
  538. package/dist/src/utils/visible-retry.js +10 -1
  539. package/dist/src/verify/entrypoint.d.ts +1 -1
  540. package/dist/src/verify/entrypoint.js +52 -17
  541. package/dist/src/verify/orchestrator.d.ts +1 -1
  542. package/dist/src/verify/orchestrator.js +20 -3
  543. package/dist/src/verify/recipes.d.ts +13 -0
  544. package/dist/src/verify/recipes.js +15 -0
  545. package/package.json +134 -132
  546. package/dist/src/cli/bw-vault.d.ts +0 -55
  547. package/dist/src/cli/bw-vault.js +0 -133
  548. package/dist/src/mcp/ee-tools.d.ts +0 -46
  549. package/dist/src/mcp/ee-tools.js +0 -193
  550. package/dist/src/providers/auth/gcloud.d.ts +0 -28
  551. package/dist/src/providers/auth/gcloud.js +0 -102
  552. package/dist/src/providers/auth/gemini-oauth.d.ts +0 -82
  553. package/dist/src/providers/auth/gemini-oauth.js +0 -472
  554. package/dist/src/providers/gemini.d.ts +0 -11
  555. package/dist/src/providers/gemini.js +0 -45
  556. package/dist/src/providers/siliconflow-sse-repair.d.ts +0 -58
  557. package/dist/src/providers/siliconflow-sse-repair.js +0 -177
  558. package/dist/src/providers/strategies/google.strategy.d.ts +0 -22
  559. package/dist/src/providers/strategies/google.strategy.js +0 -174
  560. package/dist/src/providers/strategies/siliconflow.strategy.js +0 -29
  561. package/dist/src/ui/containers/chat-feed.d.ts +0 -40
  562. package/dist/src/ui/containers/chat-feed.js +0 -66
@@ -1,9 +1,14 @@
1
1
  import type { CouncilMessage } from "../../types/index.js";
2
+ import type { Theme } from "../theme.js";
2
3
  export interface CouncilSynthesisBannerProps {
3
4
  msg: CouncilMessage;
5
+ theme: Theme;
4
6
  }
5
7
  export declare function buildSynthesisTitle(round: number | undefined): string;
6
8
  /**
7
- * Full-width double-border pinned banner for round and final synthesis.
9
+ * Round / final synthesis, rendered as a linear group-chat row that closes the
10
+ * thread. A synthesis-colored left bar + bold title distinguishes the leader's
11
+ * verdict from the debate turns while staying in the same downward stream (no
12
+ * centered/full-width banner that broke the chat flow).
8
13
  */
9
- export declare function CouncilSynthesisBanner({ msg }: CouncilSynthesisBannerProps): import("react").ReactNode;
14
+ export declare function CouncilSynthesisBanner({ msg, theme: t }: CouncilSynthesisBannerProps): import("react").ReactNode;
@@ -1,15 +1,30 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "@opentui/react/jsx-runtime";
2
- import { dark } from "../theme.js";
3
2
  import { truncateCodeBlocks } from "./code-block-truncate.js";
3
+ import { CouncilConclusionCard, parseConclusion } from "./council-conclusion-card.js";
4
4
  export function buildSynthesisTitle(round) {
5
5
  return round === undefined ? "Final Synthesis" : `Round ${round} Synthesis`;
6
6
  }
7
7
  /**
8
- * Full-width double-border pinned banner for round and final synthesis.
8
+ * Round / final synthesis, rendered as a linear group-chat row that closes the
9
+ * thread. A synthesis-colored left bar + bold title distinguishes the leader's
10
+ * verdict from the debate turns while staying in the same downward stream (no
11
+ * centered/full-width banner that broke the chat flow).
9
12
  */
10
- export function CouncilSynthesisBanner({ msg }) {
11
- const bodyText = truncateCodeBlocks(msg.text.trim());
13
+ export function CouncilSynthesisBanner({ msg, theme: t }) {
14
+ // When the synthesis is a structured evaluation/decision JSON, render it as a
15
+ // scannable conclusion card instead of dumping raw JSON as freetext. Prose
16
+ // syntheses (no parseable JSON object) fall through to the plain-text path.
17
+ const conclusion = parseConclusion(msg.text);
18
+ if (conclusion) {
19
+ return _jsx(CouncilConclusionCard, { conclusion: conclusion, round: msg.round, theme: t });
20
+ }
21
+ // A `---READABLE---` marker means the synthesizer already produced a human
22
+ // prose tail — show ONLY that tail, not the raw JSON above it. Empty tail
23
+ // (marker at the very end) falls back to the full text.
24
+ const raw = msg.text.trim();
25
+ const readableIdx = raw.indexOf("---READABLE---");
26
+ const bodyText = truncateCodeBlocks(readableIdx !== -1 ? raw.slice(readableIdx + "---READABLE---".length).trim() || raw : raw);
12
27
  const title = buildSynthesisTitle(msg.round);
13
- return (_jsx("box", { flexDirection: "column", marginBottom: 1, children: _jsxs("box", { borderStyle: "double", borderColor: dark.councilSynthesisBorder, flexDirection: "column", paddingLeft: 1, paddingRight: 1, children: [_jsx("text", { fg: dark.councilSynthesisBorder, attributes: 1, children: title }), _jsx("text", { fg: dark.text, children: bodyText })] }) }));
28
+ return (_jsxs("box", { flexDirection: "column", marginBottom: 1, border: ["left"], borderColor: t.councilSynthesisBorder, paddingLeft: 2, children: [_jsx("text", { fg: t.councilSynthesisBorder, attributes: 1, children: title }), _jsx("text", { fg: t.text, children: bodyText })] }));
14
29
  }
15
30
  //# sourceMappingURL=council-synthesis-banner.js.map
@@ -14,14 +14,18 @@ import { Semantic } from "@muonroi/agent-harness-opentui";
14
14
  const MAX_CARD_COLS = 100;
15
15
  const FALLBACK_THRESHOLD = 70;
16
16
  const REASON_LABELS = {
17
- no_recipe: "No verify recipe detected",
18
- zero_coverage: "Zero test coverage detected",
19
- budget_exhausted: "Token budget exhausted",
17
+ no_recipe: "No verification recipe found",
18
+ zero_coverage: "No test coverage found",
19
+ budget_exhausted: "Token budget used up",
20
+ sprint_failed: "Sprint failed",
20
21
  };
21
22
  export function HaltRecoveryCard({ halt, selectedIndex, terminalCols, theme }) {
22
23
  const fallback = terminalCols < FALLBACK_THRESHOLD;
23
24
  const width = fallback ? terminalCols : Math.min(terminalCols - 2, MAX_CARD_COLS);
24
- const title = `Halted ${REASON_LABELS[halt.reason] ?? halt.reason}`;
25
- return (_jsx(Semantic, { id: "ideal-halt-card", role: "dialog", name: "Recovery options", isModal: true, children: _jsx("box", { flexDirection: "column", marginBottom: 1, children: _jsxs("box", { width: width, borderStyle: "single", borderColor: theme.haltCardBorder, flexDirection: "column", paddingLeft: 1, paddingRight: 1, children: [_jsx("text", { fg: theme.haltCardTitle, attributes: 1, children: title }), halt.detail && (_jsx("text", { fg: theme.haltCardDetail, marginTop: 1, children: halt.detail })), _jsx("box", { flexDirection: "column", marginTop: 1, children: halt.recovery_options.map((opt, i) => (_jsxs(Semantic, { id: `halt-option-${opt.id}`, role: "listitem", name: opt.label, selected: i === selectedIndex || undefined, children: [_jsx("box", { flexDirection: "row", marginBottom: 0, children: _jsxs("text", { fg: i === selectedIndex ? theme.haltCardOptionSelected : theme.haltCardOptionDefault, children: [i === selectedIndex ? "▶ " : " ", opt.label] }) }), _jsx("box", { flexDirection: "row", marginLeft: 2, children: _jsx("text", { fg: theme.haltCardOptionDesc, children: opt.description }) })] }, opt.id))) }), _jsx("text", { fg: theme.haltCardHint, marginTop: 1, children: "\u2191\u2193 navigate \u00B7 Enter select \u00B7 Esc dismiss" })] }) }) }));
25
+ // A a sprint break titles with the failing sprint number ("Sprint 3 failed").
26
+ const title = halt.reason === "sprint_failed" && typeof halt.sprintN === "number"
27
+ ? `Halted — Sprint ${halt.sprintN} failed`
28
+ : `Halted — ${REASON_LABELS[halt.reason] ?? halt.reason}`;
29
+ return (_jsx(Semantic, { id: "ideal-halt-card", role: "dialog", name: "Recovery options", isModal: true, children: _jsx("box", { flexDirection: "column", marginBottom: 1, children: _jsxs("box", { width: width, borderStyle: "single", borderColor: theme.haltCardBorder, flexDirection: "column", paddingLeft: 1, paddingRight: 1, children: [_jsx("text", { fg: theme.haltCardTitle, attributes: 1, children: title }), halt.detail && (_jsx("text", { fg: theme.haltCardDetail, marginTop: 1, children: halt.detail })), _jsx("box", { flexDirection: "column", marginTop: 1, children: halt.recovery_options.map((opt, i) => (_jsxs(Semantic, { id: `halt-option-${opt.id}`, role: "listitem", name: opt.label, selected: i === selectedIndex || undefined, children: [_jsx("box", { flexDirection: "row", marginBottom: 0, children: _jsxs("text", { fg: i === selectedIndex ? theme.haltCardOptionSelected : theme.haltCardOptionDefault, children: [i === selectedIndex ? "▶ " : " ", opt.label] }) }), _jsx("box", { flexDirection: "row", marginLeft: 2, children: _jsx("text", { fg: theme.haltCardOptionDesc, children: opt.description }) })] }, opt.id))) }), _jsx("text", { fg: theme.haltCardHint, marginTop: 1, children: "\u2191/\u2193 to browse \u00B7 Enter to select \u00B7 Esc to dismiss" })] }) }) }));
26
30
  }
27
31
  //# sourceMappingURL=halt-recovery-card.js.map
@@ -0,0 +1,11 @@
1
+ export interface JumpToLatestPillProps {
2
+ /** Number of new appends suppressed since the user scrolled up. */
3
+ newSinceLock: number;
4
+ }
5
+ /**
6
+ * Scroll-lock affordance (MUONROI_SCROLL_LOCK): shown pinned to the bottom of
7
+ * the transcript when the user has scrolled up while new content is arriving.
8
+ * Pressing End re-pins to the live tail. Glyph-free (ASCII only) so it renders
9
+ * on every terminal — the debate pill work proved non-`● ✓` glyphs are unsafe.
10
+ */
11
+ export declare function JumpToLatestPill({ newSinceLock }: JumpToLatestPillProps): import("react").ReactNode;
@@ -0,0 +1,14 @@
1
+ import { jsx as _jsx } from "@opentui/react/jsx-runtime";
2
+ import { Semantic } from "@muonroi/agent-harness-opentui";
3
+ import { dark } from "../theme.js";
4
+ /**
5
+ * Scroll-lock affordance (MUONROI_SCROLL_LOCK): shown pinned to the bottom of
6
+ * the transcript when the user has scrolled up while new content is arriving.
7
+ * Pressing End re-pins to the live tail. Glyph-free (ASCII only) so it renders
8
+ * on every terminal — the debate pill work proved non-`● ✓` glyphs are unsafe.
9
+ */
10
+ export function JumpToLatestPill({ newSinceLock }) {
11
+ const label = newSinceLock > 0 ? `${newSinceLock} new below - press End to jump` : "press End to jump to latest";
12
+ return (_jsx(Semantic, { id: "jump-to-latest", role: "region", props: { newSinceLock }, children: _jsx("box", { flexDirection: "row", alignSelf: "center", paddingLeft: 1, paddingRight: 1, backgroundColor: dark.accent, children: _jsx("text", { fg: "#ffffff", attributes: 1, children: label }) }) }));
13
+ }
14
+ //# sourceMappingURL=jump-to-latest-pill.js.map
@@ -1,5 +1,20 @@
1
1
  import type { ChatEntry } from "../../types/index.js";
2
2
  import type { Theme } from "../theme.js";
3
+ /**
4
+ * Index of the newest entry that renders a `ctrl+e` affordance, or -1.
5
+ *
6
+ * The TUI has ONE global ctrl+e, so it must resolve to a single target. Every
7
+ * component that prints "ctrl+e expand" must be represented here, otherwise the
8
+ * affordance lies: it tells the user a key works while nothing is listening.
9
+ * Mirrors the collapse conditions in AssistantMessageContent / UserMessageContent
10
+ * / ReasoningContent / ToolGroupView — keep the two in sync.
11
+ */
12
+ export declare function findLastCollapsibleIndex(messages: ChatEntry[]): number;
13
+ export declare function ReasoningContent({ content, t, expanded }: {
14
+ content: string;
15
+ t: Theme;
16
+ expanded: boolean;
17
+ }): import("react").ReactNode;
3
18
  export declare function AssistantMessageContent({ content, t, expanded, isFinal, }: {
4
19
  content: string;
5
20
  t: Theme;
@@ -28,6 +28,55 @@ const USER_MSG_COLLAPSED_LINES = 5;
28
28
  // to this many lines to stop the chat scroll wall and cut markdown re-render
29
29
  // cost. 8 fits comfortably on a short terminal and conveys the gist.
30
30
  const ASSISTANT_MSG_COLLAPSED_LINES = 8;
31
+ // Chain-of-thought is never the answer — it is the model talking to itself.
32
+ // Unlike the final assistant message (which must stay fully visible), reasoning
33
+ // collapses even on the final entry: once the turn is answered, a wall of
34
+ // "[Thought]" above the reply is pure noise. 3 lines keeps a gist visible.
35
+ const REASONING_COLLAPSED_LINES = 3;
36
+ /**
37
+ * Index of the newest entry that renders a `ctrl+e` affordance, or -1.
38
+ *
39
+ * The TUI has ONE global ctrl+e, so it must resolve to a single target. Every
40
+ * component that prints "ctrl+e expand" must be represented here, otherwise the
41
+ * affordance lies: it tells the user a key works while nothing is listening.
42
+ * Mirrors the collapse conditions in AssistantMessageContent / UserMessageContent
43
+ * / ReasoningContent / ToolGroupView — keep the two in sync.
44
+ */
45
+ export function findLastCollapsibleIndex(messages) {
46
+ let lastAssistantIdx = -1;
47
+ for (let i = messages.length - 1; i >= 0; i--) {
48
+ if (messages[i]?.type === "assistant") {
49
+ lastAssistantIdx = i;
50
+ break;
51
+ }
52
+ }
53
+ const lineCount = (s) => (s ? s.split("\n").length : 0);
54
+ for (let i = messages.length - 1; i >= 0; i--) {
55
+ const m = messages[i];
56
+ if (!m)
57
+ continue;
58
+ if (m.type === "user" && lineCount(m.content) > USER_MSG_COLLAPSED_LINES)
59
+ return i;
60
+ if (m.type === "assistant") {
61
+ if (lineCount(m.reasoning) > REASONING_COLLAPSED_LINES)
62
+ return i;
63
+ // The final assistant message never auto-collapses its body (F7), so it
64
+ // offers no body affordance to toggle.
65
+ if (i !== lastAssistantIdx && lineCount(m.content) > ASSISTANT_MSG_COLLAPSED_LINES)
66
+ return i;
67
+ }
68
+ if (m.type === "tool_group" && m.toolGroup?.state === "done" && (m.toolGroup?.items.length ?? 0) > 0)
69
+ return i;
70
+ }
71
+ return -1;
72
+ }
73
+ export function ReasoningContent({ content, t, expanded }) {
74
+ const lines = content.split("\n");
75
+ const isLong = lines.length > REASONING_COLLAPSED_LINES;
76
+ const body = !isLong || expanded ? content : lines.slice(0, REASONING_COLLAPSED_LINES).join("\n");
77
+ const hidden = lines.length - REASONING_COLLAPSED_LINES;
78
+ return (_jsxs("box", { paddingLeft: 0, marginBottom: 1, flexShrink: 0, flexDirection: "column", children: [_jsx("text", { fg: t.textMuted, children: "[Thought] Thought" }), _jsxs("box", { border: ["left"], borderColor: t.textMuted, paddingLeft: 2, marginTop: 1, flexDirection: "column", children: [_jsx(Markdown, { content: body, t: t }), isLong && (_jsxs("text", { fg: t.textDim, children: ["ctrl+e ", _jsx("span", { style: { fg: t.textMuted }, children: expanded ? "collapse" : `expand (${hidden} more lines)` })] }))] })] }));
79
+ }
31
80
  export function AssistantMessageContent({ content, t, expanded, isFinal, }) {
32
81
  // Strip stray model self-annotation macros (e.g. grok's trailing
33
82
  // `\confidence{85}`) that leak into the answer — not instructed in the prompt.
@@ -142,7 +191,7 @@ function MessageViewImpl({ entry, index, t, modeColor, expandedMessages, mcpRun,
142
191
  // ignore
143
192
  }
144
193
  }
145
- return (_jsxs("box", { paddingLeft: 3, marginTop: 1, flexShrink: 0, flexDirection: "column", children: [entry.sourceLabel ? _jsx("text", { fg: t.textMuted, children: entry.sourceLabel }) : null, entry.reasoning ? (_jsxs("box", { paddingLeft: 0, marginBottom: 1, flexShrink: 0, flexDirection: "column", children: [_jsx("text", { fg: t.textMuted, children: "[Thought] Thought" }), _jsx("box", { border: ["left"], borderColor: t.textMuted, paddingLeft: 2, marginTop: 1, flexDirection: "column", children: _jsx(Markdown, { content: entry.reasoning, t: t }) })] })) : null, fallbackSr ? (_jsx(StructuredResponseView, { t: t, sr: fallbackSr, modeColor: entry.modeColor || modeColor })) : (_jsx(AssistantMessageContent, { content: entry.content, t: t, expanded: expandedMessages?.has(index) ?? false, isFinal: isFinalAssistant === true }))] }));
194
+ return (_jsxs("box", { paddingLeft: 3, marginTop: 1, flexShrink: 0, flexDirection: "column", children: [entry.sourceLabel ? _jsx("text", { fg: t.textMuted, children: entry.sourceLabel }) : null, entry.reasoning ? (_jsx(ReasoningContent, { content: entry.reasoning, t: t, expanded: expandedMessages?.has(index) ?? false })) : null, fallbackSr ? (_jsx(StructuredResponseView, { t: t, sr: fallbackSr, modeColor: entry.modeColor || modeColor })) : (_jsx(AssistantMessageContent, { content: entry.content, t: t, expanded: expandedMessages?.has(index) ?? false, isFinal: isFinalAssistant === true }))] }));
146
195
  }
147
196
  case "tool_call":
148
197
  return (_jsx("box", { paddingLeft: 3, marginTop: 1, children: _jsxs("text", { children: [_jsx("span", { style: { fg: entry.modeColor || modeColor }, children: "▣ " }), _jsx("span", { style: { fg: t.textMuted }, children: entry.content.replace("▣ ", "") })] }) }));
@@ -1,7 +1,7 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "@opentui/react/jsx-runtime";
2
- import { Semantic } from "@muonroi/agent-harness-opentui";
1
+ import { jsx as _jsx, jsxs as _jsxs } from "@opentui/react/jsx-runtime";
3
2
  import { useEffect, useState } from "react";
4
3
  import { PROMPT_LOADING_FRAMES } from "../constants.js";
4
+ import { Menu, TextBox } from "../primitives/index.js";
5
5
  import { withAlpha } from "../utils/color.js";
6
6
  import { SuggestionOverlay } from "./SuggestionOverlay.js";
7
7
  import { ContextMeter } from "./session-header.js";
@@ -40,27 +40,29 @@ export function PromptModeLabel({ t, modeInfo, isProcessing, }) {
40
40
  export function PromptBox({ t, inputRef, isProcessing, showModelPicker, showSandboxPicker, showWalletPicker, showSlashMenu, showPlanQuestions, showApiKeyModal, blockPrompt, onSubmit, onPaste, pasteBlocks: _pasteBlocks, modeInfo, model, modelInfo, contextStats, placeholder, queuedCount, queuedMessages, typeahead, slashItems, slashSelectedIndex, slashInputIsMatched, composerValue, }) {
41
41
  const hasQueue = (queuedMessages?.length ?? 0) > 0;
42
42
  const showSuggestions = typeahead?.visible ?? false;
43
+ // Single source of truth for composer focus — mirrored to BOTH the OpenTUI
44
+ // textarea (`focused`) and the semantic node (via TextBox `focused`). Keeping
45
+ // one expression avoids the two drifting apart (the harness would otherwise
46
+ // report a focus state that disagrees with what the textarea actually has).
47
+ const composerFocused = !showModelPicker &&
48
+ !showSandboxPicker &&
49
+ !showWalletPicker &&
50
+ !showPlanQuestions &&
51
+ !showApiKeyModal &&
52
+ !blockPrompt;
43
53
  return (_jsxs("box", { backgroundColor: t.backgroundPanel, children: [_jsxs("box", { children: [hasQueue && (_jsxs("box", { paddingLeft: 2, paddingRight: 2, paddingTop: 1, paddingBottom: 1, backgroundColor: t.queueBg, flexShrink: 0, children: [queuedMessages.map((msg, i) => (
44
54
  // biome-ignore lint/suspicious/noArrayIndexKey: append-only queue of plain strings
45
- _jsxs("text", { fg: t.text, children: ["→ ", msg] }, i))), _jsx("box", { height: 1 }), _jsxs("text", { children: [_jsx("span", { style: { fg: t.primary }, children: "enter " }), _jsx("span", { style: { fg: t.textMuted }, children: "send now" }), _jsx("span", { style: { fg: t.textDim }, children: " · " }), _jsx("span", { style: { fg: t.primary }, children: "↑ " }), _jsx("span", { style: { fg: t.textMuted }, children: "edit" }), _jsx("span", { style: { fg: t.textDim }, children: " · " }), _jsx("span", { style: { fg: t.primary }, children: "esc " }), _jsx("span", { style: { fg: t.textMuted }, children: "cancel" })] })] })), showSlashMenu && slashItems && (_jsx(Semantic, { id: "slash-menu", role: "menu", isModal: true, name: "Slash commands", children: _jsx(SlashInlineMenu, { t: t, items: slashItems, selectedIndex: slashSelectedIndex ?? 0 }) })), showSuggestions && typeahead && (_jsx(SuggestionOverlay, { t: t, suggestions: typeahead.suggestions, selectedIndex: typeahead.selectedIndex })), _jsxs("box", { paddingLeft: 2, paddingRight: 2, paddingTop: 1, paddingBottom: 1, backgroundColor: t.backgroundElement, flexDirection: "row", gap: 2, alignItems: "flex-start", flexShrink: 0, children: [_jsx(PromptModeLabel, { t: t, modeInfo: modeInfo, isProcessing: isProcessing }), _jsx("box", { flexGrow: 1, children: _jsx(Semantic, { id: "composer", role: "textbox",
55
+ _jsxs("text", { fg: t.text, children: ["→ ", msg] }, i))), _jsx("box", { height: 1 }), _jsxs("text", { children: [_jsx("span", { style: { fg: t.primary }, children: "enter " }), _jsx("span", { style: { fg: t.textMuted }, children: "send now" }), _jsx("span", { style: { fg: t.textDim }, children: " · " }), _jsx("span", { style: { fg: t.primary }, children: "↑ " }), _jsx("span", { style: { fg: t.textMuted }, children: "edit" }), _jsx("span", { style: { fg: t.textDim }, children: " · " }), _jsx("span", { style: { fg: t.primary }, children: "esc " }), _jsx("span", { style: { fg: t.textMuted }, children: "cancel" })] })] })), showSlashMenu && slashItems && (_jsx(Menu, { id: "slash-menu", name: "Slash commands", children: _jsx(SlashInlineMenu, { t: t, items: slashItems, selectedIndex: slashSelectedIndex ?? 0 }) })), showSuggestions && typeahead && (_jsx(SuggestionOverlay, { t: t, suggestions: typeahead.suggestions, selectedIndex: typeahead.selectedIndex })), _jsxs("box", { paddingLeft: 2, paddingRight: 2, paddingTop: 1, paddingBottom: 1, backgroundColor: t.backgroundElement, flexDirection: "row", gap: 2, alignItems: "flex-start", flexShrink: 0, children: [_jsx(PromptModeLabel, { t: t, modeInfo: modeInfo, isProcessing: isProcessing }), _jsx("box", { flexGrow: 1, children: _jsx(TextBox, { id: "composer",
46
56
  // Mirror current composer text so external harness drivers
47
57
  // can read back what the user typed. Prefer the textarea's
48
58
  // actual plainText (ground truth) over composerValue (derived
49
59
  // from slashSearchQuery). This makes post-Tab state visible
50
60
  // even while the slash menu is technically still open — was
51
61
  // hiding the trailing space inserted by Tab autocomplete.
52
- value: inputRef.current?.plainText ?? composerValue ?? "", focus: !showModelPicker &&
53
- !showSandboxPicker &&
54
- !showWalletPicker &&
55
- !showPlanQuestions &&
56
- !showApiKeyModal &&
57
- !blockPrompt
58
- ? true
59
- : undefined, children: _jsx("textarea", { ref: inputRef, focused: !showModelPicker &&
60
- !showSandboxPicker &&
61
- !showWalletPicker &&
62
- !showPlanQuestions &&
63
- !showApiKeyModal &&
64
- !blockPrompt, placeholder: isProcessing ? "Queue a follow-up... (esc to interrupt)" : placeholder || "Message muonroi-cli...", textColor: slashInputIsMatched ? "#3b82f6" : t.text, backgroundColor: t.backgroundElement, placeholderColor: t.textMuted, minHeight: 1, maxHeight: 10, wrapMode: "word", keyBindings: TEXTAREA_KEYBINDINGS, onSubmit: onSubmit, onPaste: onPaste }) }) })] })] }), _jsxs("box", { flexDirection: "row", justifyContent: "space-between", alignItems: "center", paddingLeft: 2, paddingRight: 2, height: 1, flexShrink: 0, children: [_jsxs("box", { flexDirection: "row", gap: 1, alignItems: "center", height: 1, children: [_jsx("text", { fg: t.text, children: modelInfo?.name || model }), contextStats ? _jsx(ContextMeter, { t: t, stats: contextStats }) : null] }), _jsx("box", { flexDirection: "row", gap: 1, alignItems: "center", height: 1, children: isProcessing ? (_jsxs("box", { flexDirection: "row", gap: 1, children: [_jsxs("text", { fg: t.text, children: ["enter ", _jsx("span", { style: { fg: t.textMuted }, children: "queue" })] }), _jsxs("text", { fg: t.text, children: ["esc ", _jsx("span", { style: { fg: t.textMuted }, children: (queuedCount ?? 0) > 0 ? "clear queue" : "interrupt" })] })] })) : showSlashMenu ? (_jsxs("box", { flexDirection: "row", gap: 1, children: [_jsxs("text", { fg: t.text, children: ["↑↓ ", _jsx("span", { style: { fg: t.textMuted }, children: "navigate" })] }), _jsxs("text", { fg: t.text, children: ["enter ", _jsx("span", { style: { fg: t.textMuted }, children: "select" })] }), _jsxs("text", { fg: t.text, children: ["esc ", _jsx("span", { style: { fg: t.textMuted }, children: "dismiss" })] })] })) : showSuggestions ? (_jsxs("box", { flexDirection: "row", gap: 1, children: [_jsxs("text", { fg: t.text, children: ["tab ", _jsx("span", { style: { fg: t.textMuted }, children: "accept" })] }), _jsxs("text", { fg: t.text, children: ["↑↓ ", _jsx("span", { style: { fg: t.textMuted }, children: "navigate" })] }), _jsxs("text", { fg: t.text, children: ["esc ", _jsx("span", { style: { fg: t.textMuted }, children: "dismiss" })] })] })) : (_jsxs(_Fragment, { children: [_jsxs("text", { fg: t.text, children: ["@ ", _jsx("span", { style: { fg: t.textMuted }, children: "files" })] }), _jsxs("text", { fg: t.text, children: ["shift+enter ", _jsx("span", { style: { fg: t.textMuted }, children: "new line" })] }), _jsxs("text", { fg: t.text, children: ["tab ", _jsx("span", { style: { fg: t.textMuted }, children: "modes" })] })] })) })] })] }));
62
+ value: inputRef.current?.plainText ?? composerValue ?? "", focused: composerFocused, children: _jsx("textarea", { ref: inputRef, focused: composerFocused, placeholder: isProcessing ? "Queue a follow-up... (esc to interrupt)" : placeholder || "Message muonroi-cli...", textColor: slashInputIsMatched ? "#3b82f6" : t.text, backgroundColor: t.backgroundElement, placeholderColor: t.textMuted, minHeight: 1, maxHeight: 10, wrapMode: "word", keyBindings: TEXTAREA_KEYBINDINGS, onSubmit: onSubmit, onPaste: onPaste }) }) })] })] }), _jsxs("box", { flexDirection: "row", justifyContent: "space-between", alignItems: "center", paddingLeft: 2, paddingRight: 2, height: 1, flexShrink: 0, children: [_jsxs("box", { flexDirection: "row", gap: 1, alignItems: "center", height: 1, children: [_jsx("text", { fg: t.text, children: modelInfo?.name || model }), contextStats ? _jsx(ContextMeter, { t: t, stats: contextStats }) : null] }), _jsx("box", { flexDirection: "row", gap: 1, alignItems: "center", height: 1, children: isProcessing ? (_jsxs("box", { flexDirection: "row", gap: 1, children: [_jsxs("text", { fg: t.text, children: ["enter ", _jsx("span", { style: { fg: t.textMuted }, children: "queue" })] }), _jsxs("text", { fg: t.text, children: ["esc ", _jsx("span", { style: { fg: t.textMuted }, children: (queuedCount ?? 0) > 0 ? "clear queue" : "interrupt" })] })] })) : showSlashMenu ? (_jsxs("box", { flexDirection: "row", gap: 1, children: [_jsxs("text", { fg: t.text, children: ["↑↓ ", _jsx("span", { style: { fg: t.textMuted }, children: "navigate" })] }), _jsxs("text", { fg: t.text, children: ["enter ", _jsx("span", { style: { fg: t.textMuted }, children: "select" })] }), _jsxs("text", { fg: t.text, children: ["esc ", _jsx("span", { style: { fg: t.textMuted }, children: "dismiss" })] })] })) : showSuggestions ? (_jsxs("box", { flexDirection: "row", gap: 1, children: [_jsxs("text", { fg: t.text, children: ["tab ", _jsx("span", { style: { fg: t.textMuted }, children: "accept" })] }), _jsxs("text", { fg: t.text, children: ["↑↓ ", _jsx("span", { style: { fg: t.textMuted }, children: "navigate" })] }), _jsxs("text", { fg: t.text, children: ["esc ", _jsx("span", { style: { fg: t.textMuted }, children: "dismiss" })] })] })) : (
63
+ // Wrap in a gap'd row like the other three hint branches — a bare
64
+ // fragment let the three hints run together ("@ filesshift+enter new
65
+ // linetab modes"); the inner box restores the 1-col separators.
66
+ _jsxs("box", { flexDirection: "row", gap: 1, children: [_jsxs("text", { fg: t.text, children: ["@ ", _jsx("span", { style: { fg: t.textMuted }, children: "files" })] }), _jsxs("text", { fg: t.text, children: ["shift+enter ", _jsx("span", { style: { fg: t.textMuted }, children: "new line" })] }), _jsxs("text", { fg: t.text, children: ["tab ", _jsx("span", { style: { fg: t.textMuted }, children: "modes" })] })] })) })] })] }));
65
67
  }
66
68
  //# sourceMappingURL=prompt-box.js.map
@@ -0,0 +1,14 @@
1
+ import type { SessionChainNode } from "../../storage/transcript.js";
2
+ /**
3
+ * Rail "Sessions" block: the session tree this TUI hosts — the root
4
+ * conversation plus every rotation / sub-agent descendant. The children's
5
+ * message content is already merged into the transcript on resume; this makes
6
+ * the multi-session structure VISIBLE (which session produced what, how many
7
+ * messages, whether it is the current one) instead of a flat anonymous timeline.
8
+ *
9
+ * Renders nothing extra when the tree is a single conversation (no sub-sessions)
10
+ * — keeps a lean rail for the common single-session case.
11
+ */
12
+ export declare function SessionTreeCard({ nodes }: {
13
+ nodes: SessionChainNode[];
14
+ }): import("react").ReactNode;
@@ -0,0 +1,46 @@
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
+ /** Short kind badge for the rail — keeps rows narrow in a ~34-col panel. */
5
+ function kindBadge(kind) {
6
+ switch (kind) {
7
+ case "subagent":
8
+ return "sub";
9
+ case "rotation":
10
+ return "rot";
11
+ case "conversation":
12
+ return "conv";
13
+ default:
14
+ return "·";
15
+ }
16
+ }
17
+ /** Trim a model id to its last path segment so "deepseek/deepseek-v4-flash"
18
+ * reads as "deepseek-v4-flash" in the narrow rail. */
19
+ function shortModel(model) {
20
+ if (!model)
21
+ return "—";
22
+ const seg = model.includes("/") ? model.slice(model.lastIndexOf("/") + 1) : model;
23
+ return seg.length > 16 ? `${seg.slice(0, 15)}…` : seg;
24
+ }
25
+ /**
26
+ * Rail "Sessions" block: the session tree this TUI hosts — the root
27
+ * conversation plus every rotation / sub-agent descendant. The children's
28
+ * message content is already merged into the transcript on resume; this makes
29
+ * the multi-session structure VISIBLE (which session produced what, how many
30
+ * messages, whether it is the current one) instead of a flat anonymous timeline.
31
+ *
32
+ * Renders nothing extra when the tree is a single conversation (no sub-sessions)
33
+ * — keeps a lean rail for the common single-session case.
34
+ */
35
+ export function SessionTreeCard({ nodes }) {
36
+ if (nodes.length <= 1)
37
+ return null;
38
+ return (_jsx(Semantic, { id: "session-tree", role: "listbox", name: "Sessions", props: { count: nodes.length, ids: nodes.map((n) => n.id.slice(0, 8)).join(",") }, children: _jsxs("box", { flexDirection: "column", flexShrink: 0, paddingTop: 1, children: [_jsx("text", { fg: dark.textMuted, attributes: 1, children: `Sessions (${nodes.length})` }), nodes.map((n) => {
39
+ const indent = " ".repeat(Math.min(n.depth, 3));
40
+ const marker = n.isCurrent ? "●" : n.depth > 0 ? "↳" : "○";
41
+ const badge = kindBadge(n.kind);
42
+ const done = n.status && n.status !== "active";
43
+ return (_jsx(Semantic, { id: `session-node-${n.id}`, role: "listitem", name: `${badge} ${n.id.slice(0, 8)}`, value: `${n.messageCount} msg`, selected: n.isCurrent ? true : undefined, props: { kind: n.kind ?? "", status: n.status ?? "", messageCount: n.messageCount, depth: n.depth }, children: _jsx("box", { flexDirection: "column", children: _jsxs("text", { children: [_jsx("span", { style: { fg: n.isCurrent ? dark.selected : dark.textMuted }, children: `${indent}${marker} ` }), _jsx("span", { style: { fg: n.isCurrent ? dark.selected : dark.text }, children: `${badge} ` }), _jsx("span", { style: { fg: dark.textMuted }, children: `${n.id.slice(0, 8)} ${shortModel(n.model)} ` }), _jsx("span", { style: { fg: dark.text }, children: `${n.messageCount} msg` }), done ? _jsx("span", { style: { fg: dark.textDim }, children: ` ${n.status}` }) : null] }) }) }, n.id));
44
+ })] }) }));
45
+ }
46
+ //# sourceMappingURL=session-tree-card.js.map
@@ -1,5 +1,17 @@
1
1
  import type { SlashMenuItem } from "../slash/menu-items.js";
2
2
  import type { Theme } from "../theme.js";
3
+ /**
4
+ * Compute the scrolling viewport for the slash dropdown so the highlighted row
5
+ * stays visible when the filtered list exceeds the window. Pure + exported so
6
+ * the scroll behavior is unit-testable without a live TUI (the api-key modal
7
+ * blocks a clean greenfield harness drive of the menu).
8
+ */
9
+ export declare function computeSlashMenuWindow(total: number, selectedIndex: number, maxVisible?: number): {
10
+ start: number;
11
+ end: number;
12
+ hiddenAbove: number;
13
+ hiddenBelow: number;
14
+ };
3
15
  export declare function SlashInlineMenu({ t, items, selectedIndex, }: {
4
16
  t: Theme;
5
17
  items: SlashMenuItem[];
@@ -1,14 +1,35 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "@opentui/react/jsx-runtime";
2
2
  import { Semantic } from "@muonroi/agent-harness-opentui";
3
3
  const SLASH_MENU_MAX_VISIBLE = 8;
4
+ /**
5
+ * Compute the scrolling viewport for the slash dropdown so the highlighted row
6
+ * stays visible when the filtered list exceeds the window. Pure + exported so
7
+ * the scroll behavior is unit-testable without a live TUI (the api-key modal
8
+ * blocks a clean greenfield harness drive of the menu).
9
+ */
10
+ export function computeSlashMenuWindow(total, selectedIndex, maxVisible = SLASH_MENU_MAX_VISIBLE) {
11
+ if (total <= 0)
12
+ return { start: 0, end: 0, hiddenAbove: 0, hiddenBelow: 0 };
13
+ const clamped = Math.min(Math.max(0, selectedIndex), total - 1);
14
+ const start = total <= maxVisible ? 0 : Math.min(Math.max(0, clamped - maxVisible + 1), total - maxVisible);
15
+ const end = Math.min(start + maxVisible, total);
16
+ return { start, end, hiddenAbove: start, hiddenBelow: total - end };
17
+ }
4
18
  export function SlashInlineMenu({ t, items, selectedIndex, }) {
5
- const visible = items.slice(0, SLASH_MENU_MAX_VISIBLE);
6
- if (visible.length === 0) {
19
+ if (items.length === 0) {
7
20
  return (_jsx("box", { paddingLeft: 2, paddingRight: 2, paddingTop: 1, flexShrink: 0, flexDirection: "column", children: _jsx("box", { height: 1, paddingLeft: 1, children: _jsx("text", { fg: t.textMuted, children: "No commands match" }) }) }));
8
21
  }
9
- return (_jsxs("box", { paddingLeft: 2, paddingRight: 2, paddingTop: 1, flexShrink: 0, flexDirection: "column", children: [visible.map((item, i) => {
10
- const isSelected = i === selectedIndex;
22
+ // Scrolling viewport: keep the highlighted row in view when the filtered list
23
+ // exceeds the visible window. Without this the window was pinned to
24
+ // items.slice(0,8) and pressing Down past index 7 moved the selection
25
+ // off-screen — the list "wouldn't continue past the initial suggestions".
26
+ const clampedSelected = Math.min(Math.max(0, selectedIndex), items.length - 1);
27
+ const { start: windowStart, hiddenAbove, hiddenBelow } = computeSlashMenuWindow(items.length, clampedSelected);
28
+ const visible = items.slice(windowStart, windowStart + SLASH_MENU_MAX_VISIBLE);
29
+ return (_jsxs("box", { paddingLeft: 2, paddingRight: 2, paddingTop: 1, flexShrink: 0, flexDirection: "column", children: [hiddenAbove > 0 && _jsx("text", { fg: t.textDim, children: ` ▲ ${hiddenAbove} more` }), visible.map((item, i) => {
30
+ const absoluteIndex = windowStart + i;
31
+ const isSelected = absoluteIndex === clampedSelected;
11
32
  return (_jsx(Semantic, { id: `slash-item-${item.id}`, role: "listitem", name: `/${item.label}`, value: item.description, selected: isSelected ? true : undefined, children: _jsxs("box", { height: 1, backgroundColor: isSelected ? t.selectedBg : undefined, flexDirection: "row", justifyContent: "space-between", paddingLeft: 1, paddingRight: 1, children: [_jsxs("text", { fg: isSelected ? t.selected : t.text, children: ["/", item.label] }), _jsx("text", { fg: t.textMuted, children: item.description })] }) }, item.id));
12
- }), items.length > SLASH_MENU_MAX_VISIBLE && (_jsx("text", { fg: t.textDim, children: ` +${items.length - SLASH_MENU_MAX_VISIBLE} more` }))] }));
33
+ }), hiddenBelow > 0 && _jsx("text", { fg: t.textDim, children: ` ▼ ${hiddenBelow} more` })] }));
13
34
  }
14
35
  //# sourceMappingURL=slash-inline-menu.js.map
@@ -19,14 +19,27 @@
19
19
  import type { TaskListItem, TaskListSnapshot } from "../../types/index.js";
20
20
  import type { Theme } from "../theme.js";
21
21
  declare function sortItems(items: ReadonlyArray<TaskListItem>): TaskListItem[];
22
+ /**
23
+ * One-line summary used by the collapsed panel. Kept pure + exported so it can be
24
+ * unit-tested without rendering OpenTUI. Mirrors the expanded footer's bucket
25
+ * wording so the two views read consistently.
26
+ */
27
+ declare function buildCollapsedLine(snapshot: TaskListSnapshot): string;
22
28
  export interface TaskListPanelProps {
23
29
  snapshot: TaskListSnapshot;
24
30
  t: Theme;
25
31
  expanded: boolean;
32
+ /**
33
+ * Render a single summary line instead of the full panel. Set while a council
34
+ * debate is active so the todo band stops eating the debate scrollbox's height
35
+ * (~11 rows → 1). `ctrl+e` flips it back to the full panel for a peek.
36
+ */
37
+ collapsed?: boolean;
26
38
  }
27
- export declare function TaskListPanel({ snapshot, t, expanded }: TaskListPanelProps): import("react").ReactNode;
39
+ export declare function TaskListPanel({ snapshot, t, expanded, collapsed }: TaskListPanelProps): import("react").ReactNode;
28
40
  export declare const __TEST_ONLY__: {
29
41
  sortItems: typeof sortItems;
30
42
  MAX_VISIBLE: number;
43
+ buildCollapsedLine: typeof buildCollapsedLine;
31
44
  };
32
45
  export {};
@@ -54,9 +54,29 @@ function ItemRow({ item, t }) {
54
54
  }
55
55
  return (_jsx(Semantic, { id: `task-${item.id}`, role: "listitem", name: label, state: item.status, children: _jsx("box", { width: "100%", children: _jsxs("text", { fg: textColor, children: [_jsx("span", { style: { fg: glyphColor }, children: `${glyph} ` }), trunc(label, 70)] }) }) }));
56
56
  }
57
- export function TaskListPanel({ snapshot, t, expanded }) {
57
+ /**
58
+ * One-line summary used by the collapsed panel. Kept pure + exported so it can be
59
+ * unit-tested without rendering OpenTUI. Mirrors the expanded footer's bucket
60
+ * wording so the two views read consistently.
61
+ */
62
+ function buildCollapsedLine(snapshot) {
63
+ const { completed, inProgress, pending } = snapshot.counts;
64
+ const parts = [];
65
+ if (completed > 0)
66
+ parts.push(`${completed} completed`);
67
+ if (inProgress > 0)
68
+ parts.push(`${inProgress} in progress`);
69
+ if (pending > 0)
70
+ parts.push(`${pending} queued`);
71
+ const body = parts.length > 0 ? parts.join(" · ") : "0 todos";
72
+ return `▸ Todos · ${body} (ctrl+e)`;
73
+ }
74
+ export function TaskListPanel({ snapshot, t, expanded, collapsed = false }) {
58
75
  if (snapshot.items.length === 0)
59
76
  return null;
77
+ if (collapsed) {
78
+ return (_jsx(Semantic, { id: "task-list", role: "listbox", name: "Todos", state: "collapsed", children: _jsx("box", { paddingLeft: 2, paddingRight: 2, marginBottom: 1, children: _jsx("text", { fg: t.textMuted, children: buildCollapsedLine(snapshot) }) }) }));
79
+ }
60
80
  const sorted = sortItems(snapshot.items);
61
81
  const overflow = !expanded && sorted.length > MAX_VISIBLE ? sorted.length - MAX_VISIBLE : 0;
62
82
  const visible = overflow > 0 ? sorted.slice(0, MAX_VISIBLE) : sorted;
@@ -71,5 +91,5 @@ export function TaskListPanel({ snapshot, t, expanded }) {
71
91
  const footer = footerParts.length > 0 ? footerParts.join(" · ") : "0 todos";
72
92
  return (_jsx(Semantic, { id: "task-list", role: "listbox", name: "Todos", children: _jsxs("box", { border: true, borderColor: t.border, paddingLeft: 2, paddingRight: 2, paddingTop: 0, paddingBottom: 0, marginBottom: 1, flexDirection: "column", children: [_jsx("box", { paddingBottom: 1, children: _jsx("text", { fg: t.textMuted, children: _jsx("b", { children: "Todos" }) }) }), _jsx("box", { flexDirection: "column", children: visible.map((it) => (_jsx(ItemRow, { item: it, t: t }, it.id))) }), overflow > 0 && (_jsx("box", { marginTop: 1, children: _jsx("text", { fg: t.textMuted, children: `… +${overflow} more (ctrl+e to expand)` }) })), _jsx("box", { marginTop: 1, paddingTop: 1, border: ["top"], borderColor: t.border, children: _jsx("text", { fg: t.textDim, children: footer }) })] }) }));
73
93
  }
74
- export const __TEST_ONLY__ = { sortItems, MAX_VISIBLE };
94
+ export const __TEST_ONLY__ = { sortItems, MAX_VISIBLE, buildCollapsedLine };
75
95
  //# sourceMappingURL=task-list-panel.js.map
@@ -3,16 +3,28 @@
3
3
  *
4
4
  * Claude-Code-style "tool streak" panel — replaces the previous one-line-per-
5
5
  * tool render. Lifecycle:
6
- * - active → header "● <Verb>… (N tools · Ms)" + indented item list
7
- * - done → collapsed "● Done (N tool uses · Ms) ctrl+e to expand"
6
+ * - active → header "● Reading 2 files… (N tools · Ms)" + indented item list
7
+ * - done → collapsed "● Read 2 files, ran 1 shell command ctrl+e to expand"
8
8
  * - failed → always-expanded header + items, error item flagged red
9
9
  *
10
+ * The header names the work per CATEGORY (see utils/tool-summary.ts) rather
11
+ * than saying "Done": once the group collapses that line is all the user has,
12
+ * so it has to carry the meaning. Items add the detail a glance needs — the
13
+ * full shell command for bash, "Wrote N lines to <path>" before a write diff.
14
+ *
10
15
  * The active group lives at the tail of the message stream as a regular
11
16
  * ChatEntry of type "tool_group"; closing the streak (assistant text arrives
12
17
  * or stream ends) flips its state to done/failed in place.
13
18
  */
14
- import type { ChatEntry } from "../../types/index.js";
19
+ import type { ChatEntry, FileDiff, ToolCall } from "../../types/index.js";
15
20
  import type { Theme } from "../theme.js";
21
+ /** The command a bash item ran, split for multi-line display. Null when absent. */
22
+ export declare function bashCommandLines(tc: ToolCall): string[] | null;
23
+ /**
24
+ * One-line prose outcome for a write/edit, e.g. "Wrote 161 lines to a.ts" or
25
+ * "Edited a.ts (+12 -3)". Null when the tool isn't a file mutation.
26
+ */
27
+ export declare function writeOutcomeLine(toolName: string, diff: FileDiff): string | null;
16
28
  export interface ToolGroupViewProps {
17
29
  entry: ChatEntry;
18
30
  t: Theme;