mixdog 0.9.2 → 0.9.4

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 (417) hide show
  1. package/package.json +8 -3
  2. package/scripts/anthropic-maxtokens-test.mjs +119 -0
  3. package/scripts/bench/lead-review-tasks-r3.json +20 -0
  4. package/scripts/bench/lead-review-tasks.json +20 -0
  5. package/scripts/bench/r4-mixed-tasks.json +20 -0
  6. package/scripts/bench/review-tasks.json +20 -0
  7. package/scripts/bench/round-codex.json +114 -0
  8. package/scripts/bench/round-mixdog-lead-r3.json +269 -0
  9. package/scripts/bench/round-mixdog-lead.json +269 -0
  10. package/scripts/bench/round-mixdog.json +126 -0
  11. package/scripts/bench/round-r10-bigsample.json +679 -0
  12. package/scripts/bench/round-r11-codexalign.json +257 -0
  13. package/scripts/bench/round-r4-codex.json +114 -0
  14. package/scripts/bench/round-r4-mixed.json +225 -0
  15. package/scripts/bench/round-r5-gpt-lead.json +259 -0
  16. package/scripts/bench/round-r6-codex.json +114 -0
  17. package/scripts/bench/round-r6-solo.json +257 -0
  18. package/scripts/bench/round-r7-full.json +254 -0
  19. package/scripts/bench/round-r8-fulldefault.json +255 -0
  20. package/scripts/bench-run.mjs +215 -29
  21. package/scripts/build-tui.mjs +13 -1
  22. package/scripts/explore-bench.mjs +124 -0
  23. package/scripts/freevar-smoke.mjs +95 -0
  24. package/scripts/hook-bus-test.mjs +191 -0
  25. package/scripts/internal-comms-bench.mjs +1 -0
  26. package/scripts/internal-comms-smoke.mjs +10 -9
  27. package/scripts/mouse-probe.mjs +45 -0
  28. package/scripts/output-style-bench.mjs +13 -6
  29. package/scripts/output-style-smoke.mjs +4 -4
  30. package/scripts/path-suffix-test.mjs +57 -0
  31. package/scripts/provider-toolcall-test.mjs +7 -3
  32. package/scripts/recall-bench.mjs +207 -0
  33. package/scripts/recall-usecase-cases.json +18 -0
  34. package/scripts/recall-usecase-probe.json +6 -0
  35. package/scripts/session-bench.mjs +152 -6
  36. package/scripts/tool-smoke.mjs +30 -67
  37. package/scripts/tui-render-smoke.mjs +90 -0
  38. package/scripts/webhook-smoke.mjs +208 -0
  39. package/src/agents/debugger/AGENT.md +5 -2
  40. package/src/agents/heavy-worker/AGENT.md +21 -11
  41. package/src/agents/maintainer/AGENT.md +4 -0
  42. package/src/agents/reviewer/AGENT.md +3 -2
  43. package/src/agents/worker/AGENT.md +21 -11
  44. package/src/lib/rules-builder.cjs +4 -0
  45. package/src/mixdog-session-runtime.mjs +933 -3731
  46. package/src/output-styles/default.md +34 -9
  47. package/src/output-styles/{oneline.md → extreme-minimal.md} +5 -4
  48. package/src/output-styles/minimal.md +4 -1
  49. package/src/output-styles/simple.md +22 -7
  50. package/src/repl.mjs +5 -5
  51. package/src/rules/agent/00-common.md +2 -0
  52. package/src/rules/agent/30-explorer.md +8 -11
  53. package/src/rules/lead/lead-brief.md +12 -0
  54. package/src/rules/lead/lead-tool.md +2 -9
  55. package/src/rules/shared/01-tool.md +11 -5
  56. package/src/runtime/agent/orchestrator/agent-runtime/agent-loop-policy.mjs +25 -0
  57. package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +100 -23
  58. package/src/runtime/agent/orchestrator/agent-runtime/session-builder.mjs +6 -15
  59. package/src/runtime/agent/orchestrator/agent-trace-format.mjs +362 -0
  60. package/src/runtime/agent/orchestrator/agent-trace-io.mjs +410 -0
  61. package/src/runtime/agent/orchestrator/agent-trace.mjs +16 -735
  62. package/src/runtime/agent/orchestrator/config.mjs +69 -2
  63. package/src/runtime/agent/orchestrator/context/collect.mjs +51 -0
  64. package/src/runtime/agent/orchestrator/mcp/client.mjs +6 -2
  65. package/src/runtime/agent/orchestrator/providers/anthropic-effort.mjs +63 -21
  66. package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens.mjs +93 -0
  67. package/src/runtime/agent/orchestrator/providers/anthropic-model-resolve.mjs +209 -0
  68. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +489 -0
  69. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +97 -1343
  70. package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +607 -0
  71. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +78 -10
  72. package/src/runtime/agent/orchestrator/providers/api-usage.mjs +1 -13
  73. package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +81 -0
  74. package/src/runtime/agent/orchestrator/providers/gemini-cache.mjs +248 -0
  75. package/src/runtime/agent/orchestrator/providers/gemini-schema.mjs +303 -0
  76. package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +505 -0
  77. package/src/runtime/agent/orchestrator/providers/gemini.mjs +44 -1014
  78. package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +18 -4
  79. package/src/runtime/agent/orchestrator/providers/lib/usage-primitives.mjs +32 -0
  80. package/src/runtime/agent/orchestrator/providers/model-catalog.mjs +86 -11
  81. package/src/runtime/agent/orchestrator/providers/model-list-sanitize.mjs +348 -0
  82. package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +54 -20
  83. package/src/runtime/agent/orchestrator/providers/openai-codex-model.mjs +108 -0
  84. package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +19 -12
  85. package/src/runtime/agent/orchestrator/providers/openai-compat-trace.mjs +58 -0
  86. package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +368 -0
  87. package/src/runtime/agent/orchestrator/providers/openai-compat-xai.mjs +760 -0
  88. package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +41 -1142
  89. package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +732 -0
  90. package/src/runtime/agent/orchestrator/providers/openai-oauth-login.mjs +193 -0
  91. package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +303 -2119
  92. package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +140 -995
  93. package/src/runtime/agent/orchestrator/providers/openai-ws-delta.mjs +227 -0
  94. package/src/runtime/agent/orchestrator/providers/openai-ws-events.mjs +67 -0
  95. package/src/runtime/agent/orchestrator/providers/openai-ws-pool.mjs +436 -0
  96. package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +1105 -0
  97. package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +2 -1
  98. package/src/runtime/agent/orchestrator/providers/opencode-go-usage.mjs +38 -12
  99. package/src/runtime/agent/orchestrator/providers/retry-classifier.mjs +7 -8
  100. package/src/runtime/agent/orchestrator/session/compact/budget.mjs +288 -0
  101. package/src/runtime/agent/orchestrator/session/compact/constants.mjs +85 -0
  102. package/src/runtime/agent/orchestrator/session/compact/engine.mjs +749 -0
  103. package/src/runtime/agent/orchestrator/session/compact/messages.mjs +82 -0
  104. package/src/runtime/agent/orchestrator/session/compact/summary-schema.mjs +315 -0
  105. package/src/runtime/agent/orchestrator/session/compact/summary.mjs +643 -0
  106. package/src/runtime/agent/orchestrator/session/compact/text-utils.mjs +326 -0
  107. package/src/runtime/agent/orchestrator/session/compact.mjs +40 -2282
  108. package/src/runtime/agent/orchestrator/session/loop/compact-debug.mjs +28 -0
  109. package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +274 -0
  110. package/src/runtime/agent/orchestrator/session/loop/completion-guards.mjs +61 -0
  111. package/src/runtime/agent/orchestrator/session/loop/context-overflow.mjs +38 -0
  112. package/src/runtime/agent/orchestrator/session/loop/env.mjs +14 -0
  113. package/src/runtime/agent/orchestrator/session/loop/hidden-agents.mjs +21 -0
  114. package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +47 -0
  115. package/src/runtime/agent/orchestrator/session/loop/recall-fasttrack.mjs +182 -0
  116. package/src/runtime/agent/orchestrator/session/loop/steering-ladder.mjs +173 -0
  117. package/src/runtime/agent/orchestrator/session/loop/steering.mjs +63 -0
  118. package/src/runtime/agent/orchestrator/session/loop/stored-tool-args.mjs +100 -0
  119. package/src/runtime/agent/orchestrator/session/loop/termination.mjs +58 -0
  120. package/src/runtime/agent/orchestrator/session/loop/tool-classify.mjs +52 -0
  121. package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +239 -0
  122. package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +218 -0
  123. package/src/runtime/agent/orchestrator/session/loop/transcript-repair.mjs +101 -0
  124. package/src/runtime/agent/orchestrator/session/loop/usage.mjs +35 -0
  125. package/src/runtime/agent/orchestrator/session/loop.mjs +409 -1304
  126. package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +471 -0
  127. package/src/runtime/agent/orchestrator/session/manager/context-meta.mjs +230 -0
  128. package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +235 -0
  129. package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +149 -0
  130. package/src/runtime/agent/orchestrator/session/manager/rules-cache.mjs +155 -0
  131. package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +406 -0
  132. package/src/runtime/agent/orchestrator/session/manager/status-telemetry.mjs +80 -0
  133. package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +303 -0
  134. package/src/runtime/agent/orchestrator/session/manager/usage-metrics.mjs +210 -0
  135. package/src/runtime/agent/orchestrator/session/manager.mjs +226 -2114
  136. package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +189 -0
  137. package/src/runtime/agent/orchestrator/session/store.mjs +74 -179
  138. package/src/runtime/agent/orchestrator/stall-policy.mjs +3 -3
  139. package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +70 -20
  140. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +22 -2
  141. package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +33 -42
  142. package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.mjs +241 -0
  143. package/src/runtime/agent/orchestrator/tools/builtin/fuzzy-match.mjs +1 -1
  144. package/src/runtime/agent/orchestrator/tools/builtin/list-tool.mjs +40 -0
  145. package/src/runtime/agent/orchestrator/tools/builtin/path-diagnostics.mjs +42 -2
  146. package/src/runtime/agent/orchestrator/tools/builtin/read-formatting.mjs +1 -1
  147. package/src/runtime/agent/orchestrator/tools/builtin/read-single-tool.mjs +11 -4
  148. package/src/runtime/agent/orchestrator/tools/builtin/rg-runner.mjs +29 -0
  149. package/src/runtime/agent/orchestrator/tools/builtin/search-builders.mjs +8 -0
  150. package/src/runtime/agent/orchestrator/tools/builtin/search-path-diagnostics.mjs +126 -0
  151. package/src/runtime/agent/orchestrator/tools/builtin/search-tool.mjs +81 -87
  152. package/src/runtime/agent/orchestrator/tools/builtin/shell-job-paths.mjs +161 -0
  153. package/src/runtime/agent/orchestrator/tools/builtin/shell-job-process.mjs +108 -0
  154. package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +78 -304
  155. package/src/runtime/agent/orchestrator/tools/builtin.mjs +11 -6
  156. package/src/runtime/agent/orchestrator/tools/code-graph/build.mjs +303 -0
  157. package/src/runtime/agent/orchestrator/tools/code-graph/constants.mjs +43 -0
  158. package/src/runtime/agent/orchestrator/tools/code-graph/disk-cache.mjs +382 -0
  159. package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +551 -0
  160. package/src/runtime/agent/orchestrator/tools/code-graph/graph-binary.mjs +295 -0
  161. package/src/runtime/agent/orchestrator/tools/code-graph/graph-model.mjs +158 -0
  162. package/src/runtime/agent/orchestrator/tools/code-graph/keyword-match.mjs +82 -0
  163. package/src/runtime/agent/orchestrator/tools/code-graph/lang-predicates.mjs +128 -0
  164. package/src/runtime/agent/orchestrator/tools/code-graph/memory-cache.mjs +66 -0
  165. package/src/runtime/agent/orchestrator/tools/code-graph/project-root.mjs +44 -0
  166. package/src/runtime/agent/orchestrator/tools/code-graph/search.mjs +1080 -0
  167. package/src/runtime/agent/orchestrator/tools/code-graph/source-access.mjs +81 -0
  168. package/src/runtime/agent/orchestrator/tools/code-graph/span.mjs +19 -0
  169. package/src/runtime/agent/orchestrator/tools/code-graph/symbol-index.mjs +280 -0
  170. package/src/runtime/agent/orchestrator/tools/code-graph/text-columns.mjs +45 -0
  171. package/src/runtime/agent/orchestrator/tools/code-graph/text-mask.mjs +347 -0
  172. package/src/runtime/agent/orchestrator/tools/code-graph-tool-defs.mjs +6 -6
  173. package/src/runtime/agent/orchestrator/tools/code-graph.mjs +36 -4277
  174. package/src/runtime/agent/orchestrator/tools/graph-binary-fetcher.mjs +6 -3
  175. package/src/runtime/agent/orchestrator/tools/patch/constants.mjs +9 -0
  176. package/src/runtime/agent/orchestrator/tools/patch/dispatch.mjs +171 -0
  177. package/src/runtime/agent/orchestrator/tools/patch/matcher.mjs +471 -0
  178. package/src/runtime/agent/orchestrator/tools/patch/native-server.mjs +436 -0
  179. package/src/runtime/agent/orchestrator/tools/patch/orchestrator.mjs +342 -0
  180. package/src/runtime/agent/orchestrator/tools/patch/parsing.mjs +359 -0
  181. package/src/runtime/agent/orchestrator/tools/patch/paths.mjs +340 -0
  182. package/src/runtime/agent/orchestrator/tools/patch/v4a-convert.mjs +643 -0
  183. package/src/runtime/agent/orchestrator/tools/patch.mjs +36 -2959
  184. package/src/runtime/agent/orchestrator/tools/progress-message.mjs +1 -23
  185. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +10 -74
  186. package/src/runtime/agent/orchestrator/tools/shell-powershell.mjs +77 -0
  187. package/src/runtime/agent/orchestrator/tools/shell-snapshot.mjs +2 -4
  188. package/src/runtime/agent/orchestrator/tools/shell-state.mjs +154 -0
  189. package/src/runtime/channels/backends/discord-access.mjs +32 -0
  190. package/src/runtime/channels/backends/discord-attachments.mjs +65 -0
  191. package/src/runtime/channels/backends/discord-gateway.mjs +233 -0
  192. package/src/runtime/channels/backends/discord.mjs +12 -292
  193. package/src/runtime/channels/index.mjs +241 -894
  194. package/src/runtime/channels/lib/backend-dispatch.mjs +44 -0
  195. package/src/runtime/channels/lib/boot-profile.mjs +23 -0
  196. package/src/runtime/channels/lib/crash-log.mjs +106 -0
  197. package/src/runtime/channels/lib/event-pipeline.mjs +18 -1
  198. package/src/runtime/channels/lib/event-queue.mjs +63 -4
  199. package/src/runtime/channels/lib/inbound-routing.mjs +111 -0
  200. package/src/runtime/channels/lib/index-drop-trace.mjs +72 -0
  201. package/src/runtime/channels/lib/output-forwarder.mjs +9 -1
  202. package/src/runtime/channels/lib/owner-heartbeat.mjs +75 -0
  203. package/src/runtime/channels/lib/parent-bridge.mjs +88 -0
  204. package/src/runtime/channels/lib/runtime-paths.mjs +14 -4
  205. package/src/runtime/channels/lib/session-discovery.mjs +56 -4
  206. package/src/runtime/channels/lib/telegram-format.mjs +19 -22
  207. package/src/runtime/channels/lib/tool-dispatch.mjs +158 -0
  208. package/src/runtime/channels/lib/tool-format.mjs +1 -1
  209. package/src/runtime/channels/lib/transcript-discovery.mjs +4 -4
  210. package/src/runtime/channels/lib/voice-runtime-fetcher.mjs +6 -3
  211. package/src/runtime/channels/lib/voice-transcription.mjs +179 -0
  212. package/src/runtime/channels/lib/webhook/deliveries.mjs +312 -0
  213. package/src/runtime/channels/lib/webhook/log.mjs +42 -0
  214. package/src/runtime/channels/lib/webhook/ngrok.mjs +181 -0
  215. package/src/runtime/channels/lib/webhook/signature.mjs +60 -0
  216. package/src/runtime/channels/lib/webhook.mjs +36 -570
  217. package/src/runtime/channels/lib/whisper-language.mjs +42 -0
  218. package/src/runtime/channels/tool-defs.mjs +11 -130
  219. package/src/runtime/memory/index.mjs +258 -2050
  220. package/src/runtime/memory/lib/core-memory-store.mjs +351 -1
  221. package/src/runtime/memory/lib/cycle-llm-adapters.mjs +58 -0
  222. package/src/runtime/memory/lib/cycle-scheduler.mjs +497 -0
  223. package/src/runtime/memory/lib/cycle-signatures.mjs +34 -0
  224. package/src/runtime/memory/lib/embedding-warmup.mjs +58 -0
  225. package/src/runtime/memory/lib/http-wire.mjs +57 -0
  226. package/src/runtime/memory/lib/memory-config-flags.mjs +91 -0
  227. package/src/runtime/memory/lib/memory-cycle.mjs +1 -1
  228. package/src/runtime/memory/lib/memory-cycle2-gate.mjs +515 -0
  229. package/src/runtime/memory/lib/memory-cycle2-mutations.mjs +324 -0
  230. package/src/runtime/memory/lib/memory-cycle2-shared.mjs +18 -0
  231. package/src/runtime/memory/lib/memory-cycle2.mjs +72 -837
  232. package/src/runtime/memory/lib/memory-embed.mjs +149 -0
  233. package/src/runtime/memory/lib/memory-process-lock.mjs +162 -0
  234. package/src/runtime/memory/lib/memory-recall-scope-filter.mjs +24 -0
  235. package/src/runtime/memory/lib/memory-recall-store.mjs +22 -2
  236. package/src/runtime/memory/lib/memory-retrievers.mjs +8 -0
  237. package/src/runtime/memory/lib/memory.mjs +20 -0
  238. package/src/runtime/memory/lib/pg/supervisor.mjs +1 -1
  239. package/src/runtime/memory/lib/promotion-fingerprint.mjs +50 -0
  240. package/src/runtime/memory/lib/query-handlers.mjs +780 -0
  241. package/src/runtime/memory/lib/recall-format.mjs +238 -0
  242. package/src/runtime/memory/lib/runtime-fetcher.mjs +8 -3
  243. package/src/runtime/memory/lib/transcript-ingest.mjs +425 -0
  244. package/src/runtime/memory/tool-defs.mjs +6 -14
  245. package/src/runtime/search/lib/http-fetch.mjs +274 -0
  246. package/src/runtime/search/lib/ssrf-guard.mjs +333 -0
  247. package/src/runtime/search/lib/web-tools.mjs +24 -602
  248. package/src/runtime/shared/abort-controller.mjs +1 -1
  249. package/src/runtime/shared/atomic-file.mjs +26 -1
  250. package/src/runtime/shared/background-tasks.mjs +2 -3
  251. package/src/runtime/shared/buffered-appender.mjs +149 -0
  252. package/src/runtime/shared/launcher-control.mjs +2 -2
  253. package/src/runtime/shared/task-notification-envelope.mjs +98 -0
  254. package/src/runtime/shared/tool-execution-contract.mjs +2 -2
  255. package/src/runtime/shared/tool-primitives.mjs +308 -0
  256. package/src/runtime/shared/tool-result-summary.mjs +515 -0
  257. package/src/runtime/shared/tool-surface.mjs +80 -898
  258. package/src/runtime/shared/transcript-writer.mjs +52 -2
  259. package/src/runtime/shared/update-checker.mjs +7 -4
  260. package/src/session-runtime/config-helpers.mjs +291 -0
  261. package/src/session-runtime/config-lifecycle.mjs +232 -0
  262. package/src/session-runtime/cwd-plugins.mjs +226 -0
  263. package/src/session-runtime/effort.mjs +128 -0
  264. package/src/session-runtime/fs-utils.mjs +10 -0
  265. package/src/session-runtime/mcp-glue.mjs +177 -0
  266. package/src/session-runtime/model-capabilities.mjs +130 -0
  267. package/src/session-runtime/model-recency.mjs +111 -0
  268. package/src/session-runtime/native-search.mjs +247 -0
  269. package/src/session-runtime/output-styles.mjs +126 -0
  270. package/src/session-runtime/plugin-mcp.mjs +114 -0
  271. package/src/session-runtime/prewarm.mjs +142 -0
  272. package/src/session-runtime/provider-models.mjs +278 -0
  273. package/src/session-runtime/provider-usage.mjs +120 -0
  274. package/src/session-runtime/quick-model-rows.mjs +170 -0
  275. package/src/session-runtime/quick-search-models.mjs +46 -0
  276. package/src/session-runtime/session-hooks.mjs +93 -0
  277. package/src/session-runtime/session-text.mjs +100 -0
  278. package/src/session-runtime/settings-api.mjs +319 -0
  279. package/src/session-runtime/statusline-route.mjs +35 -0
  280. package/src/session-runtime/tool-catalog.mjs +720 -0
  281. package/src/session-runtime/tool-defs.mjs +84 -0
  282. package/src/session-runtime/warmup-schedulers.mjs +201 -0
  283. package/src/session-runtime/workflow.mjs +358 -0
  284. package/src/standalone/agent-tool/helpers.mjs +237 -0
  285. package/src/standalone/agent-tool/notify.mjs +107 -0
  286. package/src/standalone/agent-tool/provider-init.mjs +143 -0
  287. package/src/standalone/agent-tool/render.mjs +152 -0
  288. package/src/standalone/agent-tool/tool-def.mjs +55 -0
  289. package/src/standalone/agent-tool.mjs +155 -677
  290. package/src/standalone/channel-worker.mjs +7 -9
  291. package/src/standalone/explore-tool.mjs +40 -12
  292. package/src/standalone/hook-bus/config.mjs +207 -0
  293. package/src/standalone/hook-bus/constants.mjs +90 -0
  294. package/src/standalone/hook-bus/handlers.mjs +481 -0
  295. package/src/standalone/hook-bus/payload.mjs +31 -0
  296. package/src/standalone/hook-bus/rules.mjs +77 -0
  297. package/src/standalone/hook-bus.mjs +110 -746
  298. package/src/standalone/memory-runtime-proxy.mjs +7 -0
  299. package/src/standalone/opencode-go-login.mjs +125 -0
  300. package/src/standalone/provider-admin.mjs +15 -19
  301. package/src/standalone/usage-dashboard.mjs +3 -1
  302. package/src/tui/App.jsx +1163 -7571
  303. package/src/tui/app/app-format.mjs +206 -0
  304. package/src/tui/app/channel-pickers.mjs +510 -0
  305. package/src/tui/app/clipboard.mjs +67 -0
  306. package/src/tui/app/core-memory-picker.mjs +210 -0
  307. package/src/tui/app/extension-pickers.mjs +506 -0
  308. package/src/tui/app/input-parsers.mjs +193 -0
  309. package/src/tui/app/maintenance-pickers.mjs +324 -0
  310. package/src/tui/app/model-options.mjs +330 -0
  311. package/src/tui/app/model-picker.mjs +365 -0
  312. package/src/tui/app/onboarding-steps.mjs +400 -0
  313. package/src/tui/app/project-picker.mjs +247 -0
  314. package/src/tui/app/provider-setup-picker.mjs +580 -0
  315. package/src/tui/app/resume-picker.mjs +55 -0
  316. package/src/tui/app/route-pickers.mjs +419 -0
  317. package/src/tui/app/settings-picker.mjs +490 -0
  318. package/src/tui/app/slash-commands.mjs +101 -0
  319. package/src/tui/app/slash-dispatch.mjs +427 -0
  320. package/src/tui/app/text-layout.mjs +46 -0
  321. package/src/tui/app/theme-effort-pickers.mjs +154 -0
  322. package/src/tui/app/transcript-window.mjs +671 -0
  323. package/src/tui/app/use-mouse-input.mjs +460 -0
  324. package/src/tui/app/use-prompt-handlers.mjs +310 -0
  325. package/src/tui/app/use-transcript-scroll.mjs +510 -0
  326. package/src/tui/app/use-transcript-window.mjs +589 -0
  327. package/src/tui/components/ConfirmBar.jsx +1 -1
  328. package/src/tui/components/Picker.jsx +32 -4
  329. package/src/tui/components/PromptInput.jsx +259 -80
  330. package/src/tui/components/SlashCommandPalette.jsx +8 -1
  331. package/src/tui/components/StatusLine.jsx +63 -12
  332. package/src/tui/components/TextEntryPanel.jsx +11 -0
  333. package/src/tui/components/ToolExecution.jsx +56 -588
  334. package/src/tui/components/TranscriptItem.jsx +105 -0
  335. package/src/tui/components/UsagePanel.jsx +18 -4
  336. package/src/tui/components/prompt-input/edit-helpers.mjs +72 -0
  337. package/src/tui/components/prompt-input/voice-indicator.mjs +39 -0
  338. package/src/tui/components/tool-execution/ResultBody.jsx +56 -0
  339. package/src/tui/components/tool-execution/surface-detail.mjs +405 -0
  340. package/src/tui/components/tool-execution/text-format.mjs +161 -0
  341. package/src/tui/components/tool-output-format.mjs +2 -2
  342. package/src/tui/display-width.mjs +20 -3
  343. package/src/tui/dist/index.mjs +18034 -17188
  344. package/src/tui/engine/agent-envelope.mjs +296 -0
  345. package/src/tui/engine/agent-job-feed.mjs +133 -0
  346. package/src/tui/engine/boot-profile.mjs +21 -0
  347. package/src/tui/engine/labels.mjs +67 -0
  348. package/src/tui/engine/notice-text.mjs +112 -0
  349. package/src/tui/engine/notification-plan.mjs +76 -0
  350. package/src/tui/engine/queue-helpers.mjs +161 -0
  351. package/src/tui/engine/render-timing.mjs +17 -0
  352. package/src/tui/engine/session-stats.mjs +46 -0
  353. package/src/tui/engine/tool-approval.mjs +94 -0
  354. package/src/tui/engine/tool-call-fields.mjs +23 -0
  355. package/src/tui/engine/tool-card-results.mjs +234 -0
  356. package/src/tui/engine/tool-result-status.mjs +135 -0
  357. package/src/tui/engine/tool-result-text.mjs +126 -0
  358. package/src/tui/engine.mjs +405 -1385
  359. package/src/tui/figures.mjs +5 -0
  360. package/src/tui/index.jsx +105 -0
  361. package/src/tui/input-editing.mjs +60 -10
  362. package/src/tui/keyboard-protocol.mjs +2 -2
  363. package/src/tui/lib/voice-recorder.mjs +35 -19
  364. package/src/tui/markdown/format-token.mjs +11 -9
  365. package/src/tui/paste-attachments.mjs +38 -0
  366. package/src/tui/statusline-ansi-bridge.mjs +11 -3
  367. package/src/tui/theme.mjs +6 -0
  368. package/src/tui/themes/base.mjs +2 -2
  369. package/src/tui/themes/kanagawa.mjs +4 -4
  370. package/src/tui/themes/teal.mjs +4 -5
  371. package/src/tui/themes/utils.mjs +1 -1
  372. package/src/ui/statusline-agents.mjs +213 -0
  373. package/src/ui/statusline-format.mjs +146 -0
  374. package/src/ui/statusline-segments.mjs +148 -0
  375. package/src/ui/statusline.mjs +77 -462
  376. package/src/ui/tool-card.mjs +0 -1
  377. package/src/vendor/statusline/bin/statusline-route.mjs +15 -2
  378. package/src/workflows/default/WORKFLOW.md +16 -9
  379. package/src/workflows/sequential/WORKFLOW.md +16 -11
  380. package/src/workflows/solo/WORKFLOW.md +5 -1
  381. package/vendor/ink/build/display-width.js +19 -3
  382. package/vendor/ink/build/ink.js +103 -6
  383. package/vendor/ink/build/log-update.js +17 -3
  384. package/vendor/ink/build/wrap-text.js +125 -0
  385. package/scripts/_test-folder-dialog.mjs +0 -30
  386. package/scripts/fix-brief-fn.mjs +0 -35
  387. package/scripts/fix-format-tool-surface.mjs +0 -24
  388. package/scripts/fix-tool-exec-visible.mjs +0 -42
  389. package/scripts/patch-agent-brief.mjs +0 -48
  390. package/scripts/patch-app.mjs +0 -21
  391. package/scripts/patch-app2.mjs +0 -18
  392. package/scripts/patch-dist-brief.mjs +0 -96
  393. package/scripts/patch-tool-exec.mjs +0 -70
  394. package/src/examples/schedules/SCHEDULE.example.md +0 -32
  395. package/src/examples/webhooks/WEBHOOK.example.md +0 -40
  396. package/src/runtime/agent/orchestrator/session/manager.reactive-persist.test.mjs +0 -107
  397. package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.test.mjs +0 -143
  398. package/src/runtime/agent/orchestrator/tools/builtin/diagnostics-tool.mjs +0 -285
  399. package/src/runtime/agent/orchestrator/tools/builtin/open-config-tool.mjs +0 -26
  400. package/src/runtime/shared/channel-notification-routing.test.mjs +0 -45
  401. package/src/runtime/shared/tool-execution-contract.test.mjs +0 -183
  402. package/src/standalone/agent-task-status.test.mjs +0 -76
  403. package/src/tui/components/tool-output-format.test.mjs +0 -399
  404. package/src/tui/display-width.test.mjs +0 -35
  405. package/src/tui/engine-runtime-notification.test.mjs +0 -115
  406. package/src/tui/engine-tool-result-text.test.mjs +0 -75
  407. package/src/tui/markdown/format-token.test.mjs +0 -354
  408. package/src/tui/markdown/render-ansi.test.mjs +0 -108
  409. package/src/tui/markdown/stream-fence.test.mjs +0 -26
  410. package/src/tui/markdown/streaming-markdown.test.mjs +0 -70
  411. package/src/tui/prompt-history-store.test.mjs +0 -52
  412. package/src/tui/statusline-ansi-bridge.test.mjs +0 -159
  413. package/src/tui/transcript-tool-failures.test.mjs +0 -111
  414. package/src/ui/markdown.test.mjs +0 -70
  415. package/src/ui/statusline-context-label.test.mjs +0 -15
  416. package/src/vendor/statusline/bin/statusline-lib.mjs +0 -186
  417. package/src/vendor/statusline/bin/statusline-route.test.mjs +0 -80
@@ -0,0 +1,471 @@
1
+ // Session compaction runner — recall-fasttrack / semantic / prune-fallback.
2
+ // Extracted verbatim from manager.mjs (behavior-preserving). Self-contained:
3
+ // operates on a live `session` object + opts, using pure compact/context
4
+ // helpers. No runtime-liveness (_runtimeState) coupling — manager.mjs still
5
+ // owns scheduling / stage gating and simply calls runSessionCompaction().
6
+ import { createHash } from 'crypto';
7
+ import { getProvider } from '../../providers/registry.mjs';
8
+ import {
9
+ recallFastTrackCompactMessages,
10
+ semanticCompactMessages,
11
+ pruneToolOutputsUnanchored,
12
+ effectiveBudget as compactEffectiveBudget,
13
+ compactTypeIsRecallFastTrack,
14
+ compactTypeIsSemantic,
15
+ drainSessionCycle1,
16
+ } from '../compact.mjs';
17
+ import { estimateMessagesTokens, estimateRequestReserveTokens, estimateTranscriptContextUsage, resolveCompactBufferRatio } from '../context-utils.mjs';
18
+ import { executeInternalTool } from '../../internal-tools.mjs';
19
+ import {
20
+ positiveContextWindow,
21
+ compactTriggerForSession,
22
+ compactTargetBudget,
23
+ semanticCompactionEnabledForSession,
24
+ compactTypeForSession,
25
+ } from './context-meta.mjs';
26
+ import { uncachedInputTokensForProvider } from './usage-metrics.mjs';
27
+
28
+ // 'compacting' is a transient in-flight stage written just before semantic /
29
+ // recall-fasttrack compaction runs. If the process crashes or only partially
30
+ // saves while it is set, a later load/resume reads a session that is NOT
31
+ // actually compacting but whose UI marker (App.jsx / ContextPanel) shows
32
+ // "Compacting conversation" permanently. Normalize that stale transient stage
33
+ // to 'interrupted' so the surface recovers. Terminal stages (post_turn /
34
+ // manual / auto_clear / *_failed / overflow_failed) are intentionally left as
35
+ // the durable record of the last real outcome.
36
+ export function normalizeStaleCompactingStage(session) {
37
+ const c = session?.compaction;
38
+ if (!c || typeof c !== 'object') return false;
39
+ if (c.lastStage !== 'compacting' && c.inProgress !== true) return false;
40
+ c.lastStage = 'interrupted';
41
+ c.inProgress = false;
42
+ c.lastCheckedAt = Date.now();
43
+ return true;
44
+ }
45
+ function addCompactUsageToSession(session, usage) {
46
+ if (!session || !usage) return;
47
+ const inputTokens = usage.inputTokens || 0;
48
+ const outputTokens = usage.outputTokens || 0;
49
+ const cachedTokens = usage.cachedTokens || 0;
50
+ const cacheWriteTokens = usage.cacheWriteTokens || 0;
51
+ const uncachedInputTokens = uncachedInputTokensForProvider(session.provider, inputTokens, cachedTokens, cacheWriteTokens);
52
+ session.totalInputTokens = (session.totalInputTokens || 0) + inputTokens;
53
+ session.totalOutputTokens = (session.totalOutputTokens || 0) + outputTokens;
54
+ session.totalCachedReadTokens = (session.totalCachedReadTokens || 0) + cachedTokens;
55
+ session.totalCacheWriteTokens = (session.totalCacheWriteTokens || 0) + cacheWriteTokens;
56
+ session.totalUncachedInputTokens = (session.totalUncachedInputTokens || 0) + uncachedInputTokens;
57
+ session.tokensCumulative = (session.tokensCumulative || 0) + inputTokens + outputTokens;
58
+ }
59
+ async function runRecallFastTrackForSession(session, messages, opts = {}) {
60
+ const sessionId = opts.sessionId || session?.id || null;
61
+ if (!sessionId) throw new Error('recall-fasttrack requires a session id');
62
+ const query = `session:${sessionId}:all-chunks`;
63
+ const querySha = createHash('sha256').update(query).digest('hex').slice(0, 16);
64
+ const callerCtx = {
65
+ callerSessionId: sessionId,
66
+ callerCwd: session?.cwd || undefined,
67
+ routingSessionId: sessionId,
68
+ clientHostPid: session?.clientHostPid,
69
+ signal: opts.signal || null,
70
+ };
71
+ const hydrateLimit = positiveContextWindow(session?.compaction?.recallIngestLimit)
72
+ || Math.max(500, Math.min(5000, messages.length || 0));
73
+ try {
74
+ await executeInternalTool('memory', {
75
+ action: 'ingest_session',
76
+ sessionId,
77
+ messages,
78
+ cwd: session?.cwd,
79
+ limit: hydrateLimit,
80
+ }, callerCtx);
81
+ } catch (err) {
82
+ try { process.stderr.write(`[session] recall-fasttrack ingest skipped (sess=${sessionId}): ${err?.message || err}\n`); } catch {}
83
+ }
84
+ const dumpArgs = {
85
+ action: 'dump_session_roots',
86
+ sessionId,
87
+ includeRaw: true,
88
+ limit: positiveContextWindow(session?.compaction?.recallChunkLimit ?? session?.compaction?.recallLimit) || hydrateLimit,
89
+ };
90
+ const runTool = (name, args) => executeInternalTool(name, args, callerCtx);
91
+ let recallText = await executeInternalTool('memory', dumpArgs, callerCtx);
92
+ let cycle1Text = '';
93
+ let cycle1Error = null;
94
+ const hasRawRows = /(?:^|\n)# raw_pending\s+\d+\s+id=/i.test(String(recallText || ''));
95
+ if (hasRawRows) {
96
+ try {
97
+ // Drain this session's cycle1 in window×concurrency units until no
98
+ // raw rows remain, so the injected root is fully chunked rather than
99
+ // carrying the unprocessed transcript tail (single-pass left raw in).
100
+ const drained = await drainSessionCycle1(runTool, {
101
+ sessionId,
102
+ dumpArgs,
103
+ deadlineMs: positiveContextWindow(session?.compaction?.recallCycle1DeadlineMs) || 120_000,
104
+ maxPasses: positiveContextWindow(session?.compaction?.recallCycle1MaxPasses) || 0,
105
+ cycleArgs: {
106
+ min_batch: 1,
107
+ session_cap: 1,
108
+ batch_size: positiveContextWindow(session?.compaction?.recallCycle1BatchSize) || 100,
109
+ rows_per_session: positiveContextWindow(session?.compaction?.recallRowsPerSession) || 100,
110
+ window_size: positiveContextWindow(session?.compaction?.recallWindowSize) || 20,
111
+ concurrency: positiveContextWindow(session?.compaction?.recallConcurrency) || 5,
112
+ },
113
+ });
114
+ recallText = drained.recallText;
115
+ cycle1Text = drained.cycle1Text;
116
+ if (drained.error) {
117
+ cycle1Error = drained.error;
118
+ try { process.stderr.write(`[session] recall-fasttrack cycle1 error (sess=${sessionId}): ${drained.error}\n`); } catch {}
119
+ }
120
+ if (drained.rawRemaining > 0) {
121
+ try { process.stderr.write(`[session] recall-fasttrack drained passes=${drained.passes} rawRemaining=${drained.rawRemaining} (sess=${sessionId})\n`); } catch {}
122
+ }
123
+ } catch (err) {
124
+ try { process.stderr.write(`[session] recall-fasttrack cycle1 skipped (sess=${sessionId}): ${err?.message || err}\n`); } catch {}
125
+ }
126
+ } else {
127
+ cycle1Text = 'cycle1: skipped (session chunks already hydrated)';
128
+ }
129
+ return { query, querySha, cycle1Error, recallText: [`session_id=${sessionId}`, cycle1Text, recallText].map(v => String(v || '').trim()).filter(Boolean).join('\n\n') };
130
+ }
131
+ // Element-identity change detection (same approach as loop.mjs messagesArrayChanged): two
132
+ // arrays are "unchanged" only when same length AND every slot is the same object
133
+ // reference. Used to reject a no-op prune (which returns a fresh array whose
134
+ // elements are the untouched originals) from being accepted as a recovery.
135
+ function messagesChanged(before, after) {
136
+ if (!Array.isArray(before) || !Array.isArray(after)) return before !== after;
137
+ if (before.length !== after.length) return true;
138
+ for (let i = 0; i < before.length; i += 1) {
139
+ if (before[i] !== after[i]) return true;
140
+ }
141
+ return false;
142
+ }
143
+ export async function runSessionCompaction(session, opts = {}) {
144
+ if (!session || session.closed === true) return null;
145
+ const mode = opts.mode === 'auto' ? 'auto' : 'manual';
146
+ const force = opts.force === true || mode === 'manual';
147
+ if (mode === 'auto' && session.compaction?.auto === false) return null;
148
+ const messages = Array.isArray(session.messages) ? session.messages : [];
149
+ if (messages.length < 3 && !force) return null;
150
+ const boundary = positiveContextWindow(session.compactBoundaryTokens)
151
+ || positiveContextWindow(session.autoCompactTokenLimit)
152
+ || positiveContextWindow(session.contextWindow);
153
+ if (!boundary) {
154
+ if (force) throw new Error('compact: no context window is available for this session');
155
+ return null;
156
+ }
157
+ // Reserve must mirror loop.mjs (buildCompactPolicy): request reserve (tool
158
+ // schema) PLUS the configured reserve (session.compaction.reservedTokens or
159
+ // MIXDOG_AGENT_COMPACT_RESERVED_TOKENS env). The old request-only value left
160
+ // the manual / auto-clear compact budget without the configured headroom the
161
+ // loop path reserves, so a compacted transcript could overflow on next send.
162
+ const requestReserveTokens = estimateRequestReserveTokens(session.tools || []);
163
+ const configuredReserveTokens = positiveContextWindow(session.compaction?.reservedTokens)
164
+ || positiveContextWindow(process.env.MIXDOG_AGENT_COMPACT_RESERVED_TOKENS)
165
+ || 0;
166
+ const reserveTokens = requestReserveTokens + configuredReserveTokens;
167
+ const beforeMessageTokens = estimateMessagesTokens(messages);
168
+ const triggerTokens = compactTriggerForSession(session, boundary)
169
+ || positiveContextWindow(session.compaction?.triggerTokens)
170
+ || boundary;
171
+ const bufferTokens = Math.max(0, boundary - triggerTokens);
172
+ const bufferRatio = boundary ? (bufferTokens / boundary) : resolveCompactBufferRatio(session.compaction || {});
173
+ const pressureTokens = estimateTranscriptContextUsage(messages, session.tools || []);
174
+ const beforeTokens = pressureTokens;
175
+ const compactType = compactTypeForSession(session);
176
+ if (!force && pressureTokens < triggerTokens) return {
177
+ changed: false,
178
+ reason: 'below threshold',
179
+ compactType,
180
+ beforeMessages: messages.length,
181
+ afterMessages: messages.length,
182
+ beforeTokens,
183
+ afterTokens: beforeTokens,
184
+ beforeMessageTokens,
185
+ afterMessageTokens: beforeMessageTokens,
186
+ pressureTokens,
187
+ triggerTokens,
188
+ bufferTokens,
189
+ bufferRatio,
190
+ boundaryTokens: boundary,
191
+ budgetTokens: boundary,
192
+ targetBudgetTokens: boundary,
193
+ reserveTokens,
194
+ semanticCompact: false,
195
+ };
196
+ const budgetSourceTokens = force ? Math.max(pressureTokens, triggerTokens) : pressureTokens;
197
+ const compactBudget = compactTargetBudget(boundary, reserveTokens, budgetSourceTokens);
198
+ const budget = compactBudget || boundary;
199
+ try { opts.onStageChange?.('compacting'); } catch { /* best-effort */ }
200
+ const provider = opts.provider || getProvider(session.provider) || null;
201
+ let compacted;
202
+ let compactError = null;
203
+ let semanticCompactResult = null;
204
+ let semanticCompactError = null;
205
+ let recallFastTrackResult = null;
206
+ let recallFastTrackError = null;
207
+ if (compactTypeIsRecallFastTrack(compactType)) {
208
+ try {
209
+ const recallPayload = await runRecallFastTrackForSession(session, messages, opts);
210
+ recallFastTrackResult = recallFastTrackCompactMessages(messages, budget, {
211
+ reserveTokens,
212
+ force: true,
213
+ recallText: recallPayload.recallText,
214
+ query: recallPayload.query,
215
+ querySha: recallPayload.querySha,
216
+ // Ingest just ran on the live transcript, so an empty recall dump
217
+ // means the memory pipeline is broken — do NOT erase history
218
+ // behind an empty summary shell. Empty recall now throws and is
219
+ // handled by the semantic fallback below (or recorded failure).
220
+ allowEmptyRecall: false,
221
+ tailTurns: positiveContextWindow(session.compaction?.tailTurns) || 2,
222
+ keepTokens: positiveContextWindow(session.compaction?.keepTokens ?? session.compaction?.keep?.tokens),
223
+ preserveRecentTokens: positiveContextWindow(session.compaction?.preserveRecentTokens),
224
+ });
225
+ if (Array.isArray(recallFastTrackResult?.messages)) {
226
+ compacted = recallFastTrackResult.messages;
227
+ }
228
+ if (recallPayload.cycle1Error) {
229
+ recallFastTrackError = new Error(String(recallPayload.cycle1Error));
230
+ }
231
+ } catch (err) {
232
+ recallFastTrackError = err;
233
+ compactError = err;
234
+ try {
235
+ process.stderr.write(`[session] recall-fasttrack ${mode} compact failed (sess=${session.id || 'unknown'}): ${err?.message || err}\n`);
236
+ } catch { /* best-effort */ }
237
+ // Degraded-compact fallback: recall-fasttrack failed (empty recall,
238
+ // ingest error, fit failure). Before recording a hard failure, try
239
+ // the semantic path once so auto-clear/manual compaction still makes
240
+ // progress WITHOUT shipping an empty-recall summary. History is only
241
+ // replaced when the semantic summary actually succeeds.
242
+ if (semanticCompactionEnabledForSession(session)
243
+ && provider && typeof provider.send === 'function') {
244
+ try {
245
+ semanticCompactResult = await semanticCompactMessages(
246
+ provider,
247
+ messages,
248
+ opts.model || session.model,
249
+ budget,
250
+ {
251
+ reserveTokens,
252
+ providerName: session.provider || provider?.name || null,
253
+ sessionId: opts.sessionId || session.id || null,
254
+ signal: opts.signal || null,
255
+ promptCacheKey: session.promptCacheKey || null,
256
+ providerCacheKey: session.promptCacheKey || null,
257
+ timeoutMs: positiveContextWindow(session.compaction?.timeoutMs) || 30_000,
258
+ tailTurns: positiveContextWindow(session.compaction?.tailTurns) || 2,
259
+ keepTokens: positiveContextWindow(session.compaction?.keepTokens ?? session.compaction?.keep?.tokens),
260
+ preserveRecentTokens: positiveContextWindow(session.compaction?.preserveRecentTokens),
261
+ force: true,
262
+ },
263
+ );
264
+ if (Array.isArray(semanticCompactResult?.messages)) {
265
+ compacted = semanticCompactResult.messages;
266
+ compactError = null;
267
+ addCompactUsageToSession(session, semanticCompactResult.usage);
268
+ try {
269
+ process.stderr.write(`[session] degraded compact: recall-fasttrack failed, semantic fallback succeeded (sess=${session.id || 'unknown'}, mode=${mode})\n`);
270
+ } catch { /* best-effort */ }
271
+ }
272
+ } catch (fallbackErr) {
273
+ semanticCompactError = fallbackErr;
274
+ try {
275
+ process.stderr.write(`[session] degraded compact: semantic fallback also failed (sess=${session.id || 'unknown'}): ${fallbackErr?.message || fallbackErr}\n`);
276
+ } catch { /* best-effort */ }
277
+ }
278
+ }
279
+ }
280
+ } else if (compactTypeIsSemantic(compactType)) {
281
+ try {
282
+ if (!semanticCompactionEnabledForSession(session)) {
283
+ throw new Error('semantic compact is disabled for this session');
284
+ }
285
+ if (!provider || typeof provider.send !== 'function') {
286
+ throw new Error(`semantic compact provider unavailable: ${session.provider || 'unknown'}`);
287
+ }
288
+ semanticCompactResult = await semanticCompactMessages(
289
+ provider,
290
+ messages,
291
+ opts.model || session.model,
292
+ budget,
293
+ {
294
+ reserveTokens,
295
+ providerName: session.provider || provider?.name || null,
296
+ sessionId: opts.sessionId || session.id || null,
297
+ signal: opts.signal || null,
298
+ promptCacheKey: session.promptCacheKey || null,
299
+ providerCacheKey: session.promptCacheKey || null,
300
+ timeoutMs: positiveContextWindow(session.compaction?.timeoutMs) || 30_000,
301
+ tailTurns: positiveContextWindow(session.compaction?.tailTurns) || 2,
302
+ keepTokens: positiveContextWindow(session.compaction?.keepTokens ?? session.compaction?.keep?.tokens),
303
+ preserveRecentTokens: positiveContextWindow(session.compaction?.preserveRecentTokens),
304
+ force: true,
305
+ },
306
+ );
307
+ if (Array.isArray(semanticCompactResult?.messages)) {
308
+ compacted = semanticCompactResult.messages;
309
+ addCompactUsageToSession(session, semanticCompactResult.usage);
310
+ }
311
+ } catch (err) {
312
+ semanticCompactError = err;
313
+ compactError = err;
314
+ try {
315
+ process.stderr.write(`[session] semantic ${mode} compact failed (sess=${session.id || 'unknown'}): ${err?.message || err}\n`);
316
+ } catch { /* best-effort */ }
317
+ }
318
+ }
319
+ if (!compacted && !compactError) {
320
+ compactError = new Error(`${compactType} compact produced no messages`);
321
+ }
322
+ // Anchor-independent prune safety net (mirror loop.mjs compact catch): when a
323
+ // non-recall (semantic) compact failed, try one non-LLM prune that needs no
324
+ // user anchor before recording failure, so Lead manual / auto-clear paths
325
+ // recover the same transcripts the loop path does. Gated off the recall
326
+ // path — a recall failure keeps its original contract (no silent prune).
327
+ if (!compacted && !recallFastTrackError) {
328
+ try {
329
+ const acceptThreshold = compactEffectiveBudget(budget, { reserveTokens });
330
+ const salvaged = pruneToolOutputsUnanchored(messages, budget, { reserveTokens });
331
+ // pruneToolOutputsUnanchored ALWAYS returns a fresh reconciled array
332
+ // (never the input identity), so `salvaged !== messages` is always
333
+ // true and cannot detect a no-op. Compare by element identity so a
334
+ // transcript that already fit (nothing pruned) is NOT falsely accepted
335
+ // as a recovery — that would clear compactError and unconditionally
336
+ // invalidate providerState for an unchanged transcript.
337
+ if (Array.isArray(salvaged)
338
+ && messagesChanged(messages, salvaged)
339
+ && estimateMessagesTokens(salvaged) <= acceptThreshold) {
340
+ compacted = salvaged;
341
+ compactError = null;
342
+ try {
343
+ process.stderr.write(`[session] compact fallback prune recovered (sess=${session.id || 'unknown'}, mode=${mode})\n`);
344
+ } catch { /* best-effort */ }
345
+ }
346
+ } catch { /* fall through to failure record */ }
347
+ }
348
+ if (!compacted) {
349
+ const now = Date.now();
350
+ session.compaction = {
351
+ ...(session.compaction || {}),
352
+ auto: mode === 'auto' ? true : session.compaction?.auto !== false,
353
+ boundaryTokens: boundary,
354
+ triggerTokens,
355
+ bufferTokens,
356
+ bufferRatio,
357
+ reserveTokens,
358
+ lastStage: mode === 'auto' ? 'post_turn_failed' : 'manual_failed',
359
+ lastBeforeTokens: beforeTokens,
360
+ lastAfterTokens: beforeTokens,
361
+ lastBeforeMessageTokens: beforeMessageTokens,
362
+ lastAfterMessageTokens: beforeMessageTokens,
363
+ lastPressureTokens: pressureTokens,
364
+ lastCheckedAt: now,
365
+ lastChanged: false,
366
+ type: compactType,
367
+ compactType,
368
+ lastCompactType: compactType,
369
+ lastSemantic: false,
370
+ lastSemanticError: semanticCompactError?.message || null,
371
+ lastRecallFastTrack: false,
372
+ lastRecallFastTrackError: recallFastTrackError?.message || null,
373
+ lastError: compactError?.message || semanticCompactError?.message || recallFastTrackError?.message || String(compactError || semanticCompactError || recallFastTrackError || 'compact failed'),
374
+ };
375
+ return {
376
+ changed: false,
377
+ error: session.compaction.lastError,
378
+ compactType,
379
+ beforeMessages: messages.length,
380
+ afterMessages: messages.length,
381
+ beforeTokens,
382
+ afterTokens: beforeTokens,
383
+ beforeMessageTokens,
384
+ afterMessageTokens: beforeMessageTokens,
385
+ pressureTokens,
386
+ triggerTokens,
387
+ bufferTokens,
388
+ bufferRatio,
389
+ boundaryTokens: boundary,
390
+ budgetTokens: boundary,
391
+ targetBudgetTokens: budget,
392
+ reserveTokens,
393
+ semanticCompact: false,
394
+ semanticError: semanticCompactError?.message || null,
395
+ recallFastTrack: false,
396
+ recallFastTrackError: recallFastTrackError?.message || null,
397
+ };
398
+ }
399
+ let beforeEncoded = '';
400
+ let afterEncoded = '';
401
+ try { beforeEncoded = JSON.stringify(messages); } catch { beforeEncoded = ''; }
402
+ try { afterEncoded = JSON.stringify(compacted); } catch { afterEncoded = ''; }
403
+ const afterMessageTokens = estimateMessagesTokens(compacted);
404
+ const afterTokens = afterMessageTokens + reserveTokens;
405
+ const changed = beforeEncoded && afterEncoded
406
+ ? beforeEncoded !== afterEncoded
407
+ : (compacted.length !== messages.length || afterMessageTokens !== beforeMessageTokens);
408
+ const unchangedReason = changed ? null : (force ? 'nothing to compact' : 'below threshold');
409
+ const now = Date.now();
410
+ session.messages = compacted;
411
+ session.providerState = undefined;
412
+ session.compaction = {
413
+ ...(session.compaction || {}),
414
+ auto: mode === 'auto' ? true : session.compaction?.auto !== false,
415
+ boundaryTokens: boundary,
416
+ triggerTokens,
417
+ bufferTokens,
418
+ bufferRatio,
419
+ reserveTokens,
420
+ type: compactType,
421
+ compactType,
422
+ lastCompactType: compactType,
423
+ lastStage: mode === 'auto' ? 'post_turn' : 'manual',
424
+ lastBeforeTokens: beforeTokens,
425
+ lastAfterTokens: afterTokens,
426
+ lastBeforeMessageTokens: beforeMessageTokens,
427
+ lastAfterMessageTokens: afterMessageTokens,
428
+ lastPressureTokens: pressureTokens,
429
+ lastCheckedAt: now,
430
+ lastChanged: changed,
431
+ lastChangedAt: changed ? now : session.compaction?.lastChangedAt || null,
432
+ lastCompactAt: changed ? now : session.compaction?.lastCompactAt || null,
433
+ lastSemantic: semanticCompactResult?.semantic === true,
434
+ lastSemanticError: semanticCompactError?.message || null,
435
+ lastRecallFastTrack: recallFastTrackResult?.recallFastTrack === true,
436
+ lastRecallFastTrackError: recallFastTrackError?.message || null,
437
+ lastRecallFastTrackQuerySha: recallFastTrackResult?.query ? createHash('sha256').update(recallFastTrackResult.query).digest('hex').slice(0, 16) : null,
438
+ lastSemanticUsage: semanticCompactResult?.usage ? {
439
+ inputTokens: semanticCompactResult.usage.inputTokens || 0,
440
+ outputTokens: semanticCompactResult.usage.outputTokens || 0,
441
+ cachedTokens: semanticCompactResult.usage.cachedTokens || 0,
442
+ cacheWriteTokens: semanticCompactResult.usage.cacheWriteTokens || 0,
443
+ } : null,
444
+ compactCount: (session.compaction?.compactCount || 0) + (changed ? 1 : 0),
445
+ };
446
+ if (changed && mode === 'auto') session.lastContextTokensStaleAfterCompact = true;
447
+ return {
448
+ changed,
449
+ reason: unchangedReason,
450
+ compactType,
451
+ beforeMessages: messages.length,
452
+ afterMessages: compacted.length,
453
+ beforeTokens,
454
+ afterTokens,
455
+ beforeMessageTokens,
456
+ afterMessageTokens,
457
+ pressureTokens,
458
+ triggerTokens,
459
+ bufferTokens,
460
+ bufferRatio,
461
+ boundaryTokens: boundary,
462
+ budgetTokens: boundary,
463
+ targetBudgetTokens: budget,
464
+ reserveTokens,
465
+ semanticCompact: semanticCompactResult?.semantic === true,
466
+ semanticError: semanticCompactError?.message || null,
467
+ recallFastTrack: recallFastTrackResult?.recallFastTrack === true,
468
+ recallFastTrackError: recallFastTrackError?.message || null,
469
+ usage: semanticCompactResult?.usage || null,
470
+ };
471
+ }