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
@@ -43,12 +43,12 @@ export class SessionStore {
43
43
  const now = new Date().toISOString();
44
44
  const id = createSessionId();
45
45
  const db = getDatabase();
46
- db.prepare(`
47
- INSERT INTO sessions (
48
- id, workspace_id, title, model, mode, cwd_at_start, cwd_last, status, created_at, updated_at
49
- ) VALUES (
50
- @id, @workspace_id, NULL, @model, @mode, @cwd_at_start, @cwd_last, 'active', @created_at, @updated_at
51
- )
46
+ db.prepare(`
47
+ INSERT INTO sessions (
48
+ id, workspace_id, title, model, mode, cwd_at_start, cwd_last, status, created_at, updated_at
49
+ ) VALUES (
50
+ @id, @workspace_id, NULL, @model, @mode, @cwd_at_start, @cwd_last, 'active', @created_at, @updated_at
51
+ )
52
52
  `).run({
53
53
  id,
54
54
  workspace_id: this.workspace.id,
@@ -64,37 +64,44 @@ export class SessionStore {
64
64
  /**
65
65
  * List recent sessions in this workspace (most recently updated first).
66
66
  * Used by the `/sessions` slash command for resume picking.
67
+ *
68
+ * Only sessions that actually have a persisted message are returned. Every
69
+ * CLI launch WITHOUT `--session` opens a fresh empty session, and test /
70
+ * harness runs leave behind title-only stubs — without this filter the picker
71
+ * fills with empty rows that resume to a blank screen, so a user picking one
72
+ * thinks resume is broken.
67
73
  */
68
74
  listRecentSessions(limit = 20) {
69
75
  const rows = getDatabase()
70
- .prepare(`
71
- SELECT id, workspace_id, title, model, mode, cwd_at_start, cwd_last, status, created_at, updated_at
72
- FROM sessions
73
- WHERE workspace_id = ?
74
- ORDER BY updated_at DESC
75
- LIMIT ?
76
+ .prepare(`
77
+ SELECT s.id, s.workspace_id, s.title, s.model, s.mode, s.cwd_at_start, s.cwd_last, s.status, s.created_at, s.updated_at
78
+ FROM sessions s
79
+ WHERE s.workspace_id = ?
80
+ AND EXISTS (SELECT 1 FROM messages m WHERE m.session_id = s.id)
81
+ ORDER BY s.updated_at DESC
82
+ LIMIT ?
76
83
  `)
77
84
  .all(this.workspace.id, limit);
78
85
  return rows.map(toSessionInfo);
79
86
  }
80
87
  getLatestSession() {
81
88
  const row = getDatabase()
82
- .prepare(`
83
- SELECT id, workspace_id, title, model, mode, cwd_at_start, cwd_last, status, created_at, updated_at
84
- FROM sessions
85
- WHERE workspace_id = ?
86
- ORDER BY updated_at DESC
87
- LIMIT 1
89
+ .prepare(`
90
+ SELECT id, workspace_id, title, model, mode, cwd_at_start, cwd_last, status, created_at, updated_at
91
+ FROM sessions
92
+ WHERE workspace_id = ?
93
+ ORDER BY updated_at DESC
94
+ LIMIT 1
88
95
  `)
89
96
  .get(this.workspace.id);
90
97
  return row ? toSessionInfo(row) : null;
91
98
  }
92
99
  getSessionById(id) {
93
100
  const row = getDatabase()
94
- .prepare(`
95
- SELECT id, workspace_id, title, model, mode, cwd_at_start, cwd_last, status, created_at, updated_at
96
- FROM sessions
97
- WHERE id = ?
101
+ .prepare(`
102
+ SELECT id, workspace_id, title, model, mode, cwd_at_start, cwd_last, status, created_at, updated_at
103
+ FROM sessions
104
+ WHERE id = ?
98
105
  `)
99
106
  .get(id);
100
107
  return row ? toSessionInfo(row) : null;
@@ -109,49 +116,49 @@ export class SessionStore {
109
116
  setStatus(id, status) {
110
117
  const now = new Date().toISOString();
111
118
  getDatabase()
112
- .prepare(`
113
- UPDATE sessions
114
- SET status = ?, updated_at = ?
115
- WHERE id = ?
119
+ .prepare(`
120
+ UPDATE sessions
121
+ SET status = ?, updated_at = ?
122
+ WHERE id = ?
116
123
  `)
117
124
  .run(status, now, id);
118
125
  }
119
126
  setTitle(id, title) {
120
127
  const now = new Date().toISOString();
121
128
  getDatabase()
122
- .prepare(`
123
- UPDATE sessions
124
- SET title = ?, updated_at = ?
125
- WHERE id = ?
129
+ .prepare(`
130
+ UPDATE sessions
131
+ SET title = ?, updated_at = ?
132
+ WHERE id = ?
126
133
  `)
127
134
  .run(title, now, id);
128
135
  }
129
136
  setModel(id, model) {
130
137
  const now = new Date().toISOString();
131
138
  getDatabase()
132
- .prepare(`
133
- UPDATE sessions
134
- SET model = ?, updated_at = ?
135
- WHERE id = ?
139
+ .prepare(`
140
+ UPDATE sessions
141
+ SET model = ?, updated_at = ?
142
+ WHERE id = ?
136
143
  `)
137
144
  .run(model, now, id);
138
145
  }
139
146
  setMode(id, mode) {
140
147
  const now = new Date().toISOString();
141
148
  getDatabase()
142
- .prepare(`
143
- UPDATE sessions
144
- SET mode = ?, updated_at = ?
145
- WHERE id = ?
149
+ .prepare(`
150
+ UPDATE sessions
151
+ SET mode = ?, updated_at = ?
152
+ WHERE id = ?
146
153
  `)
147
154
  .run(mode, now, id);
148
155
  }
149
156
  touchSession(id, cwd) {
150
157
  getDatabase()
151
- .prepare(`
152
- UPDATE sessions
153
- SET cwd_last = ?, updated_at = ?
154
- WHERE id = ?
158
+ .prepare(`
159
+ UPDATE sessions
160
+ SET cwd_last = ?, updated_at = ?
161
+ WHERE id = ?
155
162
  `)
156
163
  .run(cwd, new Date().toISOString(), id);
157
164
  }
@@ -9,7 +9,13 @@ export function buildEffectiveTranscript(messages, seqs, timestamps, compaction)
9
9
  };
10
10
  }
11
11
  const firstKeptIndex = seqs.findIndex((seq) => seq >= compaction.firstKeptSeq);
12
- const keptIndex = firstKeptIndex >= 0 ? firstKeptIndex : messages.length;
12
+ let keptIndex = firstKeptIndex >= 0 ? firstKeptIndex : messages.length;
13
+ // Anti-mù / Resilience: if firstKeptSeq landed on a `tool` message (e.g. due to seq array
14
+ // misalignment or forced cut), we MUST step back to include its preceding `assistant` message.
15
+ // Otherwise Vercel AI SDK throws: "Messages with role 'tool' must be a response to a preceding message with 'tool_calls'"
16
+ if (keptIndex > 0 && messages[keptIndex]?.role === "tool") {
17
+ keptIndex -= 1;
18
+ }
13
19
  const keptMessages = messages.slice(keptIndex);
14
20
  const keptSeqs = seqs.slice(keptIndex);
15
21
  const keptTimestamps = timestamps.slice(keptIndex);
@@ -105,3 +105,4 @@ export declare function sweepStalePendingRows(staleAfterMs?: number): {
105
105
  export declare function markToolCallErrored(sessionId: string, toolCallId: string, errorMessage: string): void;
106
106
  export declare function appendCompaction(sessionId: string, firstKeptSeq: number, summary: string, tokensBefore: number): void;
107
107
  export declare function buildChatEntries(sessionId: string): ChatEntry[];
108
+ export declare function getLastTodoWriteArgs(sessionId: string): string | null;
@@ -383,8 +383,18 @@ export function buildChatEntries(sessionId) {
383
383
  const toolResults = loadStoredToolResults(sessionId);
384
384
  const callMap = new Map();
385
385
  const entries = [];
386
+ // Response-tool callIds already rendered as a structured_response from a
387
+ // persisted tool-RESULT row (success path). After the loop we recover any
388
+ // response tool that was CALLED but produced no result row — i.e. respond_*
389
+ // whose execution ERRORED (the AI SDK does not persist tool-error parts as
390
+ // tool-result rows). Its answer lives in the call args; without this it is
391
+ // dropped on the turn-finalize rebuild and the user sees an empty turn or
392
+ // only the last council debate round.
393
+ const renderedResponseCallIds = new Set();
394
+ let lastTimestamp;
386
395
  for (const row of buildEffectiveMessageRecords(sessionId)) {
387
396
  const { message, timestamp } = row;
397
+ lastTimestamp = timestamp;
388
398
  if (message.role === "user") {
389
399
  const content = renderUserContent(message.content);
390
400
  if (content) {
@@ -432,6 +442,7 @@ export function buildChatEntries(sessionId) {
432
442
  // wraps tool outputs as `{type:"json", value:{...}}`; unwrap to expose
433
443
  // the schema-shaped payload to the renderer.
434
444
  if (isResponseTool(part.toolName)) {
445
+ renderedResponseCallIds.add(part.toolCallId);
435
446
  const rawOutput = part.output;
436
447
  const unwrapped = rawOutput && typeof rawOutput === "object" && rawOutput.type === "json"
437
448
  ? (rawOutput.value ?? {})
@@ -463,6 +474,33 @@ export function buildChatEntries(sessionId) {
463
474
  }
464
475
  }
465
476
  }
477
+ // Recover response-tool answers that were CALLED but never produced a
478
+ // tool-result row (execution ERRORED). The payload lives in the call args.
479
+ // Without this, a respond_* that errored after the council debate is dropped
480
+ // on finalize and only the last debate round stays visible.
481
+ for (const [callId, call] of callMap) {
482
+ if (renderedResponseCallIds.has(callId))
483
+ continue;
484
+ if (!isResponseTool(call.function.name))
485
+ continue;
486
+ let data;
487
+ try {
488
+ data = JSON.parse(call.function.arguments || "{}");
489
+ }
490
+ catch {
491
+ // Args unparseable — nothing to recover for this call.
492
+ continue;
493
+ }
494
+ entries.push({
495
+ type: "structured_response",
496
+ content: "",
497
+ timestamp: lastTimestamp ?? new Date(),
498
+ structuredResponse: {
499
+ taskType: getResponseTaskType(call.function.name) ?? call.function.name,
500
+ data,
501
+ },
502
+ });
503
+ }
466
504
  return entries;
467
505
  }
468
506
  function getNextSequence(db, sessionId) {
@@ -540,4 +578,21 @@ function toFallbackToolCall(toolCallId, toolName) {
540
578
  },
541
579
  };
542
580
  }
581
+ export function getLastTodoWriteArgs(sessionId) {
582
+ try {
583
+ const row = getDatabase()
584
+ .prepare(`
585
+ SELECT args_json
586
+ FROM tool_calls
587
+ WHERE session_id = ? AND tool_name = 'todo_write'
588
+ ORDER BY id DESC
589
+ LIMIT 1
590
+ `)
591
+ .get(sessionId);
592
+ return row?.args_json ?? null;
593
+ }
594
+ catch {
595
+ return null;
596
+ }
597
+ }
543
598
  //# sourceMappingURL=transcript.js.map
@@ -107,6 +107,20 @@ interface InitNewRetryPayload {
107
107
  feStack: string;
108
108
  bbTemplate: string | null;
109
109
  }
110
+ /** Auto-resolved loop-cap event (no user prompt). Replaces the old askcard_open for tool-loop-cap. */
111
+ interface LoopCapAutoPayload {
112
+ questionId: string;
113
+ phase: "tool-loop-cap";
114
+ autoVerdict: "continue" | "stop";
115
+ kind: "pattern" | "cap";
116
+ stepNumber: number;
117
+ /** Only present for pattern kind. */
118
+ toolName?: string;
119
+ count?: number;
120
+ naturalCeiling?: number | null;
121
+ /** Only present for cap kind. */
122
+ cap?: number;
123
+ }
110
124
  type Payload = {
111
125
  subtype: "route_decision";
112
126
  data: RouteDecisionPayload;
@@ -146,6 +160,9 @@ type Payload = {
146
160
  } | {
147
161
  subtype: "init_new_retry";
148
162
  data: InitNewRetryPayload;
163
+ } | {
164
+ subtype: "loop_cap_auto";
165
+ data: LoopCapAutoPayload;
149
166
  };
150
167
  /**
151
168
  * Persist a UI lifecycle event. Caller passes a discriminated payload so
@@ -12,31 +12,31 @@ export function recordUsageEvent(sessionId, source, model, usage, messageSeq, pi
12
12
  const cacheCreationTokens = usage.cacheCreationTokens ?? 0;
13
13
  const costMicros = estimateCostMicros(model, inputTokens, outputTokens, cacheReadTokens);
14
14
  getDatabase()
15
- .prepare(`
16
- INSERT INTO usage_events (
17
- session_id, message_seq, source, model, input_tokens, output_tokens, total_tokens, cost_micros, created_at,
18
- pil_active, enrichment_delta, cache_read_tokens, cache_creation_tokens, provider_options_shape
19
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
15
+ .prepare(`
16
+ INSERT INTO usage_events (
17
+ session_id, message_seq, source, model, input_tokens, output_tokens, total_tokens, cost_micros, created_at,
18
+ pil_active, enrichment_delta, cache_read_tokens, cache_creation_tokens, provider_options_shape
19
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
20
20
  `)
21
21
  .run(sessionId, messageSeq ?? null, source, model, inputTokens, outputTokens, totalTokens, costMicros, new Date().toISOString(), pilActive ? 1 : 0, enrichmentDelta, cacheReadTokens, cacheCreationTokens, providerOptionsShape);
22
22
  }
23
23
  export function getSessionTotalTokens(sessionId) {
24
24
  const row = getDatabase()
25
- .prepare(`
26
- SELECT COALESCE(SUM(total_tokens), 0) AS total_tokens
27
- FROM usage_events
28
- WHERE session_id = ?
25
+ .prepare(`
26
+ SELECT COALESCE(SUM(total_tokens), 0) AS total_tokens
27
+ FROM usage_events
28
+ WHERE session_id = ?
29
29
  `)
30
30
  .get(sessionId);
31
31
  return row?.total_tokens ?? 0;
32
32
  }
33
33
  export function listSessionUsage(sessionId) {
34
34
  const rows = getDatabase()
35
- .prepare(`
36
- SELECT id, session_id, message_seq, source, model, input_tokens, output_tokens, total_tokens, cost_micros, created_at, cache_read_tokens, cache_creation_tokens
37
- FROM usage_events
38
- WHERE session_id = ?
39
- ORDER BY id ASC
35
+ .prepare(`
36
+ SELECT id, session_id, message_seq, source, model, input_tokens, output_tokens, total_tokens, cost_micros, created_at, cache_read_tokens, cache_creation_tokens
37
+ FROM usage_events
38
+ WHERE session_id = ?
39
+ ORDER BY id ASC
40
40
  `)
41
41
  .all(sessionId);
42
42
  return rows.map((row) => ({
@@ -8,14 +8,14 @@ export function ensureWorkspace(cwd) {
8
8
  const now = new Date().toISOString();
9
9
  const id = createHash("sha1").update(resolved.scopeKey).digest("hex").slice(0, 16);
10
10
  const db = getDatabase();
11
- db.prepare(`
12
- INSERT INTO workspaces (id, scope_key, canonical_path, git_root, display_name, last_seen_at)
13
- VALUES (@id, @scope_key, @canonical_path, @git_root, @display_name, @last_seen_at)
14
- ON CONFLICT(scope_key) DO UPDATE SET
15
- canonical_path = excluded.canonical_path,
16
- git_root = excluded.git_root,
17
- display_name = excluded.display_name,
18
- last_seen_at = excluded.last_seen_at
11
+ db.prepare(`
12
+ INSERT INTO workspaces (id, scope_key, canonical_path, git_root, display_name, last_seen_at)
13
+ VALUES (@id, @scope_key, @canonical_path, @git_root, @display_name, @last_seen_at)
14
+ ON CONFLICT(scope_key) DO UPDATE SET
15
+ canonical_path = excluded.canonical_path,
16
+ git_root = excluded.git_root,
17
+ display_name = excluded.display_name,
18
+ last_seen_at = excluded.last_seen_at
19
19
  `).run({
20
20
  id,
21
21
  scope_key: resolved.scopeKey,
@@ -25,10 +25,10 @@ export function ensureWorkspace(cwd) {
25
25
  last_seen_at: now,
26
26
  });
27
27
  const row = db
28
- .prepare(`
29
- SELECT id, scope_key, canonical_path, git_root, display_name, last_seen_at
30
- FROM workspaces
31
- WHERE scope_key = ?
28
+ .prepare(`
29
+ SELECT id, scope_key, canonical_path, git_root, display_name, last_seen_at
30
+ FROM workspaces
31
+ WHERE scope_key = ?
32
32
  `)
33
33
  .get(resolved.scopeKey);
34
34
  if (!row) {
@@ -33,6 +33,12 @@ describe("registerNativeMuonroiTools", () => {
33
33
  registerNativeMuonroiTools(tools);
34
34
  expect(await exec(tools, "ee_feedback", { verdict: "followed" })).toMatch(/invalid_args/);
35
35
  });
36
+ it("ee_write rejects a too-short lesson (no network call)", async () => {
37
+ const tools = {};
38
+ registerNativeMuonroiTools(tools);
39
+ expect(await exec(tools, "ee_write", { lesson: "oops" })).toMatch(/invalid_args/);
40
+ expect(await exec(tools, "ee_write", {})).toMatch(/invalid_args/);
41
+ });
36
42
  it("selfverify_status returns not_found for an unknown runId (shared JobManager)", async () => {
37
43
  const tools = {};
38
44
  registerNativeMuonroiTools(tools);
@@ -14,7 +14,13 @@ export interface BackgroundProcess {
14
14
  exitCode: number | null;
15
15
  }
16
16
  interface BashToolOptions {
17
- sandboxMode?: SandboxMode;
17
+ /**
18
+ * Accepted for backward compatibility with callers that pass sandboxMode.
19
+ * Sandbox has been removed; this value is ignored — mode is always "off".
20
+ * Will be repurposed when the new sandbox is implemented.
21
+ * @deprecated
22
+ */
23
+ sandboxMode?: string;
18
24
  sandboxSettings?: SandboxSettings;
19
25
  shellSettings?: ShellSettings;
20
26
  }
@@ -22,12 +28,17 @@ export declare class BashTool {
22
28
  private cwd;
23
29
  private bgProcesses;
24
30
  private tmpDir;
25
- private sandboxMode;
26
- private sandboxSettings;
27
31
  private shellSettings;
28
32
  private resolvedShell;
29
- private sandboxUnsupportedWarned;
33
+ private sandboxSettings;
30
34
  constructor(initialCwd?: string, options?: BashToolOptions);
35
+ /**
36
+ * Sandbox has been removed. Always returns "off".
37
+ * Kept for backward compatibility with orchestrator / stream-runner callers.
38
+ */
39
+ getSandboxMode(): SandboxMode;
40
+ getSandboxSettings(): SandboxSettings;
41
+ setSandboxSettings(settings: SandboxSettings): void;
31
42
  private ensureTmpDir;
32
43
  execute(command: string, timeout?: number, abortSignal?: AbortSignal): Promise<ToolResult>;
33
44
  startBackground(command: string): Promise<ToolResult>;
@@ -37,29 +48,31 @@ export declare class BashTool {
37
48
  cleanup(): Promise<void>;
38
49
  getCwd(): string;
39
50
  setCwd(next: string): void;
40
- getSandboxMode(): SandboxMode;
41
- setSandboxMode(mode: SandboxMode): void;
42
- /**
43
- * The sandbox mode that actually takes effect. When "shuru" is configured but
44
- * the current platform cannot run Shuru (non-macOS/arm64), the sandbox is
45
- * inert: every wrapped command would fail with the macOS-only error, and the
46
- * tool description would still advertise a `/workspace` mount that does not
47
- * exist — so the model `cd`s into a phantom dir and abandons verification.
48
- * Degrade to "off" (host execution) with a one-time warning so bash keeps
49
- * working and the description reflects reality. A stale checked-in project
50
- * `sandboxMode: "shuru"` therefore no longer bricks the shell off-platform.
51
- */
52
- private effectiveSandboxMode;
53
- getSandboxSettings(): SandboxSettings;
54
- setSandboxSettings(settings: SandboxSettings): void;
55
51
  getToolDescription(): string;
56
52
  getResolvedShell(): ResolvedShell;
57
53
  private spawnInvocation;
54
+ /**
55
+ * Pre-execution command preparation.
56
+ *
57
+ * Layer 1 — Catastrophic hard-block: checks the command against
58
+ * CATASTROPHIC_PATTERNS in permission-mode.ts. These are irreversible or
59
+ * severely dangerous operations that are blocked regardless of permission
60
+ * mode (safe / auto-edit / yolo) and regardless of sandbox state.
61
+ *
62
+ * Layer 2 — Future sandbox: when a new sandbox is wired in, wrap the
63
+ * command here before returning.
64
+ */
65
+ /**
66
+ * Pre-execution command preparation with two-layer safety.
67
+ *
68
+ * Layer 1 — Catastrophic hard-block: checks the command against
69
+ * CATASTROPHIC_PATTERNS in permission-mode.ts. Returns structured block
70
+ * result so callers can route to askcard approval flow.
71
+ *
72
+ * Layer 2 — Future sandbox: when a new sandbox is wired in, wrap the
73
+ * command here before returning.
74
+ */
58
75
  private prepareCommand;
59
- private formatSandboxRuntimeError;
60
76
  }
61
- export declare function wrapCommandForShuru(cwd: string, command: string, settings?: SandboxSettings): string;
62
- export declare function shouldRunOnHostInSandboxMode(command: string, settings?: SandboxSettings): boolean;
63
77
  export declare function wrapHostBrowserCommand(command: string): string;
64
- export declare function getSandboxMutationBlockReason(command: string, settings?: SandboxSettings): string | null;
65
78
  export {};