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
@@ -4,17 +4,23 @@ import { jsx as _jsx, jsxs as _jsxs } from "@opentui/react/jsx-runtime";
4
4
  *
5
5
  * Claude-Code-style "tool streak" panel — replaces the previous one-line-per-
6
6
  * tool render. Lifecycle:
7
- * - active → header "● <Verb>… (N tools · Ms)" + indented item list
8
- * - done → collapsed "● Done (N tool uses · Ms) ctrl+e to expand"
7
+ * - active → header "● Reading 2 files… (N tools · Ms)" + indented item list
8
+ * - done → collapsed "● Read 2 files, ran 1 shell command ctrl+e to expand"
9
9
  * - failed → always-expanded header + items, error item flagged red
10
10
  *
11
+ * The header names the work per CATEGORY (see utils/tool-summary.ts) rather
12
+ * than saying "Done": once the group collapses that line is all the user has,
13
+ * so it has to carry the meaning. Items add the detail a glance needs — the
14
+ * full shell command for bash, "Wrote N lines to <path>" before a write diff.
15
+ *
11
16
  * The active group lives at the tail of the message stream as a regular
12
17
  * ChatEntry of type "tool_group"; closing the streak (assistant text arrives
13
18
  * or stream ends) flips its state to done/failed in place.
14
19
  */
15
20
  import { Semantic } from "@muonroi/agent-harness-opentui";
16
21
  import { trunc } from "../utils/text.js";
17
- import { dominantVerb, toolLabel } from "../utils/tools.js";
22
+ import { activeToolGroupHeader, doneToolGroupSummary } from "../utils/tool-summary.js";
23
+ import { toolLabel } from "../utils/tools.js";
18
24
  import { DiffView } from "./diff-view.js";
19
25
  // Tools whose result carries a FileDiff worth rendering inline under the item
20
26
  // line. Mirrors the per-tool branch in message-view.tsx so grouped edits show
@@ -33,6 +39,42 @@ function fmtElapsed(ms) {
33
39
  const remS = Math.floor(s % 60);
34
40
  return `${m}m ${remS.toString().padStart(2, "0")}s`;
35
41
  }
42
+ // Max command lines rendered inline for a bash item; the rest are elided so a
43
+ // 40-line heredoc can't take over the transcript.
44
+ const BASH_INLINE_LINES = 8;
45
+ /** The command a bash item ran, split for multi-line display. Null when absent. */
46
+ export function bashCommandLines(tc) {
47
+ let cmd;
48
+ try {
49
+ cmd = JSON.parse(tc.function.arguments)?.command;
50
+ }
51
+ catch (err) {
52
+ // Arguments stream in as partial JSON while the call is still assembling —
53
+ // an unparseable value here is expected, not an error worth surfacing.
54
+ return null;
55
+ }
56
+ if (typeof cmd !== "string" || !cmd.trim())
57
+ return null;
58
+ const lines = cmd.replace(/\r\n/g, "\n").split("\n");
59
+ if (lines.length <= BASH_INLINE_LINES)
60
+ return lines;
61
+ const hidden = lines.length - BASH_INLINE_LINES;
62
+ return [...lines.slice(0, BASH_INLINE_LINES), `… +${hidden} more line${hidden > 1 ? "s" : ""}`];
63
+ }
64
+ /**
65
+ * One-line prose outcome for a write/edit, e.g. "Wrote 161 lines to a.ts" or
66
+ * "Edited a.ts (+12 -3)". Null when the tool isn't a file mutation.
67
+ */
68
+ export function writeOutcomeLine(toolName, diff) {
69
+ if (toolName === "write_file") {
70
+ const n = diff.additions;
71
+ return `Wrote ${n} line${n === 1 ? "" : "s"} to ${diff.filePath}`;
72
+ }
73
+ if (toolName === "edit_file") {
74
+ return `Edited ${diff.filePath} (+${diff.additions} -${diff.removals})`;
75
+ }
76
+ return null;
77
+ }
36
78
  function itemGlyph(item) {
37
79
  if (item.failed)
38
80
  return "✗";
@@ -51,21 +93,23 @@ export function ToolGroupView({ entry, t, expanded, modeColor }) {
51
93
  const g = entry.toolGroup;
52
94
  if (!g)
53
95
  return null;
54
- const verb = dominantVerb(g.items.map((it) => it.toolCall.function.name));
96
+ const toolNames = g.items.map((it) => it.toolCall.function.name);
55
97
  const elapsed = (g.finishedAt ?? Date.now()) - g.startedAt;
56
98
  const errorCount = g.items.filter((it) => it.failed).length;
57
99
  const total = g.items.length;
58
100
  // Decide whether the items list is visible. Active and failed always show
59
101
  // items; done collapses unless user expanded with ctrl+e.
60
102
  const showItems = g.state === "active" || g.state === "failed" || expanded;
61
- // Header text mirrors Claude Code phrasing:
62
- // active: "Reading…"
63
- // done: "Done"
103
+ // Header names the actual work, counted per category:
104
+ // active: "Reading 2 files…"
105
+ // done: "Read 2 files, ran 1 shell command"
64
106
  // failed: "Failed (k errors)"
107
+ // A bare "Done" told the user nothing about what just happened; the recap is
108
+ // the only line left once the group collapses, so it carries the meaning.
65
109
  let headerVerb;
66
110
  let headerColor;
67
111
  if (g.state === "active") {
68
- headerVerb = `${verb}…`;
112
+ headerVerb = activeToolGroupHeader(toolNames);
69
113
  headerColor = entry.modeColor || modeColor || t.accent;
70
114
  }
71
115
  else if (g.state === "failed") {
@@ -73,10 +117,14 @@ export function ToolGroupView({ entry, t, expanded, modeColor }) {
73
117
  headerColor = t.diffRemovedFg;
74
118
  }
75
119
  else {
76
- headerVerb = "Done";
120
+ headerVerb = doneToolGroupSummary(toolNames);
77
121
  headerColor = t.diffAddedFg;
78
122
  }
79
- const stats = `${total} tool${total !== 1 ? "s" : ""} · ${fmtElapsed(elapsed)}`;
123
+ // A restored group's timestamps are write-time, not a measured span print
124
+ // the count only rather than a fabricated duration.
125
+ const stats = g.restored
126
+ ? `${total} tool${total !== 1 ? "s" : ""}`
127
+ : `${total} tool${total !== 1 ? "s" : ""} · ${fmtElapsed(elapsed)}`;
80
128
  // Items to render: active capped at ACTIVE_INLINE_LIMIT (overflow line);
81
129
  // expanded done/failed shows everything.
82
130
  const overflow = g.state === "active" && total > ACTIVE_INLINE_LIMIT ? total - ACTIVE_INLINE_LIMIT : 0;
@@ -85,7 +133,17 @@ export function ToolGroupView({ entry, t, expanded, modeColor }) {
85
133
  const label = trunc(toolLabel(it.toolCall), 90);
86
134
  const errSuffix = it.failed && it.result?.error ? ` — ${trunc(it.result.error.replace(/\s+/g, " "), 60)}` : "";
87
135
  const diff = !it.failed && DIFF_TOOLS.has(it.toolCall.function.name) ? it.result?.diff : undefined;
88
- return (_jsxs("box", { flexDirection: "column", children: [_jsxs("text", { children: [_jsx("span", { style: { fg: itemColor(it, t) }, children: `${itemGlyph(it)} ` }), _jsx("span", { style: { fg: t.textMuted }, children: label }), errSuffix && _jsx("span", { style: { fg: t.diffRemovedFg }, children: errSuffix })] }), diff && _jsx(DiffView, { t: t, diff: diff })] }, it.toolCall.id));
136
+ // A bash call's whole point is WHICH command ran; truncating it to
137
+ // one elided line hides that. Show every line, indented under the
138
+ // item, the way a shell transcript reads.
139
+ const bashLines = it.toolCall.function.name === "bash" ? bashCommandLines(it.toolCall) : null;
140
+ // Shell transcript shape: "$ <first line>" on the item line, any
141
+ // continuation lines aligned under it.
142
+ const headLine = bashLines ? `$ ${bashLines[0]}` : label;
143
+ const restLines = bashLines ? bashLines.slice(1) : [];
144
+ return (_jsxs("box", { flexDirection: "column", children: [_jsxs("text", { children: [_jsx("span", { style: { fg: itemColor(it, t) }, children: `${itemGlyph(it)} ` }), _jsx("span", { style: { fg: t.textMuted }, children: trunc(headLine, 100) }), errSuffix && _jsx("span", { style: { fg: t.diffRemovedFg }, children: errSuffix })] }), restLines.map((line, li) => (
145
+ // biome-ignore lint/suspicious/noArrayIndexKey: command lines are positional and immutable
146
+ _jsx("box", { paddingLeft: 2, children: _jsx("text", { fg: t.textMuted, children: trunc(line, 100) }) }, `${it.toolCall.id}-cmd-${li}`))), diff && writeOutcomeLine(it.toolCall.function.name, diff) && (_jsx("box", { paddingLeft: 2, children: _jsx("text", { fg: t.textMuted, children: writeOutcomeLine(it.toolCall.function.name, diff) }) })), diff && _jsx(DiffView, { t: t, diff: diff })] }, it.toolCall.id));
89
147
  })] })), g.state === "done" && !expanded && total > 0 && (_jsx("box", { paddingLeft: 2, children: _jsx("text", { fg: t.textDim, children: "ctrl+e to expand" }) }))] }) }));
90
148
  }
91
149
  //# sourceMappingURL=tool-group.js.map
@@ -1,3 +1,4 @@
1
+ import type { ResumeEntry } from "../../types/index.js";
1
2
  export interface ModalsLayerProps {
2
3
  agentRows: any;
3
4
  agentsEditorDraft: any;
@@ -10,7 +11,8 @@ export interface ModalsLayerProps {
10
11
  apiKeyError: any;
11
12
  apiKeyInputRef: any;
12
13
  apiKeyPrompt: any;
13
- bwSync: any;
14
+ oauthProviders: any;
15
+ oauthLogin: any;
14
16
  configuredProviders: any;
15
17
  connectModalIndex: any;
16
18
  defaultProvider: any;
@@ -50,7 +52,7 @@ export interface ModalsLayerProps {
50
52
  scheduleRows: any;
51
53
  scheduleSearchQuery: any;
52
54
  sessionPickerIndex: any;
53
- sessionPickerList: any;
55
+ sessionPickerList: ResumeEntry[];
54
56
  showAgentsEditor: any;
55
57
  showAgentsModal: any;
56
58
  showApiKeyModal: any;
@@ -12,7 +12,7 @@ import { UpdateModal } from "../modals/update-modal.js";
12
12
  import { WalletPickerModal } from "../modals/wallet-picker-modal.js";
13
13
  import { ScheduleBrowserModal } from "../schedule-modal.js";
14
14
  export function ModalsLayer(props) {
15
- const { agentRows, agentsEditorDraft, agentsEditorError, agentsEditorField, agentsEditorModelIndex, agentsEditorSyncKey, agentsModalIndex, agentsSearchQuery, apiKeyError, apiKeyInputRef, apiKeyPrompt, bwSync, configuredProviders, connectModalIndex, defaultProvider, disabledModels, disabledProviders, editingMcpId, editingSubagent, filteredModels, height, mcpArgsRef, mcpCommandRef, mcpCwdRef, mcpEditorDraft, mcpEditorError, mcpEditorField, mcpEditorSyncKey, mcpEnvRef, mcpHeadersRef, mcpLabelRef, mcpModalIndex, mcpRows, mcpSearchQuery, mcpUrlRef, model, modelPickerFocus, modelPickerIndex, modelSearchQuery, providerChipIndex, providersWithKey, reasoningEffortByModel, sandboxMode, sandboxSettings, sandboxSettingsEditBuffer, sandboxSettingsEditing, sandboxSettingsFocusIndex, scheduleModalIndex, scheduleRows, scheduleSearchQuery, sessionPickerIndex, sessionPickerList, showAgentsEditor, showAgentsModal, showApiKeyModal, showConnectModal, showMcpEditor, showMcpModal, showModelPicker, showSandboxPicker, showScheduleModal, showSessionPicker, showTelegramPairModal, showTelegramTokenModal, showUpdateModal, showWalletPicker, startupConfig, subagentInstructionRef, subagentNameRef, submitApiKey, submitMcpEditor, submitSubagentEditor, submitTelegramPair, submitTelegramToken, t, telegramPairError, telegramPairInputRef, telegramTokenError, telegramTokenInputRef, updateInfo, walletDisplayInfo, walletFocusIndex, walletSettings, width, } = props;
16
- return (_jsxs(_Fragment, { children: [showApiKeyModal && (_jsx(ApiKeyModal, { t: t, width: width, height: height, inputRef: apiKeyInputRef, error: apiKeyError, onSubmit: submitApiKey })), showUpdateModal && updateInfo && (_jsx(UpdateModal, { t: t, width: width, height: height, currentVersion: startupConfig.version, latestVersion: updateInfo.latestVersion })), showMcpModal && !showMcpEditor && (_jsx(McpBrowserModal, { t: t, width: width, height: height, selectedIndex: mcpModalIndex, searchQuery: mcpSearchQuery, rows: mcpRows })), showMcpEditor && (_jsx(McpEditorModal, { t: t, width: width, height: height, draft: mcpEditorDraft, focusedField: mcpEditorField, syncKey: mcpEditorSyncKey, error: mcpEditorError, title: editingMcpId ? "Edit MCP Server" : "Add MCP Server", labelRef: mcpLabelRef, urlRef: mcpUrlRef, headersRef: mcpHeadersRef, commandRef: mcpCommandRef, argsRef: mcpArgsRef, cwdRef: mcpCwdRef, envRef: mcpEnvRef, onSubmit: submitMcpEditor })), showScheduleModal && (_jsx(ScheduleBrowserModal, { t: t, width: width, height: height, selectedIndex: scheduleModalIndex, searchQuery: scheduleSearchQuery, rows: scheduleRows })), showAgentsModal && !showAgentsEditor && (_jsx(SubagentsBrowserModal, { t: t, width: width, height: height, selectedIndex: agentsModalIndex, searchQuery: agentsSearchQuery, rows: agentRows })), showAgentsEditor && (_jsx(SubagentEditorModal, { t: t, width: width, height: height, draft: agentsEditorDraft, focusedField: agentsEditorField, modelIndex: agentsEditorModelIndex, error: agentsEditorError, title: editingSubagent ? `Edit sub-agent: ${formatSubagentName(editingSubagent.name)}` : "Add sub-agent", nameRef: subagentNameRef, instructionRef: subagentInstructionRef, onSubmit: submitSubagentEditor, showRemoveHint: !!editingSubagent }, `subagent-editor-${agentsEditorSyncKey}`)), showModelPicker && (_jsx(ModelPickerModal, { t: t, currentModel: model, selectedIndex: modelPickerIndex, width: width, height: height, searchQuery: modelSearchQuery, filteredModels: filteredModels, reasoningEffortByModel: reasoningEffortByModel, configuredProviders: configuredProviders, disabledProviders: disabledProviders, disabledModels: disabledModels, defaultProvider: defaultProvider, focus: modelPickerFocus, providerChipIndex: providerChipIndex, providersWithKey: providersWithKey, apiKeyPrompt: apiKeyPrompt, bwSync: bwSync })), showSessionPicker && (_jsx(SessionPickerModal, { t: t, sessions: sessionPickerList, focusIndex: sessionPickerIndex, width: width, height: height })), showWalletPicker && (_jsx(WalletPickerModal, { t: t, settings: walletSettings, walletInfo: walletDisplayInfo, focusIndex: walletFocusIndex, width: width, height: height })), showSandboxPicker && (_jsx(SandboxPickerModal, { t: t, currentMode: sandboxMode, settings: sandboxSettings, focusIndex: sandboxSettingsFocusIndex, editing: sandboxSettingsEditing, editBuffer: sandboxSettingsEditBuffer, width: width, height: height })), showConnectModal && (_jsx(ConnectModal, { t: t, width: width, height: height, selectedIndex: connectModalIndex, channels: CONNECT_CHANNELS })), showTelegramTokenModal && (_jsx(TelegramTokenModal, { t: t, width: width, height: height, inputRef: telegramTokenInputRef, error: telegramTokenError, onSubmit: submitTelegramToken })), showTelegramPairModal && (_jsx(TelegramPairModal, { t: t, width: width, height: height, inputRef: telegramPairInputRef, error: telegramPairError, onSubmit: () => void submitTelegramPair() }))] }));
15
+ const { agentRows, agentsEditorDraft, agentsEditorError, agentsEditorField, agentsEditorModelIndex, agentsEditorSyncKey, agentsModalIndex, agentsSearchQuery, apiKeyError, apiKeyInputRef, apiKeyPrompt, oauthProviders, oauthLogin, configuredProviders, connectModalIndex, defaultProvider, disabledModels, disabledProviders, editingMcpId, editingSubagent, filteredModels, height, mcpArgsRef, mcpCommandRef, mcpCwdRef, mcpEditorDraft, mcpEditorError, mcpEditorField, mcpEditorSyncKey, mcpEnvRef, mcpHeadersRef, mcpLabelRef, mcpModalIndex, mcpRows, mcpSearchQuery, mcpUrlRef, model, modelPickerFocus, modelPickerIndex, modelSearchQuery, providerChipIndex, providersWithKey, reasoningEffortByModel, sandboxMode, sandboxSettings, sandboxSettingsEditBuffer, sandboxSettingsEditing, sandboxSettingsFocusIndex, scheduleModalIndex, scheduleRows, scheduleSearchQuery, sessionPickerIndex, sessionPickerList, showAgentsEditor, showAgentsModal, showApiKeyModal, showConnectModal, showMcpEditor, showMcpModal, showModelPicker, showSandboxPicker, showScheduleModal, showSessionPicker, showTelegramPairModal, showTelegramTokenModal, showUpdateModal, showWalletPicker, startupConfig, subagentInstructionRef, subagentNameRef, submitApiKey, submitMcpEditor, submitSubagentEditor, submitTelegramPair, submitTelegramToken, t, telegramPairError, telegramPairInputRef, telegramTokenError, telegramTokenInputRef, updateInfo, walletDisplayInfo, walletFocusIndex, walletSettings, width, } = props;
16
+ return (_jsxs(_Fragment, { children: [showApiKeyModal && (_jsx(ApiKeyModal, { t: t, width: width, height: height, inputRef: apiKeyInputRef, error: apiKeyError, onSubmit: submitApiKey })), showUpdateModal && updateInfo && (_jsx(UpdateModal, { t: t, width: width, height: height, currentVersion: startupConfig.version, latestVersion: updateInfo.latestVersion })), showMcpModal && !showMcpEditor && (_jsx(McpBrowserModal, { t: t, width: width, height: height, selectedIndex: mcpModalIndex, searchQuery: mcpSearchQuery, rows: mcpRows })), showMcpEditor && (_jsx(McpEditorModal, { t: t, width: width, height: height, draft: mcpEditorDraft, focusedField: mcpEditorField, syncKey: mcpEditorSyncKey, error: mcpEditorError, title: editingMcpId ? "Edit MCP Server" : "Add MCP Server", labelRef: mcpLabelRef, urlRef: mcpUrlRef, headersRef: mcpHeadersRef, commandRef: mcpCommandRef, argsRef: mcpArgsRef, cwdRef: mcpCwdRef, envRef: mcpEnvRef, onSubmit: submitMcpEditor })), showScheduleModal && (_jsx(ScheduleBrowserModal, { t: t, width: width, height: height, selectedIndex: scheduleModalIndex, searchQuery: scheduleSearchQuery, rows: scheduleRows })), showAgentsModal && !showAgentsEditor && (_jsx(SubagentsBrowserModal, { t: t, width: width, height: height, selectedIndex: agentsModalIndex, searchQuery: agentsSearchQuery, rows: agentRows })), showAgentsEditor && (_jsx(SubagentEditorModal, { t: t, width: width, height: height, draft: agentsEditorDraft, focusedField: agentsEditorField, modelIndex: agentsEditorModelIndex, error: agentsEditorError, title: editingSubagent ? `Edit sub-agent: ${formatSubagentName(editingSubagent.name)}` : "Add sub-agent", nameRef: subagentNameRef, instructionRef: subagentInstructionRef, onSubmit: submitSubagentEditor, showRemoveHint: !!editingSubagent }, `subagent-editor-${agentsEditorSyncKey}`)), showModelPicker && (_jsx(ModelPickerModal, { t: t, currentModel: model, selectedIndex: modelPickerIndex, width: width, height: height, searchQuery: modelSearchQuery, filteredModels: filteredModels, reasoningEffortByModel: reasoningEffortByModel, configuredProviders: configuredProviders, disabledProviders: disabledProviders, disabledModels: disabledModels, defaultProvider: defaultProvider, focus: modelPickerFocus, providerChipIndex: providerChipIndex, providersWithKey: providersWithKey, apiKeyPrompt: apiKeyPrompt, oauthProviders: oauthProviders, oauthLogin: oauthLogin })), showSessionPicker && (_jsx(SessionPickerModal, { t: t, sessions: sessionPickerList, focusIndex: sessionPickerIndex, width: width, height: height })), showWalletPicker && (_jsx(WalletPickerModal, { t: t, settings: walletSettings, walletInfo: walletDisplayInfo, focusIndex: walletFocusIndex, width: width, height: height })), showSandboxPicker && (_jsx(SandboxPickerModal, { t: t, currentMode: sandboxMode, settings: sandboxSettings, focusIndex: sandboxSettingsFocusIndex, editing: sandboxSettingsEditing, editBuffer: sandboxSettingsEditBuffer, width: width, height: height })), showConnectModal && (_jsx(ConnectModal, { t: t, width: width, height: height, selectedIndex: connectModalIndex, channels: CONNECT_CHANNELS })), showTelegramTokenModal && (_jsx(TelegramTokenModal, { t: t, width: width, height: height, inputRef: telegramTokenInputRef, error: telegramTokenError, onSubmit: submitTelegramToken })), showTelegramPairModal && (_jsx(TelegramPairModal, { t: t, width: width, height: height, inputRef: telegramPairInputRef, error: telegramPairError, onSubmit: () => void submitTelegramPair() }))] }));
17
17
  }
18
18
  //# sourceMappingURL=modals-layer.js.map
@@ -0,0 +1,57 @@
1
+ /**
2
+ * src/ui/council-harness-event.ts
3
+ *
4
+ * Pure mapping from a council `CouncilStatusData` chunk to the harness
5
+ * `council-speaker` LiveEvent payload.
6
+ *
7
+ * Why this exists. The long research phase (`llm.research`, up to ~10 min /
8
+ * 15 tool steps) runs as a single internal `generateText` — the MAIN stream is
9
+ * quiet the whole time, so `tui_wait_for(idle)` reports a FALSE idle and an
10
+ * agent driving the TUI misjudges the run as hung. The only signal during that
11
+ * window is the 1s `council_status` heartbeat (`state:"tick"`, advancing
12
+ * `elapsedMs`) emitted by `tracedAsync`. Previously the emit site collapsed
13
+ * every non-start state to `status:"done"` and DROPPED `elapsedMs`, so a poller
14
+ * reading `tui_last_event("council-speaker")` saw a frozen "done" event and
15
+ * concluded the speaker had finished — the exact false-stall this fixes.
16
+ *
17
+ * Carrying `state:"tick"` + `elapsedMs` through lets a harness monitor
18
+ * distinguish ALIVE (elapsedMs advancing across polls) from HUNG (elapsedMs
19
+ * frozen past a threshold) with a single `tui_last_event` call.
20
+ */
21
+ import type { CouncilStatusState } from "../types/index.js";
22
+ /** Harness `council-speaker` status: adds "tick" progress heartbeat to start/done. */
23
+ export type CouncilSpeakerStatus = "start" | "tick" | "done";
24
+ export interface CouncilStatusLike {
25
+ state: CouncilStatusState;
26
+ statusId: string;
27
+ role?: string;
28
+ label?: string;
29
+ elapsedMs?: number;
30
+ streamedChars?: number;
31
+ lastDeltaAgeMs?: number;
32
+ }
33
+ export interface CouncilSpeakerEvent {
34
+ t: "event";
35
+ kind: "council-speaker";
36
+ role: string;
37
+ status: CouncilSpeakerStatus;
38
+ correlationId: string;
39
+ elapsedMs?: number;
40
+ /** Chars (text + reasoning deltas) streamed since this phase began. */
41
+ streamedChars?: number;
42
+ /** Age of the most recent stream delta, in ms. */
43
+ lastDeltaAgeMs?: number;
44
+ }
45
+ /**
46
+ * Map a council status chunk to the `council-speaker` harness event payload.
47
+ * `start`→"start", `tick`→"tick" (progress heartbeat), `done`/`error`→"done".
48
+ * `elapsedMs` is passed through unchanged so a poller can measure progress.
49
+ *
50
+ * `streamedChars` / `lastDeltaAgeMs` ride along when the council emitted them.
51
+ * `elapsedMs` can freeze even on a healthy call — the tick generator only
52
+ * advances when its consumer pulls, and a round awaiting pairs via Promise.all
53
+ * does not pull. These two are pushed from the token stream itself, so they
54
+ * separate SLOW-BUT-ALIVE (chars growing, small delta age) from STUCK (chars
55
+ * static, delta age growing) without depending on generator pumping.
56
+ */
57
+ export declare function mapCouncilStatusToSpeakerEvent(cs: CouncilStatusLike): CouncilSpeakerEvent;
@@ -0,0 +1,46 @@
1
+ /**
2
+ * src/ui/council-harness-event.ts
3
+ *
4
+ * Pure mapping from a council `CouncilStatusData` chunk to the harness
5
+ * `council-speaker` LiveEvent payload.
6
+ *
7
+ * Why this exists. The long research phase (`llm.research`, up to ~10 min /
8
+ * 15 tool steps) runs as a single internal `generateText` — the MAIN stream is
9
+ * quiet the whole time, so `tui_wait_for(idle)` reports a FALSE idle and an
10
+ * agent driving the TUI misjudges the run as hung. The only signal during that
11
+ * window is the 1s `council_status` heartbeat (`state:"tick"`, advancing
12
+ * `elapsedMs`) emitted by `tracedAsync`. Previously the emit site collapsed
13
+ * every non-start state to `status:"done"` and DROPPED `elapsedMs`, so a poller
14
+ * reading `tui_last_event("council-speaker")` saw a frozen "done" event and
15
+ * concluded the speaker had finished — the exact false-stall this fixes.
16
+ *
17
+ * Carrying `state:"tick"` + `elapsedMs` through lets a harness monitor
18
+ * distinguish ALIVE (elapsedMs advancing across polls) from HUNG (elapsedMs
19
+ * frozen past a threshold) with a single `tui_last_event` call.
20
+ */
21
+ /**
22
+ * Map a council status chunk to the `council-speaker` harness event payload.
23
+ * `start`→"start", `tick`→"tick" (progress heartbeat), `done`/`error`→"done".
24
+ * `elapsedMs` is passed through unchanged so a poller can measure progress.
25
+ *
26
+ * `streamedChars` / `lastDeltaAgeMs` ride along when the council emitted them.
27
+ * `elapsedMs` can freeze even on a healthy call — the tick generator only
28
+ * advances when its consumer pulls, and a round awaiting pairs via Promise.all
29
+ * does not pull. These two are pushed from the token stream itself, so they
30
+ * separate SLOW-BUT-ALIVE (chars growing, small delta age) from STUCK (chars
31
+ * static, delta age growing) without depending on generator pumping.
32
+ */
33
+ export function mapCouncilStatusToSpeakerEvent(cs) {
34
+ const status = cs.state === "start" ? "start" : cs.state === "tick" ? "tick" : "done";
35
+ return {
36
+ t: "event",
37
+ kind: "council-speaker",
38
+ role: cs.role ?? cs.label ?? "unknown",
39
+ status,
40
+ correlationId: cs.statusId,
41
+ ...(typeof cs.elapsedMs === "number" ? { elapsedMs: cs.elapsedMs } : {}),
42
+ ...(typeof cs.streamedChars === "number" ? { streamedChars: cs.streamedChars } : {}),
43
+ ...(typeof cs.lastDeltaAgeMs === "number" ? { lastDeltaAgeMs: cs.lastDeltaAgeMs } : {}),
44
+ };
45
+ }
46
+ //# sourceMappingURL=council-harness-event.js.map
@@ -0,0 +1,29 @@
1
+ /**
2
+ * src/ui/heartbeat-debug.ts
3
+ *
4
+ * Env-gated instrumentation to pinpoint the council rail "frozen elapsed / static
5
+ * spinner" during long phases. Live evidence (harness 60Hz dedup frames identical
6
+ * for 110s + braille spinner not rotating) shows a real in-phase render/paint
7
+ * freeze, but NOT which link starves: (T) the setInterval TIMER not firing, (R)
8
+ * the timer fires but React does not re-render/commit, or (P) React commits but
9
+ * OpenTUI does not repaint.
10
+ *
11
+ * When `MUONROI_HEARTBEAT_DEBUG` is set to a file path, we append one JSONL line
12
+ * per event so a single instrumented council run answers T/R/P:
13
+ * - kind:"timer" → a setInterval callback actually fired (rules in/out T)
14
+ * - kind:"render" → a component's render body ran (rules in/out R)
15
+ * Compare timestamps against the sidechannel council-step timeline: if `timer`
16
+ * lines keep landing every ~100/1000ms through a phase but the harness frame is
17
+ * frozen, the starve is at paint (P); if `timer` lines STOP during the phase, the
18
+ * event loop / timer is starved (T).
19
+ *
20
+ * Unset → a single boolean check per call, zero file I/O, zero behaviour change.
21
+ */
22
+ export declare function heartbeatDebugEnabled(): boolean;
23
+ /**
24
+ * Append one instrumentation record. No-op unless MUONROI_HEARTBEAT_DEBUG points
25
+ * at a file. `kind` is "timer" (a setInterval callback fired) or "render" (a
26
+ * component render body executed). `extra` carries component-specific detail
27
+ * (frame index, computed elapsedMs, phase label).
28
+ */
29
+ export declare function heartbeatDebug(component: string, kind: "timer" | "render", extra?: Record<string, unknown>): void;
@@ -0,0 +1,45 @@
1
+ /**
2
+ * src/ui/heartbeat-debug.ts
3
+ *
4
+ * Env-gated instrumentation to pinpoint the council rail "frozen elapsed / static
5
+ * spinner" during long phases. Live evidence (harness 60Hz dedup frames identical
6
+ * for 110s + braille spinner not rotating) shows a real in-phase render/paint
7
+ * freeze, but NOT which link starves: (T) the setInterval TIMER not firing, (R)
8
+ * the timer fires but React does not re-render/commit, or (P) React commits but
9
+ * OpenTUI does not repaint.
10
+ *
11
+ * When `MUONROI_HEARTBEAT_DEBUG` is set to a file path, we append one JSONL line
12
+ * per event so a single instrumented council run answers T/R/P:
13
+ * - kind:"timer" → a setInterval callback actually fired (rules in/out T)
14
+ * - kind:"render" → a component's render body ran (rules in/out R)
15
+ * Compare timestamps against the sidechannel council-step timeline: if `timer`
16
+ * lines keep landing every ~100/1000ms through a phase but the harness frame is
17
+ * frozen, the starve is at paint (P); if `timer` lines STOP during the phase, the
18
+ * event loop / timer is starved (T).
19
+ *
20
+ * Unset → a single boolean check per call, zero file I/O, zero behaviour change.
21
+ */
22
+ import { appendFileSync } from "node:fs";
23
+ const SINK = process.env.MUONROI_HEARTBEAT_DEBUG?.trim() || null;
24
+ export function heartbeatDebugEnabled() {
25
+ return SINK !== null;
26
+ }
27
+ /**
28
+ * Append one instrumentation record. No-op unless MUONROI_HEARTBEAT_DEBUG points
29
+ * at a file. `kind` is "timer" (a setInterval callback fired) or "render" (a
30
+ * component render body executed). `extra` carries component-specific detail
31
+ * (frame index, computed elapsedMs, phase label).
32
+ */
33
+ export function heartbeatDebug(component, kind, extra) {
34
+ if (SINK === null)
35
+ return;
36
+ try {
37
+ const rec = { ts: Date.now(), component, kind, ...(extra ?? {}) };
38
+ appendFileSync(SINK, `${JSON.stringify(rec)}\n`);
39
+ }
40
+ catch (err) {
41
+ // Instrumentation must never break the UI; surface once at debug level.
42
+ console.error(`[heartbeat-debug] append failed: ${err?.message}`);
43
+ }
44
+ }
45
+ //# sourceMappingURL=heartbeat-debug.js.map
@@ -1,4 +1,4 @@
1
- import type { SessionInfo } from "../../types/index.js";
1
+ import type { ResumeEntry } from "../../types/index.js";
2
2
  /**
3
3
  * State for the /sessions picker modal. Sessions are loaded lazily when the
4
4
  * picker is opened (the SQLite query is cheap — ORDER BY updated_at LIMIT 20
@@ -9,6 +9,6 @@ export declare function useSessionPicker(): {
9
9
  setShowSessionPicker: import("react").Dispatch<import("react").SetStateAction<boolean>>;
10
10
  sessionPickerIndex: number;
11
11
  setSessionPickerIndex: import("react").Dispatch<import("react").SetStateAction<number>>;
12
- sessions: SessionInfo[];
13
- setSessions: import("react").Dispatch<import("react").SetStateAction<SessionInfo[]>>;
12
+ sessions: ResumeEntry[];
13
+ setSessions: import("react").Dispatch<import("react").SetStateAction<ResumeEntry[]>>;
14
14
  };
@@ -53,8 +53,7 @@ export function McpBrowserModal({ t, width, height, selectedIndex, searchQuery,
53
53
  const contentHeight = itemCount + 7;
54
54
  const maxHeight = Math.floor(height * 0.68);
55
55
  const panelHeight = Math.min(contentHeight, maxHeight);
56
- const overlayBg = "#000000cc";
57
- return (_jsx(Semantic, { id: "mcp-modal", role: "dialog", name: "MCP Servers", isModal: true, children: _jsx("box", { position: "absolute", left: 0, top: 0, width: width, height: height, alignItems: "center", paddingTop: bottomAlignedModalTop(height, panelHeight), backgroundColor: overlayBg, children: _jsxs("box", { width: Math.min(96, width - 4), height: panelHeight, backgroundColor: t.backgroundPanel, paddingTop: 1, paddingBottom: 1, flexDirection: "column", children: [_jsxs("box", { flexShrink: 0, flexDirection: "row", justifyContent: "space-between", paddingLeft: 2, paddingRight: 2, children: [_jsx("text", { fg: t.primary, children: _jsx("b", { children: "MCP Servers" }) }), _jsx("text", { fg: t.textMuted, children: "esc" })] }), _jsx("box", { flexShrink: 0, paddingLeft: 2, paddingRight: 2, paddingTop: 1, paddingBottom: 1, children: _jsx("text", { fg: t.text, children: searchQuery || _jsx("span", { style: { fg: t.textMuted }, children: "Search servers..." }) }) }), _jsx(Semantic, { id: "mcp-list", role: "listbox", children: _jsx("scrollbox", { ref: listRef, flexGrow: 1, minHeight: 0, children: rows.map((row, idx) => {
56
+ return (_jsx(Semantic, { id: "mcp-modal", role: "dialog", name: "MCP Servers", isModal: true, children: _jsx("box", { position: "absolute", left: 0, top: 0, width: width, height: height, alignItems: "center", paddingTop: bottomAlignedModalTop(height, panelHeight), backgroundColor: t.overlay, children: _jsxs("box", { width: Math.min(96, width - 4), height: panelHeight, backgroundColor: t.backgroundPanel, paddingTop: 1, paddingBottom: 1, flexDirection: "column", children: [_jsxs("box", { flexShrink: 0, flexDirection: "row", justifyContent: "space-between", paddingLeft: 2, paddingRight: 2, children: [_jsx("text", { fg: t.primary, children: _jsx("b", { children: "MCP Servers" }) }), _jsx("text", { fg: t.textMuted, children: "esc" })] }), _jsx("box", { flexShrink: 0, paddingLeft: 2, paddingRight: 2, paddingTop: 1, paddingBottom: 1, children: _jsx("text", { fg: t.text, children: searchQuery || _jsx("span", { style: { fg: t.textMuted }, children: "Search servers..." }) }) }), _jsx(Semantic, { id: "mcp-list", role: "listbox", children: _jsx("scrollbox", { ref: listRef, flexGrow: 1, minHeight: 0, children: rows.map((row, idx) => {
58
57
  const selected = idx === selectedIndex;
59
58
  if (row.kind === "server") {
60
59
  const enabledColor = row.server.enabled ? t.diffAddedFg : selected ? t.selected : t.text;
@@ -74,7 +73,6 @@ function syncRef(ref, value) {
74
73
  }
75
74
  export function McpEditorModal({ t, width, height, draft, focusedField, syncKey, error, title, labelRef, urlRef, headersRef, commandRef, argsRef, cwdRef, envRef, onSubmit, }) {
76
75
  const panelHeight = Math.min(30, Math.floor(height * 0.82));
77
- const overlayBg = "#000000cc";
78
76
  const isRemote = draft.transport === "http" || draft.transport === "sse";
79
77
  // biome-ignore lint/correctness/useExhaustiveDependencies: syncKey is an intentional cache-bust prop
80
78
  useEffect(() => {
@@ -86,7 +84,7 @@ export function McpEditorModal({ t, width, height, draft, focusedField, syncKey,
86
84
  syncRef(cwdRef, draft.cwd);
87
85
  syncRef(envRef, draft.envText);
88
86
  }, [draft, syncKey, labelRef, urlRef, headersRef, commandRef, argsRef, cwdRef, envRef]);
89
- return (_jsx(Semantic, { id: "mcp-editor", role: "dialog", name: title, isModal: true, children: _jsx("box", { position: "absolute", left: 0, top: 0, width: width, height: height, alignItems: "center", paddingTop: bottomAlignedModalTop(height, panelHeight), backgroundColor: overlayBg, children: _jsxs("box", { width: Math.min(86, width - 6), height: panelHeight, backgroundColor: t.backgroundPanel, paddingTop: 1, paddingBottom: 1, flexDirection: "column", children: [_jsxs("box", { flexShrink: 0, flexDirection: "row", justifyContent: "space-between", paddingLeft: 2, paddingRight: 2, children: [_jsx("text", { fg: t.primary, children: _jsx("b", { children: title }) }), _jsx("text", { fg: t.textMuted, children: "esc" })] }), _jsx("box", { flexShrink: 0, paddingLeft: 2, paddingRight: 2, paddingTop: 1, children: _jsxs("box", { flexDirection: "row", gap: 1, alignItems: "center", children: [_jsx("text", { fg: focusedField === "transport" ? t.primary : t.textMuted, children: "Transport" }), ["stdio", "http", "sse"].map((option) => {
87
+ return (_jsx(Semantic, { id: "mcp-editor", role: "dialog", name: title, isModal: true, children: _jsx("box", { position: "absolute", left: 0, top: 0, width: width, height: height, alignItems: "center", paddingTop: bottomAlignedModalTop(height, panelHeight), backgroundColor: t.overlay, children: _jsxs("box", { width: Math.min(86, width - 6), height: panelHeight, backgroundColor: t.backgroundPanel, paddingTop: 1, paddingBottom: 1, flexDirection: "column", children: [_jsxs("box", { flexShrink: 0, flexDirection: "row", justifyContent: "space-between", paddingLeft: 2, paddingRight: 2, children: [_jsx("text", { fg: t.primary, children: _jsx("b", { children: title }) }), _jsx("text", { fg: t.textMuted, children: "esc" })] }), _jsx("box", { flexShrink: 0, paddingLeft: 2, paddingRight: 2, paddingTop: 1, children: _jsxs("box", { flexDirection: "row", gap: 1, alignItems: "center", children: [_jsx("text", { fg: focusedField === "transport" ? t.primary : t.textMuted, children: "Transport" }), ["stdio", "http", "sse"].map((option) => {
90
88
  const active = draft.transport === option;
91
89
  const focused = focusedField === "transport";
92
90
  return (_jsx("box", { backgroundColor: active ? (focused ? t.selectedBg : t.backgroundElement) : undefined, paddingLeft: 1, paddingRight: 1, children: _jsx("text", { fg: active ? (focused ? t.primary : t.text) : t.textMuted, children: option }) }, option));
@@ -10,6 +10,6 @@ export function ApiKeyModal({ t, width, height, inputRef, error, onSubmit, }) {
10
10
  const panelWidth = Math.min(68, width - 6);
11
11
  const panelHeight = 13;
12
12
  const top = bottomAlignedModalTop(height, panelHeight);
13
- return (_jsx(Semantic, { id: "api-key-modal", role: "dialog", name: "API Key", isModal: true, children: _jsx("box", { position: "absolute", left: 0, top: 0, width: width, height: height, alignItems: "center", paddingTop: top, backgroundColor: overlayBg, children: _jsxs("box", { width: panelWidth, height: panelHeight, backgroundColor: t.backgroundPanel, paddingTop: 1, paddingBottom: 1, flexDirection: "column", children: [_jsxs("box", { flexShrink: 0, flexDirection: "row", justifyContent: "space-between", paddingLeft: 2, paddingRight: 2, children: [_jsx("text", { fg: t.primary, children: _jsx("b", { children: "Add API key" }) }), _jsx("text", { fg: t.textMuted, children: "esc" })] }), _jsx("box", { paddingLeft: 2, paddingRight: 2, paddingTop: 1, children: _jsx("text", { fg: t.text, children: "Paste your DeepSeek or SiliconFlow API key to unlock chat. Esc hides this prompt." }) }), _jsx("box", { paddingLeft: 2, paddingRight: 2, paddingTop: 1, children: _jsx("box", { backgroundColor: t.backgroundElement, paddingLeft: 1, paddingRight: 1, width: "100%", children: _jsx(Semantic, { id: "api-key-input", role: "textbox", children: _jsx("textarea", { ref: inputRef, focused: true, placeholder: "sk-...", textColor: t.text, backgroundColor: t.backgroundElement, placeholderColor: t.textMuted, minHeight: 1, maxHeight: 3, wrapMode: "word", keyBindings: TEXTAREA_KEYBINDINGS, onSubmit: onSubmit }) }) }) }), _jsx("box", { flexGrow: 1, minHeight: 0 }), _jsx("box", { paddingLeft: 2, paddingRight: 2, paddingTop: 2, paddingBottom: 1, children: error ? (_jsx("text", { fg: t.diffRemovedFg, children: error })) : (_jsxs("text", { children: [_jsx("span", { style: { fg: t.primary }, children: "enter " }), _jsx("span", { style: { fg: t.textMuted }, children: "save key · " }), _jsx("span", { style: { fg: t.primary }, children: "esc " }), _jsx("span", { style: { fg: t.textMuted }, children: "hide" })] })) })] }) }) }));
13
+ return (_jsx(Semantic, { id: "api-key-modal", role: "dialog", name: "API Key", isModal: true, children: _jsx("box", { position: "absolute", left: 0, top: 0, width: width, height: height, alignItems: "center", paddingTop: top, backgroundColor: overlayBg, children: _jsxs("box", { width: panelWidth, height: panelHeight, backgroundColor: t.backgroundPanel, paddingTop: 1, paddingBottom: 1, flexDirection: "column", children: [_jsxs("box", { flexShrink: 0, flexDirection: "row", justifyContent: "space-between", paddingLeft: 2, paddingRight: 2, children: [_jsx("text", { fg: t.primary, children: _jsx("b", { children: "Add API key" }) }), _jsx("text", { fg: t.textMuted, children: "esc" })] }), _jsx("box", { paddingLeft: 2, paddingRight: 2, paddingTop: 1, children: _jsx("text", { fg: t.text, children: "Paste a provider API key, or press Esc and use /providers to sign in (OAuth)." }) }), _jsx("box", { paddingLeft: 2, paddingRight: 2, paddingTop: 1, children: _jsx("box", { backgroundColor: t.backgroundElement, paddingLeft: 1, paddingRight: 1, width: "100%", children: _jsx(Semantic, { id: "api-key-input", role: "textbox", children: _jsx("textarea", { ref: inputRef, focused: true, placeholder: "sk-...", textColor: t.text, backgroundColor: t.backgroundElement, placeholderColor: t.textMuted, minHeight: 1, maxHeight: 3, wrapMode: "word", keyBindings: TEXTAREA_KEYBINDINGS, onSubmit: onSubmit }) }) }) }), _jsx("box", { flexGrow: 1, minHeight: 0 }), _jsx("box", { paddingLeft: 2, paddingRight: 2, paddingTop: 2, paddingBottom: 1, children: error ? (_jsx("text", { fg: t.diffRemovedFg, children: error })) : (_jsxs("text", { children: [_jsx("span", { style: { fg: t.primary }, children: "enter " }), _jsx("span", { style: { fg: t.textMuted }, children: "save key · " }), _jsx("span", { style: { fg: t.primary }, children: "esc " }), _jsx("span", { style: { fg: t.textMuted }, children: "hide" })] })) })] }) }) }));
14
14
  }
15
15
  //# sourceMappingURL=api-key-modal.js.map
@@ -1,5 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "@opentui/react/jsx-runtime";
2
2
  import { useEffect, useRef } from "react";
3
+ import { Dialog } from "../primitives/index.js";
3
4
  import { bottomAlignedModalTop } from "../utils/modal.js";
4
5
  const TEXTAREA_KEYBINDINGS = [
5
6
  { name: "return", action: "submit" },
@@ -15,20 +16,20 @@ export function ConnectModal({ t, width, height, selectedIndex, channels, }) {
15
16
  const panelHeight = Math.min(channels.length + 9, Math.floor(height * 0.5));
16
17
  const top = bottomAlignedModalTop(height, panelHeight);
17
18
  const overlayBg = "#000000cc";
18
- return (_jsx("box", { position: "absolute", left: 0, top: 0, width: width, height: height, alignItems: "center", paddingTop: top, backgroundColor: overlayBg, children: _jsxs("box", { width: Math.min(56, width - 6), height: panelHeight, backgroundColor: t.backgroundPanel, paddingTop: 1, paddingBottom: 1, flexDirection: "column", children: [_jsxs("box", { flexShrink: 0, flexDirection: "row", justifyContent: "space-between", paddingLeft: 2, paddingRight: 2, children: [_jsx("text", { fg: t.primary, children: _jsx("b", { children: "Connect" }) }), _jsx("text", { fg: t.textMuted, children: "esc" })] }), _jsx("box", { flexShrink: 0, paddingLeft: 2, paddingRight: 2, paddingTop: 1, paddingBottom: 1, children: _jsx("text", { fg: t.textMuted, children: "Choose a channel" }) }), _jsx("scrollbox", { ref: listRef, flexGrow: 1, minHeight: 0, children: channels.map((ch, idx) => (_jsx("box", { id: `connect-${ch.id}`, backgroundColor: idx === selectedIndex ? t.selectedBg : undefined, paddingLeft: 2, paddingRight: 2, children: _jsxs("box", { flexDirection: "row", justifyContent: "space-between", children: [_jsx("text", { fg: idx === selectedIndex ? t.selected : t.text, children: ch.label }), _jsx("text", { fg: t.textMuted, children: ch.description })] }) }, ch.id))) }), _jsx("box", { flexShrink: 0, paddingLeft: 2, paddingRight: 2, paddingTop: 2, paddingBottom: 1, children: _jsxs("text", { children: [_jsx("span", { style: { fg: t.primary }, children: "enter " }), _jsx("span", { style: { fg: t.textMuted }, children: "select · " }), _jsx("span", { style: { fg: t.primary }, children: "↑↓ " }), _jsx("span", { style: { fg: t.textMuted }, children: "navigate · " }), _jsx("span", { style: { fg: t.primary }, children: "esc " }), _jsx("span", { style: { fg: t.textMuted }, children: "close" })] }) })] }) }));
19
+ return (_jsx(Dialog, { id: "connect-modal", name: "Connect", children: _jsx("box", { position: "absolute", left: 0, top: 0, width: width, height: height, alignItems: "center", paddingTop: top, backgroundColor: overlayBg, children: _jsxs("box", { width: Math.min(56, width - 6), height: panelHeight, backgroundColor: t.backgroundPanel, paddingTop: 1, paddingBottom: 1, flexDirection: "column", children: [_jsxs("box", { flexShrink: 0, flexDirection: "row", justifyContent: "space-between", paddingLeft: 2, paddingRight: 2, children: [_jsx("text", { fg: t.primary, children: _jsx("b", { children: "Connect" }) }), _jsx("text", { fg: t.textMuted, children: "esc" })] }), _jsx("box", { flexShrink: 0, paddingLeft: 2, paddingRight: 2, paddingTop: 1, paddingBottom: 1, children: _jsx("text", { fg: t.textMuted, children: "Choose a channel" }) }), _jsx("scrollbox", { ref: listRef, flexGrow: 1, minHeight: 0, children: channels.map((ch, idx) => (_jsx("box", { id: `connect-${ch.id}`, backgroundColor: idx === selectedIndex ? t.selectedBg : undefined, paddingLeft: 2, paddingRight: 2, children: _jsxs("box", { flexDirection: "row", justifyContent: "space-between", children: [_jsx("text", { fg: idx === selectedIndex ? t.selected : t.text, children: ch.label }), _jsx("text", { fg: t.textMuted, children: ch.description })] }) }, ch.id))) }), _jsx("box", { flexShrink: 0, paddingLeft: 2, paddingRight: 2, paddingTop: 2, paddingBottom: 1, children: _jsxs("text", { children: [_jsx("span", { style: { fg: t.primary }, children: "enter " }), _jsx("span", { style: { fg: t.textMuted }, children: "select · " }), _jsx("span", { style: { fg: t.primary }, children: "↑↓ " }), _jsx("span", { style: { fg: t.textMuted }, children: "navigate · " }), _jsx("span", { style: { fg: t.primary }, children: "esc " }), _jsx("span", { style: { fg: t.textMuted }, children: "close" })] }) })] }) }) }));
19
20
  }
20
21
  export function TelegramTokenModal({ t, width, height, inputRef, error, onSubmit, }) {
21
22
  const overlayBg = "#000000cc";
22
23
  const panelWidth = Math.min(68, width - 6);
23
24
  const panelHeight = 14;
24
25
  const top = bottomAlignedModalTop(height, panelHeight);
25
- return (_jsx("box", { position: "absolute", left: 0, top: 0, width: width, height: height, alignItems: "center", paddingTop: top, backgroundColor: overlayBg, children: _jsxs("box", { width: panelWidth, height: panelHeight, backgroundColor: t.backgroundPanel, paddingTop: 1, paddingBottom: 1, flexDirection: "column", children: [_jsxs("box", { flexShrink: 0, flexDirection: "row", justifyContent: "space-between", paddingLeft: 2, paddingRight: 2, children: [_jsx("text", { fg: t.primary, children: _jsx("b", { children: "Telegram bot token" }) }), _jsx("text", { fg: t.textMuted, children: "esc" })] }), _jsx("box", { paddingLeft: 2, paddingRight: 2, paddingTop: 1, children: _jsx("text", { fg: t.text, children: "From @BotFather: /newbot, then paste the token here. Stored in ~/.muonroi-cli/user-settings.json." }) }), _jsx("box", { paddingLeft: 2, paddingRight: 2, paddingTop: 1, children: _jsx("box", { backgroundColor: t.backgroundElement, paddingLeft: 1, paddingRight: 1, width: "100%", children: _jsx("textarea", { ref: inputRef, focused: true, placeholder: "123456:ABC...", textColor: t.text, backgroundColor: t.backgroundElement, placeholderColor: t.textMuted, minHeight: 1, maxHeight: 3, wrapMode: "word", keyBindings: TEXTAREA_KEYBINDINGS, onSubmit: onSubmit }) }) }), _jsx("box", { flexGrow: 1, minHeight: 0 }), _jsx("box", { paddingLeft: 2, paddingRight: 2, paddingTop: 2, paddingBottom: 1, children: error ? (_jsx("text", { fg: t.diffRemovedFg, children: error })) : (_jsxs("text", { children: [_jsx("span", { style: { fg: t.primary }, children: "enter " }), _jsx("span", { style: { fg: t.textMuted }, children: "save token · " }), _jsx("span", { style: { fg: t.primary }, children: "esc " }), _jsx("span", { style: { fg: t.textMuted }, children: "close" })] })) })] }) }));
26
+ return (_jsx(Dialog, { id: "telegram-token-modal", name: "Telegram bot token", children: _jsx("box", { position: "absolute", left: 0, top: 0, width: width, height: height, alignItems: "center", paddingTop: top, backgroundColor: overlayBg, children: _jsxs("box", { width: panelWidth, height: panelHeight, backgroundColor: t.backgroundPanel, paddingTop: 1, paddingBottom: 1, flexDirection: "column", children: [_jsxs("box", { flexShrink: 0, flexDirection: "row", justifyContent: "space-between", paddingLeft: 2, paddingRight: 2, children: [_jsx("text", { fg: t.primary, children: _jsx("b", { children: "Telegram bot token" }) }), _jsx("text", { fg: t.textMuted, children: "esc" })] }), _jsx("box", { paddingLeft: 2, paddingRight: 2, paddingTop: 1, children: _jsx("text", { fg: t.text, children: "From @BotFather: /newbot, then paste the token here. Stored in ~/.muonroi-cli/user-settings.json." }) }), _jsx("box", { paddingLeft: 2, paddingRight: 2, paddingTop: 1, children: _jsx("box", { backgroundColor: t.backgroundElement, paddingLeft: 1, paddingRight: 1, width: "100%", children: _jsx("textarea", { ref: inputRef, focused: true, placeholder: "123456:ABC...", textColor: t.text, backgroundColor: t.backgroundElement, placeholderColor: t.textMuted, minHeight: 1, maxHeight: 3, wrapMode: "word", keyBindings: TEXTAREA_KEYBINDINGS, onSubmit: onSubmit }) }) }), _jsx("box", { flexGrow: 1, minHeight: 0 }), _jsx("box", { paddingLeft: 2, paddingRight: 2, paddingTop: 2, paddingBottom: 1, children: error ? (_jsx("text", { fg: t.diffRemovedFg, children: error })) : (_jsxs("text", { children: [_jsx("span", { style: { fg: t.primary }, children: "enter " }), _jsx("span", { style: { fg: t.textMuted }, children: "save token · " }), _jsx("span", { style: { fg: t.primary }, children: "esc " }), _jsx("span", { style: { fg: t.textMuted }, children: "close" })] })) })] }) }) }));
26
27
  }
27
28
  export function TelegramPairModal({ t, width, height, inputRef, error, onSubmit, }) {
28
29
  const overlayBg = "#000000cc";
29
30
  const panelWidth = Math.min(68, width - 6);
30
31
  const panelHeight = 13;
31
32
  const top = bottomAlignedModalTop(height, panelHeight);
32
- return (_jsx("box", { position: "absolute", left: 0, top: 0, width: width, height: height, alignItems: "center", paddingTop: top, backgroundColor: overlayBg, children: _jsxs("box", { width: panelWidth, height: panelHeight, backgroundColor: t.backgroundPanel, paddingTop: 1, paddingBottom: 1, flexDirection: "column", children: [_jsxs("box", { flexShrink: 0, flexDirection: "row", justifyContent: "space-between", paddingLeft: 2, paddingRight: 2, children: [_jsx("text", { fg: t.primary, children: _jsx("b", { children: "Pairing code" }) }), _jsx("text", { fg: t.textMuted, children: "esc" })] }), _jsx("box", { paddingLeft: 2, paddingRight: 2, paddingTop: 1, children: _jsx("text", { fg: t.text, children: "DM your bot with /pair, then paste the 6-character code." }) }), _jsx("box", { paddingLeft: 2, paddingRight: 2, paddingTop: 1, children: _jsx("box", { backgroundColor: t.backgroundElement, paddingLeft: 1, paddingRight: 1, width: "100%", children: _jsx("textarea", { ref: inputRef, focused: true, placeholder: "ABC123", textColor: t.text, backgroundColor: t.backgroundElement, placeholderColor: t.textMuted, minHeight: 1, maxHeight: 2, wrapMode: "word", keyBindings: TEXTAREA_KEYBINDINGS, onSubmit: onSubmit }) }) }), _jsx("box", { flexGrow: 1, minHeight: 0 }), _jsx("box", { paddingLeft: 2, paddingRight: 2, paddingTop: 2, paddingBottom: 1, children: error ? (_jsx("text", { fg: t.diffRemovedFg, children: error })) : (_jsxs("text", { children: [_jsx("span", { style: { fg: t.primary }, children: "enter " }), _jsx("span", { style: { fg: t.textMuted }, children: "approve pairing · " }), _jsx("span", { style: { fg: t.primary }, children: "esc " }), _jsx("span", { style: { fg: t.textMuted }, children: "close" })] })) })] }) }));
33
+ return (_jsx(Dialog, { id: "telegram-pair-modal", name: "Pairing code", children: _jsx("box", { position: "absolute", left: 0, top: 0, width: width, height: height, alignItems: "center", paddingTop: top, backgroundColor: overlayBg, children: _jsxs("box", { width: panelWidth, height: panelHeight, backgroundColor: t.backgroundPanel, paddingTop: 1, paddingBottom: 1, flexDirection: "column", children: [_jsxs("box", { flexShrink: 0, flexDirection: "row", justifyContent: "space-between", paddingLeft: 2, paddingRight: 2, children: [_jsx("text", { fg: t.primary, children: _jsx("b", { children: "Pairing code" }) }), _jsx("text", { fg: t.textMuted, children: "esc" })] }), _jsx("box", { paddingLeft: 2, paddingRight: 2, paddingTop: 1, children: _jsx("text", { fg: t.text, children: "DM your bot with /pair, then paste the 6-character code." }) }), _jsx("box", { paddingLeft: 2, paddingRight: 2, paddingTop: 1, children: _jsx("box", { backgroundColor: t.backgroundElement, paddingLeft: 1, paddingRight: 1, width: "100%", children: _jsx("textarea", { ref: inputRef, focused: true, placeholder: "ABC123", textColor: t.text, backgroundColor: t.backgroundElement, placeholderColor: t.textMuted, minHeight: 1, maxHeight: 2, wrapMode: "word", keyBindings: TEXTAREA_KEYBINDINGS, onSubmit: onSubmit }) }) }), _jsx("box", { flexGrow: 1, minHeight: 0 }), _jsx("box", { paddingLeft: 2, paddingRight: 2, paddingTop: 2, paddingBottom: 1, children: error ? (_jsx("text", { fg: t.diffRemovedFg, children: error })) : (_jsxs("text", { children: [_jsx("span", { style: { fg: t.primary }, children: "enter " }), _jsx("span", { style: { fg: t.textMuted }, children: "approve pairing · " }), _jsx("span", { style: { fg: t.primary }, children: "esc " }), _jsx("span", { style: { fg: t.textMuted }, children: "close" })] })) })] }) }) }));
33
34
  }
34
35
  //# sourceMappingURL=connect-modal.js.map
@@ -14,24 +14,12 @@ export interface ApiKeyPromptState {
14
14
  /** When true the field shows the raw key instead of mask dots (Ctrl+R). */
15
15
  reveal?: boolean;
16
16
  }
17
- export type BwSyncState = {
18
- phase: "password";
19
- value: string;
20
- error: string | null;
21
- loading: boolean;
22
- } | {
23
- phase: "picker";
24
- session: string;
25
- items: Array<{
26
- provider: ProviderId;
27
- key: string;
28
- }>;
29
- selected: Set<ProviderId>;
30
- focusIndex: number;
31
- loading: boolean;
17
+ /** In-progress OAuth login overlay state (browser-based subscription sign-in). */
18
+ export interface OAuthLoginState {
19
+ provider: ProviderId;
32
20
  error: string | null;
33
- };
34
- export declare function ModelPickerModal({ t, width, height, configuredProviders, disabledProviders, defaultProvider, providerChipIndex, providersWithKey, apiKeyPrompt, bwSync, }: {
21
+ }
22
+ export declare function ModelPickerModal({ t, width, height, configuredProviders, disabledProviders, defaultProvider, providerChipIndex, providersWithKey, apiKeyPrompt, oauthProviders, oauthLogin, }: {
35
23
  t: Theme;
36
24
  currentModel?: string;
37
25
  selectedIndex?: number;
@@ -48,5 +36,7 @@ export declare function ModelPickerModal({ t, width, height, configuredProviders
48
36
  providerChipIndex: number;
49
37
  providersWithKey?: ReadonlySet<ProviderId>;
50
38
  apiKeyPrompt?: ApiKeyPromptState | null;
51
- bwSync?: BwSyncState | null;
39
+ /** Providers that support OAuth subscription login (openai, xai). */
40
+ oauthProviders?: ReadonlySet<ProviderId>;
41
+ oauthLogin?: OAuthLoginState | null;
52
42
  }): import("react").ReactNode;
@@ -21,9 +21,10 @@ export function groupModelsByTier(models) {
21
21
  const order = ["premium", "balanced", "fast", "other"];
22
22
  return order.filter((t) => map.has(t)).map((t) => ({ tier: t, items: map.get(t) }));
23
23
  }
24
- export function ModelPickerModal({ t, width, height, configuredProviders, disabledProviders, defaultProvider, providerChipIndex, providersWithKey, apiKeyPrompt, bwSync, }) {
24
+ export function ModelPickerModal({ t, width, height, configuredProviders, disabledProviders, defaultProvider, providerChipIndex, providersWithKey, apiKeyPrompt, oauthProviders, oauthLogin, }) {
25
25
  const disabledSet = new Set(disabledProviders);
26
26
  const keyedSet = providersWithKey ?? new Set();
27
+ const oauthSet = oauthProviders ?? new Set();
27
28
  const panelWidth = Math.min(64, width - 6);
28
29
  const rowCount = Math.max(configuredProviders.length, 1);
29
30
  const contentHeight = rowCount + 7;
@@ -32,13 +33,9 @@ export function ModelPickerModal({ t, width, height, configuredProviders, disabl
32
33
  const top = bottomAlignedModalTop(height, panelHeight);
33
34
  const overlayBg = "#000000cc";
34
35
  // Sub-modal: API key prompt overlay (rendered on top of the picker).
35
- const subModal = apiKeyPrompt ? (_jsx(Semantic, { id: "provider-key-prompt", role: "dialog", isModal: true, name: `Set ${apiKeyPrompt.provider} key`, children: _jsx("box", { position: "absolute", left: 0, top: 0, width: width, height: height, alignItems: "center", paddingTop: Math.floor(height / 3), backgroundColor: "#000000dd", children: _jsxs("box", { width: Math.min(60, width - 8), backgroundColor: t.backgroundPanel, paddingTop: 1, paddingBottom: 1, paddingLeft: 2, paddingRight: 2, flexDirection: "column", children: [_jsx("text", { fg: t.primary, children: _jsx("b", { children: `Set API key — ${apiKeyPrompt.provider}` }) }), _jsx("box", { paddingTop: 1, children: _jsx("text", { fg: t.textMuted, children: "Key is saved to the OS keychain (keytar). Bitwarden sync via `muonroi-cli keys import-bw`." }) }), _jsx(Semantic, { id: "provider-key-input", role: "textbox", name: `${apiKeyPrompt.provider} API key`, focus: true, value: apiKeyPrompt.value, children: _jsxs("box", { paddingTop: 1, backgroundColor: t.backgroundElement, paddingLeft: 1, paddingRight: 1, flexDirection: "row", justifyContent: "space-between", children: [apiKeyPrompt.value.length > 0 ? (_jsx("text", { fg: t.text, children: `${apiKeyPrompt.reveal ? apiKeyPrompt.value.slice(0, 40) : "•".repeat(Math.min(apiKeyPrompt.value.length, 40))}▏` })) : (_jsx("text", { fg: t.textDim, children: "▏(type or paste key)" })), apiKeyPrompt.value.length > 0 ? (_jsx("text", { fg: t.textMuted, children: `${apiKeyPrompt.reveal ? "shown" : "hidden"} · ${apiKeyPrompt.value.length} chars` })) : null] }) }), apiKeyPrompt.error ? (_jsx("box", { paddingTop: 1, children: _jsx("text", { fg: t.initFormError, children: apiKeyPrompt.error }) })) : null, _jsx("box", { paddingTop: 1, children: _jsx("text", { fg: t.textMuted, children: "Enter save · Esc cancel · Ctrl+R reveal · paste works" }) })] }) }) })) : null;
36
- // Sub-modal: Bitwarden sync (Option A) password phase, then provider picker.
37
- const bwModal = bwSync ? (_jsx(Semantic, { id: "provider-bw-sync", role: "dialog", isModal: true, name: "Bitwarden sync", children: _jsx("box", { position: "absolute", left: 0, top: 0, width: width, height: height, alignItems: "center", paddingTop: Math.floor(height / 4), backgroundColor: "#000000dd", children: _jsx("box", { width: Math.min(64, width - 8), backgroundColor: t.backgroundPanel, paddingTop: 1, paddingBottom: 1, paddingLeft: 2, paddingRight: 2, flexDirection: "column", children: bwSync.phase === "password" ? (_jsxs(_Fragment, { children: [_jsx("text", { fg: t.primary, children: _jsx("b", { children: "Sync from Bitwarden" }) }), _jsx("box", { paddingTop: 1, children: _jsx("text", { fg: t.textMuted, children: "Unlocks vault with master password, finds items named 'muonroi-cli/<provider>', imports keys." }) }), _jsx(Semantic, { id: "bw-password-input", role: "textbox", name: "Bitwarden master password", focus: true, value: bwSync.value, children: _jsxs("box", { paddingTop: 1, backgroundColor: t.backgroundElement, paddingLeft: 1, paddingRight: 1, flexDirection: "row", justifyContent: "space-between", children: [bwSync.value.length > 0 ? (_jsx("text", { fg: t.text, children: `${"•".repeat(Math.min(bwSync.value.length, 40))}▏` })) : (_jsx("text", { fg: t.textDim, children: "▏(master password)" })), bwSync.value.length > 0 ? _jsx("text", { fg: t.textMuted, children: `${bwSync.value.length} chars` }) : null] }) }), bwSync.error ? (_jsx("box", { paddingTop: 1, children: _jsx("text", { fg: t.initFormError, children: bwSync.error }) })) : null, _jsx("box", { paddingTop: 1, children: _jsx("text", { fg: t.textMuted, children: bwSync.loading ? "unlocking..." : "Enter unlock Esc cancel" }) })] })) : (_jsxs(_Fragment, { children: [_jsx("text", { fg: t.primary, children: _jsx("b", { children: `Import from Bitwarden (${bwSync.items.length} found)` }) }), _jsx("box", { paddingTop: 1, flexDirection: "column", children: bwSync.items.map((item, i) => {
38
- const focused = i === bwSync.focusIndex;
39
- const checked = bwSync.selected.has(item.provider);
40
- return (_jsx("box", { paddingLeft: 1, paddingRight: 1, backgroundColor: focused ? t.selectedBg : undefined, children: _jsx("text", { fg: focused ? t.accent : t.text, children: `${focused ? "›" : " "} [${checked ? "x" : " "}] ${item.provider}` }) }, item.provider));
41
- }) }), bwSync.error ? (_jsx("box", { paddingTop: 1, children: _jsx("text", { fg: t.initFormError, children: bwSync.error }) })) : null, _jsx("box", { paddingTop: 1, children: _jsx("text", { fg: t.textMuted, children: bwSync.loading ? "importing..." : "↑↓ nav Space toggle Enter import Esc cancel" }) })] })) }) }) })) : null;
36
+ const subModal = apiKeyPrompt ? (_jsx(Semantic, { id: "provider-key-prompt", role: "dialog", isModal: true, name: `Set ${apiKeyPrompt.provider} key`, children: _jsx("box", { position: "absolute", left: 0, top: 0, width: width, height: height, alignItems: "center", paddingTop: Math.floor(height / 3), backgroundColor: "#000000dd", children: _jsxs("box", { width: Math.min(60, width - 8), backgroundColor: t.backgroundPanel, paddingTop: 1, paddingBottom: 1, paddingLeft: 2, paddingRight: 2, flexDirection: "column", children: [_jsx("text", { fg: t.primary, children: _jsx("b", { children: `Set API key — ${apiKeyPrompt.provider}` }) }), _jsx("box", { paddingTop: 1, children: _jsx("text", { fg: t.textMuted, children: "Key is stored as an environment variable (~/.muonroi-cli/.env, mirrored to your OS env)." }) }), _jsx(Semantic, { id: "provider-key-input", role: "textbox", name: `${apiKeyPrompt.provider} API key`, focus: true, value: apiKeyPrompt.value, children: _jsxs("box", { paddingTop: 1, backgroundColor: t.backgroundElement, paddingLeft: 1, paddingRight: 1, flexDirection: "row", justifyContent: "space-between", children: [apiKeyPrompt.value.length > 0 ? (_jsx("text", { fg: t.text, children: `${apiKeyPrompt.reveal ? apiKeyPrompt.value.slice(0, 40) : "•".repeat(Math.min(apiKeyPrompt.value.length, 40))}▏` })) : (_jsx("text", { fg: t.textDim, children: "▏(type or paste key)" })), apiKeyPrompt.value.length > 0 ? (_jsx("text", { fg: t.textMuted, children: `${apiKeyPrompt.reveal ? "shown" : "hidden"} · ${apiKeyPrompt.value.length} chars` })) : null] }) }), apiKeyPrompt.error ? (_jsx("box", { paddingTop: 1, children: _jsx("text", { fg: t.initFormError, children: apiKeyPrompt.error }) })) : null, _jsx("box", { paddingTop: 1, children: _jsx("text", { fg: t.textMuted, children: "Enter save · Esc cancel · Ctrl+R reveal · paste works" }) })] }) }) })) : null;
37
+ // Sub-modal: OAuth subscription login (browser-based) for openai / xai.
38
+ const oauthModal = oauthLogin ? (_jsx(Semantic, { id: "provider-oauth-login", role: "dialog", isModal: true, name: `Sign in to ${oauthLogin.provider}`, children: _jsx("box", { position: "absolute", left: 0, top: 0, width: width, height: height, alignItems: "center", paddingTop: Math.floor(height / 3), backgroundColor: "#000000dd", children: _jsxs("box", { width: Math.min(60, width - 8), backgroundColor: t.backgroundPanel, paddingTop: 1, paddingBottom: 1, paddingLeft: 2, paddingRight: 2, flexDirection: "column", children: [_jsx("text", { fg: t.primary, children: _jsx("b", { children: `Sign in to ${oauthLogin.provider} (OAuth)` }) }), _jsx("box", { paddingTop: 1, children: _jsx("text", { fg: t.textMuted, children: "A browser window is opening. Complete the sign-in there; this returns automatically." }) }), oauthLogin.error ? (_jsx("box", { paddingTop: 1, children: _jsx("text", { fg: t.initFormError, children: oauthLogin.error }) })) : (_jsx("box", { paddingTop: 1, children: _jsx("text", { fg: t.textMuted, children: "Waiting for authorization… Esc cancel" }) }))] }) }) })) : null;
42
39
  return (_jsxs(_Fragment, { children: [_jsx(Semantic, { id: "model-picker", role: "dialog", isModal: true, name: "Providers", children: _jsx("box", { position: "absolute", left: 0, top: 0, width: width, height: height, alignItems: "center", paddingTop: top, backgroundColor: overlayBg, children: _jsxs("box", { width: panelWidth, height: panelHeight, backgroundColor: t.backgroundPanel, paddingTop: 1, paddingBottom: 1, flexDirection: "column", children: [_jsxs("box", { flexShrink: 0, flexDirection: "row", justifyContent: "space-between", paddingLeft: 2, paddingRight: 2, children: [_jsx("text", { fg: t.primary, children: _jsx("b", { children: "Providers" }) }), _jsx("text", { fg: t.textMuted, children: "esc" })] }), _jsx("box", { flexShrink: 0, paddingLeft: 2, paddingRight: 2, paddingTop: 1, flexDirection: "column", children: configuredProviders.length === 0 ? (_jsx("text", { fg: t.textMuted, children: "No providers configured" })) : (configuredProviders.map((p, i) => {
43
40
  const hasKey = keyedSet.has(p);
44
41
  const enabled = hasKey && !disabledSet.has(p);
@@ -48,8 +45,9 @@ export function ModelPickerModal({ t, width, height, configuredProviders, disabl
48
45
  const star = isDefault ? "★" : " ";
49
46
  const fg = focused ? t.accent : enabled ? t.text : t.textMuted;
50
47
  const starFg = isDefault ? t.primary : t.textDim;
51
- const suffix = !hasKey ? " (no key — press K)" : "";
48
+ const canOAuth = oauthSet.has(p);
49
+ const suffix = !hasKey ? (canOAuth ? " (Enter sign in · K key)" : " (no key — press K)") : "";
52
50
  return (_jsx(Semantic, { id: `provider-chip-${p}`, role: "button", selected: enabled ? true : undefined, disabled: !hasKey ? true : undefined, name: p, children: _jsxs("box", { paddingLeft: 1, paddingRight: 1, backgroundColor: focused ? t.selectedBg : undefined, width: "100%", flexDirection: "row", children: [_jsx("text", { fg: fg, children: `${focused ? "›" : " "} ${mark} ` }), _jsx("text", { fg: starFg, children: `${star} ` }), _jsx("text", { fg: fg, children: p }), suffix ? _jsx("text", { fg: t.textMuted, children: suffix }) : null] }) }, p));
53
- })) }), _jsx("box", { flexGrow: 1, minHeight: 0 }), _jsx("box", { flexShrink: 0, paddingLeft: 2, paddingRight: 2, paddingTop: 1, children: _jsx("text", { fg: t.textMuted, children: "↑↓ nav Space toggle D default K set key B sync BW Esc close" }) })] }) }) }), subModal, bwModal] }));
51
+ })) }), _jsx("box", { flexGrow: 1, minHeight: 0 }), _jsx("box", { flexShrink: 0, paddingLeft: 2, paddingRight: 2, paddingTop: 1, children: _jsx("text", { fg: t.textMuted, children: "↑↓ nav Space toggle D default O sign in K set key Esc close" }) })] }) }) }), subModal, oauthModal] }));
54
52
  }
55
53
  //# sourceMappingURL=model-picker-modal.js.map
@@ -1,4 +1,4 @@
1
- import type { SessionInfo } from "../../types/index.js";
1
+ import type { ResumeEntry } from "../../types/index.js";
2
2
  import type { Theme } from "../theme.js";
3
3
  /**
4
4
  * Recent-sessions picker. Opened by `/sessions` or `/session`. Selecting a
@@ -7,7 +7,7 @@ import type { Theme } from "../theme.js";
7
7
  */
8
8
  export declare function SessionPickerModal({ t, sessions, focusIndex, width, height, }: {
9
9
  t: Theme;
10
- sessions: SessionInfo[];
10
+ sessions: ResumeEntry[];
11
11
  focusIndex: number;
12
12
  width: number;
13
13
  height: number;