muonroi-cli 1.7.1 → 1.8.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 (328) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +122 -122
  3. package/dist/packages/agent-harness-core/src/event-filter.js +1 -0
  4. package/dist/packages/agent-harness-core/src/event-redact.js +8 -0
  5. package/dist/packages/agent-harness-core/src/mcp-server.d.ts +16 -0
  6. package/dist/packages/agent-harness-core/src/mcp-server.js +88 -10
  7. package/dist/packages/agent-harness-core/src/protocol.d.ts +15 -0
  8. package/dist/packages/agent-harness-core/src/selector.js +2 -2
  9. package/dist/packages/agent-harness-core/src/transports/sidechannel.js +1 -1
  10. package/dist/packages/agent-harness-opentui/src/agent-mode.js +1 -1
  11. package/dist/packages/agent-harness-opentui/src/install.js +1 -1
  12. package/dist/src/__test-stubs__/vitest-setup.js +4 -0
  13. package/dist/src/agent-harness/__tests__/mock-model.spec.js +54 -0
  14. package/dist/src/agent-harness/mock-model.d.ts +1 -1
  15. package/dist/src/agent-harness/mock-model.js +32 -3
  16. package/dist/src/agent-harness/test-spawn.js +3 -1
  17. package/dist/src/chat/chat-keychain.js +9 -1
  18. package/dist/src/cli/cost-forensics.js +12 -12
  19. package/dist/src/cli/keys.d.ts +2 -2
  20. package/dist/src/cli/keys.js +107 -28
  21. package/dist/src/cli/usage-report.js +2 -2
  22. package/dist/src/council/__tests__/abort-threading.test.d.ts +1 -0
  23. package/dist/src/council/__tests__/abort-threading.test.js +193 -0
  24. package/dist/src/council/__tests__/clarification-prompt.test.js +21 -1
  25. package/dist/src/council/__tests__/council-turn-length-emit.test.d.ts +1 -0
  26. package/dist/src/council/__tests__/council-turn-length-emit.test.js +130 -0
  27. package/dist/src/council/__tests__/debate-round-budget.test.d.ts +1 -0
  28. package/dist/src/council/__tests__/debate-round-budget.test.js +45 -0
  29. package/dist/src/council/__tests__/evaluator-metrics.test.js +3 -0
  30. package/dist/src/council/__tests__/post-debate-recommendation.test.d.ts +1 -0
  31. package/dist/src/council/__tests__/post-debate-recommendation.test.js +58 -0
  32. package/dist/src/council/__tests__/research-tools.test.js +4 -0
  33. package/dist/src/council/__tests__/round-tools.test.js +6 -0
  34. package/dist/src/council/clarifier-question-cap.test.d.ts +12 -0
  35. package/dist/src/council/clarifier-question-cap.test.js +73 -0
  36. package/dist/src/council/clarifier.d.ts +29 -1
  37. package/dist/src/council/clarifier.js +64 -1
  38. package/dist/src/council/debate-planner.d.ts +2 -1
  39. package/dist/src/council/debate-planner.js +5 -3
  40. package/dist/src/council/debate.d.ts +9 -0
  41. package/dist/src/council/debate.js +88 -8
  42. package/dist/src/council/index.d.ts +46 -1
  43. package/dist/src/council/index.js +125 -19
  44. package/dist/src/council/llm.js +41 -13
  45. package/dist/src/council/prompts.js +56 -21
  46. package/dist/src/council/types.d.ts +14 -1
  47. package/dist/src/ee/__tests__/export-transcripts.test.js +1 -1
  48. package/dist/src/ee/bridge.d.ts +3 -1
  49. package/dist/src/ee/bridge.js +9 -3
  50. package/dist/src/ee/bridge.test.js +1 -2
  51. package/dist/src/ee/client.js +15 -2
  52. package/dist/src/ee/recall-ledger.d.ts +20 -0
  53. package/dist/src/ee/recall-ledger.js +40 -1
  54. package/dist/src/ee/search.d.ts +25 -0
  55. package/dist/src/ee/search.js +73 -0
  56. package/dist/src/ee/types.d.ts +15 -1
  57. package/dist/src/ee/who-am-i.d.ts +41 -0
  58. package/dist/src/ee/who-am-i.js +143 -0
  59. package/dist/src/ee/who-am-i.test.d.ts +1 -0
  60. package/dist/src/ee/who-am-i.test.js +101 -0
  61. package/dist/src/generated/version.d.ts +1 -1
  62. package/dist/src/generated/version.js +1 -1
  63. package/dist/src/headless/council-answers.js +1 -0
  64. package/dist/src/headless/output.d.ts +30 -1
  65. package/dist/src/headless/output.js +180 -0
  66. package/dist/src/headless/output.test.js +61 -1
  67. package/dist/src/hooks/index.js +48 -2
  68. package/dist/src/index.d.ts +2 -0
  69. package/dist/src/index.js +143 -104
  70. package/dist/src/lsp/client-normalize.test.d.ts +12 -0
  71. package/dist/src/lsp/client-normalize.test.js +34 -0
  72. package/dist/src/lsp/client.d.ts +1 -0
  73. package/dist/src/lsp/client.js +10 -2
  74. package/dist/src/lsp/manager.d.ts +1 -1
  75. package/dist/src/lsp/manager.js +2 -2
  76. package/dist/src/lsp/manager.test.js +2 -2
  77. package/dist/src/lsp/runtime.d.ts +1 -1
  78. package/dist/src/lsp/runtime.js +2 -2
  79. package/dist/src/maintain/__tests__/gh-create-pr.test.js +7 -3
  80. package/dist/src/maintain/__tests__/pr-builder.test.js +7 -3
  81. package/dist/src/mcp/__tests__/client-pool.spec.js +3 -3
  82. package/dist/src/mcp/__tests__/ee-tools.test.js +42 -14
  83. package/dist/src/mcp/__tests__/forensics-tools.test.js +3 -3
  84. package/dist/src/mcp/__tests__/lsp-tools.test.js +4 -4
  85. package/dist/src/mcp/client-pool.d.ts +1 -1
  86. package/dist/src/mcp/client-pool.js +25 -9
  87. package/dist/src/mcp/ee-tools.d.ts +10 -0
  88. package/dist/src/mcp/ee-tools.js +34 -0
  89. package/dist/src/mcp/oauth-callback.js +2 -2
  90. package/dist/src/mcp/parse-headers.test.js +14 -14
  91. package/dist/src/mcp/self-verify-jobs.js +1 -3
  92. package/dist/src/mcp/setup-guide-text.js +74 -74
  93. package/dist/src/mcp/smoke.test.js +43 -43
  94. package/dist/src/models/catalog-gemini.test.js +12 -10
  95. package/dist/src/models/catalog.json +106 -38
  96. package/dist/src/ops/doctor.js +7 -7
  97. package/dist/src/orchestrator/__tests__/auto-commit.test.d.ts +1 -0
  98. package/dist/src/orchestrator/__tests__/auto-commit.test.js +142 -0
  99. package/dist/src/orchestrator/__tests__/batch-turn-runner.test.js +2 -0
  100. package/dist/src/orchestrator/__tests__/delegations.test.d.ts +1 -0
  101. package/dist/src/orchestrator/__tests__/delegations.test.js +96 -0
  102. package/dist/src/orchestrator/__tests__/message-processor.test.js +1 -0
  103. package/dist/src/orchestrator/__tests__/stream-runner.test.js +29 -0
  104. package/dist/src/orchestrator/agent.test.js +5 -2
  105. package/dist/src/orchestrator/auto-commit.d.ts +110 -0
  106. package/dist/src/orchestrator/auto-commit.js +364 -0
  107. package/dist/src/orchestrator/batch-turn-runner.d.ts +3 -2
  108. package/dist/src/orchestrator/batch-turn-runner.js +2 -1
  109. package/dist/src/orchestrator/compaction-proposer-prompt.d.ts +8 -0
  110. package/dist/src/orchestrator/compaction-proposer-prompt.js +43 -0
  111. package/dist/src/orchestrator/compaction.d.ts +22 -0
  112. package/dist/src/orchestrator/compaction.js +42 -0
  113. package/dist/src/orchestrator/delegations.d.ts +1 -0
  114. package/dist/src/orchestrator/delegations.js +41 -0
  115. package/dist/src/orchestrator/error-utils.js +27 -2
  116. package/dist/src/orchestrator/message-processor.d.ts +21 -5
  117. package/dist/src/orchestrator/message-processor.js +219 -2573
  118. package/dist/src/orchestrator/orchestrator.d.ts +8 -2
  119. package/dist/src/orchestrator/orchestrator.js +187 -34
  120. package/dist/src/orchestrator/preprocessor.d.ts +13 -0
  121. package/dist/src/orchestrator/preprocessor.js +145 -0
  122. package/dist/src/orchestrator/prompts.d.ts +8 -0
  123. package/dist/src/orchestrator/prompts.js +76 -60
  124. package/dist/src/orchestrator/safety-askcard.d.ts +66 -0
  125. package/dist/src/orchestrator/safety-askcard.js +74 -0
  126. package/dist/src/orchestrator/sandbox.test.js +8 -5
  127. package/dist/src/orchestrator/scope-ceiling.js +1 -1
  128. package/dist/src/orchestrator/stall-watchdog.d.ts +47 -0
  129. package/dist/src/orchestrator/stall-watchdog.js +23 -0
  130. package/dist/src/orchestrator/stall-watchdog.test.js +36 -1
  131. package/dist/src/orchestrator/stream-runner.js +52 -30
  132. package/dist/src/orchestrator/sub-agent-model-tier.js +1 -1
  133. package/dist/src/orchestrator/subagent-compactor.d.ts +14 -0
  134. package/dist/src/orchestrator/subagent-compactor.js +83 -10
  135. package/dist/src/orchestrator/subagent-compactor.spec.js +132 -0
  136. package/dist/src/orchestrator/text-tool-call-detector.d.ts +9 -5
  137. package/dist/src/orchestrator/text-tool-call-detector.js +16 -12
  138. package/dist/src/orchestrator/text-tool-call-detector.test.js +66 -8
  139. package/dist/src/orchestrator/tool-args-repair.js +1 -1
  140. package/dist/src/orchestrator/tool-engine.d.ts +151 -0
  141. package/dist/src/orchestrator/tool-engine.js +3079 -0
  142. package/dist/src/orchestrator/turn-runner-deps.d.ts +1 -0
  143. package/dist/src/pil/__tests__/discovery-types.test.js +15 -4
  144. package/dist/src/pil/__tests__/discovery.test.js +89 -145
  145. package/dist/src/pil/__tests__/dual-run.test.js +2 -0
  146. package/dist/src/pil/__tests__/layer1-intent-trace.test.js +3 -0
  147. package/dist/src/pil/__tests__/layer1-intent.test.js +3 -0
  148. package/dist/src/pil/__tests__/layer16-clarity.test.js +35 -32
  149. package/dist/src/pil/__tests__/layer18-acceptance.test.js +1 -78
  150. package/dist/src/pil/__tests__/layer2_5-ponytail.test.d.ts +1 -0
  151. package/dist/src/pil/__tests__/layer2_5-ponytail.test.js +53 -0
  152. package/dist/src/pil/__tests__/layer3-ee-injection.test.js +67 -4
  153. package/dist/src/pil/__tests__/layer3-injected-chunk.test.js +14 -2
  154. package/dist/src/pil/__tests__/layer4-gsd.test.js +30 -0
  155. package/dist/src/pil/__tests__/layer5-context.test.js +39 -1
  156. package/dist/src/pil/__tests__/layer6-output.test.js +30 -2
  157. package/dist/src/pil/__tests__/orchestrator-integration.test.js +3 -1
  158. package/dist/src/pil/__tests__/pipeline.test.js +11 -8
  159. package/dist/src/pil/__tests__/response-tools.test.js +52 -0
  160. package/dist/src/pil/agent-operating-contract.d.ts +1 -1
  161. package/dist/src/pil/agent-operating-contract.js +5 -3
  162. package/dist/src/pil/agent-operating-contract.test.js +2 -2
  163. package/dist/src/pil/cheap-model-playbook.d.ts +1 -1
  164. package/dist/src/pil/cheap-model-playbook.js +1 -1
  165. package/dist/src/pil/cheap-model-workbooks.d.ts +1 -1
  166. package/dist/src/pil/cheap-model-workbooks.js +1 -1
  167. package/dist/src/pil/config.d.ts +20 -0
  168. package/dist/src/pil/config.js +35 -0
  169. package/dist/src/pil/discovery-types.d.ts +32 -9
  170. package/dist/src/pil/discovery.d.ts +3 -3
  171. package/dist/src/pil/discovery.js +138 -244
  172. package/dist/src/pil/index.d.ts +1 -1
  173. package/dist/src/pil/index.js +1 -1
  174. package/dist/src/pil/layer1-intent.d.ts +9 -1
  175. package/dist/src/pil/layer1-intent.js +99 -44
  176. package/dist/src/pil/layer1-intent.test.js +112 -2
  177. package/dist/src/pil/layer15-context-scan.js +1 -1
  178. package/dist/src/pil/layer16-clarity.d.ts +21 -25
  179. package/dist/src/pil/layer16-clarity.js +52 -88
  180. package/dist/src/pil/layer18-acceptance.d.ts +13 -3
  181. package/dist/src/pil/layer18-acceptance.js +1 -75
  182. package/dist/src/pil/layer2-personality.js +7 -8
  183. package/dist/src/pil/layer2_5-ponytail.d.ts +2 -0
  184. package/dist/src/pil/layer2_5-ponytail.js +41 -0
  185. package/dist/src/pil/layer3-ee-injection.js +180 -14
  186. package/dist/src/pil/layer4-gsd.js +22 -8
  187. package/dist/src/pil/layer5-context.d.ts +1 -0
  188. package/dist/src/pil/layer5-context.js +26 -11
  189. package/dist/src/pil/layer6-output.js +23 -5
  190. package/dist/src/pil/llm-classify.js +3 -3
  191. package/dist/src/pil/native-capabilities-workbook.d.ts +1 -1
  192. package/dist/src/pil/native-capabilities-workbook.js +4 -3
  193. package/dist/src/pil/pipeline.js +15 -1
  194. package/dist/src/pil/response-tools.d.ts +16 -0
  195. package/dist/src/pil/response-tools.js +41 -0
  196. package/dist/src/pil/schema.d.ts +8 -0
  197. package/dist/src/pil/schema.js +24 -3
  198. package/dist/src/pil/task-tier-map.js +7 -7
  199. package/dist/src/pil/types.d.ts +9 -3
  200. package/dist/src/product-loop/__tests__/discovery-interview.test.js +103 -1
  201. package/dist/src/product-loop/__tests__/gather-selectable-alts.test.js +34 -0
  202. package/dist/src/product-loop/__tests__/sprint-self-verify.test.js +12 -12
  203. package/dist/src/product-loop/discovery-interview.d.ts +20 -0
  204. package/dist/src/product-loop/discovery-interview.js +121 -7
  205. package/dist/src/product-loop/done-gate.js +3 -3
  206. package/dist/src/product-loop/gather.js +19 -5
  207. package/dist/src/product-loop/loop-driver.js +20 -20
  208. package/dist/src/product-loop/progress-snapshot.js +4 -4
  209. package/dist/src/product-loop/sprint-self-verify.js +2 -2
  210. package/dist/src/providers/__tests__/reasoning-roundtrip.test.js +12 -0
  211. package/dist/src/providers/auth/__tests__/gemini-oauth.test.d.ts +1 -5
  212. package/dist/src/providers/auth/__tests__/gemini-oauth.test.js +1 -5
  213. package/dist/src/providers/auth/gcloud.d.ts +28 -0
  214. package/dist/src/providers/auth/gcloud.js +102 -0
  215. package/dist/src/providers/auth/gemini-oauth.d.ts +46 -19
  216. package/dist/src/providers/auth/gemini-oauth.js +292 -105
  217. package/dist/src/providers/auth/grok-oauth.d.ts +1 -1
  218. package/dist/src/providers/auth/grok-oauth.js +1 -1
  219. package/dist/src/providers/auth/registry.js +28 -6
  220. package/dist/src/providers/gemini.d.ts +1 -1
  221. package/dist/src/providers/gemini.js +10 -3
  222. package/dist/src/providers/keychain.d.ts +2 -2
  223. package/dist/src/providers/keychain.js +20 -2
  224. package/dist/src/providers/mcp-vision-bridge.js +48 -48
  225. package/dist/src/providers/openai.js +5 -1
  226. package/dist/src/providers/runtime.d.ts +1 -1
  227. package/dist/src/providers/runtime.js +11 -2
  228. package/dist/src/providers/siliconflow-sse-repair.js +1 -1
  229. package/dist/src/providers/strategies/google.strategy.d.ts +9 -2
  230. package/dist/src/providers/strategies/google.strategy.js +159 -9
  231. package/dist/src/providers/strategies/thinking-mode.js +19 -6
  232. package/dist/src/providers/types.d.ts +1 -1
  233. package/dist/src/reporter/index.js +1 -1
  234. package/dist/src/router/decide.test.js +40 -8
  235. package/dist/src/router/step-router.d.ts +20 -0
  236. package/dist/src/router/step-router.js +73 -0
  237. package/dist/src/scaffold/bb-ecosystem-apply.js +47 -47
  238. package/dist/src/scaffold/bb-quality-gate.js +5 -5
  239. package/dist/src/scaffold/continuation-prompt.js +60 -60
  240. package/dist/src/scaffold/init-new.js +453 -453
  241. package/dist/src/self-qa/__tests__/scenario-planner.test.js +3 -3
  242. package/dist/src/self-qa/agentic-loop.js +19 -19
  243. package/dist/src/self-qa/orchestrator.js +5 -5
  244. package/dist/src/self-qa/scenario-planner.js +1 -1
  245. package/dist/src/self-qa/spec-emitter.js +4 -4
  246. package/dist/src/storage/__tests__/migrations.test.js +2 -2
  247. package/dist/src/storage/index.d.ts +1 -1
  248. package/dist/src/storage/index.js +1 -1
  249. package/dist/src/storage/interaction-log.js +5 -5
  250. package/dist/src/storage/migrations.js +122 -122
  251. package/dist/src/storage/session-experience-store.js +4 -4
  252. package/dist/src/storage/sessions.d.ts +6 -0
  253. package/dist/src/storage/sessions.js +49 -42
  254. package/dist/src/storage/transcript-view.js +7 -1
  255. package/dist/src/storage/transcript.d.ts +1 -0
  256. package/dist/src/storage/transcript.js +55 -0
  257. package/dist/src/storage/ui-interaction-log.d.ts +17 -0
  258. package/dist/src/storage/usage.js +14 -14
  259. package/dist/src/storage/workspaces.js +12 -12
  260. package/dist/src/tools/__tests__/native-tools.test.js +6 -0
  261. package/dist/src/tools/bash.d.ts +36 -23
  262. package/dist/src/tools/bash.js +59 -301
  263. package/dist/src/tools/bash.test.js +2 -257
  264. package/dist/src/tools/file-tracker.d.ts +5 -0
  265. package/dist/src/tools/file-tracker.js +14 -0
  266. package/dist/src/tools/file.js +2 -0
  267. package/dist/src/tools/git-safety.d.ts +38 -1
  268. package/dist/src/tools/git-safety.js +94 -4
  269. package/dist/src/tools/git-safety.test.js +45 -1
  270. package/dist/src/tools/native-tools.d.ts +1 -1
  271. package/dist/src/tools/native-tools.js +56 -0
  272. package/dist/src/tools/registry-bash-empty-command.test.js +4 -3
  273. package/dist/src/tools/registry-git-safety.test.js +17 -6
  274. package/dist/src/tools/registry.d.ts +5 -0
  275. package/dist/src/tools/registry.js +185 -11
  276. package/dist/src/types/index.d.ts +7 -1
  277. package/dist/src/ui/app.d.ts +2 -1
  278. package/dist/src/ui/app.js +0 -0
  279. package/dist/src/ui/components/council-question-card.js +1 -0
  280. package/dist/src/ui/components/message-view.js +37 -3
  281. package/dist/src/ui/components/structured-response-view.js +7 -0
  282. package/dist/src/ui/components/task-list-panel.js +3 -12
  283. package/dist/src/ui/containers/chat-feed.d.ts +40 -0
  284. package/dist/src/ui/containers/chat-feed.js +66 -0
  285. package/dist/src/ui/containers/modals-layer.d.ts +87 -0
  286. package/dist/src/ui/containers/modals-layer.js +18 -0
  287. package/dist/src/ui/modals/session-picker-modal.js +14 -9
  288. package/dist/src/ui/modals/update-modal.js +2 -1
  289. package/dist/src/ui/slash/__tests__/menu-parity.test.d.ts +1 -0
  290. package/dist/src/ui/slash/__tests__/menu-parity.test.js +1 -0
  291. package/dist/src/ui/slash/__tests__/ponytail.test.d.ts +1 -0
  292. package/dist/src/ui/slash/__tests__/ponytail.test.js +37 -0
  293. package/dist/src/ui/slash/council-inspect.js +4 -4
  294. package/dist/src/ui/slash/export.js +16 -1
  295. package/dist/src/ui/slash/menu-items.js +1 -0
  296. package/dist/src/ui/slash/ponytail.d.ts +2 -0
  297. package/dist/src/ui/slash/ponytail.js +19 -0
  298. package/dist/src/ui/status-bar/store.js +0 -1
  299. package/dist/src/ui/status-bar/store.test.js +2 -2
  300. package/dist/src/ui/types.d.ts +7 -0
  301. package/dist/src/ui/use-app-logic.d.ts +26 -0
  302. package/dist/src/ui/use-app-logic.js +0 -0
  303. package/dist/src/ui/utils/relaunch.d.ts +17 -0
  304. package/dist/src/ui/utils/relaunch.js +28 -4
  305. package/dist/src/ui/utils/relaunch.test.js +50 -0
  306. package/dist/src/ui/utils/text.d.ts +11 -0
  307. package/dist/src/ui/utils/text.js +21 -1
  308. package/dist/src/ui/utils/text.test.js +25 -1
  309. package/dist/src/ui/utils/tools.js +3 -1
  310. package/dist/src/usage/cost-log.js +2 -2
  311. package/dist/src/usage/estimator.d.ts +14 -0
  312. package/dist/src/usage/estimator.js +22 -0
  313. package/dist/src/utils/__tests__/compaction-caps.test.d.ts +21 -0
  314. package/dist/src/utils/__tests__/compaction-caps.test.js +187 -0
  315. package/dist/src/utils/__tests__/llm-deadline-abort.test.d.ts +1 -0
  316. package/dist/src/utils/__tests__/llm-deadline-abort.test.js +33 -0
  317. package/dist/src/utils/clipboard-image.js +23 -23
  318. package/dist/src/utils/llm-deadline.d.ts +9 -1
  319. package/dist/src/utils/llm-deadline.js +31 -2
  320. package/dist/src/utils/permission-mode.d.ts +33 -0
  321. package/dist/src/utils/permission-mode.js +164 -3
  322. package/dist/src/utils/permission-mode.test.js +92 -1
  323. package/dist/src/utils/settings.d.ts +27 -31
  324. package/dist/src/utils/settings.js +100 -109
  325. package/dist/src/utils/side-question.js +2 -2
  326. package/dist/src/utils/skills.js +3 -3
  327. package/dist/src/verify/__tests__/coverage-parsers.test.js +30 -30
  328. package/package.json +1 -1
@@ -10,9 +10,9 @@ export async function queryLsp(cwd, input) {
10
10
  filePath: path.isAbsolute(input.filePath) ? input.filePath : path.resolve(cwd, input.filePath),
11
11
  });
12
12
  }
13
- export async function syncFileWithLsp(cwd, filePath, content, save = true, waitForDiagnostics = true) {
13
+ export async function syncFileWithLsp(cwd, filePath, content, save = true, waitForDiagnostics = true, diagnosticsTimeoutMs) {
14
14
  const manager = getOrCreateManager(cwd);
15
- return manager.syncFile(path.isAbsolute(filePath) ? filePath : path.resolve(cwd, filePath), content, save, waitForDiagnostics);
15
+ return manager.syncFile(path.isAbsolute(filePath) ? filePath : path.resolve(cwd, filePath), content, save, waitForDiagnostics, diagnosticsTimeoutMs);
16
16
  }
17
17
  export function isLspToolEnabled(_cwd) {
18
18
  const settings = getCurrentLspSettings();
@@ -12,9 +12,13 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
12
12
  // ── Mocks ──────────────────────────────────────────────────────────────────
13
13
  // vi.hoisted ensures the factory variable is available when vi.mock is hoisted.
14
14
  const { mockExecFile } = vi.hoisted(() => ({ mockExecFile: vi.fn() }));
15
- vi.mock("node:child_process", () => ({
16
- execFile: mockExecFile,
17
- }));
15
+ vi.mock("node:child_process", async () => {
16
+ const actual = await vi.importActual("node:child_process");
17
+ return {
18
+ ...actual,
19
+ execFile: mockExecFile,
20
+ };
21
+ });
18
22
  vi.mock("node:fs", async (importOriginal) => {
19
23
  const actual = (await importOriginal());
20
24
  return {
@@ -11,9 +11,13 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
11
11
  // ── Mocks ──────────────────────────────────────────────────────────────────
12
12
  // vi.hoisted ensures the factory variable is available when vi.mock is hoisted.
13
13
  const { mockExecFile } = vi.hoisted(() => ({ mockExecFile: vi.fn() }));
14
- vi.mock("node:child_process", () => ({
15
- execFile: mockExecFile,
16
- }));
14
+ vi.mock("node:child_process", async () => {
15
+ const actual = await vi.importActual("node:child_process");
16
+ return {
17
+ ...actual,
18
+ execFile: mockExecFile,
19
+ };
20
+ });
17
21
  vi.mock("../../council/leader.js", () => ({
18
22
  pickCouncilTaskModel: vi.fn((_task, leaderId) => leaderId),
19
23
  }));
@@ -54,7 +54,7 @@ describe("acquireMcpTools — cross-turn client pool", () => {
54
54
  client: { close: async () => { } },
55
55
  }));
56
56
  const b1 = await acquireMcpTools([srv("fs")]);
57
- await expect(b1.tools["mcp_fs__boom"].execute({}, {})).rejects.toThrow(/transport closed/);
57
+ await expect(b1.tools.mcp_fs__boom.execute({}, {})).rejects.toThrow(/transport closed/);
58
58
  // Initial connect + exactly ONE in-turn reconnect — the retry is not looped.
59
59
  expect(connectOneServer).toHaveBeenCalledTimes(2);
60
60
  });
@@ -77,7 +77,7 @@ describe("acquireMcpTools — cross-turn client pool", () => {
77
77
  };
78
78
  });
79
79
  const b = await acquireMcpTools([srv("docs")]);
80
- const result = await b.tools["mcp_docs__ping"].execute({}, {});
80
+ const result = await b.tools.mcp_docs__ping.execute({}, {});
81
81
  expect(result).toBe("pong"); // recovered within the SAME turn
82
82
  expect(connectOneServer).toHaveBeenCalledTimes(2); // drop + one reconnect
83
83
  });
@@ -104,7 +104,7 @@ describe("acquireMcpTools — cross-turn client pool", () => {
104
104
  };
105
105
  });
106
106
  const b = await acquireMcpTools([srv("docs")]);
107
- const tool = b.tools["mcp_docs__ping"];
107
+ const tool = b.tools.mcp_docs__ping;
108
108
  const results = await Promise.all(Array.from({ length: 14 }, () => tool.execute({}, {})));
109
109
  expect(results.every((r) => r === "pong")).toBe(true);
110
110
  expect(connectOneServer).toHaveBeenCalledTimes(2); // 14 failures → exactly ONE shared reconnect
@@ -46,7 +46,7 @@ describe("ee-tools", () => {
46
46
  }),
47
47
  health: async () => ({ ok: true, status: 200 }),
48
48
  }));
49
- const out = rawTextOf(await handlers["ee_query"]({ query: "redactor" }));
49
+ const out = rawTextOf(await handlers.ee_query({ query: "redactor" }));
50
50
  expect(out.isError).toBeFalsy();
51
51
  expect(out.text).toContain("recall:redactor");
52
52
  expect(out.text).toContain("[id:abc col:experience-behavioral]"); // handle preserved for exp-feedback
@@ -58,7 +58,7 @@ describe("ee-tools", () => {
58
58
  recall: async () => ({ text: "x".repeat(50_000), entries: [], count: 42 }),
59
59
  health: async () => ({ ok: true, status: 200 }),
60
60
  }));
61
- const out = rawTextOf(await handlers["ee_query"]({ query: "wide", maxChars: 6000 }));
61
+ const out = rawTextOf(await handlers.ee_query({ query: "wide", maxChars: 6000 }));
62
62
  expect(out.isError).toBeFalsy();
63
63
  expect(out.text.length).toBeLessThan(7000); // capped, not the full 50k dump
64
64
  expect(out.text).toContain("truncated");
@@ -73,18 +73,18 @@ describe("ee-tools", () => {
73
73
  },
74
74
  health: async () => ({ ok: true, status: 200 }),
75
75
  }));
76
- await handlers["ee_query"]({ query: "scope filter", project: "storyflow" });
76
+ await handlers.ee_query({ query: "scope filter", project: "storyflow" });
77
77
  expect(seenProject).toBe("storyflow");
78
78
  });
79
79
  it("ee_query returns ee_unavailable when recall yields null", async () => {
80
80
  const handlers = collectTools((s) => registerEETools(s, { recall: async () => null, health: async () => ({ ok: false, status: 0 }) }));
81
- const out = textOf(await handlers["ee_query"]({ query: "x" }));
81
+ const out = textOf(await handlers.ee_query({ query: "x" }));
82
82
  expect(out.isError).toBe(true);
83
83
  expect(out.json.error).toBe("ee_unavailable");
84
84
  });
85
85
  it("ee_health returns the injected status", async () => {
86
86
  const handlers = collectTools((s) => registerEETools(s, { recall: async () => null, health: async () => ({ ok: true, status: 200 }) }));
87
- const out = textOf(await handlers["ee_health"]({}));
87
+ const out = textOf(await handlers.ee_health({}));
88
88
  expect(out.json).toEqual({ ok: true, status: 200 });
89
89
  });
90
90
  it("ee_health returns ee_unavailable when health throws", async () => {
@@ -94,7 +94,7 @@ describe("ee-tools", () => {
94
94
  throw new Error("boom");
95
95
  },
96
96
  }));
97
- const out = textOf(await handlers["ee_health"]({}));
97
+ const out = textOf(await handlers.ee_health({}));
98
98
  expect(out.isError).toBe(true);
99
99
  expect(out.json.error).toBe("ee_unavailable");
100
100
  });
@@ -111,7 +111,7 @@ describe("ee-tools", () => {
111
111
  return { ok: true, resolvedId: id, verdict: verdict === "followed" ? "FOLLOWED" : verdict };
112
112
  },
113
113
  }));
114
- const out = textOf(await handlers["ee_feedback"]({ id: "abc", collection: "experience-behavioral", verdict: "followed" }));
114
+ const out = textOf(await handlers.ee_feedback({ id: "abc", collection: "experience-behavioral", verdict: "followed" }));
115
115
  expect(out.isError).toBeFalsy();
116
116
  expect(seen).toEqual({ id: "abc", collection: "experience-behavioral", verdict: "followed", reason: undefined });
117
117
  expect(out.json.ok).toBe(true);
@@ -120,7 +120,7 @@ describe("ee-tools", () => {
120
120
  });
121
121
  it("ee_feedback requires a reason for verdict=noise", async () => {
122
122
  const handlers = collectTools((s) => registerEETools(s, { feedback: async () => ({ ok: true }) }));
123
- const out = textOf(await handlers["ee_feedback"]({ id: "x", collection: "experience-selfqa", verdict: "noise" }));
123
+ const out = textOf(await handlers.ee_feedback({ id: "x", collection: "experience-selfqa", verdict: "noise" }));
124
124
  expect(out.isError).toBe(true);
125
125
  expect(out.json.error).toBe("reason_required");
126
126
  });
@@ -128,7 +128,7 @@ describe("ee-tools", () => {
128
128
  const ledger = createRecallLedger();
129
129
  ledger.record([{ id: "abc", collection: "experience-behavioral" }], "q");
130
130
  const handlers = collectTools((s) => registerEETools(s, { ledger, feedback: async () => ({ ok: false, error: "HTTP 500" }) }));
131
- const out = textOf(await handlers["ee_feedback"]({ id: "abc", collection: "experience-behavioral", verdict: "ignored" }));
131
+ const out = textOf(await handlers.ee_feedback({ id: "abc", collection: "experience-behavioral", verdict: "ignored" }));
132
132
  expect(out.isError).toBe(true);
133
133
  expect(out.json.error).toBe("feedback_failed");
134
134
  expect(ledger.pendingCount()).toBe(1); // NOT cleared on failure
@@ -145,11 +145,11 @@ describe("ee-tools", () => {
145
145
  health: async () => ({ ok: true, status: 200 }),
146
146
  }));
147
147
  // First recall — no prior debt, so no gate prefix.
148
- const first = rawTextOf(await handlers["ee_query"]({ query: "first" }));
148
+ const first = rawTextOf(await handlers.ee_query({ query: "first" }));
149
149
  expect(first.text).not.toContain("still unrated");
150
150
  expect(ledger.pendingCount()).toBe(1);
151
151
  // Second recall — the prior id1 is still unrated → soft prefix, but recall still returned.
152
- const second = rawTextOf(await handlers["ee_query"]({ query: "second" }));
152
+ const second = rawTextOf(await handlers.ee_query({ query: "second" }));
153
153
  expect(second.isError).toBeFalsy();
154
154
  expect(second.text).toContain("still unrated");
155
155
  expect(second.text).toContain("id1");
@@ -172,7 +172,7 @@ describe("ee-tools", () => {
172
172
  return { text: "should not run", entries: [], count: 0 };
173
173
  },
174
174
  }));
175
- const out = textOf(await handlers["ee_query"]({ query: "blocked" }));
175
+ const out = textOf(await handlers.ee_query({ query: "blocked" }));
176
176
  expect(out.isError).toBe(true);
177
177
  expect(out.json.error).toBe("feedback_required");
178
178
  expect(out.json.message).toContain("FEEDBACK GATE");
@@ -190,9 +190,37 @@ describe("ee-tools", () => {
190
190
  }),
191
191
  health: async () => ({ ok: true, status: 200 }),
192
192
  }));
193
- await handlers["ee_query"]({ query: "one" });
194
- await handlers["ee_query"]({ query: "two" });
193
+ await handlers.ee_query({ query: "one" });
194
+ await handlers.ee_query({ query: "two" });
195
195
  expect(ledger.pendingCount()).toBe(0); // nothing stamped when gate is off
196
196
  });
197
+ // ─── ee_write (Layer 1 — agent records a new lesson) ───────────────────────
198
+ it("ee_write forwards the lesson to the write helper and returns the new id", async () => {
199
+ let seen = null;
200
+ const handlers = collectTools((s) => registerEETools(s, {
201
+ write: async (lesson, opts) => {
202
+ seen = { lesson, opts };
203
+ return { ok: true, id: "new-point-1" };
204
+ },
205
+ }));
206
+ const out = textOf(await handlers.ee_write({
207
+ lesson: "always call flushFrob() before reindex or reads go stale",
208
+ title: "reindex pitfall",
209
+ project: "experience-engine",
210
+ }));
211
+ expect(out.isError).toBeFalsy();
212
+ expect(out.json.ok).toBe(true);
213
+ expect(out.json.id).toBe("new-point-1");
214
+ expect(out.json.collection).toBe("experience-behavioral");
215
+ expect(seen.lesson).toContain("flushFrob");
216
+ expect(seen.opts.collection).toBe("experience-behavioral");
217
+ expect(seen.opts.projectSlug).toBe("experience-engine");
218
+ });
219
+ it("ee_write surfaces write_failed when the write helper fails", async () => {
220
+ const handlers = collectTools((s) => registerEETools(s, { write: async () => ({ ok: false, error: "import-memory HTTP 500" }) }));
221
+ const out = textOf(await handlers.ee_write({ lesson: "a sufficiently long lesson body here" }));
222
+ expect(out.isError).toBe(true);
223
+ expect(out.json.error).toBe("write_failed");
224
+ });
197
225
  });
198
226
  //# sourceMappingURL=ee-tools.test.js.map
@@ -32,20 +32,20 @@ const fakeSummary = (id) => ({
32
32
  describe("forensics-tools", () => {
33
33
  it("usage_forensics returns the summary for a unique prefix", async () => {
34
34
  const handlers = collectTools((s) => registerForensicsTools(s, { resolve: () => ["sess123"], collect: (id) => fakeSummary(id) }));
35
- const out = parse(await handlers["usage_forensics"]({ prefix: "sess" }));
35
+ const out = parse(await handlers.usage_forensics({ prefix: "sess" }));
36
36
  expect(out.isError).toBeFalsy();
37
37
  expect(out.json.sessionId).toBe("sess123");
38
38
  expect(out.json.peakSingleCallInput).toBe(100);
39
39
  });
40
40
  it("usage_forensics returns not_found for zero matches", async () => {
41
41
  const handlers = collectTools((s) => registerForensicsTools(s, { resolve: () => [], collect: () => fakeSummary("x") }));
42
- const out = parse(await handlers["usage_forensics"]({ prefix: "nope" }));
42
+ const out = parse(await handlers.usage_forensics({ prefix: "nope" }));
43
43
  expect(out.isError).toBe(true);
44
44
  expect(out.json.error).toBe("not_found");
45
45
  });
46
46
  it("usage_forensics returns ambiguous for multiple matches", async () => {
47
47
  const handlers = collectTools((s) => registerForensicsTools(s, { resolve: () => ["a1", "a2"], collect: () => fakeSummary("a1") }));
48
- const out = parse(await handlers["usage_forensics"]({ prefix: "a" }));
48
+ const out = parse(await handlers.usage_forensics({ prefix: "a" }));
49
49
  expect(out.isError).toBe(true);
50
50
  expect(out.json.error).toBe("ambiguous");
51
51
  expect(out.json.matches).toEqual(["a1", "a2"]);
@@ -18,13 +18,13 @@ describe("lsp-tools", () => {
18
18
  it("lsp_query passes through the LspToolResponse when enabled", async () => {
19
19
  const resp = { success: true, output: "def at file.ts:10" };
20
20
  const handlers = collectTools((s) => registerLspTools(s, { enabled: () => true, query: async () => resp }));
21
- const out = parse(await handlers["lsp_query"]({ operation: "goToDefinition", filePath: "a.ts", line: 1, character: 2 }));
21
+ const out = parse(await handlers.lsp_query({ operation: "goToDefinition", filePath: "a.ts", line: 1, character: 2 }));
22
22
  expect(out.isError).toBeFalsy();
23
23
  expect(out.json).toEqual(resp);
24
24
  });
25
25
  it("lsp_query returns lsp_disabled when LSP is off", async () => {
26
26
  const handlers = collectTools((s) => registerLspTools(s, { enabled: () => false, query: async () => ({ success: true, output: "x" }) }));
27
- const out = parse(await handlers["lsp_query"]({ operation: "hover", filePath: "a.ts", line: 0, character: 0 }));
27
+ const out = parse(await handlers.lsp_query({ operation: "hover", filePath: "a.ts", line: 0, character: 0 }));
28
28
  expect(out.isError).toBe(true);
29
29
  expect(out.json.error).toBe("lsp_disabled");
30
30
  });
@@ -35,7 +35,7 @@ describe("lsp-tools", () => {
35
35
  throw new Error("server launch failed");
36
36
  },
37
37
  }));
38
- const out = parse(await handlers["lsp_query"]({ operation: "findReferences", filePath: "a.ts", line: 3, character: 4 }));
38
+ const out = parse(await handlers.lsp_query({ operation: "findReferences", filePath: "a.ts", line: 3, character: 4 }));
39
39
  expect(out.isError).toBe(true);
40
40
  expect(out.json.error).toBe("lsp_error");
41
41
  expect(out.json.message).toContain("server launch failed");
@@ -47,7 +47,7 @@ describe("lsp-tools", () => {
47
47
  },
48
48
  query: async () => ({ success: true, output: "x" }),
49
49
  }));
50
- const out = parse(await handlers["lsp_query"]({ operation: "hover", filePath: "a.ts", line: 0, character: 0 }));
50
+ const out = parse(await handlers.lsp_query({ operation: "hover", filePath: "a.ts", line: 0, character: 0 }));
51
51
  expect(out.isError).toBe(true);
52
52
  expect(out.json.error).toBe("lsp_error");
53
53
  expect(out.json.message).toContain("settings read failed");
@@ -44,7 +44,7 @@ export declare function acquireMcpTools(servers: McpServerConfig[], opts?: McpBu
44
44
  * has connected. Idempotent (cached entries are reused); a failed connect is
45
45
  * evicted by getOrConnect so a real turn retries.
46
46
  */
47
- export declare function warmMcpClients(servers: McpServerConfig[]): void;
47
+ export declare function warmMcpClients(servers: McpServerConfig[], syncAndLog?: boolean): Promise<void>;
48
48
  /** Tear down every pooled client. Call on orchestrator/process shutdown. */
49
49
  export declare function closeAllMcpClients(): Promise<void>;
50
50
  /** Test-only: reset pool state between cases. */
@@ -236,15 +236,31 @@ export async function acquireMcpTools(servers, opts) {
236
236
  * has connected. Idempotent (cached entries are reused); a failed connect is
237
237
  * evicted by getOrConnect so a real turn retries.
238
238
  */
239
- export function warmMcpClients(servers) {
240
- for (const s of servers) {
241
- if (!s.enabled)
242
- continue;
243
- if (!validateMcpServerConfig(s).ok)
244
- continue;
245
- void getOrConnect(s).catch(() => {
246
- /* warm is best-effort — the eviction in getOrConnect lets a real turn retry */
247
- });
239
+ export async function warmMcpClients(servers, syncAndLog = false) {
240
+ const validServers = servers.filter(s => s.enabled && validateMcpServerConfig(s).ok);
241
+ if (syncAndLog && validServers.length > 0) {
242
+ console.log(`[MCP] Warming up ${validServers.length} server(s)...`);
243
+ }
244
+ const promises = validServers.map(async (s) => {
245
+ try {
246
+ await getOrConnect(s);
247
+ if (syncAndLog) {
248
+ console.log(`[MCP] ✅ ${s.id}: healthy`);
249
+ }
250
+ }
251
+ catch (e) {
252
+ if (syncAndLog) {
253
+ const msg = e instanceof Error ? e.message : String(e);
254
+ console.log(`[MCP] ❌ ${s.id}: failed - ${msg}`);
255
+ }
256
+ }
257
+ });
258
+ if (syncAndLog) {
259
+ await Promise.all(promises);
260
+ }
261
+ else {
262
+ // Fire-and-forget for background warmup
263
+ void Promise.all(promises);
248
264
  }
249
265
  }
250
266
  /** Tear down every pooled client. Call on orchestrator/process shutdown. */
@@ -30,6 +30,16 @@ export interface EEToolDeps {
30
30
  status: number;
31
31
  }>;
32
32
  feedback?: (pointId: string, collection: string, verdict: FeedbackVerdict, reason?: NoiseReason) => Promise<FeedbackResult>;
33
+ write?: (lesson: string, opts: {
34
+ collection?: string;
35
+ title?: string;
36
+ projectSlug?: string;
37
+ confidence?: number;
38
+ }) => Promise<{
39
+ ok: boolean;
40
+ id?: string;
41
+ error?: string;
42
+ }>;
33
43
  /** Session pending-recall ledger. Defaults to the process singleton. */
34
44
  ledger?: RecallLedger;
35
45
  }
@@ -155,5 +155,39 @@ export function registerEETools(server, deps = {}) {
155
155
  return fail("ee_unavailable", e instanceof Error ? e.message : String(e));
156
156
  }
157
157
  });
158
+ server.registerTool("ee_write", {
159
+ description: "Save a NEW lesson to the Experience Engine brain so you and future sessions recall it. Call the MOMENT you " +
160
+ "hit a mistake / error / dead-end and find the working fix: record the pitfall AND the fix in one concise, " +
161
+ "generalizable lesson (1-3 sentences — what to do or avoid next time, NOT a play-by-play of this turn). The " +
162
+ "lesson is embedded immediately (via /api/import-memory: dense + sparse) and becomes recallable via ee_query " +
163
+ "in this and future sessions. Use ee_query first if unsure a lesson already exists. collection defaults to " +
164
+ "experience-behavioral (use experience-principles only for a broad, project-independent principle); project " +
165
+ "scopes the lesson.",
166
+ inputSchema: {
167
+ lesson: z.string().min(12).max(4000),
168
+ title: z.string().max(200).optional(),
169
+ collection: z.enum(["experience-behavioral", "experience-principles"]).optional(),
170
+ project: z.string().max(200).optional(),
171
+ },
172
+ }, async ({ lesson, title, collection, project }) => {
173
+ const trimmed = lesson.trim();
174
+ const text = trimmed.length > 1500 ? `${trimmed.slice(0, 1497)}...` : trimmed;
175
+ const targetCollection = collection ?? "experience-behavioral";
176
+ const write = deps.write ?? ((l, o) => import("../ee/search.js").then((m) => m.writeExperienceEE(l, o)));
177
+ try {
178
+ const result = await write(text, {
179
+ collection: targetCollection,
180
+ title,
181
+ projectSlug: project,
182
+ confidence: 0.65,
183
+ });
184
+ if (!result.ok)
185
+ return fail("write_failed", result.error ?? "import-memory POST failed");
186
+ return ok({ ok: true, id: result.id, collection: targetCollection, recallable: "now via ee_query" });
187
+ }
188
+ catch (e) {
189
+ return fail("write_failed", e instanceof Error ? e.message : String(e));
190
+ }
191
+ });
158
192
  }
159
193
  //# sourceMappingURL=ee-tools.js.map
@@ -1,7 +1,7 @@
1
1
  import http from "node:http";
2
2
  import { URL } from "node:url";
3
- const SUCCESS_HTML = `<!DOCTYPE html><html><body style="font-family:system-ui;text-align:center;padding:60px">
4
- <h2>Authorization successful</h2><p>You can close this tab and return to the terminal.</p>
3
+ const SUCCESS_HTML = `<!DOCTYPE html><html><body style="font-family:system-ui;text-align:center;padding:60px">
4
+ <h2>Authorization successful</h2><p>You can close this tab and return to the terminal.</p>
5
5
  </body></html>`;
6
6
  export function startOAuthCallbackServer(opts) {
7
7
  const callbackPath = opts.path ?? "/callback";
@@ -2,19 +2,19 @@ import { describe, expect, it } from "vitest";
2
2
  import { parseEnvLines, parseHeaderLines } from "./parse-headers.js";
3
3
  describe("parseHeaderLines", () => {
4
4
  it("parses colon-separated headers and trims whitespace", () => {
5
- expect(parseHeaderLines(`
6
- Authorization: Bearer token
7
- X-Trace-Id: abc123
5
+ expect(parseHeaderLines(`
6
+ Authorization: Bearer token
7
+ X-Trace-Id: abc123
8
8
  `)).toEqual({
9
9
  Authorization: "Bearer token",
10
10
  "X-Trace-Id": "abc123",
11
11
  });
12
12
  });
13
13
  it("ignores blank and malformed lines while preserving later colons in values", () => {
14
- expect(parseHeaderLines(`
15
- invalid
16
- : missing-name
17
- Host: example.com:443
14
+ expect(parseHeaderLines(`
15
+ invalid
16
+ : missing-name
17
+ Host: example.com:443
18
18
  `)).toEqual({
19
19
  Host: "example.com:443",
20
20
  });
@@ -22,19 +22,19 @@ describe("parseHeaderLines", () => {
22
22
  });
23
23
  describe("parseEnvLines", () => {
24
24
  it("parses equals-separated env assignments and trims whitespace", () => {
25
- expect(parseEnvLines(`
26
- API_KEY = secret
27
- MODE= production
25
+ expect(parseEnvLines(`
26
+ API_KEY = secret
27
+ MODE= production
28
28
  `)).toEqual({
29
29
  API_KEY: "secret",
30
30
  MODE: "production",
31
31
  });
32
32
  });
33
33
  it("ignores blank and malformed lines while preserving later equals in values", () => {
34
- expect(parseEnvLines(`
35
- missing
36
- = no-name
37
- URL=https://example.com?a=b
34
+ expect(parseEnvLines(`
35
+ missing
36
+ = no-name
37
+ URL=https://example.com?a=b
38
38
  `)).toEqual({
39
39
  URL: "https://example.com?a=b",
40
40
  });
@@ -34,9 +34,7 @@ export class JobManager {
34
34
  job.logBuffer.splice(0, job.logBuffer.length - LOG_CAP);
35
35
  }
36
36
  };
37
- const run = opts.kind === "tier1"
38
- ? this.runner.tier1(opts, log, ctrl.signal)
39
- : this.runner.agentic(opts, log, ctrl.signal);
37
+ const run = opts.kind === "tier1" ? this.runner.tier1(opts, log, ctrl.signal) : this.runner.agentic(opts, log, ctrl.signal);
40
38
  run.then((report) => {
41
39
  this.controllers.delete(runId); // I2: keep maps symmetric after natural completion
42
40
  if (job.status === "cancelled")
@@ -6,79 +6,79 @@
6
6
  * and the muonroi-tools MCP server (src/mcp/tools-server.ts, for external agents).
7
7
  * Keeping it here avoids duplicating ~70 lines across the two.
8
8
  */
9
- export const SETUP_GUIDE_TEXT = `# muonroi-cli Setup Guide
10
-
11
- ## Install (zero runtime deps — recommended)
12
- Linux / macOS:
13
- curl -fsSL https://raw.githubusercontent.com/muonroi/muonroi-cli/master/install.sh | bash
14
-
15
- Windows PowerShell:
16
- irm https://raw.githubusercontent.com/muonroi/muonroi-cli/master/install.ps1 | iex
17
-
18
- Bun (requires Bun >= 1.3):
19
- bun add -g muonroi-cli
20
- # (npm install -g is NOT supported — TUI engine uses Bun-only ESM features)
21
-
22
- The installers fetch a pre-compiled single binary from GitHub Releases.
23
-
24
- ## First run
25
- - Wizard appears automatically.
26
- - Lists supported providers (DeepSeek + SiliconFlow ready; others via BYOK).
27
- - Four credential options: paste key, Bitwarden sync (B in /providers), keys export/import (encrypted bundle), or skip for later.
28
- - Keys land in OS keychain (keytar). Settings written to ~/.muonroi-cli/user-settings.json.
29
- - Role routing (leader/implement/verify/research) is configured for you.
30
-
31
- After setup: run \`muonroi-cli doctor\` to validate.
32
-
33
- ## Essential commands
34
- - Interactive TUI: \`muonroi-cli\` (or \`node dist/index.js\` after build)
35
- - Headless one-shot: \`muonroi-cli --prompt "your task" --max-tool-rounds 8\`
36
- - Health + MCP nudge: \`muonroi-cli doctor\`
37
- - Update: \`muonroi-cli update\` (or set "autoUpdate": true in user-settings)
38
- - Keys move between machines: \`muonroi-cli keys export file.json\` then import on target
39
- - Native tools MCP (for external agents): \`muonroi-cli tools-mcp\` (stdio)
40
- - Harness driver MCP: \`muonroi-cli mcp-driver\`
41
-
42
- ## MCP integration (for Claude Desktop, Cursor, other agents)
43
- Add to your MCP client config:
44
-
45
- {
46
- "mcpServers": {
47
- "muonroi-tools": {
48
- "command": "bun",
49
- "args": ["run", "/absolute/path/to/muonroi-cli/src/index.ts", "tools-mcp"]
50
- }
51
- }
52
- }
53
-
54
- (Use absolute path. After \`bun run build\`: "node", "dist/index.js", "tools-mcp")
55
-
56
- The CLI's OWN inner agent exposes these as NATIVE in-process tools (no MCP self-spawn):
57
- - setup_guide (this document)
58
- - ee_query / ee_health / ee_feedback — Experience Engine semantic recall + compaction checkpoints + feedback for learning
59
- - usage_forensics <id-prefix> — per-session cost/token forensics (peak input, cache hits, anomalies)
60
- - lsp_query — goToDefinition, findReferences, hover, symbols, call hierarchy etc.
61
- - selfverify_* — Tier-1 heuristic + Tier-2 agentic self-QA harness runs (start/poll/result/cancel/list)
62
-
63
- For BB/.NET template recipes and package docs, also connect an external "muonroi-docs" MCP server if available (provides docs_search + setup_guide for the templates).
64
-
65
- ## Development
66
- git clone https://github.com/muonroi/muonroi-cli.git
67
- cd muonroi-cli && bun install
68
-
69
- bun run dev # run from source (TUI)
70
- bun run typecheck # tsc --noEmit
71
- bun run test # vitest (unit + headless)
72
- bunx vitest -c vitest.harness.config.ts run tests/harness/ # TUI E2E (named-pipes on Win, fd3/4 on POSIX)
73
- bun run build # or build:binary for standalone exe
74
-
75
- See AGENTS.md (quick ref + rules), CLAUDE.md (harness verification), README.md.
76
-
77
- ## Verify
78
- muonroi-cli doctor
79
- # Checks runtimes, catalog load, keychain, MCP servers enabled, council research MCP nudge, EE reachability, recent error rate.
80
- # Any "warn" entries tell you exactly what to enable (e.g. tavily for web research in council).
81
-
82
- For BB-aware scaffolding (/ideal on a muonroi-building-block target): ensure dotnet SDK + the three Muonroi.*.Template packages are installed via NuGet; doctor surfaces missing feed/template cases.
9
+ export const SETUP_GUIDE_TEXT = `# muonroi-cli Setup Guide
10
+
11
+ ## Install (zero runtime deps — recommended)
12
+ Linux / macOS:
13
+ curl -fsSL https://raw.githubusercontent.com/muonroi/muonroi-cli/master/install.sh | bash
14
+
15
+ Windows PowerShell:
16
+ irm https://raw.githubusercontent.com/muonroi/muonroi-cli/master/install.ps1 | iex
17
+
18
+ Bun (requires Bun >= 1.3):
19
+ bun add -g muonroi-cli
20
+ # (npm install -g is NOT supported — TUI engine uses Bun-only ESM features)
21
+
22
+ The installers fetch a pre-compiled single binary from GitHub Releases.
23
+
24
+ ## First run
25
+ - Wizard appears automatically.
26
+ - Lists supported providers (DeepSeek + SiliconFlow ready; others via BYOK).
27
+ - Four credential options: paste key, Bitwarden sync (B in /providers), keys export/import (encrypted bundle), or skip for later.
28
+ - Keys land in OS keychain (keytar). Settings written to ~/.muonroi-cli/user-settings.json.
29
+ - Role routing (leader/implement/verify/research) is configured for you.
30
+
31
+ After setup: run \`muonroi-cli doctor\` to validate.
32
+
33
+ ## Essential commands
34
+ - Interactive TUI: \`muonroi-cli\` (or \`node dist/index.js\` after build)
35
+ - Headless one-shot: \`muonroi-cli --prompt "your task" --max-tool-rounds 8\`
36
+ - Health + MCP nudge: \`muonroi-cli doctor\`
37
+ - Update: \`muonroi-cli update\` (or set "autoUpdate": true in user-settings)
38
+ - Keys move between machines: \`muonroi-cli keys export file.json\` then import on target
39
+ - Native tools MCP (for external agents): \`muonroi-cli tools-mcp\` (stdio)
40
+ - Harness driver MCP: \`muonroi-cli mcp-driver\`
41
+
42
+ ## MCP integration (for Claude Desktop, Cursor, other agents)
43
+ Add to your MCP client config:
44
+
45
+ {
46
+ "mcpServers": {
47
+ "muonroi-tools": {
48
+ "command": "bun",
49
+ "args": ["run", "/absolute/path/to/muonroi-cli/src/index.ts", "tools-mcp"]
50
+ }
51
+ }
52
+ }
53
+
54
+ (Use absolute path. After \`bun run build\`: "node", "dist/index.js", "tools-mcp")
55
+
56
+ The CLI's OWN inner agent exposes these as NATIVE in-process tools (no MCP self-spawn):
57
+ - setup_guide (this document)
58
+ - ee_query / ee_health / ee_feedback — Experience Engine semantic recall + compaction checkpoints + feedback for learning
59
+ - usage_forensics <id-prefix> — per-session cost/token forensics (peak input, cache hits, anomalies)
60
+ - lsp_query — goToDefinition, findReferences, hover, symbols, call hierarchy etc.
61
+ - selfverify_* — Tier-1 heuristic + Tier-2 agentic self-QA harness runs (start/poll/result/cancel/list)
62
+
63
+ For BB/.NET template recipes and package docs, also connect an external "muonroi-docs" MCP server if available (provides docs_search + setup_guide for the templates).
64
+
65
+ ## Development
66
+ git clone https://github.com/muonroi/muonroi-cli.git
67
+ cd muonroi-cli && bun install
68
+
69
+ bun run dev # run from source (TUI)
70
+ bun run typecheck # tsc --noEmit
71
+ bun run test # vitest (unit + headless)
72
+ bunx vitest -c vitest.harness.config.ts run tests/harness/ # TUI E2E (named-pipes on Win, fd3/4 on POSIX)
73
+ bun run build # or build:binary for standalone exe
74
+
75
+ See AGENTS.md (quick ref + rules), CLAUDE.md (harness verification), README.md.
76
+
77
+ ## Verify
78
+ muonroi-cli doctor
79
+ # Checks runtimes, catalog load, keychain, MCP servers enabled, council research MCP nudge, EE reachability, recent error rate.
80
+ # Any "warn" entries tell you exactly what to enable (e.g. tavily for web research in council).
81
+
82
+ For BB-aware scaffolding (/ideal on a muonroi-building-block target): ensure dotnet SDK + the three Muonroi.*.Template packages are installed via NuGet; doctor surfaces missing feed/template cases.
83
83
  `;
84
84
  //# sourceMappingURL=setup-guide-text.js.map