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
@@ -1,10 +1,11 @@
1
1
  import type { ModelMessage } from "ai";
2
2
  import { type ProviderId } from "../providers/types.js";
3
3
  import { type ScheduleDaemonStatus, type StoredSchedule } from "../tools/schedule.js";
4
- import type { AgentMode, ChatEntry, SessionInfo, SessionSnapshot, StreamChunk, SubagentStatus, TaskRequest, ToolResult, VerifyRecipe } from "../types/index.js";
4
+ import type { AgentMode, ChatEntry, SessionInfo, SessionSnapshot, StreamChunk, SubagentStatus, TaskListSnapshot, TaskRequest, ToolResult, VerifyRecipe } from "../types/index.js";
5
5
  import { type SandboxMode, type SandboxSettings } from "../utils/settings.js";
6
6
  import { type SideQuestionResult } from "../utils/side-question.js";
7
7
  import { type AgentOptions, type ProcessMessageObserver } from "./agent-options.js";
8
+ import type { SafetyOverrideAskInfo, SafetyOverrideVerdict } from "./safety-askcard.js";
8
9
  import type { ToolLoopCapAsk } from "./tool-loop-cap.js";
9
10
  export declare class Agent {
10
11
  private provider;
@@ -111,7 +112,7 @@ export declare class Agent {
111
112
  setModel(model: string): void;
112
113
  getMode(): AgentMode;
113
114
  getSandboxMode(): SandboxMode;
114
- setSandboxMode(mode: SandboxMode): void;
115
+ setSandboxMode(_mode: SandboxMode): void;
115
116
  getSandboxSettings(): SandboxSettings;
116
117
  setSandboxSettings(settings: SandboxSettings): void;
117
118
  setMode(mode: AgentMode): void;
@@ -140,6 +141,8 @@ export declare class Agent {
140
141
  cleanup(): Promise<void>;
141
142
  private _toolLoopCapHandler;
142
143
  setToolLoopCapHandler(fn: ToolLoopCapAsk | null): void;
144
+ private _safetyOverrideHandler;
145
+ setSafetyOverrideHandler(fn: ((block: SafetyOverrideAskInfo) => Promise<SafetyOverrideVerdict>) | null): void;
143
146
  respondToToolApproval(approvalId: string, approved: boolean): void;
144
147
  clearHistory(): Promise<void>;
145
148
  startNewSession(): SessionSnapshot | null;
@@ -161,6 +164,7 @@ export declare class Agent {
161
164
  unpinMessageBySeq(seq: number): boolean;
162
165
  getPinnedSeqs(): number[];
163
166
  getChatEntries(): ChatEntry[];
167
+ getLastTodoSnapshot(): TaskListSnapshot | null;
164
168
  getSessionSnapshot(): SessionSnapshot | null;
165
169
  onSubagentStatus(listener: (status: SubagentStatus | null) => void): () => void;
166
170
  private emitSubagentStatus;
@@ -183,6 +187,7 @@ export declare class Agent {
183
187
  private runDelegation;
184
188
  private readDelegation;
185
189
  private listDelegations;
190
+ private killDelegation;
186
191
  private getCompactionSettings;
187
192
  private _resolveCompactModel;
188
193
  private _resolveModelForTask;
@@ -225,6 +230,7 @@ export declare class Agent {
225
230
  * allocation cost is negligible against the batch polling spend.
226
231
  */
227
232
  private _buildBatchTurnRunnerDeps;
233
+ private appendMidTurnMessages;
228
234
  private appendCompletedTurn;
229
235
  private fireHook;
230
236
  processMessage(userMessage: string, observer?: ProcessMessageObserver, images?: Array<{
@@ -14,22 +14,24 @@ import { apiBaseFor } from "../providers/endpoints.js";
14
14
  import { loadKeyForProvider } from "../providers/keychain.js";
15
15
  import { createProviderFactory, createProviderFactoryAsync, detectProviderForModel, requireRuntimeProvider, resolveModelRuntime as resolveRuntime, } from "../providers/runtime.js";
16
16
  import { ALL_PROVIDER_IDS } from "../providers/types.js";
17
- import { appendCompaction, appendMessages, appendSystemMessage, buildChatEntries, getNextMessageSequence, getSessionTotalTokens, loadTranscript, loadTranscriptState, logInteraction, markMessageCompleted, recordUsageEvent, SessionStore, } from "../storage/index.js";
17
+ import { appendCompaction, appendMessages, appendSystemMessage, buildChatEntries, getLastTodoWriteArgs, getNextMessageSequence, getSessionTotalTokens, loadTranscript, loadTranscriptState, logInteraction, markMessageCompleted, recordUsageEvent, SessionStore, } from "../storage/index.js";
18
18
  import { BashTool } from "../tools/bash.js";
19
19
  import { createBuiltinTools } from "../tools/registry.js";
20
20
  import { ScheduleManager } from "../tools/schedule.js";
21
+ import { snapshotFromTodoWriteArgs } from "../tools/todo-write-snapshot.js";
21
22
  import { statusBarStore } from "../ui/status-bar/store.js";
22
23
  import { appendCostLog } from "../usage/cost-log.js";
23
24
  import { appendDecisionLog } from "../usage/decision-log.js";
24
- import { projectCostUSD } from "../usage/estimator.js";
25
+ import { projectCostUSD, sanitizeInputTokens } from "../usage/estimator.js";
25
26
  import { getAutoCompactThresholdPct, getCouncilRounds, getCurrentModel, getCurrentShellSettings, getModeSpecificModel, getRoleModel, getRoleModels, isAutoCompactAfterTurnEnabled, isCouncilMultiProviderPreferred, isProviderDisabled, } from "../utils/settings.js";
26
27
  import { runSideQuestion } from "../utils/side-question.js";
27
28
  import { buildVerifyDetectPrompt, normalizeVerifyRecipe } from "../verify/entrypoint.js";
28
29
  import { runVerifyOrchestration } from "../verify/orchestrator.js";
29
30
  import { COUNCIL_COLOR_BG, COUNCIL_COLOR_RESET, COUNCIL_ROLE_COLORS, } from "./agent-options.js";
31
+ import { AUTO_COMMIT_ATTRIBUTION, isAutoCommitEnabled, maybeAutoCommitTurn, snapshotDirtyPaths, } from "./auto-commit.js";
30
32
  import { BatchTurnRunner } from "./batch-turn-runner.js";
31
33
  import { accumulateUsage, buildAssistantBatchMessage, buildBatchChatCompletionRequest, buildBatchName, buildToolBatchMessage, extractJsonObject, getBatchUsage, hasUsage, parseToolArgumentsOrRaw, toLocalToolCall, } from "./batch-utils.js";
32
- import { createCompactionSummaryMessage, DEFAULT_KEEP_RECENT_TOKENS, DEFAULT_RESERVE_TOKENS, estimateConversationTokens, extractUserContent, generateCompactionSummary, POST_TURN_MIN_TOKENS, prepareCompaction, shouldCompactContext, } from "./compaction.js";
34
+ import { createCompactionSummaryMessage, DEFAULT_KEEP_RECENT_TOKENS, DEFAULT_RESERVE_TOKENS, estimateConversationTokens, extractUserContent, generateCompactionSummary, POST_TURN_MIN_TOKENS, prepareCompaction, proposeCompaction, shouldCompactContext, } from "./compaction.js";
33
35
  import { CouncilManager } from "./council-manager.js";
34
36
  import { CrossTurnDedup, isCrossTurnDedupEnabled } from "./cross-turn-dedup.js";
35
37
  import { DelegationManager } from "./delegations.js";
@@ -105,6 +107,7 @@ function createTools(_bash, _provider, _mode, _opts) {
105
107
  runDelegation: _opts?.runDelegation,
106
108
  readDelegation: _opts?.readDelegation,
107
109
  listDelegations: _opts?.listDelegations,
110
+ killDelegation: _opts?.killDelegation,
108
111
  modelId: _opts?.modelId,
109
112
  });
110
113
  }
@@ -355,10 +358,12 @@ export class Agent {
355
358
  return this.mode;
356
359
  }
357
360
  getSandboxMode() {
361
+ // Sandbox has been removed; BashTool.getSandboxMode() always returns "off".
358
362
  return this.bash.getSandboxMode();
359
363
  }
360
- setSandboxMode(mode) {
361
- this.bash.setSandboxMode(mode);
364
+ setSandboxMode(_mode) {
365
+ // No-op: sandbox has been removed. BashTool no longer has a mutable sandbox mode.
366
+ // Will be re-implemented when the new sandbox is ready.
362
367
  }
363
368
  getSandboxSettings() {
364
369
  return this.bash.getSandboxSettings();
@@ -516,6 +521,15 @@ export class Agent {
516
521
  setToolLoopCapHandler(fn) {
517
522
  this._toolLoopCapHandler = fn;
518
523
  }
524
+ // Safety-override handler — set by the UI (app.tsx) at startup. Invoked
525
+ // from the message-processor tool-result pipeline when a safety block
526
+ // (catastrophic, dangerous, git-safety, empty-bash) is detected. The UI
527
+ // surfaces an askcard ("Allow once / Allow session / Block") and resolves
528
+ // with the verdict. When unset, blocks pass through as normal errors.
529
+ _safetyOverrideHandler = null;
530
+ setSafetyOverrideHandler(fn) {
531
+ this._safetyOverrideHandler = fn;
532
+ }
519
533
  respondToToolApproval(approvalId, approved) {
520
534
  const toolApprovalResponse = {
521
535
  role: "tool",
@@ -640,6 +654,14 @@ export class Agent {
640
654
  return [];
641
655
  return buildChatEntries(this.session.id);
642
656
  }
657
+ getLastTodoSnapshot() {
658
+ if (!this.session)
659
+ return null;
660
+ const argsJson = getLastTodoWriteArgs(this.session.id);
661
+ if (!argsJson)
662
+ return null;
663
+ return snapshotFromTodoWriteArgs(argsJson);
664
+ }
643
665
  getSessionSnapshot() {
644
666
  if (!this.session || !this.workspace)
645
667
  return null;
@@ -765,6 +787,10 @@ export class Agent {
765
787
  // where orchestrator/task/title traffic is actually spending.
766
788
  // Best-effort: failures inside appendCostLog are swallowed (see cost-log.ts).
767
789
  const breakdown = source === "message" ? (this._lastPromptBreakdown ?? undefined) : undefined;
790
+ // Sanitize actualInputTokens for providers (e.g. SiliconFlow) that return
791
+ // implausibly low prompt_tokens (e.g. 10) regardless of prompt size.
792
+ const estIn = breakdown ? Math.ceil(((breakdown.systemChars ?? 0) + (breakdown.messagesChars ?? 0)) / 4) : 0;
793
+ const actualInput = sanitizeInputTokens(totalInput, estIn);
768
794
  appendCostLog({
769
795
  ts: Date.now(),
770
796
  provider: this.providerId,
@@ -772,7 +798,7 @@ export class Agent {
772
798
  estimatedUsd: turnCostMicros / 1_000_000,
773
799
  callsite: `orchestrator.${source}`,
774
800
  phase: source,
775
- actualInputTokens: totalInput,
801
+ actualInputTokens: actualInput,
776
802
  actualOutputTokens: output,
777
803
  cachedInputTokens: cacheRead,
778
804
  systemChars: breakdown?.systemChars,
@@ -1162,15 +1188,29 @@ export class Agent {
1162
1188
  };
1163
1189
  }
1164
1190
  }
1191
+ async killDelegation(id) {
1192
+ try {
1193
+ return await this.delegations.kill(id);
1194
+ }
1195
+ catch (err) {
1196
+ const msg = err instanceof Error ? err.message : String(err);
1197
+ return {
1198
+ success: false,
1199
+ output: `Failed to terminate delegation: ${msg}`,
1200
+ };
1201
+ }
1202
+ }
1165
1203
  getCompactionSettings(contextWindow) {
1166
1204
  let keepRecentTokens = DEFAULT_KEEP_RECENT_TOKENS;
1167
1205
  // For models with very large context windows, keep more recent tokens
1168
1206
  if (contextWindow && contextWindow > 200_000) {
1169
1207
  keepRecentTokens = Math.min(100_000, Math.max(20_000, Math.floor(contextWindow * 0.1)));
1170
1208
  }
1171
- // Compact more aggressively for long sessions to prevent runaway token growth
1209
+ // For long sessions, reduce keepRecentTokens slightly to slow context growth
1210
+ // (0.85 instead of old 0.75 — session bf58d0f46b51 showed 0.75 created a
1211
+ // tight compact-loop: keep 15K → add 50K tool results → re-compact immediately).
1172
1212
  if (this._compactionStats.count >= 2) {
1173
- keepRecentTokens = Math.floor(keepRecentTokens * 0.75);
1213
+ keepRecentTokens = Math.floor(keepRecentTokens * 0.85);
1174
1214
  }
1175
1215
  return {
1176
1216
  reserveTokens: Math.max(this.maxTokens, DEFAULT_RESERVE_TOKENS),
@@ -1186,12 +1226,28 @@ export class Agent {
1186
1226
  async compactForContext(provider, system, contextWindow, signal, settings = this.getCompactionSettings(contextWindow), force = false) {
1187
1227
  if (!this.session)
1188
1228
  return false;
1229
+ // Phase 1: ask the compaction proposer model whether to compact and what to keep/drop.
1230
+ // Only compact if the model says yes. On error/skip, fall back to heuristic.
1231
+ const compactModelId = this._resolveCompactModel();
1232
+ const proposal = await proposeCompaction(provider, compactModelId, this.messages, signal);
1233
+ if (proposal !== null) {
1234
+ // Model decided — compact only if model says shouldCompact
1235
+ if (force) {
1236
+ // force always proceeds; the proposer's actions still guide what to keep/drop
1237
+ }
1238
+ else if (!proposal.shouldCompact) {
1239
+ return false;
1240
+ }
1241
+ }
1242
+ else {
1243
+ // Proposer unavailable — fall back to heuristic token-threshold check
1244
+ if (!force && !shouldCompactContext(estimateConversationTokens(system, this.messages), contextWindow, settings)) {
1245
+ return false;
1246
+ }
1247
+ }
1189
1248
  const preparation = prepareCompaction(this.messages, system, settings);
1190
1249
  if (!preparation)
1191
1250
  return false;
1192
- if (!force && !shouldCompactContext(preparation.tokensBefore, contextWindow, settings)) {
1193
- return false;
1194
- }
1195
1251
  const trigger = force ? "manual" : "auto";
1196
1252
  // Fire-and-forget: notify EE of stale suggestions before compaction
1197
1253
  const { surfacedIds, timestamp } = getLastSurfacedState();
@@ -1219,7 +1275,6 @@ export class Agent {
1219
1275
  await this.fireHook(preCompactInput, signal).catch(() => { });
1220
1276
  const keptSeqs = this.messageSeqs.slice(preparation.firstKeptIndex);
1221
1277
  const firstKeptSeq = keptSeqs.find((seq) => seq !== null) ?? getNextMessageSequence(this.session.id);
1222
- const compactModelId = this._resolveCompactModel();
1223
1278
  const compactStartedAt = Date.now();
1224
1279
  const { summary, usage: compactUsage } = await generateCompactionSummary(provider, compactModelId, preparation, undefined, signal);
1225
1280
  // Record compaction call in cost-log — bypasses recordUsage because
@@ -1285,11 +1340,15 @@ export class Agent {
1285
1340
  .catch(() => { });
1286
1341
  // Mark as surfaced for prompt-stale reconciliation (per plan Phase 1).
1287
1342
  updateLastSurfacedState([`compact-checkpoint-${this._compactionStats.count + 1}`]);
1288
- // Track compaction stats — net of the tokens spent ON compaction itself.
1343
+ // Track compaction stats — report the GROSS context reduction, NOT net-after-compact-cost.
1344
+ // Rationale: the compaction call's own prompt/completion tokens ARE already counted in
1345
+ // in_tokens/out_tokens/session_usd (updateStatusBar at line 986). Subtracting them here
1346
+ // would double-penalize: the user sees the real cost in the token counter AND sees
1347
+ // "0 saved" because compactCost >= grossSaved (the compact prompt is the full conversation).
1348
+ // grossSaved tells the user how many context tokens were reclaimed — a real benefit that
1349
+ // reduces subsequent turn costs.
1289
1350
  const tokensAfter = estimateConversationTokens(system, this.messages);
1290
- const grossSaved = Math.max(0, preparation.tokensBefore - tokensAfter);
1291
- const compactCost = compactUsage.promptTokens + compactUsage.completionTokens;
1292
- const saved = Math.max(0, grossSaved - compactCost);
1351
+ const saved = Math.max(0, preparation.tokensBefore - tokensAfter);
1293
1352
  const pct = preparation.tokensBefore > 0 ? ((saved / preparation.tokensBefore) * 100).toFixed(1) : "0.0";
1294
1353
  this._compactionStats.count++;
1295
1354
  this._compactionStats.totalSaved += saved;
@@ -1317,8 +1376,6 @@ export class Agent {
1317
1376
  tokensBefore: preparation.tokensBefore,
1318
1377
  tokensAfter,
1319
1378
  saved,
1320
- grossSaved,
1321
- compactCost,
1322
1379
  pct,
1323
1380
  isLongSession,
1324
1381
  },
@@ -1383,23 +1440,67 @@ export class Agent {
1383
1440
  const councilStats = { calls: 0, startMs: Date.now(), phases: [] };
1384
1441
  const llm = createCouncilLLM(this.bash, this.mode, this.session?.id, councilStats);
1385
1442
  const processMessageFn = (message) => this.processMessage(message, options?.observer);
1386
- const gen = runCouncil(topic, this.modelId, this.messages, this.session?.id, llm, this.councilManager.createQuestionResponder(), this.councilManager.createPreflightResponder(), processMessageFn, {
1387
- skipClarification: options?.skipClarification,
1388
- userModelMessage: options?.userModelMessage,
1389
- cwd: this.bash.getCwd(),
1390
- councilStats, // NEWshare orchestrator's stats object with runCouncil (Phase 14 CQ-01)
1391
- });
1392
- let result;
1393
- do {
1394
- result = await gen.next();
1395
- if (!result.done && result.value) {
1396
- yield result.value;
1443
+ // Ensure a turn-scoped AbortController exists so Esc agent.abort()
1444
+ // this.abortController.abort() actually cancels the council. Two entry points
1445
+ // reach here: the auto-council path runs INSIDE processMessage, which already
1446
+ // set this.abortController; the /council SLASH path calls runCouncilV2
1447
+ // directly with NONE set so before this guard, pressing Esc during an
1448
+ // explicit /council run was a no-op (abort() hit a null controller) and the
1449
+ // multi-minute debate ran to completion regardless. Create one when absent
1450
+ // so the user-abort signal threads into every council generate/debate/
1451
+ // research call for BOTH entry points. Only tear down a controller we own.
1452
+ const ownsController = !this.abortController;
1453
+ if (ownsController) {
1454
+ this.abortController = new AbortController();
1455
+ }
1456
+ const signal = this.abortController?.signal;
1457
+ // B1: Resolve a run directory so runCouncil persists decisions.lock.md after
1458
+ // synthesis. The auto-council/sprint paths get a runDir from their own flow
1459
+ // wiring, but the explicit /council SLASH path never did — so its outcome was
1460
+ // never written to disk (no audit trail, nothing for a later /ideal to read).
1461
+ // Reuse the session's active flow run; create one if the session never booted
1462
+ // a flow. Fail-open: a runDir-resolution error must not block the council.
1463
+ let runDir;
1464
+ try {
1465
+ const nodePath = await import("node:path");
1466
+ const flowDir = await ensureFlowDir(this.bash.getCwd());
1467
+ let runId = this._activeRunId ?? (await getActiveRunId(flowDir));
1468
+ if (!runId) {
1469
+ runId = (await createRun(flowDir)).id;
1470
+ await setActiveRunId(flowDir, runId);
1471
+ this._activeRunId = runId;
1472
+ }
1473
+ runDir = nodePath.join(flowDir, "runs", runId);
1474
+ }
1475
+ catch (err) {
1476
+ console.error(`[council] runDir resolution failed (decisions.lock will be skipped): ${err?.message}`);
1477
+ }
1478
+ try {
1479
+ const gen = runCouncil(topic, this.modelId, this.messages, this.session?.id, llm, this.councilManager.createQuestionResponder(), this.councilManager.createPreflightResponder(), processMessageFn, {
1480
+ skipClarification: options?.skipClarification,
1481
+ userModelMessage: options?.userModelMessage,
1482
+ cwd: this.bash.getCwd(),
1483
+ councilStats, // NEW — share orchestrator's stats object with runCouncil (Phase 14 CQ-01)
1484
+ signal,
1485
+ runDir, // B1 — persist decisions.lock.md for the /council slash path
1486
+ });
1487
+ let result;
1488
+ do {
1489
+ result = await gen.next();
1490
+ if (!result.done && result.value) {
1491
+ yield result.value;
1492
+ }
1493
+ } while (!result.done);
1494
+ const synthesis = result.value;
1495
+ this.councilManager.setLastSynthesis(synthesis);
1496
+ if (options?.userModelMessage && synthesis) {
1497
+ this.appendCompletedTurn(options.userModelMessage, [{ role: "assistant", content: synthesis }]);
1498
+ }
1499
+ }
1500
+ finally {
1501
+ if (ownsController && this.abortController?.signal === signal) {
1502
+ this.abortController = null;
1397
1503
  }
1398
- } while (!result.done);
1399
- const synthesis = result.value;
1400
- this.councilManager.setLastSynthesis(synthesis);
1401
- if (options?.userModelMessage && synthesis) {
1402
- this.appendCompletedTurn(options.userModelMessage, [{ role: "assistant", content: synthesis }]);
1403
1504
  }
1404
1505
  }
1405
1506
  // ========================================================================
@@ -1930,12 +2031,27 @@ export class Agent {
1930
2031
  runDelegation: (request, signal) => self.runDelegation(request, signal),
1931
2032
  readDelegation: (id) => self.readDelegation(id),
1932
2033
  listDelegations: () => self.listDelegations(),
2034
+ killDelegation: (id) => self.killDelegation(id),
1933
2035
  executeBatchToolCall: (tools, toolCall, messages, signal) => self.executeBatchToolCall(tools, toolCall, messages, signal),
1934
2036
  appendCompletedTurn: (user, asst) => self.appendCompletedTurn(user, asst),
1935
2037
  discardAbortedTurn: (user) => self.discardAbortedTurn(user),
1936
2038
  recordUsage: (usage, source, model, shape) => self.recordUsage(usage, source, model, shape),
1937
2039
  };
1938
2040
  }
2041
+ appendMidTurnMessages(newMessages) {
2042
+ if (newMessages.length === 0)
2043
+ return;
2044
+ if (!this.sessionStore || !this.session) {
2045
+ this.messages.push(...newMessages);
2046
+ this.messageSeqs.push(...newMessages.map(() => null));
2047
+ return;
2048
+ }
2049
+ const insertedSeqs = appendMessages(this.session.id, newMessages);
2050
+ this.messages.push(...newMessages);
2051
+ this.messageSeqs.push(...insertedSeqs);
2052
+ this.sessionStore.touchSession(this.session.id, this.bash.getCwd());
2053
+ this.session = this.sessionStore.getRequiredSession(this.session.id);
2054
+ }
1939
2055
  appendCompletedTurn(userMessage, newMessages) {
1940
2056
  if (newMessages.length === 0)
1941
2057
  return;
@@ -1987,7 +2103,28 @@ export class Agent {
1987
2103
  // ========================================================================
1988
2104
  async *processMessage(userMessage, observer, images) {
1989
2105
  const processor = new MessageProcessor(this._buildMessageProcessorDeps());
2106
+ // Deterministic "task done -> commit" (auto-commit): snapshot the dirty set
2107
+ // before the turn so we can commit ONLY the files the agent changes during it
2108
+ // (and never the user's pre-existing work-in-progress). Gated off under tests
2109
+ // and via MUONROI_AUTO_COMMIT=0.
2110
+ const autoCommitOn = isAutoCommitEnabled();
2111
+ const cwd = this.bash.getCwd();
2112
+ const dirtyBefore = autoCommitOn ? await snapshotDirtyPaths(cwd) : new Set();
1990
2113
  yield* processor.run(userMessage, observer, images);
2114
+ // Reached only when the turn completed normally (an abort/throw propagates
2115
+ // through yield* and skips this) — exactly when committing is appropriate.
2116
+ if (autoCommitOn) {
2117
+ const auto = await maybeAutoCommitTurn({ cwd, dirtyBefore, userMessage }).catch((err) => {
2118
+ console.error(`[auto-commit] unexpected failure: ${err?.message}`);
2119
+ return { committed: false };
2120
+ });
2121
+ if (auto.committed) {
2122
+ yield {
2123
+ type: "content",
2124
+ content: `\n✓ Auto-committed ${auto.fileCount} file(s) → ${auto.sha} (${AUTO_COMMIT_ATTRIBUTION})\n`,
2125
+ };
2126
+ }
2127
+ }
1991
2128
  }
1992
2129
  /**
1993
2130
  * Build the DI surface MessageProcessor (Phase 12.4) needs to reach back
@@ -2133,7 +2270,9 @@ export class Agent {
2133
2270
  runDelegation: (request, signal) => self.runDelegation(request, signal),
2134
2271
  readDelegation: (id) => self.readDelegation(id),
2135
2272
  listDelegations: () => self.listDelegations(),
2273
+ killDelegation: (id) => self.killDelegation(id),
2136
2274
  drainSteerMessages: () => self.steerDrain?.() ?? [],
2275
+ appendMidTurnMessages: (msgs) => self.appendMidTurnMessages(msgs),
2137
2276
  appendCompletedTurn: (user, asst) => self.appendCompletedTurn(user, asst),
2138
2277
  discardAbortedTurn: (user) => self.discardAbortedTurn(user),
2139
2278
  recordUsage: (usage, source, model, shape) => self.recordUsage(usage, source, model, shape),
@@ -2150,6 +2289,20 @@ export class Agent {
2150
2289
  return "stop";
2151
2290
  }
2152
2291
  },
2292
+ askSafetyOverride: async (info) => {
2293
+ const h = self._safetyOverrideHandler;
2294
+ if (!h) {
2295
+ console.warn(`[Agent] askSafetyOverride called but no handler registered — blocking ${info.kind}: ${info.reason}`);
2296
+ return { action: "block" };
2297
+ }
2298
+ try {
2299
+ return await h(info);
2300
+ }
2301
+ catch (err) {
2302
+ console.error(`[Agent] askSafetyOverride crashed: ${err?.message ?? err}`);
2303
+ return { action: "block" };
2304
+ }
2305
+ },
2153
2306
  runCouncilV2: (msg, opts) => self.runCouncilV2(msg, opts),
2154
2307
  processMessage: (msg, obs, imgs) => self.processMessage(msg, obs, imgs),
2155
2308
  processMessageBatchTurn: (args) => self.processMessageBatchTurn(args),
@@ -0,0 +1,13 @@
1
+ import { runPipeline } from "../pil/pipeline.js";
2
+ import type { StreamChunk } from "../types/index.js";
3
+ import type { MessageProcessorDeps } from "./message-processor.js";
4
+ import { type ComplexitySize } from "./scope-ceiling.js";
5
+ export interface PreprocessorResult {
6
+ pilCtx: Awaited<ReturnType<typeof runPipeline>>;
7
+ _stepCeiling: number;
8
+ _pilStart: number;
9
+ _naturalCeiling: number;
10
+ _ceilingTaskType: string;
11
+ _ceilingSize: ComplexitySize;
12
+ }
13
+ export declare function prepareTurnContext(deps: MessageProcessorDeps, userMessage: string, _budgetOverride: any): AsyncGenerator<StreamChunk, PreprocessorResult, unknown>;
@@ -0,0 +1,145 @@
1
+ import { runPipeline } from "../pil/pipeline.js";
2
+ import { getSessionLastTask, recordSessionLastTask, resolveCeiling } from "./scope-ceiling.js";
3
+ export async function* prepareTurnContext(deps, userMessage, _budgetOverride) {
4
+ // PIL: enrich prompt before pushing to messages (D-01, D-03, D-04)
5
+ // Promise.race timeout of 200ms is inside runPipeline — fail-open guaranteed
6
+ // --- PIL with discovery (interactive path) ---
7
+ const pilChunkQueue = [];
8
+ const pilResponder = deps.councilManager.createQuestionResponder();
9
+ const discoveryHandler = {
10
+ askQuestion: async (question) => {
11
+ pilChunkQueue.push({
12
+ type: "council_question",
13
+ content: question.question,
14
+ councilQuestion: question,
15
+ });
16
+ const text = await pilResponder(question.questionId);
17
+ return { questionId: question.questionId, text, kind: "choice" };
18
+ },
19
+ };
20
+ const _pilStart = Date.now();
21
+ let pilCtxResolved = null;
22
+ let pilDone = false;
23
+ const pilTask = (async () => {
24
+ try {
25
+ // Build Pass 4 LLM fallback closure using the orchestrator's already-
26
+ // constructed provider factory + current model. PIL stays ignorant of
27
+ // provider wiring — it just receives a `classify(prompt)` callback.
28
+ let llmFallback;
29
+ try {
30
+ const { createLlmClassifier } = await import("../pil/llm-classify.js");
31
+ llmFallback = createLlmClassifier(deps.requireProvider(), deps.modelId);
32
+ }
33
+ catch (err) {
34
+ console.error(`[pil] LLM fallback wiring failed: ${err?.message}`);
35
+ }
36
+ // Model-driven clarification proposer (for discovery interview).
37
+ // The actual task model (via the same provider + modelId) generates the
38
+ // questions based on raw + CLI enrichment. Then discovery asks user.
39
+ let clarificationProposer;
40
+ try {
41
+ const { createModelClarificationProposer } = await import("../pil/discovery.js");
42
+ clarificationProposer = createModelClarificationProposer(deps.requireProvider(), deps.modelId);
43
+ }
44
+ catch (err) {
45
+ console.error(`[pil] clarification proposer wiring failed: ${err?.message}`);
46
+ }
47
+ pilCtxResolved = await runPipeline(userMessage, {
48
+ resumeDigest: deps.getResumeDigest(),
49
+ activeRunId: deps.getActiveRunId(),
50
+ sessionId: deps.session?.id ?? null,
51
+ interactionHandler: discoveryHandler,
52
+ llmFallback,
53
+ clarificationProposer,
54
+ recentTurnsSummary: deps.buildRecentTurnsSummary(),
55
+ });
56
+ }
57
+ catch (err) {
58
+ pilCtxResolved = {
59
+ raw: userMessage,
60
+ enriched: userMessage,
61
+ taskType: null,
62
+ domain: null,
63
+ confidence: 0,
64
+ outputStyle: null,
65
+ tokenBudget: 500,
66
+ metrics: null,
67
+ layers: [],
68
+ gsdPhase: null,
69
+ activeRunId: null,
70
+ intentKind: null,
71
+ fallbackReason: err instanceof Error ? `orchestrator-catch:${err.name}` : "orchestrator-catch:unknown",
72
+ };
73
+ }
74
+ finally {
75
+ pilDone = true;
76
+ }
77
+ })();
78
+ while (!pilDone) {
79
+ while (pilChunkQueue.length > 0) {
80
+ yield pilChunkQueue.shift();
81
+ }
82
+ if (!pilDone) {
83
+ await new Promise((resolve) => setImmediate(resolve));
84
+ }
85
+ }
86
+ while (pilChunkQueue.length > 0) {
87
+ yield pilChunkQueue.shift();
88
+ }
89
+ await pilTask;
90
+ const pilCtx = pilCtxResolved;
91
+ // Phase 4 Plan 04 (4B) — resolve per-session step ceiling using
92
+ // (task_type × complexitySize) matrix. Override (from --budget-rounds N
93
+ // parsed earlier) wins. When the override differs from the natural
94
+ // ceiling, emit info toast so the user sees the explicit cap.
95
+ //
96
+ // Phase 5 Fix 2 — continuation phrases ("tiếp tục" / "continue") are
97
+ // classified `general/chitchat` by PIL Layer 1 Pass 0. Resolving the
98
+ // ceiling from that label collapses the budget to general × small = 5,
99
+ // which is wrong: the user wants the agent to RESUME the prior task,
100
+ // not start a generic chitchat. When this session has a recorded
101
+ // non-chitchat task row, inherit it for ceiling resolution. The Pass 0
102
+ // classification itself stays general so downstream code (style /
103
+ // chitchat skip / tools-empty optimization in `BUG-A guard`) reads the
104
+ // correct intent; only the ceiling row is borrowed.
105
+ const _pilTaskType = pilCtx.taskType ?? "general";
106
+ const _pilSize = pilCtx.complexitySize?.size ?? "medium";
107
+ const _sessionIdForLastTask = deps.session?.id ?? "";
108
+ const _isContinuationChitchat = _pilTaskType === "general" && pilCtx.intentKind === "chitchat" && _sessionIdForLastTask !== "";
109
+ const _lastTask = _isContinuationChitchat ? getSessionLastTask(_sessionIdForLastTask) : null;
110
+ const _ceilingTaskType = _lastTask?.taskType ?? _pilTaskType;
111
+ const _ceilingSize = _lastTask?.size ?? _pilSize;
112
+ const _naturalCeiling = resolveCeiling(_ceilingTaskType, _ceilingSize);
113
+ // Phase 5 Fix 4 (Option A) — make ceiling mutable so the stopWhen
114
+ // closure can bump it on auto-continue checkpoints. See checkpoint
115
+ // logic at dynamicStopWhen below for the bump policy.
116
+ const _stepCeiling = _budgetOverride.override ?? _naturalCeiling;
117
+ // Record this turn's task row for future continuation inheritance.
118
+ // Only non-chitchat task turns update the slot.
119
+ if (_sessionIdForLastTask && _pilTaskType !== "general" && pilCtx.intentKind === "task") {
120
+ recordSessionLastTask(_sessionIdForLastTask, _pilTaskType, _pilSize);
121
+ }
122
+ if (_budgetOverride.override !== undefined && _budgetOverride.override !== _naturalCeiling) {
123
+ try {
124
+ const _ar = globalThis.__muonroiAgentRuntime;
125
+ _ar?.emitEvent({
126
+ t: "event",
127
+ kind: "toast",
128
+ level: "info",
129
+ text: `override active: ceiling ${_budgetOverride.override}, default was ${_naturalCeiling} (task=${_ceilingTaskType}/size=${_ceilingSize})`,
130
+ });
131
+ }
132
+ catch {
133
+ /* best-effort */
134
+ }
135
+ }
136
+ return {
137
+ pilCtx,
138
+ _stepCeiling,
139
+ _pilStart,
140
+ _naturalCeiling,
141
+ _ceilingTaskType,
142
+ _ceilingSize: _ceilingSize,
143
+ };
144
+ }
145
+ //# sourceMappingURL=preprocessor.js.map
@@ -55,6 +55,12 @@ export interface SystemPromptOptions {
55
55
  * PIL Layer 1 (intentKind === "chitchat").
56
56
  */
57
57
  chitchat?: boolean;
58
+ /**
59
+ * When true (sub-agent), skip CUSTOM INSTRUCTIONS, skills catalog, and
60
+ * native capabilities — sub-agents don't need project-level instructions
61
+ * and can't run the full toolset anyway. Cuts ~6K tokens per sub-agent turn.
62
+ */
63
+ subAgent?: boolean;
58
64
  }
59
65
  /**
60
66
  * Render the LIVE per-turn MCP tool roster as a system-prompt block.
@@ -76,6 +82,8 @@ export interface SystemPromptOptions {
76
82
  */
77
83
  export declare function buildMcpCapabilityBlock(toolNames: readonly string[]): string;
78
84
  export declare function buildSystemPromptParts(cwd: string, mode: AgentMode, sandboxMode: SandboxMode, planContext?: string | null, subagents?: CustomSubagentConfig[], sandboxSettings?: SandboxSettings, providerId?: string, resumeDigest?: string | null, options?: SystemPromptOptions): SystemPromptParts;
85
+ /** Reset the static prefix cache (for tests). */
86
+ export declare function resetStaticPrefixCache(): void;
79
87
  export declare function buildSystemPrompt(cwd: string, mode: AgentMode, sandboxMode: SandboxMode, planContext?: string | null, subagents?: CustomSubagentConfig[], sandboxSettings?: SandboxSettings, providerId?: string, resumeDigest?: string | null, options?: SystemPromptOptions): string;
80
88
  export declare function buildSubagentPrompt(request: TaskRequest, cwd: string, custom: CustomSubagentConfig | null, sandboxMode: SandboxMode, subagents?: CustomSubagentConfig[], sandboxSettings?: SandboxSettings, providerId?: string): string;
81
89
  export declare function formatSandboxPromptSection(sandboxMode: SandboxMode, settings?: SandboxSettings): string;