muonroi-cli 1.8.3 → 1.8.5

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 (477) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +133 -122
  3. package/dist/packages/agent-harness-core/src/driver.d.ts +27 -1
  4. package/dist/packages/agent-harness-core/src/driver.js +46 -0
  5. package/dist/packages/agent-harness-core/src/event-tee.d.ts +48 -0
  6. package/dist/packages/agent-harness-core/src/event-tee.js +77 -0
  7. package/dist/packages/agent-harness-core/src/mcp-server.d.ts +11 -0
  8. package/dist/packages/agent-harness-core/src/mcp-server.js +87 -15
  9. package/dist/packages/agent-harness-core/src/protocol.d.ts +66 -2
  10. package/dist/packages/agent-harness-core/src/protocol.js +15 -0
  11. package/dist/packages/agent-harness-core/src/visual-quality.d.ts +58 -0
  12. package/dist/packages/agent-harness-core/src/visual-quality.js +141 -0
  13. package/dist/packages/agent-harness-opentui/src/agent-mode.d.ts +6 -0
  14. package/dist/packages/agent-harness-opentui/src/agent-mode.js +14 -1
  15. package/dist/packages/agent-harness-opentui/src/input-bridge.d.ts +2 -10
  16. package/dist/packages/agent-harness-opentui/src/input-bridge.js +103 -16
  17. package/dist/packages/agent-harness-opentui/src/install.d.ts +8 -0
  18. package/dist/packages/agent-harness-opentui/src/install.js +10 -0
  19. package/dist/packages/agent-harness-opentui/src/semantic.js +12 -10
  20. package/dist/packages/agent-harness-opentui/src/visual-capture.d.ts +56 -0
  21. package/dist/packages/agent-harness-opentui/src/visual-capture.js +103 -0
  22. package/dist/src/agent-harness/mock-model.d.ts +28 -0
  23. package/dist/src/agent-harness/mock-model.js +63 -1
  24. package/dist/src/agent-harness/test-spawn.js +31 -0
  25. package/dist/src/cli/config/screen-providers.js +1 -1
  26. package/dist/src/cli/cost-forensics.d.ts +10 -0
  27. package/dist/src/cli/cost-forensics.js +30 -15
  28. package/dist/src/cli/keys-bundle.d.ts +1 -1
  29. package/dist/src/cli/keys-bundle.js +1 -1
  30. package/dist/src/cli/keys.d.ts +2 -2
  31. package/dist/src/cli/keys.js +19 -81
  32. package/dist/src/council/clarifier.d.ts +28 -2
  33. package/dist/src/council/clarifier.js +81 -15
  34. package/dist/src/council/context.js +49 -15
  35. package/dist/src/council/debate-checkpoint.d.ts +129 -0
  36. package/dist/src/council/debate-checkpoint.js +176 -0
  37. package/dist/src/council/debate-planner.js +51 -3
  38. package/dist/src/council/debate-summary.d.ts +25 -0
  39. package/dist/src/council/debate-summary.js +85 -0
  40. package/dist/src/council/debate.d.ts +169 -2
  41. package/dist/src/council/debate.js +1210 -134
  42. package/dist/src/council/index.d.ts +85 -1
  43. package/dist/src/council/index.js +634 -196
  44. package/dist/src/council/leader.d.ts +26 -0
  45. package/dist/src/council/leader.js +150 -9
  46. package/dist/src/council/llm.d.ts +32 -0
  47. package/dist/src/council/llm.js +231 -38
  48. package/dist/src/council/panel-select.d.ts +30 -0
  49. package/dist/src/council/panel-select.js +72 -0
  50. package/dist/src/council/planner.js +23 -0
  51. package/dist/src/council/preflight.d.ts +7 -0
  52. package/dist/src/council/preflight.js +14 -2
  53. package/dist/src/council/prompts.d.ts +30 -3
  54. package/dist/src/council/prompts.js +254 -84
  55. package/dist/src/council/stance-recall.d.ts +42 -0
  56. package/dist/src/council/stance-recall.js +57 -0
  57. package/dist/src/council/strip-think.d.ts +17 -0
  58. package/dist/src/council/strip-think.js +33 -0
  59. package/dist/src/council/types.d.ts +128 -0
  60. package/dist/src/ee/artifact-cache.d.ts +16 -0
  61. package/dist/src/ee/artifact-cache.js +32 -0
  62. package/dist/src/ee/auth.d.ts +1 -0
  63. package/dist/src/ee/auth.js +15 -2
  64. package/dist/src/ee/bridge.d.ts +10 -0
  65. package/dist/src/ee/bridge.js +58 -0
  66. package/dist/src/ee/client.js +81 -18
  67. package/dist/src/ee/export-transcripts.d.ts +1 -0
  68. package/dist/src/ee/export-transcripts.js +8 -10
  69. package/dist/src/ee/extract-session.js +29 -0
  70. package/dist/src/ee/extract-style.d.ts +58 -0
  71. package/dist/src/ee/extract-style.js +270 -0
  72. package/dist/src/ee/recall-ledger.d.ts +9 -0
  73. package/dist/src/ee/recall-ledger.js +3 -0
  74. package/dist/src/ee/scope.d.ts +1 -0
  75. package/dist/src/ee/scope.js +26 -1
  76. package/dist/src/ee/search.d.ts +7 -0
  77. package/dist/src/ee/search.js +24 -0
  78. package/dist/src/ee/transcript-emit.js +2 -0
  79. package/dist/src/ee/types.d.ts +22 -0
  80. package/dist/src/ee/who-am-i-brain.d.ts +35 -0
  81. package/dist/src/ee/who-am-i-brain.js +220 -0
  82. package/dist/src/ee/who-am-i.d.ts +10 -3
  83. package/dist/src/ee/who-am-i.js +12 -0
  84. package/dist/src/ee/workflow-event.d.ts +48 -0
  85. package/dist/src/ee/workflow-event.js +81 -0
  86. package/dist/src/flow/compaction/compress.d.ts +3 -3
  87. package/dist/src/flow/compaction/compress.js +45 -8
  88. package/dist/src/flow/compaction/extract.d.ts +4 -7
  89. package/dist/src/flow/compaction/extract.js +50 -10
  90. package/dist/src/flow/compaction/index.d.ts +13 -1
  91. package/dist/src/flow/compaction/index.js +70 -3
  92. package/dist/src/flow/compaction/input-guard.d.ts +24 -0
  93. package/dist/src/flow/compaction/input-guard.js +43 -0
  94. package/dist/src/flow/fold-planning.d.ts +36 -0
  95. package/dist/src/flow/fold-planning.js +83 -0
  96. package/dist/src/flow/hierarchy.d.ts +146 -0
  97. package/dist/src/flow/hierarchy.js +427 -0
  98. package/dist/src/flow/index.d.ts +1 -0
  99. package/dist/src/flow/index.js +2 -0
  100. package/dist/src/flow/run-artifacts.d.ts +102 -0
  101. package/dist/src/flow/run-artifacts.js +208 -0
  102. package/dist/src/generated/version.d.ts +1 -1
  103. package/dist/src/generated/version.js +1 -1
  104. package/dist/src/gsd/assessment-schema.d.ts +44 -0
  105. package/dist/src/gsd/assessment-schema.js +134 -0
  106. package/dist/src/gsd/capability-registry.d.ts +45 -0
  107. package/dist/src/gsd/capability-registry.js +337 -0
  108. package/dist/src/gsd/complexity-assessor.d.ts +39 -0
  109. package/dist/src/gsd/complexity-assessor.js +152 -0
  110. package/dist/src/gsd/config-bridge.d.ts +7 -0
  111. package/dist/src/gsd/config-bridge.js +114 -0
  112. package/dist/src/gsd/config-loader.d.ts +27 -0
  113. package/dist/src/gsd/config-loader.js +50 -0
  114. package/dist/src/gsd/council-context.d.ts +44 -0
  115. package/dist/src/gsd/council-context.js +114 -0
  116. package/dist/src/gsd/ee-closure.d.ts +28 -0
  117. package/dist/src/gsd/ee-closure.js +49 -0
  118. package/dist/src/gsd/flags.d.ts +55 -0
  119. package/dist/src/gsd/flags.js +83 -0
  120. package/dist/src/gsd/gsd-dispatch.d.ts +58 -0
  121. package/dist/src/gsd/gsd-dispatch.js +131 -0
  122. package/dist/src/gsd/gsd-runtime.d.ts +22 -0
  123. package/dist/src/gsd/gsd-runtime.js +37 -0
  124. package/dist/src/gsd/host-adapter.d.ts +11 -0
  125. package/dist/src/gsd/host-adapter.js +29 -0
  126. package/dist/src/gsd/index.d.ts +24 -1
  127. package/dist/src/gsd/index.js +27 -0
  128. package/dist/src/gsd/loop-host-contract.d.ts +21 -0
  129. package/dist/src/gsd/loop-host-contract.js +39 -0
  130. package/dist/src/gsd/loop-host.d.ts +69 -0
  131. package/dist/src/gsd/loop-host.js +245 -0
  132. package/dist/src/gsd/loop-resolver.d.ts +36 -0
  133. package/dist/src/gsd/loop-resolver.js +79 -0
  134. package/dist/src/gsd/model-tier.d.ts +13 -0
  135. package/dist/src/gsd/model-tier.js +45 -0
  136. package/dist/src/gsd/mutation-gate.d.ts +16 -0
  137. package/dist/src/gsd/mutation-gate.js +41 -0
  138. package/dist/src/gsd/native-roadmap.d.ts +89 -0
  139. package/dist/src/gsd/native-roadmap.js +343 -0
  140. package/dist/src/gsd/native-state.d.ts +47 -0
  141. package/dist/src/gsd/native-state.js +220 -0
  142. package/dist/src/gsd/paths.d.ts +23 -0
  143. package/dist/src/gsd/paths.js +66 -0
  144. package/dist/src/gsd/phase-dag.d.ts +12 -0
  145. package/dist/src/gsd/phase-dag.js +94 -0
  146. package/dist/src/gsd/phase-sync.d.ts +42 -0
  147. package/dist/src/gsd/phase-sync.js +321 -0
  148. package/dist/src/gsd/pil-gate-context.d.ts +13 -0
  149. package/dist/src/gsd/pil-gate-context.js +64 -0
  150. package/dist/src/gsd/pil-gate-critic.d.ts +19 -0
  151. package/dist/src/gsd/pil-gate-critic.js +74 -0
  152. package/dist/src/gsd/plan-council-prompts.d.ts +25 -0
  153. package/dist/src/gsd/plan-council-prompts.js +79 -0
  154. package/dist/src/gsd/plan-council.d.ts +44 -0
  155. package/dist/src/gsd/plan-council.js +251 -0
  156. package/dist/src/gsd/plan-gate-vocabulary.d.ts +40 -0
  157. package/dist/src/gsd/plan-gate-vocabulary.js +64 -0
  158. package/dist/src/gsd/product-workspace.d.ts +13 -0
  159. package/dist/src/gsd/product-workspace.js +124 -0
  160. package/dist/src/gsd/ship-bridge.d.ts +25 -0
  161. package/dist/src/gsd/ship-bridge.js +65 -0
  162. package/dist/src/gsd/state-document.d.ts +40 -0
  163. package/dist/src/gsd/state-document.js +163 -0
  164. package/dist/src/gsd/verdict-schema.d.ts +39 -0
  165. package/dist/src/gsd/verdict-schema.js +144 -0
  166. package/dist/src/gsd/verify-context.d.ts +22 -0
  167. package/dist/src/gsd/verify-context.js +27 -0
  168. package/dist/src/gsd/verify-council-prompts.d.ts +19 -0
  169. package/dist/src/gsd/verify-council-prompts.js +85 -0
  170. package/dist/src/gsd/verify-council.d.ts +25 -0
  171. package/dist/src/gsd/verify-council.js +119 -0
  172. package/dist/src/gsd/verify-gate-vocabulary.d.ts +25 -0
  173. package/dist/src/gsd/verify-gate-vocabulary.js +46 -0
  174. package/dist/src/gsd/workflow-engine.d.ts +60 -0
  175. package/dist/src/gsd/workflow-engine.js +207 -0
  176. package/dist/src/gsd/workflow-tools.d.ts +13 -0
  177. package/dist/src/gsd/workflow-tools.js +277 -0
  178. package/dist/src/hooks/index.js +1 -1
  179. package/dist/src/index.js +44 -11
  180. package/dist/src/maintain/pr-builder.js +23 -13
  181. package/dist/src/mcp/auto-setup.js +57 -32
  182. package/dist/src/mcp/client-pool.js +1 -1
  183. package/dist/src/mcp/ee-tools.js +1 -0
  184. package/dist/src/mcp/oauth-callback.js +2 -2
  185. package/dist/src/mcp/research-onboarding.js +8 -7
  186. package/dist/src/mcp/runtime.js +34 -2
  187. package/dist/src/mcp/setup-guide-text.d.ts +1 -1
  188. package/dist/src/mcp/setup-guide-text.js +77 -76
  189. package/dist/src/models/catalog-client.d.ts +87 -0
  190. package/dist/src/models/catalog-client.js +105 -38
  191. package/dist/src/models/catalog.json +528 -265
  192. package/dist/src/models/registry.d.ts +22 -7
  193. package/dist/src/models/registry.js +73 -10
  194. package/dist/src/ops/doctor.js +8 -8
  195. package/dist/src/orchestrator/auto-commit.js +1 -1
  196. package/dist/src/orchestrator/batch-turn-runner.js +2 -2
  197. package/dist/src/orchestrator/cache-prefix.d.ts +67 -0
  198. package/dist/src/orchestrator/cache-prefix.js +83 -0
  199. package/dist/src/orchestrator/compact-request.d.ts +32 -0
  200. package/dist/src/orchestrator/compact-request.js +41 -0
  201. package/dist/src/orchestrator/compaction.d.ts +10 -0
  202. package/dist/src/orchestrator/compaction.js +27 -7
  203. package/dist/src/orchestrator/council-manager.d.ts +12 -3
  204. package/dist/src/orchestrator/council-manager.js +65 -24
  205. package/dist/src/orchestrator/cross-turn-dedup.d.ts +6 -0
  206. package/dist/src/orchestrator/cross-turn-dedup.js +22 -1
  207. package/dist/src/orchestrator/error-utils.d.ts +29 -0
  208. package/dist/src/orchestrator/error-utils.js +132 -24
  209. package/dist/src/orchestrator/grounding-check.js +39 -1
  210. package/dist/src/orchestrator/message-processor.js +242 -33
  211. package/dist/src/orchestrator/orchestrator.d.ts +39 -3
  212. package/dist/src/orchestrator/orchestrator.js +651 -102
  213. package/dist/src/orchestrator/preprocessor.js +1 -1
  214. package/dist/src/orchestrator/proactive-compact-detector.d.ts +26 -0
  215. package/dist/src/orchestrator/proactive-compact-detector.js +36 -0
  216. package/dist/src/orchestrator/prompts.js +159 -159
  217. package/dist/src/orchestrator/reactive-delegation.d.ts +39 -0
  218. package/dist/src/orchestrator/reactive-delegation.js +59 -0
  219. package/dist/src/orchestrator/retry-classifier.d.ts +2 -1
  220. package/dist/src/orchestrator/retry-classifier.js +46 -2
  221. package/dist/src/orchestrator/safety-intercept.d.ts +45 -0
  222. package/dist/src/orchestrator/safety-intercept.js +55 -0
  223. package/dist/src/orchestrator/scope-reminder.js +1 -1
  224. package/dist/src/orchestrator/session-experience.d.ts +2 -1
  225. package/dist/src/orchestrator/session-experience.js +2 -1
  226. package/dist/src/orchestrator/should-run-gate.d.ts +5 -0
  227. package/dist/src/orchestrator/should-run-gate.js +18 -0
  228. package/dist/src/orchestrator/stall-watchdog.d.ts +24 -3
  229. package/dist/src/orchestrator/stall-watchdog.js +47 -13
  230. package/dist/src/orchestrator/stream-runner.js +62 -29
  231. package/dist/src/orchestrator/sub-agent-cap.d.ts +13 -1
  232. package/dist/src/orchestrator/sub-agent-cap.js +16 -1
  233. package/dist/src/orchestrator/sub-agent-model-tier.d.ts +13 -1
  234. package/dist/src/orchestrator/sub-agent-model-tier.js +16 -2
  235. package/dist/src/orchestrator/subagent-compactor.d.ts +53 -1
  236. package/dist/src/orchestrator/subagent-compactor.js +126 -15
  237. package/dist/src/orchestrator/tool-engine.d.ts +26 -0
  238. package/dist/src/orchestrator/tool-engine.js +669 -56
  239. package/dist/src/orchestrator/tool-limit-auto-recover.d.ts +22 -0
  240. package/dist/src/orchestrator/tool-limit-auto-recover.js +30 -0
  241. package/dist/src/orchestrator/turn-runner-deps.d.ts +19 -0
  242. package/dist/src/orchestrator/turn-watchdog.d.ts +37 -0
  243. package/dist/src/orchestrator/turn-watchdog.js +55 -0
  244. package/dist/src/pil/agent-operating-contract.d.ts +1 -1
  245. package/dist/src/pil/agent-operating-contract.js +1 -1
  246. package/dist/src/pil/cheap-model-playbook.d.ts +1 -1
  247. package/dist/src/pil/cheap-model-playbook.js +5 -1
  248. package/dist/src/pil/cheap-model-workbooks.d.ts +1 -1
  249. package/dist/src/pil/cheap-model-workbooks.js +1 -1
  250. package/dist/src/pil/discovery-types.d.ts +1 -0
  251. package/dist/src/pil/discovery.js +16 -11
  252. package/dist/src/pil/layer1-intent.d.ts +18 -6
  253. package/dist/src/pil/layer1-intent.js +66 -757
  254. package/dist/src/pil/layer15-context-scan.js +15 -1
  255. package/dist/src/pil/layer2_5-ponytail.js +8 -8
  256. package/dist/src/pil/layer3-ee-injection.js +23 -8
  257. package/dist/src/pil/layer4-gsd.js +69 -16
  258. package/dist/src/pil/layer5-context.js +7 -3
  259. package/dist/src/pil/layer6-output.d.ts +23 -0
  260. package/dist/src/pil/layer6-output.js +5 -1
  261. package/dist/src/pil/llm-classify.d.ts +33 -2
  262. package/dist/src/pil/llm-classify.js +123 -131
  263. package/dist/src/pil/native-capabilities-workbook.d.ts +1 -1
  264. package/dist/src/pil/native-capabilities-workbook.js +1 -0
  265. package/dist/src/pil/pipeline.js +34 -2
  266. package/dist/src/pil/response-tools.js +5 -3
  267. package/dist/src/pil/schema.d.ts +1 -0
  268. package/dist/src/pil/schema.js +2 -0
  269. package/dist/src/pil/types.d.ts +18 -0
  270. package/dist/src/playbook/directives.d.ts +4 -0
  271. package/dist/src/playbook/directives.js +17 -5
  272. package/dist/src/product-loop/backlog-builder.d.ts +14 -1
  273. package/dist/src/product-loop/backlog-builder.js +30 -6
  274. package/dist/src/product-loop/discovery-context-format.js +3 -1
  275. package/dist/src/product-loop/discovery-ecosystem.js +4 -1
  276. package/dist/src/product-loop/discovery-interview.js +32 -3
  277. package/dist/src/product-loop/discovery-schema.js +5 -1
  278. package/dist/src/product-loop/done-gate.js +3 -3
  279. package/dist/src/product-loop/ideal-trace.d.ts +7 -0
  280. package/dist/src/product-loop/ideal-trace.js +64 -0
  281. package/dist/src/product-loop/index.d.ts +13 -1
  282. package/dist/src/product-loop/index.js +333 -52
  283. package/dist/src/product-loop/loop-driver.d.ts +7 -0
  284. package/dist/src/product-loop/loop-driver.js +327 -116
  285. package/dist/src/product-loop/phase-plan.d.ts +5 -0
  286. package/dist/src/product-loop/phase-plan.js +39 -2
  287. package/dist/src/product-loop/phase-runner.js +9 -1
  288. package/dist/src/product-loop/progress-snapshot.js +4 -4
  289. package/dist/src/product-loop/sprint-runner.d.ts +111 -0
  290. package/dist/src/product-loop/sprint-runner.js +559 -16
  291. package/dist/src/product-loop/types.d.ts +36 -5
  292. package/dist/src/providers/adapter.d.ts +1 -1
  293. package/dist/src/providers/adapter.js +3 -4
  294. package/dist/src/providers/auth/browser-flow.d.ts +1 -1
  295. package/dist/src/providers/auth/browser-flow.js +1 -1
  296. package/dist/src/providers/auth/openai-oauth.js +1 -1
  297. package/dist/src/providers/auth/registry.js +0 -34
  298. package/dist/src/providers/auth/token-store.js +4 -1
  299. package/dist/src/providers/auth/types.d.ts +1 -1
  300. package/dist/src/providers/auth/types.js +1 -1
  301. package/dist/src/providers/capabilities.d.ts +24 -5
  302. package/dist/src/providers/capabilities.js +42 -24
  303. package/dist/src/providers/endpoints.d.ts +2 -2
  304. package/dist/src/providers/endpoints.js +11 -10
  305. package/dist/src/providers/keychain.d.ts +1 -1
  306. package/dist/src/providers/keychain.js +7 -9
  307. package/dist/src/providers/mcp-vision-bridge.js +82 -172
  308. package/dist/src/providers/openai-compatible.js +8 -1
  309. package/dist/src/providers/pricing.d.ts +2 -2
  310. package/dist/src/providers/pricing.js +3 -13
  311. package/dist/src/providers/runtime.d.ts +27 -2
  312. package/dist/src/providers/runtime.js +78 -15
  313. package/dist/src/providers/strategies/base.strategy.d.ts +16 -0
  314. package/dist/src/providers/strategies/base.strategy.js +24 -1
  315. package/dist/src/providers/strategies/{siliconflow.strategy.d.ts → opencode-go.strategy.d.ts} +3 -3
  316. package/dist/src/providers/strategies/opencode-go.strategy.js +83 -0
  317. package/dist/src/providers/strategies/registry.js +4 -4
  318. package/dist/src/providers/strategies/thinking-mode.d.ts +109 -0
  319. package/dist/src/providers/strategies/thinking-mode.js +280 -1
  320. package/dist/src/providers/strategies/zai.strategy.d.ts +14 -0
  321. package/dist/src/providers/strategies/zai.strategy.js +44 -0
  322. package/dist/src/providers/types.d.ts +5 -6
  323. package/dist/src/providers/types.js +2 -2
  324. package/dist/src/providers/vision-backend.d.ts +47 -0
  325. package/dist/src/providers/vision-backend.js +258 -0
  326. package/dist/src/providers/vision-proxy.d.ts +22 -9
  327. package/dist/src/providers/vision-proxy.js +63 -132
  328. package/dist/src/providers/wire-debug.js +95 -0
  329. package/dist/src/reporter/index.js +1 -1
  330. package/dist/src/router/decide.d.ts +13 -0
  331. package/dist/src/router/decide.js +138 -36
  332. package/dist/src/router/peak-hour.d.ts +38 -0
  333. package/dist/src/router/peak-hour.js +107 -0
  334. package/dist/src/router/step-router.js +3 -2
  335. package/dist/src/router/warm.js +4 -5
  336. package/dist/src/scaffold/bb-ecosystem-apply.js +47 -47
  337. package/dist/src/scaffold/bb-quality-gate.js +5 -5
  338. package/dist/src/scaffold/continuation-prompt.d.ts +11 -0
  339. package/dist/src/scaffold/continuation-prompt.js +86 -60
  340. package/dist/src/scaffold/init-new.js +453 -453
  341. package/dist/src/scaffold/point-to-existing.d.ts +21 -0
  342. package/dist/src/scaffold/point-to-existing.js +25 -0
  343. package/dist/src/self-qa/agentic-loop.js +22 -22
  344. package/dist/src/{ui/state → state}/active-run.d.ts +19 -0
  345. package/dist/src/{ui/state → state}/active-run.js +21 -0
  346. package/dist/src/{ui/status-bar/store.d.ts → state/status-bar-store.d.ts} +4 -1
  347. package/dist/src/{ui/status-bar/store.js → state/status-bar-store.js} +12 -9
  348. package/dist/src/state/turn-trace.d.ts +43 -0
  349. package/dist/src/state/turn-trace.js +32 -0
  350. package/dist/src/storage/db.js +2 -1
  351. package/dist/src/storage/index.d.ts +1 -1
  352. package/dist/src/storage/index.js +1 -1
  353. package/dist/src/storage/interaction-log.d.ts +1 -1
  354. package/dist/src/storage/interaction-log.js +5 -5
  355. package/dist/src/storage/migrations.js +196 -126
  356. package/dist/src/storage/session-experience-store.js +4 -4
  357. package/dist/src/storage/sessions.d.ts +28 -10
  358. package/dist/src/storage/sessions.js +112 -55
  359. package/dist/src/storage/transcript-view.js +1 -1
  360. package/dist/src/storage/transcript.d.ts +51 -0
  361. package/dist/src/storage/transcript.js +383 -112
  362. package/dist/src/storage/usage.js +14 -14
  363. package/dist/src/storage/workspaces.js +12 -12
  364. package/dist/src/tools/file.d.ts +15 -0
  365. package/dist/src/tools/file.js +32 -0
  366. package/dist/src/tools/native-tools.js +5 -0
  367. package/dist/src/tools/registry.d.ts +3 -0
  368. package/dist/src/tools/registry.js +460 -22
  369. package/dist/src/tools/research.d.ts +29 -0
  370. package/dist/src/tools/research.js +233 -0
  371. package/dist/src/types/index.d.ts +118 -3
  372. package/dist/src/ui/app.js +0 -0
  373. package/dist/src/ui/cards/product-status-card.js +1 -1
  374. package/dist/src/ui/components/bubble-body-guard.d.ts +27 -0
  375. package/dist/src/ui/components/bubble-body-guard.js +50 -0
  376. package/dist/src/ui/components/context-rail.d.ts +26 -0
  377. package/dist/src/ui/components/context-rail.js +33 -0
  378. package/dist/src/ui/components/council-conclusion-card.d.ts +73 -0
  379. package/dist/src/ui/components/council-conclusion-card.js +420 -0
  380. package/dist/src/ui/components/council-debate-pill.d.ts +36 -0
  381. package/dist/src/ui/components/council-debate-pill.js +34 -0
  382. package/dist/src/ui/components/council-info-card.js +2 -2
  383. package/dist/src/ui/components/council-leader-bubble.d.ts +10 -3
  384. package/dist/src/ui/components/council-leader-bubble.js +21 -11
  385. package/dist/src/ui/components/council-message-bubble.d.ts +15 -2
  386. package/dist/src/ui/components/council-message-bubble.js +16 -15
  387. package/dist/src/ui/components/council-phase-timeline.d.ts +9 -1
  388. package/dist/src/ui/components/council-phase-timeline.js +49 -15
  389. package/dist/src/ui/components/council-placeholder-bubble.d.ts +16 -9
  390. package/dist/src/ui/components/council-placeholder-bubble.js +32 -29
  391. package/dist/src/ui/components/council-question-card.js +12 -12
  392. package/dist/src/ui/components/council-rail-rounds.d.ts +26 -0
  393. package/dist/src/ui/components/council-rail-rounds.js +57 -0
  394. package/dist/src/ui/components/council-round-group.d.ts +38 -0
  395. package/dist/src/ui/components/council-round-group.js +88 -0
  396. package/dist/src/ui/components/council-status-list.d.ts +3 -1
  397. package/dist/src/ui/components/council-status-list.js +36 -24
  398. package/dist/src/ui/components/council-synthesis-banner.d.ts +7 -2
  399. package/dist/src/ui/components/council-synthesis-banner.js +20 -5
  400. package/dist/src/ui/components/halt-recovery-card.js +9 -5
  401. package/dist/src/ui/components/jump-to-latest-pill.d.ts +11 -0
  402. package/dist/src/ui/components/jump-to-latest-pill.js +14 -0
  403. package/dist/src/ui/components/prompt-box.js +18 -16
  404. package/dist/src/ui/components/session-tree-card.d.ts +14 -0
  405. package/dist/src/ui/components/session-tree-card.js +46 -0
  406. package/dist/src/ui/components/slash-inline-menu.d.ts +12 -0
  407. package/dist/src/ui/components/slash-inline-menu.js +26 -5
  408. package/dist/src/ui/components/task-list-panel.d.ts +14 -1
  409. package/dist/src/ui/components/task-list-panel.js +22 -2
  410. package/dist/src/ui/containers/modals-layer.d.ts +2 -1
  411. package/dist/src/ui/hooks/use-session-picker.d.ts +3 -3
  412. package/dist/src/ui/mcp-modal.js +2 -4
  413. package/dist/src/ui/modals/api-key-modal.js +1 -1
  414. package/dist/src/ui/modals/connect-modal.js +4 -3
  415. package/dist/src/ui/modals/session-picker-modal.d.ts +2 -2
  416. package/dist/src/ui/modals/session-picker-modal.js +3 -5
  417. package/dist/src/ui/picker-providers.d.ts +1 -1
  418. package/dist/src/ui/picker-providers.js +1 -1
  419. package/dist/src/ui/primitives/index.d.ts +1 -0
  420. package/dist/src/ui/primitives/index.js +2 -0
  421. package/dist/src/ui/primitives/semantic-primitives.d.ts +76 -0
  422. package/dist/src/ui/primitives/semantic-primitives.js +81 -0
  423. package/dist/src/ui/slash/compact.js +5 -7
  424. package/dist/src/ui/slash/cost.js +1 -1
  425. package/dist/src/ui/slash/council-inspect.js +4 -4
  426. package/dist/src/ui/slash/council.js +19 -1
  427. package/dist/src/ui/slash/debug.d.ts +3 -31
  428. package/dist/src/ui/slash/debug.js +9 -20
  429. package/dist/src/ui/slash/ideal.d.ts +6 -2
  430. package/dist/src/ui/slash/ideal.js +97 -7
  431. package/dist/src/ui/slash/menu-items.d.ts +7 -0
  432. package/dist/src/ui/slash/menu-items.js +12 -18
  433. package/dist/src/ui/slash/registry.d.ts +2 -0
  434. package/dist/src/ui/slash/registry.js +4 -0
  435. package/dist/src/ui/status-bar/cache-hit.d.ts +6 -0
  436. package/dist/src/ui/status-bar/cache-hit.js +9 -0
  437. package/dist/src/ui/status-bar/index.d.ts +1 -1
  438. package/dist/src/ui/status-bar/index.js +7 -3
  439. package/dist/src/ui/status-bar/usd-meter.d.ts +5 -4
  440. package/dist/src/ui/status-bar/usd-meter.js +6 -4
  441. package/dist/src/ui/theme.d.ts +1 -0
  442. package/dist/src/ui/theme.js +2 -0
  443. package/dist/src/ui/types.d.ts +7 -0
  444. package/dist/src/ui/use-app-logic.js +0 -0
  445. package/dist/src/ui/utils/format.d.ts +14 -0
  446. package/dist/src/ui/utils/format.js +23 -3
  447. package/dist/src/usage/downgrade.js +2 -2
  448. package/dist/src/usage/product-ledger.js +2 -2
  449. package/dist/src/utils/clipboard-image.js +23 -23
  450. package/dist/src/utils/install-manager.js +14 -11
  451. package/dist/src/utils/logger.js +2 -2
  452. package/dist/src/utils/permission-mode.js +5 -3
  453. package/dist/src/utils/redactor.js +1 -1
  454. package/dist/src/utils/settings.d.ts +153 -5
  455. package/dist/src/utils/settings.js +233 -29
  456. package/dist/src/utils/side-question.js +2 -2
  457. package/dist/src/utils/skills.js +3 -3
  458. package/dist/src/utils/visible-retry.d.ts +11 -0
  459. package/dist/src/utils/visible-retry.js +10 -1
  460. package/dist/src/verify/entrypoint.d.ts +1 -1
  461. package/dist/src/verify/entrypoint.js +1 -1
  462. package/dist/src/verify/recipes.d.ts +13 -0
  463. package/dist/src/verify/recipes.js +15 -0
  464. package/package.json +135 -132
  465. package/dist/src/providers/auth/gcloud.d.ts +0 -28
  466. package/dist/src/providers/auth/gcloud.js +0 -102
  467. package/dist/src/providers/auth/gemini-oauth.d.ts +0 -82
  468. package/dist/src/providers/auth/gemini-oauth.js +0 -472
  469. package/dist/src/providers/gemini.d.ts +0 -11
  470. package/dist/src/providers/gemini.js +0 -45
  471. package/dist/src/providers/siliconflow-sse-repair.d.ts +0 -58
  472. package/dist/src/providers/siliconflow-sse-repair.js +0 -177
  473. package/dist/src/providers/strategies/google.strategy.d.ts +0 -22
  474. package/dist/src/providers/strategies/google.strategy.js +0 -174
  475. package/dist/src/providers/strategies/siliconflow.strategy.js +0 -29
  476. package/dist/src/ui/containers/chat-feed.d.ts +0 -40
  477. package/dist/src/ui/containers/chat-feed.js +0 -66
@@ -18,13 +18,28 @@
18
18
  * returns a fresh wrapper with its own counters. Don't share across
19
19
  * sub-agent runs.
20
20
  *
21
- * Tiers (default 120_000 chars cumulative ~30k tokens):
21
+ * BUDGET SOURCE — do not read the 120_000 below as "the sub-agent budget".
22
+ * DEFAULT_MAX_CUMULATIVE_CHARS (120_000) is only the fallback used when
23
+ * wrapToolSetWithCap() is called WITHOUT maxCumulativeChars. The wired
24
+ * budgets come from settings, not this constant:
25
+ * - sub-agent (`task`) turns: getSubAgentBudgetChars() → default 240_000
26
+ * (settings.ts), passed at stream-runner.ts.
27
+ * - top-level orchestrator turn: getTopLevelToolBudgetChars() → default
28
+ * 400_000, wired at tool-engine.ts with looser 0.5/0.8 tier ratios.
29
+ * See docs/agent-harness/CONTEXT-CONTROL-LAYERS.md for how this cap relates
30
+ * to the other four context-control layers (compactor, rotation, reactive
31
+ * sub-session, top-level cap).
32
+ *
33
+ * Tiers (percentages of whichever budget is in effect, NOT of 120_000):
22
34
  * < 30% → pass through (A1's 32KB per-call cap already applied)
23
35
  * 30-70% → truncate each new result to 8_000 chars head/tail
24
36
  * 70-100% → truncate to 2_000 chars head + "[budget low, finalize work]" note
25
37
  * ≥ 100% → return error stub that signals the agent to stop expanding scope
26
38
  */
27
39
  import { createHash } from "node:crypto";
40
+ // Fallback ONLY — used when wrapToolSetWithCap gets no maxCumulativeChars.
41
+ // Real wired budgets are 240_000 (sub-agent) / 400_000 (top-level) from
42
+ // settings; see the header note. Keep this in sync only as the no-arg floor.
28
43
  const DEFAULT_MAX_CUMULATIVE_CHARS = 120_000;
29
44
  const DEFAULT_DEDUP_MIN_CHARS = 500;
30
45
  const DEFAULT_MID_TIER_RATIO = 0.3;
@@ -9,5 +9,17 @@ export type TierLookup = (tier: "fast" | "balanced" | "premium", preferProvider?
9
9
  * Resolve the model id for a task kind on a given provider. Walks the tier
10
10
  * preference list, accepting only same-provider matches, and falls back to
11
11
  * `fallbackModelId` (the parent model) when nothing matches.
12
+ *
13
+ * `opts.parentTier` (the top-level / parent model's tier) acts as a ceiling:
14
+ * a delegated sub-task never runs on a HIGHER tier than the parent. Without
15
+ * this cap, a `verify` sub-agent (prefs `["premium","balanced"]`) spawned from
16
+ * a flash (fast) parent silently promotes to premium — e.g. on a DeepSeek-only
17
+ * setup (no balanced model) every verify sub-agent lands on deepseek-v4-pro.
18
+ * The parent already did the hard thinking; the sub-task should not exceed it.
19
+ *
20
+ * The cap is skipped when `parentTier` is omitted (preserves legacy behavior
21
+ * for callers that have not been threaded yet).
12
22
  */
13
- export declare function resolveModelForTask(task: ModelTaskKind, providerId: string, fallbackModelId: string, lookup?: TierLookup): string;
23
+ export declare function resolveModelForTask(task: ModelTaskKind, providerId: string, fallbackModelId: string, lookup?: TierLookup, opts?: {
24
+ parentTier?: "fast" | "balanced" | "premium";
25
+ }): string;
@@ -16,7 +16,7 @@
16
16
  * - verify : validation/verification → premium first; rigor matters
17
17
  * more than cost here, so we do NOT downgrade by default.
18
18
  */
19
- import { getModelByTier } from "../models/registry.js";
19
+ import { getRoutedModelByTier } from "../router/peak-hour.js";
20
20
  export const TASK_TIER_PREFS = {
21
21
  compact: ["fast", "balanced"],
22
22
  title: ["fast", "balanced"],
@@ -29,13 +29,27 @@ export const TASK_TIER_PREFS = {
29
29
  // exists to perform. Mirrors council `verify` role preference.
30
30
  verify: ["premium", "balanced"],
31
31
  };
32
+ const TIER_RANK = { fast: 0, balanced: 1, premium: 2 };
32
33
  /**
33
34
  * Resolve the model id for a task kind on a given provider. Walks the tier
34
35
  * preference list, accepting only same-provider matches, and falls back to
35
36
  * `fallbackModelId` (the parent model) when nothing matches.
37
+ *
38
+ * `opts.parentTier` (the top-level / parent model's tier) acts as a ceiling:
39
+ * a delegated sub-task never runs on a HIGHER tier than the parent. Without
40
+ * this cap, a `verify` sub-agent (prefs `["premium","balanced"]`) spawned from
41
+ * a flash (fast) parent silently promotes to premium — e.g. on a DeepSeek-only
42
+ * setup (no balanced model) every verify sub-agent lands on deepseek-v4-pro.
43
+ * The parent already did the hard thinking; the sub-task should not exceed it.
44
+ *
45
+ * The cap is skipped when `parentTier` is omitted (preserves legacy behavior
46
+ * for callers that have not been threaded yet).
36
47
  */
37
- export function resolveModelForTask(task, providerId, fallbackModelId, lookup = getModelByTier) {
48
+ export function resolveModelForTask(task, providerId, fallbackModelId, lookup = getRoutedModelByTier, opts) {
49
+ const ceilingRank = opts?.parentTier ? TIER_RANK[opts.parentTier] : undefined;
38
50
  for (const tier of TASK_TIER_PREFS[task] ?? ["balanced"]) {
51
+ if (ceilingRank !== undefined && TIER_RANK[tier] > ceilingRank)
52
+ continue;
39
53
  const m = lookup(tier, providerId);
40
54
  if (m?.provider === providerId)
41
55
  return m.id;
@@ -95,7 +95,7 @@ export interface SubAgentCompactorOptions {
95
95
  * stub (full raw content available here). Fire-and-forget EE persist under
96
96
  * source:"tool-artifact" so layer3/ee.query can later fetch "full tool result id=xxx".
97
97
  */
98
- persistArtifact?: (toolCallId: string, toolName: string, fullContent: string, reason: string) => void;
98
+ persistArtifact?: (toolCallId: string, toolName: string, fullContent: string, reason: string, summary?: string) => void;
99
99
  /**
100
100
  * T1.1 — strip reasoning parts from old assistant turns (older than
101
101
  * keepLastTurns). Reasoning tokens (CoT / <think>) from prior turns are
@@ -104,6 +104,18 @@ export interface SubAgentCompactorOptions {
104
104
  * models, false otherwise.
105
105
  */
106
106
  stripOldReasoning?: boolean;
107
+ /**
108
+ * O2 — max cumulative chars of the verbatim tail (the last keepLastTurns
109
+ * turns). The G2 shrink is FILL-ratio based, so on a large-context model a
110
+ * read-heavy tail (five 8-30k tool results) stays verbatim at only ~50%
111
+ * fill — pinning every tool round at 60-80k input (measured: July-8 message
112
+ * calls, 83 in the 60-80k bucket = 44% of message-fresh). When set, keepLast
113
+ * is reduced further (floor 2) until the kept tail fits this budget,
114
+ * regardless of fill ratio. High-value results (isHighValueToolResult) are
115
+ * still kept verbatim independently, so only bulk dumps get stubbed.
116
+ * Undefined = off (sub-agent path unchanged).
117
+ */
118
+ tailBudgetChars?: number;
107
119
  }
108
120
  /**
109
121
  * G1 — coarse char→token conversion. The real ratio is provider/tokenizer
@@ -136,6 +148,7 @@ export declare const HIGH_VALUE_MCP_PREFIXES: readonly ["mcp_muonroi-docs__"];
136
148
  */
137
149
  export declare function isHighValueToolResult(toolName: string, preview: string, explicitKeepIds?: Set<string>, toolCallId?: string): boolean;
138
150
  export declare function cumulativeMessageChars(messages: ReadonlyArray<ModelMessage>): number;
151
+ export declare function buildSlimContext(msgs: ModelMessage[]): ModelMessage[];
139
152
  /**
140
153
  * Compact a sub-agent message array in place-like fashion. The input is never
141
154
  * mutated. When compaction actually elides something a NEW array is returned.
@@ -148,6 +161,45 @@ export declare function cumulativeMessageChars(messages: ReadonlyArray<ModelMess
148
161
  * step.
149
162
  */
150
163
  export declare function compactSubAgentMessages(messages: ReadonlyArray<ModelMessage>, opts?: SubAgentCompactorOptions): ModelMessage[];
164
+ /**
165
+ * O3 — compaction hysteresis state, threaded across `prepareStep` calls within
166
+ * a single top-level turn. `frozenCompacted` is the compacted history captured
167
+ * at the last real compaction; `frozenStrippedLen` is the message count of the
168
+ * (un-compacted) history at that moment, so the append delta can be recovered.
169
+ */
170
+ export interface CompactionHysteresisState {
171
+ frozenCompacted: ModelMessage[] | null;
172
+ frozenStrippedLen: number;
173
+ lastCompactTriggerChars: number;
174
+ }
175
+ export declare function initCompactionHysteresisState(): CompactionHysteresisState;
176
+ /**
177
+ * Decide whether to hold the frozen compacted prefix or (re)compact.
178
+ *
179
+ * Re-running the compactor on every step slides the keepLast boundary forward
180
+ * one tool result per step, flipping that result verbatim→stub and breaking the
181
+ * provider prompt-cache prefix at its position — measured as 63% of a real
182
+ * session's FRESH input (session 1afb2728e67a). Between compactions we instead
183
+ * reuse the frozen compacted prefix and append only the messages added since
184
+ * (history is append-only within a turn), keeping the cached prefix byte-stable
185
+ * until cumulative size grows past `lastCompactTriggerChars * hysteresis`.
186
+ *
187
+ * Pure: returns the next state rather than mutating. `hysteresis <= 1.0`
188
+ * disables the freeze (legacy per-step compaction). The delta slice uses the
189
+ * ORIGINAL (pre-compaction) length, so it is correct whether or not the
190
+ * compactor preserves message count.
191
+ */
192
+ export declare function applyCompactionHysteresis(args: {
193
+ stripped: ModelMessage[];
194
+ currChars: number;
195
+ hysteresis: number;
196
+ state: CompactionHysteresisState;
197
+ runCompaction: () => ModelMessage[];
198
+ }): {
199
+ compacted: ModelMessage[];
200
+ didRecompact: boolean;
201
+ state: CompactionHysteresisState;
202
+ };
151
203
  /**
152
204
  * Injects Anthropic prompt caching (cacheControl) into the last message's content
153
205
  * block(s) if the model is Claude (starts with 'claude').
@@ -47,6 +47,9 @@
47
47
  * MUONROI_SUBAGENT_COMPACT_THRESHOLD_CHARS — 20_000..500_000, default 80_000
48
48
  * MUONROI_SUBAGENT_COMPACT_KEEP_LAST — 1..20, default 3
49
49
  */
50
+ /** O2 — floor for the tail-budget keepLast shrink; never break the live step's
51
+ * assistant↔tool pairing (that needs at least the current turn). */
52
+ const TAIL_BUDGET_MIN_KEEP = 2;
50
53
  /**
51
54
  * G1 — coarse char→token conversion. The real ratio is provider/tokenizer
52
55
  * specific (cl100k ≈ 3.5-4 chars/token for English code-heavy content, more
@@ -96,6 +99,10 @@ export function isHighValueToolResult(toolName, preview, explicitKeepIds, toolCa
96
99
  // work/findings. Truncating it causes the agent to think it lost its answer.
97
100
  if (name.startsWith("respond_"))
98
101
  return true;
102
+ // Plan context bias (user-halt + "tiếp tục" resume): keep plan text verbatim so
103
+ // compaction does not drop the APPROVED PLAN the user just approved.
104
+ if (/APPROVED PLAN|plan v|khuyến nghị hành động|sprint plan|work plan/i.test(preview))
105
+ return true;
99
106
  // Authoritative ecosystem-docs MCP results: the agent is nudged to fetch these
100
107
  // FIRST, so eliding them strands it (session 584ba476c07a). Keep verbatim.
101
108
  if (HIGH_VALUE_MCP_PREFIXES.some((p) => name.startsWith(p)))
@@ -128,8 +135,31 @@ function resolveOpts(o) {
128
135
  keepToolIds: keepIds,
129
136
  persistArtifact: o?.persistArtifact,
130
137
  stripOldReasoning: o?.stripOldReasoning ?? false,
138
+ tailBudgetChars: Math.max(0, o?.tailBudgetChars ?? 0),
131
139
  };
132
140
  }
141
+ /**
142
+ * O2 — given the fill-ratio-derived keepLast, shrink it further so the kept
143
+ * verbatim tail (the last N tool turns) fits `tailBudgetChars`. Walks keepLast
144
+ * down from its input value, measuring the actual chars of the tail each step,
145
+ * and stops at the first count that fits (or the TAIL_BUDGET_MIN_KEEP floor).
146
+ * Off (returns keepLast unchanged) when tailBudgetChars <= 0.
147
+ */
148
+ function shrinkKeepLastToTailBudget(messages, keepLast, tailBudgetChars) {
149
+ if (tailBudgetChars <= 0 || keepLast <= TAIL_BUDGET_MIN_KEEP)
150
+ return keepLast;
151
+ let k = keepLast;
152
+ while (k > TAIL_BUDGET_MIN_KEEP) {
153
+ const keepFrom = findKeepFromIndex(messages, k);
154
+ let tailChars = 0;
155
+ for (let i = keepFrom; i < messages.length; i++)
156
+ tailChars += messageChars(messages[i]);
157
+ if (tailChars <= tailBudgetChars)
158
+ return k;
159
+ k -= 1;
160
+ }
161
+ return TAIL_BUDGET_MIN_KEEP;
162
+ }
133
163
  /**
134
164
  * G1 + G2 — compute effective threshold (chars) and dynamic keepLastTurns
135
165
  * based on context-window utilization. When the prompt approaches the
@@ -276,6 +306,36 @@ function isStubbedToolResult(msg) {
276
306
  }
277
307
  return false;
278
308
  }
309
+ function generateShortSummary(toolName, content) {
310
+ if (content.length < 500)
311
+ return `${toolName}: ${content.length} chars`;
312
+ const clean = content.trim().replace(/\s+/g, " ");
313
+ if (!clean)
314
+ return `Empty ${toolName} output`;
315
+ const fileMatch = content.match(/File Path: `file:\/\/\/(.+?)`/);
316
+ if (fileMatch) {
317
+ const parts = fileMatch[1].split(/[/\\]/);
318
+ const filename = parts[parts.length - 1];
319
+ return `Read ${filename} (${clean.length} chars)`;
320
+ }
321
+ const grepMatch = content.match(/"LineContent"/);
322
+ if (grepMatch) {
323
+ try {
324
+ const lines = content.trim().split("\n");
325
+ let count = 0;
326
+ for (const line of lines) {
327
+ if (line.includes(`"LineContent"`))
328
+ count++;
329
+ }
330
+ return `Grep found ${count} matches`;
331
+ }
332
+ catch {
333
+ // fallback
334
+ }
335
+ }
336
+ const excerpt = clean.slice(0, 60);
337
+ return `${toolName}: ${excerpt}${clean.length > 60 ? "..." : ""}`;
338
+ }
279
339
  function rewriteOlderToolMessage(msg, previewChars, label, keepToolIds, persistArtifact) {
280
340
  if (!isToolResultMessage(msg) || !Array.isArray(msg.content))
281
341
  return msg;
@@ -292,10 +352,11 @@ function rewriteOlderToolMessage(msg, previewChars, label, keepToolIds, persistA
292
352
  }
293
353
  const preview = rawPreview.slice(0, previewChars).replace(/\s+/g, " ").trim();
294
354
  const stub = `[earlier tool_result for tool=${tr.toolName} (id=${tr.toolCallId}) — ${fullLen} chars elided by ${label} compactor; output: ${preview}]`;
355
+ const summary = generateShortSummary(tr.toolName, rawPreview);
295
356
  // Idea 4: for the ones we actually elide, give caller a chance to persist full raw to EE for later on-demand fetch.
296
357
  if (persistArtifact && fullLen > 200) {
297
358
  try {
298
- persistArtifact(toolCallId, tr.toolName, rawPreview, "elided-by-compactor");
359
+ persistArtifact(toolCallId, tr.toolName, rawPreview, "elided-by-compactor", summary);
299
360
  }
300
361
  catch {
301
362
  /* fail-open */
@@ -312,6 +373,9 @@ function rewriteOlderToolMessage(msg, previewChars, label, keepToolIds, persistA
312
373
  // dragging in the full provider-utils type graph at this layer.
313
374
  return { ...msg, content: rewritten };
314
375
  }
376
+ export function buildSlimContext(msgs) {
377
+ return msgs.slice(-6); // goal + last 2 turns + refs (YAGNI)
378
+ }
315
379
  /**
316
380
  * Compact a sub-agent message array in place-like fashion. The input is never
317
381
  * mutated. When compaction actually elides something a NEW array is returned.
@@ -326,25 +390,31 @@ function rewriteOlderToolMessage(msg, previewChars, label, keepToolIds, persistA
326
390
  export function compactSubAgentMessages(messages, opts = {}) {
327
391
  const resolved = resolveOpts(opts);
328
392
  const { outputPreviewChars, label, envelopeChars } = resolved;
329
- // Step 4: Hard-limit message history sent to the model to prevent token bloating
330
- // When input (messages + envelope) exceeds 50K characters and messages array is > 30,
331
- // we slice the history to keep at most 30 messages (preserving system and user start).
332
- let processedMessages = messages;
333
393
  const messagesTotal = cumulativeMessageChars(messages);
334
394
  const total = messagesTotal + envelopeChars;
335
- if (total > 50_000 && messages.length > 30) {
395
+ const { effectiveThresholdChars, effectiveKeepLastTurns } = computeDynamicParams(total, resolved);
396
+ // No-op: return the input BY REFERENCE (contract above) so `compacted === input`.
397
+ // Identity contract: callers (tool-engine.ts, stream-runner.ts) use
398
+ // `compacted !== stripped` to decide whether to fire recordCompaction. A false
399
+ // identity change (new array with zero elision) produces phantom compaction
400
+ // records — observed as 28 compactions / 0 elisions in session c43cc481a16e.
401
+ // Fix: check threshold on the ORIGINAL total before slicing.
402
+ if (total < effectiveThresholdChars)
403
+ return messages;
404
+ // Step 4: Hard-limit message history sent to the model to prevent token bloating.
405
+ // Only slice when compaction is actually warranted (threshold exceeded), so the
406
+ // slice's identity change pairs with real content reduction, not a phantom no-op.
407
+ let processedMessages = messages;
408
+ if (messages.length > 30) {
336
409
  processedMessages = sliceMessageHistory(messages, 30);
337
410
  }
338
- // Calculate effective thresholds and keep last turns using the processed messages
339
- const processedMessagesTotal = cumulativeMessageChars(processedMessages);
340
- const processedTotal = processedMessagesTotal + envelopeChars;
341
- const { effectiveThresholdChars, effectiveKeepLastTurns } = computeDynamicParams(processedTotal, resolved);
342
- // No-op: return the input BY REFERENCE (contract above) so `compacted === input`.
343
- if (processedTotal < effectiveThresholdChars)
344
- return processedMessages;
345
- const keepFrom = findKeepFromIndex(processedMessages, effectiveKeepLastTurns);
411
+ // O2 after the fill-ratio shrink, further reduce keepLast so the verbatim
412
+ // tail fits the byte budget (targets read-heavy tails that stay large at low
413
+ // fill). No-op when tailBudgetChars is unset (sub-agent path).
414
+ const budgetedKeepLast = shrinkKeepLastToTailBudget(processedMessages, effectiveKeepLastTurns, resolved.tailBudgetChars);
415
+ const keepFrom = findKeepFromIndex(processedMessages, budgetedKeepLast);
346
416
  if (keepFrom <= 0)
347
- return processedMessages;
417
+ return messages;
348
418
  // Walk older messages; rewrite fresh tool results into stubs, super-shrink
349
419
  // already-stubbed results (F1), and strip args off older assistant
350
420
  // tool-call shells (F1). The 1:1 assistant↔tool pairing required by the AI
@@ -455,6 +525,47 @@ function stripAssistantToolCallArgs(msg) {
455
525
  return msg;
456
526
  return { ...msg, content: next };
457
527
  }
528
+ export function initCompactionHysteresisState() {
529
+ return { frozenCompacted: null, frozenStrippedLen: 0, lastCompactTriggerChars: 0 };
530
+ }
531
+ /**
532
+ * Decide whether to hold the frozen compacted prefix or (re)compact.
533
+ *
534
+ * Re-running the compactor on every step slides the keepLast boundary forward
535
+ * one tool result per step, flipping that result verbatim→stub and breaking the
536
+ * provider prompt-cache prefix at its position — measured as 63% of a real
537
+ * session's FRESH input (session 1afb2728e67a). Between compactions we instead
538
+ * reuse the frozen compacted prefix and append only the messages added since
539
+ * (history is append-only within a turn), keeping the cached prefix byte-stable
540
+ * until cumulative size grows past `lastCompactTriggerChars * hysteresis`.
541
+ *
542
+ * Pure: returns the next state rather than mutating. `hysteresis <= 1.0`
543
+ * disables the freeze (legacy per-step compaction). The delta slice uses the
544
+ * ORIGINAL (pre-compaction) length, so it is correct whether or not the
545
+ * compactor preserves message count.
546
+ */
547
+ export function applyCompactionHysteresis(args) {
548
+ const { stripped, currChars, hysteresis, state, runCompaction } = args;
549
+ if (hysteresis > 1.0 && state.frozenCompacted !== null && currChars <= state.lastCompactTriggerChars * hysteresis) {
550
+ const delta = stripped.slice(state.frozenStrippedLen);
551
+ const compacted = delta.length > 0 ? [...state.frozenCompacted, ...delta] : state.frozenCompacted;
552
+ return { compacted, didRecompact: false, state };
553
+ }
554
+ const compacted = runCompaction();
555
+ const changed = compacted !== stripped;
556
+ if (changed && hysteresis > 1.0) {
557
+ return {
558
+ compacted,
559
+ didRecompact: true,
560
+ state: {
561
+ frozenCompacted: compacted,
562
+ frozenStrippedLen: stripped.length,
563
+ lastCompactTriggerChars: currChars,
564
+ },
565
+ };
566
+ }
567
+ return { compacted, didRecompact: changed, state };
568
+ }
458
569
  /**
459
570
  * Injects Anthropic prompt caching (cacheControl) into the last message's content
460
571
  * block(s) if the model is Claude (starts with 'claude').
@@ -13,6 +13,27 @@ import type { PendingCallsLog } from "./pending-calls.js";
13
13
  import type { ReadPathBudget } from "./read-path-budget.js";
14
14
  import type { SafetyOverrideAskInfo, SafetyOverrideVerdict } from "./safety-askcard.js";
15
15
  import { type ToolLoopCapAsk } from "./tool-loop-cap.js";
16
+ /**
17
+ * Resolve the per-turn `maxOutputTokens` budget.
18
+ *
19
+ * Normally the budget is derived from the PIL-classified `taskType`
20
+ * (`taskTypeToMaxTokens`). But a sprint IMPLEMENTATION turn — the /ideal
21
+ * loop's handoff into the host orchestrator via `processMessageFn`, marked
22
+ * with `SPRINT_EXECUTION_MARKER` — is a KNOWN code-writing task that must not
23
+ * be starved by a noisy classify. Observed live (2026-07-10, gsd-core
24
+ * migration): the impl prompt was classified `analyze`/default → capped at
25
+ * 4_096 output → the model spent the whole budget narrating its plan, hit
26
+ * `finishReason:"length"` mid-word, produced ZERO code, and the turn wedged.
27
+ *
28
+ * Fix: for a sprint-execution turn, floor the budget at the build/generate
29
+ * tier (12_288) regardless of the classified type. Scoped to the marker only
30
+ * (NOT the broad `isImplementationIntent`) so ordinary refactor/debug turns
31
+ * keep their intentionally tighter L6 budgets.
32
+ */
33
+ export declare function resolveTurnMaxOutputTokens(pilCtx: {
34
+ taskType: string | null;
35
+ raw?: string;
36
+ }): number;
16
37
  import type { TurnRunnerDepsBase } from "./turn-runner-deps.js";
17
38
  /**
18
39
  * Dependency surface the MessageProcessor needs to reach back into Agent
@@ -147,7 +168,12 @@ export declare function rewriteSafetyApprovedToolResults<T extends {
147
168
  role: string;
148
169
  content?: any;
149
170
  }>(messages: T[]): T[];
171
+ export declare class SimpleMutex {
172
+ private queue;
173
+ run<T>(fn: () => Promise<T> | T): Promise<T>;
174
+ }
150
175
  export interface ToolEngineArgs {
151
176
  [key: string]: any;
152
177
  }
153
178
  export declare function executeToolEngine(args: ToolEngineArgs): AsyncGenerator<StreamChunk, void, unknown>;
179
+ export declare function coalesceReadOnlyMessages(messages: any[]): any[];