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
package/dist/src/index.js CHANGED
@@ -24,8 +24,7 @@ import { createAbortContext } from "./orchestrator/abort.js";
24
24
  import { completeDelegation, failDelegation, loadDelegation } from "./orchestrator/delegations.js";
25
25
  import { Agent } from "./orchestrator/orchestrator.js";
26
26
  import { createPendingCallsLog } from "./orchestrator/pending-calls.js";
27
- import { getProviderCapabilities } from "./providers/capabilities.js";
28
- import { listStoredProviders, loadKeyForProvider, setKeyForProvider } from "./providers/keychain.js";
27
+ import { loadKeyForProvider, setKeyForProvider } from "./providers/keychain.js";
29
28
  import { detectProviderForModel } from "./providers/runtime.js";
30
29
  import { loadConfig } from "./storage/config.js";
31
30
  import { loadUsage } from "./storage/usage-cap.js";
@@ -35,7 +34,7 @@ import { runScriptManagedUninstall } from "./utils/install-manager.js";
35
34
  import { getApiKey, getBaseURL, getCurrentModel, saveUserSettings } from "./utils/settings.js";
36
35
  import { runUpdate } from "./utils/update-checker.js";
37
36
  import { buildVerifyPrompt, getVerifyCliError } from "./verify/entrypoint.js";
38
- // Hydrate chat secrets from OS keychain before CLI bootstrap
37
+ // Hydrate chat secrets (no-op now: secrets live in the environment/env-store)
39
38
  await hydrateChatEnvFromKeychain();
40
39
  const exitCleanlyOnSigterm = () => {
41
40
  process.exit(0);
@@ -61,6 +60,78 @@ export function appendCrashLog(label, msg) {
61
60
  /* crash.log is best-effort diagnostics; the logger itself must never throw */
62
61
  }
63
62
  }
63
+ /**
64
+ * Arm the event-loop freeze diagnostics for this TUI session.
65
+ *
66
+ * Every existing hang guard in this codebase (provider stall watchdog, turn
67
+ * watchdog) is driven by a timer, so all of them are blind to a blocked event
68
+ * loop — a timer cannot fire while the JS thread is stuck. Measured live
69
+ * 2026-07-16 (session 90c3ff533826): the TUI froze 304.5s, input replayed on
70
+ * recovery, and the 120s stall watchdog only rescued the turn 6.7s AFTER the
71
+ * loop came back. This closes that blind spot: the monitor reports the block
72
+ * once the loop frees up, and — when armed — the CPU profiler supplies the
73
+ * stack captured DURING it.
74
+ *
75
+ * Best-effort: never let diagnostics break the CLI.
76
+ */
77
+ async function startFreezeDiagnostics() {
78
+ try {
79
+ const { getLoopBlockThresholdMs, isLoopProfileEnabled } = await import("./utils/settings.js");
80
+ const { startEventLoopMonitor } = await import("./utils/event-loop-monitor.js");
81
+ const { logger } = await import("./utils/logger.js");
82
+ const thresholdMs = getLoopBlockThresholdMs();
83
+ if (thresholdMs <= 0)
84
+ return;
85
+ const profiler = isLoopProfileEnabled()
86
+ ? await (await import("./utils/loop-profiler.js")).createLoopProfiler()
87
+ : null;
88
+ if (profiler) {
89
+ // Bound segment size. Loop-driven ON PURPOSE: it cannot rotate during a
90
+ // block, so the segment covering a freeze survives to be captured.
91
+ const rotateTimer = setInterval(() => profiler.rotate(), 30_000);
92
+ rotateTimer.unref?.();
93
+ }
94
+ logger.info("cli", `[freeze] diagnostics armed (threshold ${thresholdMs}ms)`, {
95
+ thresholdMs,
96
+ profiler: profiler ? "on" : "off",
97
+ });
98
+ startEventLoopMonitor({
99
+ thresholdMs,
100
+ onBlock: (block) => {
101
+ logger.warn("cli", `[freeze] event loop blocked for ${block.blockedMs}ms — UI was frozen and no timer could fire`, {
102
+ blockedMs: block.blockedMs,
103
+ breadcrumb: block.breadcrumb,
104
+ detectedAt: block.detectedAt,
105
+ profiler: profiler ? "armed" : "off (set MUONROI_LOOP_PROFILE=1 for the culprit stack)",
106
+ });
107
+ if (!profiler)
108
+ return;
109
+ void profiler
110
+ .capture(block.breadcrumb ?? "unknown")
111
+ .then((res) => {
112
+ if (res) {
113
+ // The leaf is usually a native primitive (`now`, a regex step) —
114
+ // true but useless as a headline. Lead with the first frame that
115
+ // has a file:line, i.e. OUR code.
116
+ const suspect = res.hotStack.find((f) => !f.endsWith("(native)")) ?? res.hotStack[0];
117
+ logger.warn("cli", `[freeze] blocked in: ${suspect ?? "(unattributed)"}`, {
118
+ hotStack: res.hotStack,
119
+ file: res.file,
120
+ blockedMs: block.blockedMs,
121
+ });
122
+ }
123
+ })
124
+ .catch((err) => {
125
+ logger.error("cli", `[freeze] profile capture failed: ${err?.message}`, { error: err });
126
+ });
127
+ },
128
+ });
129
+ }
130
+ catch (err) {
131
+ // Diagnostics must never take the CLI down with them.
132
+ appendCrashLog("FREEZE_DIAG", err instanceof Error ? (err.stack ?? err.message) : String(err));
133
+ }
134
+ }
64
135
  process.on("uncaughtException", (err) => {
65
136
  appendCrashLog("UNCAUGHT", err.stack || err.message);
66
137
  console.error("Fatal:", err.message);
@@ -111,7 +182,7 @@ setRenderSink((lineOrChunk) => {
111
182
  // Provider console URLs are sourced from providers/capabilities.ts via ProviderCapabilities.consoleSignupURL().
112
183
  /**
113
184
  * Try to find an API key for the model the CLI is about to run with.
114
- * Resolution: env (legacy MUONROI_API_KEY) OS keychain → settings.json.
185
+ * Resolution: per-provider env var (env-store), else OAuth sentinel.
115
186
  * Returns null if nothing usable is configured anywhere.
116
187
  */
117
188
  async function resolveKeyForModel(modelId) {
@@ -154,188 +225,7 @@ async function hasOAuthForModel(modelId) {
154
225
  return false;
155
226
  }
156
227
  }
157
- /**
158
- * First-run wizard. If the keychain already has keys, prints a hint
159
- * (model probably doesn't match any stored provider). Otherwise prompts
160
- * for provider + key and persists to the OS keychain.
161
- */
162
- /**
163
- * Supported splash providers — mirrors SPLASH_PROVIDERS in ui/app.tsx.
164
- * The wizard only surfaces these; other providers still work programmatically.
165
- */
166
- const WIZARD_PROVIDERS = ["deepseek", "siliconflow"];
167
- async function firstRunWizard(currentModel) {
168
- let rl;
169
- try {
170
- rl = createInterface({ input: process.stdin, output: process.stderr });
171
- const ask = (q) => new Promise((resolve) => rl.question(q, (answer) => resolve(answer)));
172
- process.stderr.write("\nWelcome to muonroi-cli!\n\n");
173
- const stored = await listStoredProviders();
174
- if (stored.length > 0) {
175
- process.stderr.write(`Keys already in keychain for: ${stored.join(", ")}\n`);
176
- if (currentModel) {
177
- const provider = detectProviderForModel(currentModel);
178
- process.stderr.write(`Current model '${currentModel}' uses provider '${provider}', which has no stored key.\n`);
179
- }
180
- process.stderr.write("\nOptions:\n" +
181
- " 1. Run with a model that matches a stored provider:\n" +
182
- " muonroi-cli --model <model-id>\n" +
183
- " 2. Open /providers inside the TUI to add another key.\n" +
184
- " 3. muonroi-cli keys set <provider>\n\n");
185
- rl.close();
186
- return null;
187
- }
188
- process.stderr.write("Pick how you want to add credentials:\n\n");
189
- process.stderr.write(" 1. Paste an API key (most common)\n");
190
- process.stderr.write(" 2. Import an encrypted bundle file (from another device)\n");
191
- process.stderr.write(" 3. Sync from a Bitwarden vault\n");
192
- process.stderr.write(" 4. Skip — set up later via /providers inside the TUI\n\n");
193
- const actionChoice = (await ask("Choice [1-4, default 1]: ")).trim() || "1";
194
- if (actionChoice === "4") {
195
- process.stderr.write("\nSkipped. Open /providers inside the TUI to add a key any time.\n");
196
- rl.close();
197
- return null;
198
- }
199
- if (actionChoice === "2") {
200
- const file = (await ask("Path to bundle file: ")).trim();
201
- if (!file) {
202
- process.stderr.write("No file provided. Aborted.\n");
203
- rl.close();
204
- return null;
205
- }
206
- const passphrase = await ask("Bundle passphrase: ");
207
- try {
208
- const { readFileSync: readFile } = await import("node:fs");
209
- const { decryptBundle } = await import("./cli/keys-bundle.js");
210
- const raw = readFile(file, "utf8");
211
- const bundle = JSON.parse(raw);
212
- const payload = decryptBundle(bundle, passphrase);
213
- let imported = 0;
214
- for (const [prov, key] of Object.entries(payload.providers)) {
215
- if (!WIZARD_PROVIDERS.includes(prov))
216
- continue;
217
- if (typeof key !== "string" || key.length < 20)
218
- continue;
219
- const ok = await setKeyForProvider(prov, key);
220
- if (ok) {
221
- imported++;
222
- process.stderr.write(` ✓ ${prov} → keychain\n`);
223
- }
224
- }
225
- process.stderr.write(`\nImported ${imported} key(s). Launch the TUI to start.\n`);
226
- rl.close();
227
- // Return any imported key just so caller treats setup as done.
228
- return imported > 0 ? "imported" : null;
229
- }
230
- catch (err) {
231
- process.stderr.write(`\nImport failed: ${err.message}\n`);
232
- rl.close();
233
- return null;
234
- }
235
- }
236
- if (actionChoice === "3") {
237
- const password = await ask("Bitwarden master password: ");
238
- try {
239
- const { unlockWithPassword, listSecureNotesByPrefix } = await import("./cli/bw-vault.js");
240
- const unlock = await unlockWithPassword(password);
241
- if (!unlock.ok || !unlock.session) {
242
- process.stderr.write(`\nBitwarden unlock failed: ${unlock.error ?? "unknown error"}\n`);
243
- rl.close();
244
- return null;
245
- }
246
- const list = await listSecureNotesByPrefix(unlock.session, "muonroi-cli/");
247
- if (!list.ok) {
248
- process.stderr.write(`\nBitwarden list failed: ${list.error}\n`);
249
- rl.close();
250
- return null;
251
- }
252
- let imported = 0;
253
- for (const item of list.items) {
254
- const prov = item.name.slice("muonroi-cli/".length);
255
- if (!WIZARD_PROVIDERS.includes(prov))
256
- continue;
257
- if (item.notes.length < 20)
258
- continue;
259
- const ok = await setKeyForProvider(prov, item.notes);
260
- if (ok) {
261
- imported++;
262
- process.stderr.write(` ✓ ${prov} → keychain\n`);
263
- }
264
- }
265
- process.stderr.write(`\nImported ${imported} key(s) from Bitwarden. Launch the TUI to start.\n`);
266
- rl.close();
267
- return imported > 0 ? "imported" : null;
268
- }
269
- catch (err) {
270
- process.stderr.write(`\nBitwarden sync failed: ${err.message}\n`);
271
- rl.close();
272
- return null;
273
- }
274
- }
275
- // Default path: paste an API key for one of WIZARD_PROVIDERS.
276
- process.stderr.write("\nSupported providers:\n\n");
277
- WIZARD_PROVIDERS.forEach((p, i) => {
278
- process.stderr.write(` ${i + 1}. ${p.padEnd(12)} ${getProviderCapabilities(p).consoleSignupURL()}\n`);
279
- });
280
- process.stderr.write("\n");
281
- const choice = (await ask(`Provider [1-${WIZARD_PROVIDERS.length}, default 1]: `)).trim();
282
- const idx = choice ? Number.parseInt(choice, 10) - 1 : 0;
283
- if (!Number.isFinite(idx) || idx < 0 || idx >= WIZARD_PROVIDERS.length) {
284
- process.stderr.write("Invalid choice — aborted.\n");
285
- rl.close();
286
- return null;
287
- }
288
- const provider = WIZARD_PROVIDERS[idx];
289
- if (!provider) {
290
- process.stderr.write("Invalid choice — aborted.\n");
291
- rl.close();
292
- return null;
293
- }
294
- process.stderr.write(`\nGet a key here: ${getProviderCapabilities(provider).consoleSignupURL()}\n`);
295
- const raw = await ask(`Paste your ${provider} API key: `);
296
- const trimmed = raw.trim();
297
- if (!trimmed) {
298
- process.stderr.write("No key provided. Aborted.\n");
299
- rl.close();
300
- return null;
301
- }
302
- if (trimmed.length < 20) {
303
- process.stderr.write("Key looks too short (< 20 chars). Aborted.\n");
304
- rl.close();
305
- return null;
306
- }
307
- try {
308
- const ok = await setKeyForProvider(provider, trimmed);
309
- if (ok) {
310
- process.stderr.write(`\nStored ${provider} key in OS keychain.\n`);
311
- process.stderr.write("Tip: run 'muonroi-cli keys export ~/keys.json' to back up + move to other devices.\n");
312
- if (currentModel) {
313
- const currentProvider = detectProviderForModel(currentModel);
314
- if (currentProvider !== provider) {
315
- process.stderr.write(`\nNote: defaultModel '${currentModel}' is on '${currentProvider}'. ` +
316
- `Edit ~/.muonroi-cli/user-settings.json or rerun with --model to use ${provider}.\n`);
317
- }
318
- }
319
- }
320
- else {
321
- process.stderr.write("\nOS keychain unavailable (keytar or secret service backend).\n" +
322
- "Linux: sudo dnf install libsecret (Fedora) or sudo apt-get install libsecret-1-0 (Ubuntu).\n" +
323
- "Key will be used for this session only. For persistence across runs:\n" +
324
- ` export ${provider.toUpperCase()}_API_KEY=...\n`);
325
- }
326
- }
327
- catch (err) {
328
- process.stderr.write(`\nWarning: failed to store key in keychain: ${err.message}\n`);
329
- }
330
- rl.close();
331
- return trimmed;
332
- }
333
- catch {
334
- rl?.close();
335
- return null;
336
- }
337
- }
338
- async function startInteractive(apiKey, baseURL, model, maxToolRounds, batchApi, session, initialMessage, permissionMode = "safe", injectHalt = false) {
228
+ async function startInteractive(apiKey, baseURL, model, maxToolRounds, batchApi, session, initialMessage, permissionMode = "safe", injectHalt = false, injectHaltSprint = false) {
339
229
  // ── Plan 00-07 boot order ──────────────────────────────────────────────────
340
230
  // 1. redactor.installGlobalPatches() — already at top of file (line 6).
341
231
  // 2. loadConfig + loadUsage (validates storage paths, logs usage cap state).
@@ -401,6 +291,14 @@ async function startInteractive(apiKey, baseURL, model, maxToolRounds, batchApi,
401
291
  const { warmMcpClients } = await import("./mcp/client-pool.js");
402
292
  const { loadMcpServers } = await import("./utils/settings.js");
403
293
  await warmMcpClients(loadMcpServers(), !session);
294
+ // Register a factory for every credentialed provider, not just the session's.
295
+ // A model resolved for another provider (compaction, classify, a sub-agent,
296
+ // a mode-specific model) can then be routed to ITS OWN endpoint instead of
297
+ // being POSTed to the session provider's — the 404 in session 0c6728ba1a25
298
+ // (`gpt-5.4` → api.x.ai) existed only because the openai factory this
299
+ // redirect needs had never been built. Best-effort: never blocks boot.
300
+ const { warmProviderFactories } = await import("./providers/warm.js");
301
+ await warmProviderFactories();
404
302
  const agent = new Agent(apiKey, baseURL, model, maxToolRounds, {
405
303
  session,
406
304
  batchApi,
@@ -416,6 +314,14 @@ async function startInteractive(apiKey, baseURL, model, maxToolRounds, batchApi,
416
314
  const { relaunchWithSession } = await import("./ui/utils/relaunch.js");
417
315
  const renderer = await createCliRenderer({
418
316
  exitOnCtrlC: false,
317
+ // OpenTUI defaults openConsoleOnError:true — its process-level
318
+ // unhandledRejection/uncaughtException handler then calls console.show(),
319
+ // which focuses the debug console overlay and captures ALL keypresses.
320
+ // The overlay's keybindings have no hide/close action, so a stray rejection
321
+ // (e.g. a provider dropping a streaming socket) traps the user in a console
322
+ // they cannot dismiss. We surface errors in-band instead — keep it off.
323
+ // Toggle it deliberately with F12 (wired below).
324
+ openConsoleOnError: false,
419
325
  // We manage SIGINT ourselves (orchestrator abort → agent cleanup → renderer destroy).
420
326
  // Prevent OpenTUI from registering its own SIGINT/SIGTERM handler which would
421
327
  // call renderer.destroy() prematurely and race with our orderly shutdown.
@@ -426,10 +332,33 @@ async function startInteractive(apiKey, baseURL, model, maxToolRounds, batchApi,
426
332
  alternateKeys: true,
427
333
  },
428
334
  });
335
+ // Agent-mode: hand the renderer to the harness so it can snapshot the ACTUAL
336
+ // rendered cell grid (colors + attributes) via VisualFrame, not just the
337
+ // semantic tree. No-op outside agent-mode (runtime undefined).
338
+ {
339
+ const agentRt = globalThis.__muonroiAgentRuntime;
340
+ agentRt?.attachRenderer?.(renderer);
341
+ }
429
342
  // The TUI now owns the terminal — route fatal-handler behaviour away from
430
343
  // process.exit(1) (see the unhandledRejection handler above). Cleared in
431
344
  // restoreTerminalSync() the moment we begin tearing the terminal back down.
432
345
  setTuiActive(true);
346
+ // Armed only once the TUI owns the terminal: this hunts a freeze of the
347
+ // interactive session, and the logger only routes to debug.log (instead of
348
+ // stdout, which would corrupt the framebuffer) once the TUI is active.
349
+ await startFreezeDiagnostics();
350
+ // Deliberate debug-console toggle. With openConsoleOnError:false the overlay
351
+ // never auto-pops, so F12 is the ONLY way in — and, crucially, back out:
352
+ // console.toggle() hides it when it is visible+focused, so it can never trap.
353
+ try {
354
+ renderer.keyInput?.on("keypress", (key) => {
355
+ if (key?.name === "f12")
356
+ renderer.console.toggle();
357
+ });
358
+ }
359
+ catch {
360
+ /* keyInput/console are best-effort dev affordances — never block boot */
361
+ }
433
362
  /**
434
363
  * Restore terminal to main-screen mode before the process exits.
435
364
  *
@@ -616,6 +545,7 @@ async function startInteractive(apiKey, baseURL, model, maxToolRounds, batchApi,
616
545
  maxToolRounds,
617
546
  version: packageJson.version,
618
547
  injectHalt,
548
+ injectHaltSprint,
619
549
  },
620
550
  initialMessage,
621
551
  onExit,
@@ -733,7 +663,7 @@ async function runBackgroundDelegation(jobPath, options) {
733
663
  const model = explicitModel ? normalizeModelId(explicitModel) : undefined;
734
664
  // Resolve API key: explicit flag > legacy env/settings.apiKey > per-provider keychain
735
665
  // (matches the foreground flow — delegations were previously broken when the user
736
- // only had a per-provider key in the OS keychain, e.g. deepseek.)
666
+ // only had a per-provider key in the environment, e.g. deepseek.)
737
667
  let apiKey = stringOption(options.apiKey) || getApiKey();
738
668
  if (!apiKey) {
739
669
  const modelForResolve = model ?? delegation.model ?? getCurrentModel("agent");
@@ -802,8 +732,8 @@ function resolveConfig(options) {
802
732
  // flag or MUONROI_MAX_TOOL_ROUNDS env.
803
733
  const maxToolRounds = parseInt(stringOption(options.maxToolRounds) || "100", 10) || 100;
804
734
  if (typeof options.apiKey === "string" && process.env.MUONROI_TEST_NO_PERSIST !== "1") {
805
- // Persist to OS keychain (per-provider) instead of plaintext settings.json.
806
- // Fire-and-forget: keychain write is async; if it fails (no keytar), the key still
735
+ // Persist to the env-store (per-provider) instead of plaintext settings.json.
736
+ // Fire-and-forget: env-store write is sync; the key is also set in process.env so it
807
737
  // works for this run via `apiKey` above and the user can re-supply it next invocation.
808
738
  void persistApiKeyToKeychain(options.apiKey, stringOption(options.model)).catch(() => { });
809
739
  }
@@ -852,6 +782,7 @@ program
852
782
  .option("--agent-fake-clock", "Use deterministic frame-counter clock")
853
783
  .option("--mock-llm <dir>", "Use fixture-based mock LLM from <dir> instead of real provider (E2E testing)")
854
784
  .option("--inject-halt", "TEST SEAM: render a synthetic halt recovery card after boot (harness E2E only)")
785
+ .option("--inject-halt-sprint", "TEST SEAM: render a synthetic sprint-failed recovery card after boot (harness E2E only)")
855
786
  .action(async (message, options) => {
856
787
  // Agent-mode: start the sidechannel runtime BEFORE any TUI or model work.
857
788
  // The runtime is exposed on globalThis so the renderer wiring (Task 1.6c)
@@ -978,50 +909,51 @@ program
978
909
  }
979
910
  changeDirectoryOrExit(options.directory);
980
911
  // Boot model registry BEFORE any key resolution path runs —
981
- // detectProviderForModel consults the catalog's alias map to route e.g.
982
- // "deepseek-v4-flash" to provider "siliconflow". With an empty registry
983
- // it falls back to a prefix match ("deepseek") and the CLI loads the
984
- // wrong provider's key. Affects both runBackgroundDelegation and the
985
- // main interactive/headless path below.
912
+ // detectProviderForModel consults the catalog's alias map to route model
913
+ // ids to the correct provider. With an empty registry it falls back to a
914
+ // prefix match and the CLI may load the wrong provider's key. Affects both
915
+ // runBackgroundDelegation and the main interactive/headless path below.
986
916
  let catalogLoadFailed = false;
987
917
  await loadCatalog().catch(() => {
988
918
  catalogLoadFailed = true;
989
919
  });
920
+ // Load the env-store (~/.muonroi-cli/.env) into process.env and migrate any
921
+ // legacy keychain/settings keys BEFORE any key resolution. Best-effort.
922
+ try {
923
+ const { loadEnvFileIntoProcess } = await import("./providers/env-store.js");
924
+ loadEnvFileIntoProcess();
925
+ const { migrateLegacyKeysToEnv } = await import("./providers/keychain.js");
926
+ await migrateLegacyKeysToEnv();
927
+ }
928
+ catch (err) {
929
+ console.error(`[muonroi-cli] env-store init failed: ${err instanceof Error ? err.message : String(err)}`);
930
+ }
990
931
  if (options.backgroundTaskFile) {
991
932
  await runBackgroundDelegation(options.backgroundTaskFile, options);
992
933
  return;
993
934
  }
994
935
  const config = resolveConfig(options);
995
- // No legacy key in env / settings try the OS keychain for the resolved
996
- // model's provider before falling back to the wizard.
997
- if (!config.apiKey) {
936
+ // One auth mode per provider (OAuth XOR API key): if the resolved model's
937
+ // provider has an OAuth token, OAuth wins OUTRIGHT — a stored API key
938
+ // (env/flag/settings) is ignored, never blended. Only when there is no
939
+ // OAuth token do we fall back to the provider's env API key. The "oauth"
940
+ // sentinel satisfies downstream gating (which only checks for a truthy
941
+ // apiKey); the runtime injects Bearer headers.
942
+ {
998
943
  const modelForResolve = config.model ?? getCurrentModel("agent");
999
- const keychainKey = await resolveKeyForModel(modelForResolve);
1000
- if (keychainKey) {
1001
- config.apiKey = keychainKey;
1002
- }
1003
- else if (await hasOAuthForModel(modelForResolve)) {
1004
- // OAuth-authenticated provider — runtime will inject Bearer headers.
1005
- // Set placeholder so downstream gating code (which only checks for
1006
- // a truthy apiKey) is satisfied.
944
+ if (await hasOAuthForModel(modelForResolve)) {
1007
945
  config.apiKey = "oauth";
1008
946
  }
1009
- }
1010
- // First-run wizard (interactive only, before any TUI code)
1011
- const isInteractive = !options.prompt && !options.verify && process.stdin.isTTY;
1012
- if (!config.apiKey && isInteractive) {
1013
- const modelForWizard = config.model ?? getCurrentModel("agent");
1014
- const wizardKey = await firstRunWizard(modelForWizard);
1015
- if (wizardKey) {
1016
- // Key is already persisted to the OS keychain by the wizard. We DO NOT
1017
- // write it back to settings.json (avoids resurrecting plaintext that
1018
- // 'keys cleanup-settings' just removed).
1019
- config.apiKey = wizardKey;
1020
- }
1021
- else {
1022
- process.exit(1);
947
+ else if (!config.apiKey) {
948
+ const envKey = await resolveKeyForModel(modelForResolve);
949
+ if (envKey)
950
+ config.apiKey = envKey;
1023
951
  }
1024
952
  }
953
+ // First run with no credentials does NOT block: boot straight into the TUI.
954
+ // The in-chat provider picker (/providers) handles auth on demand.
955
+ // Headless (`--prompt`/`--verify`) with no key still fails via requireApiKey.
956
+ const isInteractive = !options.prompt && !options.verify && process.stdin.isTTY;
1025
957
  // Bootstrap EE auth (loads serverBaseUrl + token from ~/.experience/config.json)
1026
958
  const { loadEEAuthToken, getCachedServerBaseUrl } = await import("./ee/auth.js");
1027
959
  await loadEEAuthToken().catch(() => { });
@@ -1049,10 +981,15 @@ program
1049
981
  // so each request doesn't re-probe.
1050
982
  const { detectEEClientMode, describeMode } = await import("./ee/client-mode.js");
1051
983
  detectEEClientMode()
1052
- .then((info) => {
984
+ .then(async (info) => {
1053
985
  if (process.env.MUONROI_EE_DEBUG === "1") {
1054
986
  console.error(`[muonroi-cli] ${describeMode(info)}`);
1055
987
  }
988
+ // WhoAmI thin-client fallback: once the mode is cached, derive the working-style
989
+ // profile from the behavioral brain and prime the sync cache so the PIL picks it
990
+ // up from the next turn. Fire-and-forget, fail-open — never blocks boot.
991
+ const { warmWhoAmIFromBrain } = await import("./ee/bridge.js");
992
+ await warmWhoAmIFromBrain();
1056
993
  })
1057
994
  .catch(() => { });
1058
995
  // Patch zod-to-json-schema for Zod v4 compat (fixes tool calls for DeepSeek etc.)
@@ -1130,7 +1067,7 @@ program
1130
1067
  return;
1131
1068
  }
1132
1069
  const initialMessage = message.length > 0 ? message.join(" ") : undefined;
1133
- await startInteractive(config.apiKey, config.baseURL, config.model, config.maxToolRounds, options.batchApi === true, options.session, initialMessage, options.permission, options.injectHalt === true);
1070
+ await startInteractive(config.apiKey, config.baseURL, config.model, config.maxToolRounds, options.batchApi === true, options.session, initialMessage, options.permission, options.injectHalt === true, options.injectHaltSprint === true);
1134
1071
  });
1135
1072
  program
1136
1073
  .command("models")
@@ -1220,41 +1157,31 @@ program
1220
1157
  });
1221
1158
  const keys = program
1222
1159
  .command("keys")
1223
- .description("Manage provider API keys via the OS keychain (set, list, delete, import-bw)");
1160
+ .description("Manage provider API keys as environment variables (set, list, delete)");
1224
1161
  keys
1225
1162
  .command("set <provider>")
1226
- .description("Prompt for a provider API key and store it in the OS keychain")
1227
- .option("--bw", "Also write the key to a Bitwarden vault Secure Note (requires bw CLI + BW_SESSION)")
1228
- .option("--prefix <prefix>", "Bitwarden item name prefix when --bw is set (default: 'muonroi-cli/')", "muonroi-cli/")
1229
- .action(async (provider, opts) => {
1163
+ .description("Prompt for a provider API key and store it as an environment variable")
1164
+ .action(async (provider) => {
1230
1165
  const { runKeysSet } = await import("./cli/keys.js");
1231
- await runKeysSet(provider, { bw: opts.bw, itemPrefix: opts.prefix });
1166
+ await runKeysSet(provider);
1232
1167
  });
1233
1168
  keys
1234
1169
  .command("list")
1235
- .description("Show provider keys currently stored in the OS keychain (masked)")
1170
+ .description("Show provider keys currently set in the environment (masked)")
1236
1171
  .action(async () => {
1237
1172
  const { runKeysList } = await import("./cli/keys.js");
1238
1173
  await runKeysList();
1239
1174
  });
1240
1175
  keys
1241
1176
  .command("delete <provider>")
1242
- .description("Delete a stored provider key from the OS keychain")
1177
+ .description("Delete a stored provider key from the environment")
1243
1178
  .action(async (provider) => {
1244
1179
  const { runKeysDelete } = await import("./cli/keys.js");
1245
1180
  await runKeysDelete(provider);
1246
1181
  });
1247
- keys
1248
- .command("import-bw [providers...]")
1249
- .description("Import keys from a Bitwarden vault into the OS keychain (requires bw CLI + BW_SESSION)")
1250
- .option("--prefix <prefix>", "Vault item name prefix (default: 'muonroi-cli/')", "muonroi-cli/")
1251
- .action(async (providers, opts) => {
1252
- const { runKeysImportBw } = await import("./cli/keys.js");
1253
- await runKeysImportBw({ providers, itemPrefix: opts.prefix });
1254
- });
1255
1182
  keys
1256
1183
  .command("login <provider>")
1257
- .description("Log in to a provider via OAuth subscription (supported: openai, google/agy, xai). 'google'/'agy' now uses agy client creds.")
1184
+ .description("Log in to a provider via OAuth subscription (supported: openai, xai).")
1258
1185
  .action(async (provider) => {
1259
1186
  const { runKeysLogin } = await import("./cli/keys.js");
1260
1187
  await runKeysLogin(provider);
@@ -1268,28 +1195,21 @@ keys
1268
1195
  });
1269
1196
  keys
1270
1197
  .command("export <file>")
1271
- .description("Export all keychain keys to an encrypted portable bundle (move between devices)")
1198
+ .description("Export all provider keys to an encrypted portable bundle (move between devices)")
1272
1199
  .action(async (file) => {
1273
1200
  const { runKeysExport } = await import("./cli/keys.js");
1274
1201
  await runKeysExport(file);
1275
1202
  });
1276
1203
  keys
1277
1204
  .command("import <file>")
1278
- .description("Import an encrypted bundle into the OS keychain (created by 'keys export')")
1205
+ .description("Import an encrypted bundle of provider keys (created by 'keys export')")
1279
1206
  .action(async (file) => {
1280
1207
  const { runKeysImport } = await import("./cli/keys.js");
1281
1208
  await runKeysImport(file);
1282
1209
  });
1283
- keys
1284
- .command("cleanup-settings")
1285
- .description("Strip plaintext API keys out of ~/.muonroi-cli/user-settings.json after migrating to keychain")
1286
- .action(async () => {
1287
- const { runKeysCleanupSettings } = await import("./cli/keys.js");
1288
- await runKeysCleanupSettings();
1289
- });
1290
1210
  keys
1291
1211
  .command("set-chat <id>")
1292
- .description("Set a chat-service secret (discord-token, discord-guild-id, slack-token, slack-team-id) in the OS keychain")
1212
+ .description("Set a chat-service secret (discord-token, discord-guild-id, slack-token, slack-team-id) in the environment")
1293
1213
  .action(async (id) => {
1294
1214
  const { runChatKeySet } = await import("./cli/keys.js");
1295
1215
  if (!["discord-token", "discord-guild-id", "slack-token", "slack-team-id"].includes(id)) {
@@ -1309,14 +1229,6 @@ keys
1309
1229
  }
1310
1230
  await runChatKeySet(id, value);
1311
1231
  });
1312
- keys
1313
- .command("import-bw-chat [ids...]")
1314
- .option("--prefix <prefix>", "BW item name prefix", "muonroi-cli/chat-")
1315
- .description("Import chat-service secrets from Bitwarden vault into OS keychain")
1316
- .action(async (ids, opts) => {
1317
- const { runChatImportBw } = await import("./cli/keys.js");
1318
- await runChatImportBw({ ids: ids.length > 0 ? ids : undefined, itemPrefix: opts.prefix });
1319
- });
1320
1232
  const usage = program.command("usage").description("Inspect cost ledger and find spend bloat");
1321
1233
  usage
1322
1234
  .command("report")
@@ -1391,7 +1303,7 @@ usage
1391
1303
  const mcp = program.command("mcp").description("Manage MCP server configuration");
1392
1304
  mcp
1393
1305
  .command("setup-research")
1394
- .description("Configure web research MCP servers (context7, fetch, tavily)")
1306
+ .description("Configure web research (native fetch_url + web_search; optional MCPs for context7/muonroi-docs)")
1395
1307
  .action(async () => {
1396
1308
  const rl = createInterface({ input: process.stdin, output: process.stderr });
1397
1309
  const ask = (q) => new Promise((resolve) => rl.question(q, (a) => resolve(a)));
@@ -1410,20 +1322,10 @@ mcp
1410
1322
  });
1411
1323
  mcp
1412
1324
  .command("set <id>")
1413
- .description("Prompt for an MCP API key (e.g. tavily) and store it in the OS keychain")
1414
- .option("--bw", "Also write the key to a Bitwarden vault Secure Note (requires bw CLI + BW_SESSION)")
1415
- .option("--prefix <prefix>", "Bitwarden item name prefix when --bw is set (default: 'muonroi-cli/')", "muonroi-cli/")
1416
- .action(async (id, opts) => {
1325
+ .description("Prompt for an MCP API key (e.g. tavily) and store it as an environment variable")
1326
+ .action(async (id) => {
1417
1327
  const { runMcpKeysSet } = await import("./cli/keys.js");
1418
- await runMcpKeysSet(id, { bw: opts.bw, itemPrefix: opts.prefix });
1419
- });
1420
- mcp
1421
- .command("import-bw [keys...]")
1422
- .description("Import MCP secrets (e.g. tavily) from a Bitwarden vault into the OS keychain (requires bw CLI + BW_SESSION)")
1423
- .option("--prefix <prefix>", "Vault item name prefix (default: 'muonroi-cli/')", "muonroi-cli/")
1424
- .action(async (keys, opts) => {
1425
- const { runMcpImportBw } = await import("./cli/keys.js");
1426
- await runMcpImportBw({ keys, itemPrefix: opts.prefix });
1328
+ await runMcpKeysSet(id);
1427
1329
  });
1428
1330
  program
1429
1331
  .command("mcp-driver")
@@ -342,7 +342,9 @@ async function resolveNodeServerLaunch(root, binary, packageName, baseArgs, auto
342
342
  }
343
343
  if (!autoInstall)
344
344
  return null;
345
- const cached = await lspNpmWhich(packageName);
345
+ // Pass `binary` explicitly: a package can ship several bins and the one named
346
+ // after the package is not always the language server (see lspNpmWhich).
347
+ const cached = await lspNpmWhich(packageName, binary);
346
348
  if (cached) {
347
349
  return { command: cached, args: baseArgs };
348
350
  }
@@ -1,6 +1,6 @@
1
1
  import { type RuntimeLspServerDefinition } from "./builtins.js";
2
2
  import { type LspClientSession } from "./client.js";
3
- import type { LspDiagnosticFile, LspQueryInput, LspToolResponse, NormalizedLspSettings } from "./types.js";
3
+ import type { ImpactOfChangeResult, LspDiagnosticFile, LspQueryInput, LspQueryResult, LspToolResponse, MutationPreviewResult, NormalizedLspSettings, PolicyAction } from "./types.js";
4
4
  interface WorkspaceLspManagerOptions {
5
5
  createClient?: (input: {
6
6
  serverId: string;
@@ -13,6 +13,10 @@ export interface WorkspaceLspManager {
13
13
  touchFile(filePath: string, waitForDiagnostics?: boolean): Promise<LspDiagnosticFile[]>;
14
14
  syncFile(filePath: string, content: string, save?: boolean, waitForDiagnostics?: boolean, diagnosticsTimeoutMs?: number): Promise<LspDiagnosticFile[]>;
15
15
  query(input: LspQueryInput): Promise<LspToolResponse>;
16
+ waitForDiagnostics(filePath: string, timeout: number): Promise<LspQueryResult>;
17
+ impactOfChange(filePath: string, query?: string, timeout?: number): Promise<ImpactOfChangeResult>;
18
+ lspMutationPreview(filePath: string, change: string): Promise<MutationPreviewResult>;
19
+ lspBeforeGrep(filePath: string, query?: string): Promise<PolicyAction>;
16
20
  close(): Promise<void>;
17
21
  }
18
22
  export declare function createWorkspaceLspManager(cwd: string, settings: NormalizedLspSettings, options?: WorkspaceLspManagerOptions): WorkspaceLspManager;