mixdog 0.9.152 → 0.9.154

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 (300) hide show
  1. package/LICENSES/browser-import-NOTICE.txt +11 -0
  2. package/NOTICE.md +11 -0
  3. package/README.md +8 -10
  4. package/package.json +19 -3
  5. package/scripts/computer-task-cost-report.mjs +144 -0
  6. package/scripts/run-office-live-tests.mjs +32 -0
  7. package/src/agents/front-worker/AGENT.md +13 -0
  8. package/src/agents/front-worker/agent.json +6 -0
  9. package/src/agents/heavy-worker/AGENT.md +10 -11
  10. package/src/agents/heavy-worker/agent.json +1 -1
  11. package/src/agents/maintainer/AGENT.md +0 -2
  12. package/src/agents/reviewer/AGENT.md +9 -13
  13. package/src/agents/reviewer/agent.json +1 -1
  14. package/src/agents/security/AGENT.md +14 -0
  15. package/src/agents/security/agent.json +6 -0
  16. package/src/agents/worker/AGENT.md +8 -8
  17. package/src/agents/worker/agent.json +1 -1
  18. package/src/agents/writer/AGENT.md +14 -0
  19. package/src/agents/writer/agent.json +6 -0
  20. package/src/rules/agent/00-common.md +4 -7
  21. package/src/rules/lead/01-general.md +0 -3
  22. package/src/rules/shared/10-tool-workflow.md +10 -2
  23. package/src/rules/shared/60-verification.md +2 -0
  24. package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch.mjs +183 -26
  25. package/src/runtime/agent/orchestrator/agent-runtime/session-builder.mjs +4 -0
  26. package/src/runtime/agent/orchestrator/cache-break-trace.mjs +109 -0
  27. package/src/runtime/agent/orchestrator/config.mjs +7 -2
  28. package/src/runtime/agent/orchestrator/providers/admission-scheduler.mjs +16 -3
  29. package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +9 -1
  30. package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +30 -9
  31. package/src/runtime/agent/orchestrator/providers/openai-codex-metadata.mjs +18 -26
  32. package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +25 -2
  33. package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +103 -10
  34. package/src/runtime/agent/orchestrator/providers/openai-turn-state.mjs +68 -0
  35. package/src/runtime/agent/orchestrator/providers/openai-ws-delta.mjs +36 -11
  36. package/src/runtime/agent/orchestrator/providers/openai-ws-pool.mjs +140 -86
  37. package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +9 -13
  38. package/src/runtime/agent/orchestrator/session/agent-loop.mjs +72 -4
  39. package/src/runtime/agent/orchestrator/session/browser-snapshot-supersession.mjs +61 -0
  40. package/src/runtime/agent/orchestrator/session/compact/handoff.mjs +0 -22
  41. package/src/runtime/agent/orchestrator/session/compact/messages.mjs +2 -2
  42. package/src/runtime/agent/orchestrator/session/compact/runner.mjs +11 -23
  43. package/src/runtime/agent/orchestrator/session/compact/summary.mjs +28 -269
  44. package/src/runtime/agent/orchestrator/session/compact.mjs +0 -6
  45. package/src/runtime/agent/orchestrator/session/context-utils.mjs +86 -11
  46. package/src/runtime/agent/orchestrator/session/eager-dispatch.mjs +17 -1
  47. package/src/runtime/agent/orchestrator/session/image-strip-recovery.mjs +12 -8
  48. package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +110 -2
  49. package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +3 -16
  50. package/src/runtime/agent/orchestrator/session/loop/recall-fasttrack.mjs +80 -18
  51. package/src/runtime/agent/orchestrator/session/loop/steering.mjs +6 -0
  52. package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +3 -0
  53. package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +6 -0
  54. package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +80 -21
  55. package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +33 -72
  56. package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +21 -2
  57. package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +25 -51
  58. package/src/runtime/agent/orchestrator/session/manager/status-telemetry.mjs +3 -0
  59. package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +4 -110
  60. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-journal.mjs +39 -15
  61. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint.mjs +14 -4
  62. package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +41 -8
  63. package/src/runtime/agent/orchestrator/session/provider-prefix-guard.mjs +129 -12
  64. package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +2 -2
  65. package/src/runtime/agent/orchestrator/session/store/listing.mjs +8 -1
  66. package/src/runtime/agent/orchestrator/session/store/save-worker.mjs +15 -1
  67. package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +36 -2
  68. package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +157 -30
  69. package/src/runtime/agent/orchestrator/session/store-summary-visibility.mjs +57 -0
  70. package/src/runtime/agent/orchestrator/session/store.mjs +3 -1
  71. package/src/runtime/agent/orchestrator/session/tool-batch.mjs +22 -0
  72. package/src/runtime/agent/orchestrator/tools/builtin/read-special-files.mjs +6 -6
  73. package/src/runtime/agent/orchestrator/tools/progress-message.mjs +4 -0
  74. package/src/runtime/attachments/pdf-extract.mjs +3 -0
  75. package/src/runtime/attachments/pdfjs-runtime.mjs +13 -0
  76. package/src/runtime/browser-bridge/action-schema.mjs +251 -0
  77. package/src/runtime/browser-bridge/client.mjs +75 -26
  78. package/src/runtime/browser-bridge/tool-defs.mjs +132 -15
  79. package/src/runtime/computer-bridge/action-schema.mjs +653 -0
  80. package/src/runtime/computer-bridge/client.mjs +211 -28
  81. package/src/runtime/computer-bridge/tool-defs.mjs +25 -45
  82. package/src/runtime/office/assurance-benchmark.mjs +358 -0
  83. package/src/runtime/office/assurance.mjs +833 -0
  84. package/src/runtime/office/benchmark.mjs +496 -0
  85. package/src/runtime/office/capabilities.mjs +551 -0
  86. package/src/runtime/office/com-adapter.mjs +283 -0
  87. package/src/runtime/office/content-model.mjs +183 -0
  88. package/src/runtime/office/contract-benchmark.mjs +105 -0
  89. package/src/runtime/office/design-library.mjs +1562 -0
  90. package/src/runtime/office/design-system.mjs +1966 -0
  91. package/src/runtime/office/index.mjs +2413 -0
  92. package/src/runtime/office/journal.mjs +82 -0
  93. package/src/runtime/office/office-com-host.ps1 +3781 -0
  94. package/src/runtime/office/office-com-session-host.ps1 +855 -0
  95. package/src/runtime/office/ooxml-validator.mjs +271 -0
  96. package/src/runtime/office/pagination.mjs +132 -0
  97. package/src/runtime/office/pdf-adapter.mjs +591 -0
  98. package/src/runtime/office/pdf-analysis.mjs +372 -0
  99. package/src/runtime/office/pdf-render.mjs +167 -0
  100. package/src/runtime/office/pdf-security.mjs +63 -0
  101. package/src/runtime/office/polish-benchmark.mjs +190 -0
  102. package/src/runtime/office/portable-ooxml.mjs +1867 -0
  103. package/src/runtime/office/quality-live-benchmark.mjs +486 -0
  104. package/src/runtime/office/quality-pipeline.mjs +136 -0
  105. package/src/runtime/office/tabular.mjs +302 -0
  106. package/src/runtime/office/templates/mixdog-executive.pptx +0 -0
  107. package/src/runtime/office/templates/mixdog-executive.pptx.mixdog.json +190 -0
  108. package/src/runtime/office/tool-defs.mjs +113 -0
  109. package/src/runtime/office/visual-diff.mjs +89 -0
  110. package/src/runtime/office/xlsx-assertions.mjs +172 -0
  111. package/src/runtime/office/xlsx-contract.mjs +147 -0
  112. package/src/runtime/shared/agent-route-config.mjs +9 -0
  113. package/src/runtime/shared/tool-execution-contract.mjs +16 -0
  114. package/src/runtime/shared/tool-surface.mjs +9 -0
  115. package/src/session-runtime/context-status.mjs +9 -3
  116. package/src/session-runtime/deferred-tool-delta.mjs +104 -0
  117. package/src/session-runtime/goal-runtime.mjs +617 -197
  118. package/src/session-runtime/lifecycle-api.mjs +50 -8
  119. package/src/session-runtime/provider-request-snapshot.mjs +33 -9
  120. package/src/session-runtime/resource-api.mjs +31 -94
  121. package/src/session-runtime/runtime-core.mjs +78 -26
  122. package/src/session-runtime/session-lifecycle.mjs +34 -12
  123. package/src/session-runtime/session-title.mjs +2 -2
  124. package/src/session-runtime/session-turn-api.mjs +15 -14
  125. package/src/session-runtime/tool-catalog-data.mjs +1 -1
  126. package/src/session-runtime/tool-catalog.mjs +38 -99
  127. package/src/session-runtime/tool-defs.mjs +6 -1
  128. package/src/session-runtime/tool-surface.mjs +18 -8
  129. package/src/session-runtime/workflow-agents-api.mjs +8 -25
  130. package/src/session-runtime/workflow.mjs +8 -6
  131. package/src/standalone/agent-tool/helpers.mjs +2 -2
  132. package/src/standalone/agent-tool/job-views.mjs +3 -1
  133. package/src/standalone/agent-tool/notify.mjs +5 -1
  134. package/src/standalone/agent-tool/render.mjs +3 -0
  135. package/src/standalone/agent-tool/spawn-flow.mjs +61 -16
  136. package/src/standalone/agent-tool/tool-def.mjs +1 -1
  137. package/src/standalone/agent-tool/worker-index.mjs +123 -0
  138. package/src/standalone/agent-tool/worker-rows.mjs +2 -1
  139. package/src/standalone/agent-tool.mjs +57 -10
  140. package/src/standalone/daemon.mjs +105 -6
  141. package/src/standalone/session-runtime-host.mjs +61 -48
  142. package/src/standalone/session-runtime-inline-host.mjs +34 -127
  143. package/src/standalone/session-runtime-worker.mjs +20 -198
  144. package/src/standalone/session-service.mjs +632 -7
  145. package/src/tui/dist/index.mjs +24 -1
  146. package/src/tui/lib/voice-setup.mjs +4 -1
  147. package/src/tui/session/context-state.mjs +2 -13
  148. package/src/tui/session/goal-continuation.mjs +38 -7
  149. package/src/tui/session/session-api-ext.mjs +9 -0
  150. package/src/tui/session/session-api.mjs +15 -1
  151. package/src/tui/session/session-flow.mjs +25 -1
  152. package/src/tui/session/turn.mjs +88 -16
  153. package/src/tui/session-local.mjs +25 -3
  154. package/src/vendor/statusline/src/gateway/route-meta.mjs +31 -0
  155. package/scripts/generate-voice-runtime-manifest.test.mjs +0 -135
  156. package/scripts/native-binary-arch.test.mjs +0 -111
  157. package/scripts/patch-replay.test.mjs +0 -94
  158. package/src/headless-exec.test.mjs +0 -539
  159. package/src/runtime/agent/orchestrator/agent-trace-timing.test.mjs +0 -57
  160. package/src/runtime/agent/orchestrator/context/collect-skills.test.mjs +0 -153
  161. package/src/runtime/agent/orchestrator/mcp/cancellation.test.mjs +0 -139
  162. package/src/runtime/agent/orchestrator/mcp/features.test.mjs +0 -66
  163. package/src/runtime/agent/orchestrator/mcp/security.test.mjs +0 -80
  164. package/src/runtime/agent/orchestrator/providers/anthropic-fast-mode.test.mjs +0 -90
  165. package/src/runtime/agent/orchestrator/providers/anthropic-server-fallback.test.mjs +0 -215
  166. package/src/runtime/agent/orchestrator/providers/antigravity-oauth.test.mjs +0 -165
  167. package/src/runtime/agent/orchestrator/providers/media-parity.test.mjs +0 -142
  168. package/src/runtime/agent/orchestrator/providers/openai-codex-identity.test.mjs +0 -153
  169. package/src/runtime/agent/orchestrator/providers/openai-codex-model.test.mjs +0 -24
  170. package/src/runtime/agent/orchestrator/providers/openai-ws-delta-parity.test.mjs +0 -190
  171. package/src/runtime/agent/orchestrator/providers/provider-replay.test.mjs +0 -235
  172. package/src/runtime/agent/orchestrator/providers/sse-framing.test.mjs +0 -719
  173. package/src/runtime/agent/orchestrator/session/cache/prefetch-cache.test.mjs +0 -40
  174. package/src/runtime/agent/orchestrator/session/compact-policy.test.mjs +0 -176
  175. package/src/runtime/agent/orchestrator/session/compaction-read-reset.test.mjs +0 -161
  176. package/src/runtime/agent/orchestrator/session/eager-dispatch.test.mjs +0 -115
  177. package/src/runtime/agent/orchestrator/session/evidence-union.test.mjs +0 -228
  178. package/src/runtime/agent/orchestrator/session/image-strip-recovery.test.mjs +0 -245
  179. package/src/runtime/agent/orchestrator/session/lossless-tool-output.test.mjs +0 -125
  180. package/src/runtime/agent/orchestrator/session/manager/pending-messages-persistence.test.mjs +0 -325
  181. package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.test.mjs +0 -70
  182. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-journal.test.mjs +0 -457
  183. package/src/runtime/agent/orchestrator/session/provider-prefix-guard.test.mjs +0 -117
  184. package/src/runtime/agent/orchestrator/session/reduction-metrics.test.mjs +0 -87
  185. package/src/runtime/agent/orchestrator/session/store/serialize.test.mjs +0 -60
  186. package/src/runtime/agent/orchestrator/session/store-summary-reader.test.mjs +0 -583
  187. package/src/runtime/agent/orchestrator/session/task-wait-control.test.mjs +0 -78
  188. package/src/runtime/agent/orchestrator/tools/builtin/absence-absorption.test.mjs +0 -43
  189. package/src/runtime/agent/orchestrator/tools/builtin/absolute-glob-expand.test.mjs +0 -63
  190. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool-cwd-env.test.mjs +0 -14
  191. package/src/runtime/agent/orchestrator/tools/builtin/edit-encoding-eol.test.mjs +0 -224
  192. package/src/runtime/agent/orchestrator/tools/builtin/edit-sequential-occupation.test.mjs +0 -224
  193. package/src/runtime/agent/orchestrator/tools/builtin/enoent-outside-project.test.mjs +0 -56
  194. package/src/runtime/agent/orchestrator/tools/builtin/find-search-budget.test.mjs +0 -103
  195. package/src/runtime/agent/orchestrator/tools/builtin/git-command-policy.test.mjs +0 -30
  196. package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.test.mjs +0 -390
  197. package/src/runtime/agent/orchestrator/tools/builtin/git-repo-rw-lock.test.mjs +0 -83
  198. package/src/runtime/agent/orchestrator/tools/builtin/grep-output-budget.test.mjs +0 -31
  199. package/src/runtime/agent/orchestrator/tools/builtin/grep-single-file-rescue.test.mjs +0 -106
  200. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.test.mjs +0 -102
  201. package/src/runtime/agent/orchestrator/tools/builtin/list-tool-integrity.test.mjs +0 -152
  202. package/src/runtime/agent/orchestrator/tools/builtin/native-search-health.test.mjs +0 -24
  203. package/src/runtime/agent/orchestrator/tools/builtin/native-search-transport.test.mjs +0 -24
  204. package/src/runtime/agent/orchestrator/tools/builtin/noise-dir-visibility.test.mjs +0 -69
  205. package/src/runtime/agent/orchestrator/tools/builtin/read-glob-survey.test.mjs +0 -71
  206. package/src/runtime/agent/orchestrator/tools/builtin/runtime-capabilities.test.mjs +0 -56
  207. package/src/runtime/agent/orchestrator/tools/builtin/search-builders.test.mjs +0 -16
  208. package/src/runtime/agent/orchestrator/tools/builtin/search-glob-top-k.test.mjs +0 -39
  209. package/src/runtime/agent/orchestrator/tools/builtin/write-symlink.test.mjs +0 -153
  210. package/src/runtime/agent/orchestrator/tools/code-graph/aggregate-anchor-relocation.test.mjs +0 -55
  211. package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.test.mjs +0 -88
  212. package/src/runtime/agent/orchestrator/tools/code-graph/loose-file-target.test.mjs +0 -72
  213. package/src/runtime/agent/orchestrator/tools/code-graph/memory-cache.test.mjs +0 -54
  214. package/src/runtime/agent/orchestrator/tools/code-graph/search-references.test.mjs +0 -20
  215. package/src/runtime/agent/orchestrator/tools/code-graph/symbol-search-scope.test.mjs +0 -55
  216. package/src/runtime/agent/orchestrator/tools/code-graph/text-span-mask.test.mjs +0 -268
  217. package/src/runtime/agent/orchestrator/tools/env-scrub.test.mjs +0 -57
  218. package/src/runtime/agent/orchestrator/tools/graph-binary-fetcher.test.mjs +0 -19
  219. package/src/runtime/agent/orchestrator/tools/lib/native-spawn-client.test.mjs +0 -104
  220. package/src/runtime/agent/orchestrator/tools/patch/engine-contract-gate.test.mjs +0 -661
  221. package/src/runtime/agent/orchestrator/tools/patch/patch-codec-eol.test.mjs +0 -552
  222. package/src/runtime/agent/orchestrator/tools/patch/patch-symlink.test.mjs +0 -141
  223. package/src/runtime/agent/orchestrator/tools/patch/v4a-pure-move.test.mjs +0 -57
  224. package/src/runtime/agent/orchestrator/tools/patch/v4a-section-coalesce.test.mjs +0 -81
  225. package/src/runtime/agent/orchestrator/tools/spawn-binary-fetcher.test.mjs +0 -52
  226. package/src/runtime/attachments/store.test.mjs +0 -209
  227. package/src/runtime/channels/lib/voice-runtime-fetcher.test.mjs +0 -17
  228. package/src/runtime/channels/lib/webhook/deliveries.test.mjs +0 -18
  229. package/src/runtime/channels/lib/webhook/relay-tunnel.test.mjs +0 -68
  230. package/src/runtime/media/adapters/codex-image.test.mjs +0 -22
  231. package/src/runtime/media/download.test.mjs +0 -52
  232. package/src/runtime/media/renditions.test.mjs +0 -99
  233. package/src/runtime/media/store.test.mjs +0 -159
  234. package/src/runtime/memory/lib/archive-security.test.mjs +0 -128
  235. package/src/runtime/memory/lib/embedding-model-config.test.mjs +0 -33
  236. package/src/runtime/memory/lib/http-wire.test.mjs +0 -15
  237. package/src/runtime/memory/lib/memory-cycle-packets.test.mjs +0 -49
  238. package/src/runtime/memory/lib/memory-cycle2-shared.test.mjs +0 -78
  239. package/src/runtime/memory/lib/memory-embedding-migration.test.mjs +0 -50
  240. package/src/runtime/memory/lib/pg/process.test.mjs +0 -36
  241. package/src/runtime/memory/lib/trace-store.test.mjs +0 -57
  242. package/src/runtime/memory/lib/transcript-ingest.test.mjs +0 -52
  243. package/src/runtime/shared/background-tasks.test.mjs +0 -78
  244. package/src/runtime/shared/bounded-download.test.mjs +0 -41
  245. package/src/runtime/shared/channel-notification-routing.test.mjs +0 -25
  246. package/src/runtime/shared/child-spawn-remote.test.mjs +0 -124
  247. package/src/runtime/shared/remote-intent.test.mjs +0 -40
  248. package/src/runtime/shared/resource-admission.test.mjs +0 -43
  249. package/src/runtime/shared/runtime-root.test.mjs +0 -34
  250. package/src/runtime/shared/schedule-time.test.mjs +0 -29
  251. package/src/runtime/shared/session-runtime-health.test.mjs +0 -83
  252. package/src/runtime/shared/skill-document.test.mjs +0 -81
  253. package/src/runtime/shared/tool-surface.test.mjs +0 -87
  254. package/src/runtime/shared/update-checker.test.mjs +0 -33
  255. package/src/runtime/shared/user-cwd.test.mjs +0 -43
  256. package/src/runtime/shared/webhook-session-run.test.mjs +0 -14
  257. package/src/session-runtime/agent-disable.test.mjs +0 -123
  258. package/src/session-runtime/cwd-plugins.test.mjs +0 -75
  259. package/src/session-runtime/cwd-tool-routing.test.mjs +0 -61
  260. package/src/session-runtime/global-extensions.test.mjs +0 -28
  261. package/src/session-runtime/goal-runtime.test.mjs +0 -108
  262. package/src/session-runtime/lifecycle-api.test.mjs +0 -21
  263. package/src/session-runtime/model-settings-persist.test.mjs +0 -105
  264. package/src/session-runtime/notification-bus.test.mjs +0 -148
  265. package/src/session-runtime/plugin-mcp-standard.test.mjs +0 -177
  266. package/src/session-runtime/prewarm.test.mjs +0 -52
  267. package/src/session-runtime/provider-request-snapshot.test.mjs +0 -37
  268. package/src/session-runtime/resource-api-global.test.mjs +0 -69
  269. package/src/session-runtime/session-lifecycle.test.mjs +0 -125
  270. package/src/session-runtime/session-title.test.mjs +0 -36
  271. package/src/session-runtime/skills-api.test.mjs +0 -99
  272. package/src/session-runtime/tool-policy-surface.test.mjs +0 -331
  273. package/src/standalone/agent-tool/helpers.test.mjs +0 -62
  274. package/src/standalone/agent-tool/notify.test.mjs +0 -37
  275. package/src/standalone/agent-tool/spawn-flow.test.mjs +0 -63
  276. package/src/standalone/channel-restart.test.mjs +0 -145
  277. package/src/standalone/channel-session-router.test.mjs +0 -37
  278. package/src/standalone/channel-worker-heartbeat.test.mjs +0 -30
  279. package/src/standalone/hook-bus/handlers.test.mjs +0 -88
  280. package/src/standalone/plugin-admin.test.mjs +0 -173
  281. package/src/standalone/session-runtime-agent-control-client.test.mjs +0 -71
  282. package/src/standalone/session-runtime-dispatch-cancel.test.mjs +0 -139
  283. package/src/standalone/session-runtime-host-factory.test.mjs +0 -31
  284. package/src/standalone/session-runtime-host-health.test.mjs +0 -160
  285. package/src/standalone/session-runtime-inline-host.test.mjs +0 -83
  286. package/src/standalone/session-runtime-provider-cooldown.test.mjs +0 -80
  287. package/src/standalone/session-runtime-shard-host.test.mjs +0 -569
  288. package/src/standalone/session-runtime-shard-router.test.mjs +0 -101
  289. package/src/tui/app/live-spinner-visibility.test.mjs +0 -44
  290. package/src/tui/app/panel-epoch.test.mjs +0 -1009
  291. package/src/tui/app/panel-handoff.test.mjs +0 -311
  292. package/src/tui/app/prompt-submit.test.mjs +0 -206
  293. package/src/tui/session/completion-card-restore.test.mjs +0 -111
  294. package/src/tui/session/goal-continuation.test.mjs +0 -84
  295. package/src/tui/session/oauth-flows.test.mjs +0 -134
  296. package/src/tui/session/queue-helpers.test.mjs +0 -46
  297. package/src/tui/session/session-action-surface.test.mjs +0 -108
  298. package/src/tui/session/task-wait-submit.test.mjs +0 -80
  299. package/src/tui/session/tool-result-status.test.mjs +0 -131
  300. package/src/tui/session/tui-steering-persist.test.mjs +0 -104
@@ -239,28 +239,6 @@ export function collectWorkingFileGroups(messages, cap = Number.POSITIVE_INFINIT
239
239
  }, prior, limit, cwd);
240
240
  }
241
241
 
242
- export function collectWorkingFiles(messages, cap = Number.POSITIVE_INFINITY, options = {}) {
243
- const groups = collectWorkingFileGroups(messages, cap, options);
244
- return [...groups.modified, ...groups.referenced].map((entry) => entry.path);
245
- }
246
-
247
- export function stripWorkingFileSections(text) {
248
- const out = [];
249
- let skipping = false;
250
- for (const raw of String(text || '').split('\n')) {
251
- const line = raw.trim();
252
- if (line === '## Working files') {
253
- skipping = true;
254
- continue;
255
- }
256
- if (skipping && (/^##\s+/.test(line) || /^<\/?prior-compacted-context>$/.test(line))) {
257
- skipping = false;
258
- }
259
- if (!skipping) out.push(raw);
260
- }
261
- return out.join('\n').replace(/\n{3,}/g, '\n\n');
262
- }
263
-
264
242
  function indexToolResults(messages) {
265
243
  const map = new Map();
266
244
  for (const m of messages || []) {
@@ -43,8 +43,8 @@ export function isProtectedContextUserMessage(m) {
43
43
  // content prefix (the `<skill>` envelope from buildSkillResultEnvelope) so the
44
44
  // check survives even if the synthetic `meta` field is dropped during a tail
45
45
  // rebuild. It is NOT the human's latest prompt and must be excluded from
46
- // "latest human request" selection (deriveCurrentRequest /
47
- // buildRecallFastTrackQuery). The `meta:'skill'` marker is also honoured.
46
+ // "latest human request" selection (deriveCurrentRequest). The `meta:'skill'`
47
+ // marker is also honoured.
48
48
  export function isInjectedSkillBodyMessage(m) {
49
49
  if (m?.role !== 'user') return false;
50
50
  if (m.meta === 'skill') return true;
@@ -581,6 +581,7 @@ function truncateMessageForRecallTail(text, maxChars) {
581
581
 
582
582
  function withoutRecallReplayMetadata(message) {
583
583
  const copy = { ...(message || {}) };
584
+ delete copy.providerReplay;
584
585
  delete copy.providerMetadata;
585
586
  delete copy.thinkingBlocks;
586
587
  delete copy.reasoningItems;
@@ -716,13 +717,6 @@ function truncateTailToCap(messages, cap) {
716
717
  return estimateMessagesTokens(sanitized) <= cap ? sanitized : [];
717
718
  }
718
719
 
719
- function splitRecallFitInputs(recallText) {
720
- return {
721
- recall: String(recallText || '').trim(),
722
- prior: '',
723
- };
724
- }
725
-
726
720
  function recallTailStartIndex(live, tail) {
727
721
  if (!tail.length) return live.length;
728
722
  const first = tail[0];
@@ -746,7 +740,7 @@ function proseOnlyTurn(turn) {
746
740
  if (m.role === 'assistant' && Array.isArray(m.toolCalls) && m.toolCalls.length) {
747
741
  const text = messageText(m).trim();
748
742
  if (!text) continue;
749
- const copy = { ...m };
743
+ const copy = withoutRecallReplayMetadata(m);
750
744
  delete copy.toolCalls;
751
745
  out.push(copy);
752
746
  continue;
@@ -836,9 +830,9 @@ function _recallFastTrackCompactMessages(messages, budgetTokens, opts = {}) {
836
830
  head: recallHead,
837
831
  lastTurnStartIdx = recallHead.length,
838
832
  } = selectRecallPreservedTail(live, recallTailOpts);
839
- const recallFit = splitRecallFitInputs(opts.recallText);
833
+ const recallText = String(opts.recallText || '').trim();
840
834
  if (recallHead.length === 0
841
- && !(recallFit.recall || recallFit.prior || opts.allowEmptyRecall === true)) {
835
+ && !(recallText || opts.allowEmptyRecall === true)) {
842
836
  throw new Error('recallFastTrackCompactMessages: no compactable prior history before preserved tail');
843
837
  }
844
838
 
@@ -850,7 +844,7 @@ function _recallFastTrackCompactMessages(messages, budgetTokens, opts = {}) {
850
844
  }
851
845
  const budgetRaisedBy = Math.max(0, budget - originalBudget);
852
846
 
853
- if (!recallFit.recall && !recallFit.prior && opts.allowEmptyRecall !== true) {
847
+ if (!recallText && opts.allowEmptyRecall !== true) {
854
848
  throw new Error('recallFastTrackCompactMessages: recall text is empty');
855
849
  }
856
850
  const oldHistory = recallHead;
@@ -870,14 +864,14 @@ function _recallFastTrackCompactMessages(messages, budgetTokens, opts = {}) {
870
864
  ? Math.min(recallRoomUncapped, Math.max(512, recallTokenCap - tailTokens))
871
865
  : recallRoomUncapped;
872
866
  const toolLines = collectToolOutcomeLines(recallHead)
873
- .filter((line) => !recallFit.recall.includes(String(line || '').trim()));
867
+ .filter((line) => !recallText.includes(String(line || '').trim()));
874
868
  const workingFiles = collectWorkingFileGroups(recallHead, undefined, {
875
869
  cwd: opts.cwd,
876
870
  previousSummary: '',
877
871
  now: Date.now(),
878
872
  });
879
873
  const conversationLines = excludeTailFromConversation(
880
- conversationLinesFromMemoryText(recallFit.recall),
874
+ conversationLinesFromMemoryText(recallText),
881
875
  recallTail,
882
876
  );
883
877
  const composedRecall = composeRecallHandoff({
@@ -893,7 +887,6 @@ function _recallFastTrackCompactMessages(messages, budgetTokens, opts = {}) {
893
887
  fittedRecall,
894
888
  recallRoom,
895
889
  recallMeta,
896
- '',
897
890
  );
898
891
  if (!summaryMessage) {
899
892
  throw new Error(`recallFastTrackCompactMessages: summary cannot fit remaining budget=${recallRoom}`);
@@ -935,20 +928,15 @@ function _recallFastTrackCompactMessages(messages, budgetTokens, opts = {}) {
935
928
  remainingTokens: budget - mandatoryCost,
936
929
  recallTokenCap: (Number.isFinite(recallTokenCap) && recallTokenCap > 0) ? recallTokenCap : null,
937
930
  recallRoom,
938
- recallChars: recallFit.recall.length,
939
- recallBytes: textByteLength(recallFit.recall),
940
- priorChars: 0,
941
- priorBytes: 0,
931
+ recallChars: recallText.length,
932
+ recallBytes: textByteLength(recallText),
942
933
  summaryMessageChars: summaryContent.length,
943
934
  summaryMessageBytes: textByteLength(summaryContent),
944
- recallEmpty: !recallFit.recall,
945
- priorEmpty: !recallFit.prior,
946
- recallTruncatedInSummary: !!recallFit.recall && !summaryContent.includes(recallFit.recall),
947
- priorTruncatedInSummary: false,
935
+ recallEmpty: !recallText,
936
+ recallTruncatedInSummary: !!recallText && !summaryContent.includes(recallText),
948
937
  tailTruncated: recallTail.some((m) => messageContentHasMarker(m, RECALL_TAIL_TRUNCATION_MARKER) || messageContentHasMarker(m, RECALL_TAIL_SHORT_TRUNCATION_MARKER)),
949
938
  fileReattached: reattach.reattached,
950
939
  tailOptions: recallTailOpts,
951
- previousSummary: false,
952
940
  durationMs: Date.now() - startedAt,
953
941
  };
954
942
  compactDebugLog('recall-fasttrack result', diagnostics);
@@ -346,28 +346,6 @@ function makeSemanticSummaryMessage(oldHistory, summary, semanticMeta = {}, pres
346
346
  return makeSummaryMessage(parts.join('\n\n'));
347
347
  }
348
348
 
349
- export function buildRecallFastTrackQuery(messages, opts = {}) {
350
- const maxChars = Math.max(200, Number(opts.maxChars) || 2_000);
351
- const hints = String(opts.hints || 'current task decisions constraints file paths changed files verification failures next steps').trim();
352
- let latestUser = '';
353
- const recent = [];
354
- const input = Array.isArray(messages) ? messages : [];
355
- for (let i = input.length - 1; i >= 0; i -= 1) {
356
- const m = input[i];
357
- const text = extractText(m).trim();
358
- if (!text) continue;
359
- if (recent.length < 6) recent.unshift(text);
360
- if (!latestUser && m?.role === 'user' && !isProtectedContextUserMessage(m) && !isInjectedSkillBodyMessage(m)) {
361
- latestUser = text;
362
- }
363
- if (latestUser && recent.length >= 6) break;
364
- }
365
- const parts = [latestUser, hints, recent.join('\n')]
366
- .map((s) => String(s || '').trim())
367
- .filter(Boolean);
368
- return truncateMiddle([...new Set(parts)].join('\n'), maxChars);
369
- }
370
-
371
349
  // Fit the structured semantic summary into the remaining token budget WITHOUT
372
350
  // dropping any required section. The incoming `summary` is already schema-valid
373
351
  // (enforceSemanticSummarySchema ran upstream); here we shrink section bodies via
@@ -410,106 +388,15 @@ export function fitSemanticSummaryMessage(oldHistory, summary, remainingTokens,
410
388
  export const RECALL_TAIL_TRUNCATION_MARKER = '[... truncated during recall tail preservation ...]';
411
389
  export const RECALL_TAIL_SHORT_TRUNCATION_MARKER = '[truncated]';
412
390
 
413
- const PRIOR_COMPACTED_CONTEXT_OPEN = '<prior-compacted-context>';
414
- const PRIOR_COMPACTED_CONTEXT_CLOSE = '</prior-compacted-context>';
415
- // Matches ONLY a structural wrapper BOUNDARY line — a line whose sole content is
416
- // the open or close tag (optionally surrounded by whitespace). It deliberately
417
- // does NOT match an inline occurrence embedded in real content (e.g. a user note
418
- // like "keep <prior-compacted-context> literal here"), so flattening the wrapper
419
- // can never splice words together or corrupt marker-like text. The production
420
- // wrapper is always emitted on its own line, so boundary-line stripping removes
421
- // every real wrapper while leaving inline literals verbatim.
422
- const PRIOR_COMPACTED_CONTEXT_BOUNDARY_RE = /^[ \t]*<\/?prior-compacted-context>[ \t]*$/;
423
-
424
- // Strip the STRUCTURAL <prior-compacted-context> / </prior-compacted-context>
425
- // boundary lines from prior text so re-wrapping never nests, while preserving
426
- // any inline marker-like text inside real content exactly as written. Returns
427
- // the bare inner content with the blank lines the removed boundary lines leave
428
- // behind collapsed.
429
- export function stripPriorCompactedContextWrappers(text) {
430
- const raw = String(text ?? '');
431
- if (!raw) return '';
432
- // Keep every non-structural byte, including leading/trailing and repeated
433
- // newlines. Removing only the structural line itself (not trim/collapse)
434
- // preserves the layout of all remaining content.
435
- return raw
436
- .split('\n')
437
- .filter((line) => !PRIOR_COMPACTED_CONTEXT_BOUNDARY_RE.test(line))
438
- .join('\n');
439
- }
440
-
441
- // Remove only STRUCTURALLY IDENTICAL blank-line-separated blocks (byte-for-byte
442
- // repeats) so a prior context re-fed across many compaction cycles keeps every
443
- // distinct requirement/fact and cannot grow without bound. The dedupe is
444
- // content-preserving: the key is the block's EXACT text — internal whitespace is
445
- // never collapsed and meaningful block content is never trimmed — so distinct
446
- // strings such as `printf 'a b'` and `printf 'a b'` are BOTH kept verbatim.
447
- // Only an exact repeat of a previously emitted block is dropped; blank
448
- // separators (whitespace-only splits) are skipped, never real content.
449
- function dedupePriorCompactedBlocks(text) {
450
- const raw = String(text ?? '');
451
- if (!raw.trim()) return '';
452
- const seen = new Set();
453
- const parts = raw.split(/(\n{2,})/);
454
- const out = [];
455
- let separator = '';
456
- for (let i = 0; i < parts.length; i += 1) {
457
- const part = parts[i];
458
- if (i % 2 === 1) {
459
- separator += part;
460
- continue;
461
- }
462
- // Whitespace-only parts are layout, not a duplicate candidate.
463
- if (!part.trim()) {
464
- out.push(separator, part);
465
- separator = '';
466
- continue;
467
- }
468
- if (seen.has(part)) {
469
- // Drop only the exact repeated structural block and its preceding
470
- // separator; all retained text and whitespace stay byte-for-byte.
471
- separator = '';
472
- continue;
473
- }
474
- out.push(separator, part);
475
- separator = '';
476
- seen.add(part);
477
- }
478
- out.push(separator);
479
- return out.join('');
480
- }
481
-
482
- // Canonicalize prior compacted context to AT MOST ONE wrapper: flatten any
483
- // nested/duplicated wrappers accumulated by earlier cycles, dedupe repeated
484
- // blocks, then wrap the surviving content exactly once. Repeated compaction can
485
- // therefore never nest or duplicate the prior context, each distinct
486
- // requirement/fact is preserved exactly once, and repeated-cycle token size
487
- // stays bounded.
488
- //
489
- // Optimization-safe empty-prior interpretation: when there is NO prior content
490
- // (empty / blank / boundary-tag-only input) this returns '' so the generated
491
- // summary carries ZERO wrappers instead of an empty
492
- // <prior-compacted-context></prior-compacted-context> pair. The production
493
- // summary body joins only non-empty parts (makeRecall*SummaryMessageParts), so
494
- // an empty wrapper cannot be carried and would only waste tokens. "Exactly one
495
- // wrapper" is thus realized as: exactly one when prior content exists, none when
496
- // it does not — and never more than one, never nested.
497
- export function formatPriorCompactedContextBlock(priorText) {
498
- const flattened = dedupePriorCompactedBlocks(stripPriorCompactedContextWrappers(priorText));
499
- if (!flattened) return '';
500
- return `${PRIOR_COMPACTED_CONTEXT_OPEN}\n${flattened}\n${PRIOR_COMPACTED_CONTEXT_CLOSE}`;
501
- }
502
-
391
+ // Peel the structural summary header off a prior summary body so semantic
392
+ // compaction can feed bare text into its <previous-summary> block. Sessions
393
+ // stored before recall-fasttrack stopped chaining summaries may still carry a
394
+ // <prior-compacted-context> wrapper, so those boundary lines are dropped too.
503
395
  export function stripNestedSummaryHeaderLines(text) {
504
396
  const raw = String(text ?? '');
505
- // A generated recall summary has a canonical, provenance-bearing shape:
506
- // header + "\n\n" + OPEN + "\n" + prior + "\n" + CLOSE + "\n\n" + recall
507
- // Extracting it as lines loses ownership of a run of newlines: in
508
- // `X\n` + join + live `X`, generic block dedupe cannot know that one
509
- // newline belongs to X and must survive dropping the duplicate live X.
510
- // Peel only the emitted wrapper/header/join bytes and retain the inner
511
- // prior slice verbatim. The live recall is dropped only when it is the
512
- // same payload the wrapper already carries.
397
+ // Peel only the emitted wrapper/header/join bytes and keep the inner slice
398
+ // verbatim: splitting into lines would lose ownership of a run of newlines,
399
+ // where one newline belongs to the content and must survive.
513
400
  const openMatch = /^[ \t]*<prior-compacted-context>[ \t]*\n/m.exec(raw);
514
401
  if (openMatch) {
515
402
  const closeRe = /\n[ \t]*<\/prior-compacted-context>[ \t]*(?=\n|$)/g;
@@ -544,10 +431,9 @@ export function stripNestedSummaryHeaderLines(text) {
544
431
  followsStructuralHeader = true;
545
432
  continue;
546
433
  }
547
- // Summary parts are joined with "\n\n". The first empty line after
434
+ // Summary parts are joined with "\n\n". The first empty line after
548
435
  // stripped summary metadata is that join's structural separator, not
549
- // prior content; retaining it makes every refeed gain a newline when
550
- // formatPriorCompactedContextBlock wraps the result again.
436
+ // content.
551
437
  if (followsStructuralHeader && line === '') {
552
438
  followsStructuralHeader = false;
553
439
  continue;
@@ -570,46 +456,19 @@ export function stripNestedSummaryHeaderLines(text) {
570
456
  return out.join('\n');
571
457
  }
572
458
 
573
- function makeRecallFastTrackSummaryMessageParts(oldHistory, recallPart, priorPart, recallMeta = {}) {
459
+ function makeRecallFastTrackSummaryMessageParts(oldHistory, recallPart, recallMeta = {}) {
574
460
  const header = compactHeader(oldHistory);
575
461
  header.push(`compact_type=${COMPACT_TYPE_RECALL_FASTTRACK} source=recall-fasttrack query_sha=${recallMeta.querySha || 'none'}`);
576
462
  const parts = [header.join('\n')];
577
- const priorBlock = formatPriorCompactedContextBlock(priorPart);
578
- if (priorBlock) parts.push(priorBlock);
579
463
  const recall = String(recallPart || '').trim();
580
464
  if (recall) parts.push(recall);
581
465
  return makeSummaryMessage(parts.join('\n\n'));
582
466
  }
583
467
 
584
- export function fitRecallFastTrackSummaryMessage(oldHistory, recallText, remainingTokens, recallMeta = {}, priorPart = '') {
468
+ export function fitRecallFastTrackSummaryMessage(oldHistory, recallText, remainingTokens, recallMeta = {}) {
585
469
  const recall = String(recallText || '').trim();
586
- const prior = String(priorPart || '');
587
-
588
- let fittedPrior = prior;
589
- if (prior) {
590
- let lo = 0;
591
- let hi = prior.length;
592
- let bestPriorLen = 0;
593
- while (lo <= hi) {
594
- const mid = Math.floor((lo + hi) / 2);
595
- const candidate = makeRecallFastTrackSummaryMessageParts(oldHistory, '', prior.slice(0, mid), recallMeta);
596
- if (estimateMessagesTokens([candidate]) <= remainingTokens) {
597
- bestPriorLen = mid;
598
- lo = mid + 1;
599
- } else {
600
- hi = mid - 1;
601
- }
602
- }
603
- fittedPrior = prior.slice(0, bestPriorLen);
604
- if (!fittedPrior && prior) {
605
- const markerOnly = makeRecallFastTrackSummaryMessageParts(oldHistory, '', RECALL_TAIL_TRUNCATION_MARKER, recallMeta);
606
- if (estimateMessagesTokens([markerOnly]) <= remainingTokens) {
607
- fittedPrior = RECALL_TAIL_TRUNCATION_MARKER;
608
- }
609
- }
610
- }
611
470
 
612
- const minimal = makeRecallFastTrackSummaryMessageParts(oldHistory, '', fittedPrior, recallMeta);
471
+ const minimal = makeRecallFastTrackSummaryMessageParts(oldHistory, '', recallMeta);
613
472
  if (estimateMessagesTokens([minimal]) > remainingTokens) return null;
614
473
  if (!recall) return minimal;
615
474
 
@@ -618,14 +477,14 @@ export function fitRecallFastTrackSummaryMessage(oldHistory, recallText, remaini
618
477
  // Root-block granularity fit: drop the OLDEST blocks WHOLE (never cut
619
478
  // a `# chunk` / `# raw_pending` / `# raw_terminal` block mid-entry);
620
479
  // dropping more leading blocks only shrinks the body, so binary-search
621
- // the minimal drop count (mirrors fitRecallRootsMessage).
480
+ // the minimal drop count.
622
481
  let loB = 0;
623
482
  let hiB = blocks.length;
624
483
  let bestLo = -1;
625
484
  while (loB <= hiB) {
626
485
  const midB = Math.floor((loB + hiB) / 2);
627
486
  const body = [preamble, ...blocks.slice(midB)].filter(Boolean).join('\n\n');
628
- const candidate = makeRecallFastTrackSummaryMessageParts(oldHistory, body, fittedPrior, recallMeta);
487
+ const candidate = makeRecallFastTrackSummaryMessageParts(oldHistory, body, recallMeta);
629
488
  if (estimateMessagesTokens([candidate]) <= remainingTokens) {
630
489
  bestLo = midB;
631
490
  hiB = midB - 1;
@@ -635,12 +494,11 @@ export function fitRecallFastTrackSummaryMessage(oldHistory, recallText, remaini
635
494
  }
636
495
  if (bestLo >= 0) {
637
496
  const body = [preamble, ...blocks.slice(bestLo)].filter(Boolean).join('\n\n');
638
- return makeRecallFastTrackSummaryMessageParts(oldHistory, body, fittedPrior, recallMeta);
497
+ return makeRecallFastTrackSummaryMessageParts(oldHistory, body, recallMeta);
639
498
  }
640
- // Even zero blocks (preamble alone) overflows alongside the fitted
641
- // prior - try preamble alone, else the no-recall minimal message.
499
+ // Even the preamble alone overflows: try it, else the minimal message.
642
500
  if (preamble) {
643
- const preambleOnly = makeRecallFastTrackSummaryMessageParts(oldHistory, preamble, fittedPrior, recallMeta);
501
+ const preambleOnly = makeRecallFastTrackSummaryMessageParts(oldHistory, preamble, recallMeta);
644
502
  if (estimateMessagesTokens([preambleOnly]) <= remainingTokens) return preambleOnly;
645
503
  }
646
504
  return minimal;
@@ -654,7 +512,7 @@ export function fitRecallFastTrackSummaryMessage(oldHistory, recallText, remaini
654
512
  let best = minimal;
655
513
  while (lo <= hi) {
656
514
  const mid = Math.floor((lo + hi) / 2);
657
- const candidate = makeRecallFastTrackSummaryMessageParts(oldHistory, recall.slice(0, mid), fittedPrior, recallMeta);
515
+ const candidate = makeRecallFastTrackSummaryMessageParts(oldHistory, recall.slice(0, mid), recallMeta);
658
516
  if (estimateMessagesTokens([candidate]) <= remainingTokens) {
659
517
  best = candidate;
660
518
  lo = mid + 1;
@@ -665,28 +523,23 @@ export function fitRecallFastTrackSummaryMessage(oldHistory, recallText, remaini
665
523
  return best;
666
524
  }
667
525
 
668
- // --- Smart-compact root-based fitting (arrival-time replacement) -----------
526
+ // --- Root-block splitting for the recall digest ----------------------------
669
527
  //
670
- // dump_session_roots (memory/index.mjs dumpSessionRootChunks) renders chunks
671
- // TIME-ORDERED (oldest first; chunks.sort by sourceTurn/ts/id ascending),
672
- // each root/raw block starting with one of:
528
+ // A memory digest renders chunks TIME-ORDERED (oldest first), each root/raw
529
+ // block starting with one of:
673
530
  // # chunk N root=ID[ category=X]
674
531
  // # raw_pending N id=ID
675
532
  // # raw_terminal N id=ID
676
- // and blocks joined by "\n\n". runRecallFastTrackForSession additionally
677
- // prepends a "session_id=..." / cycle1-drain-status preamble before the dump
678
- // text (also "\n\n"-joined) — preserved verbatim as a non-block segment.
533
+ // and blocks joined by "\n\n", after an optional preamble that is kept verbatim
534
+ // as a non-block segment.
679
535
  //
680
- // Unlike fitRecallFastTrackSummaryMessage (character-slice binary search,
681
- // used by the LLM-summary-free but still-mid-turn recall-fasttrack compact
682
- // path), the smart-compact arrival path must never cut a root block
683
- // mid-entry — losing half a root's content silently corrupts that entry.
684
- // This splitter finds block boundaries by the label pattern (robust to
685
- // blank lines inside member/raw content, since it anchors on the distinctive
686
- // "# chunk /raw_pending/raw_terminal" line rather than a blank-line split).
536
+ // fitRecallFastTrackSummaryMessage drops whole blocks instead of cutting one
537
+ // mid-entry, since losing half a root's content silently corrupts that entry.
538
+ // Boundaries come from the label pattern, which stays robust to blank lines
539
+ // inside member/raw content.
687
540
  const RECALL_ROOT_BLOCK_HEADER_RE = /^# (?:chunk \d+ root=\d+(?: category=\S+)?|raw_pending \d+ id=\d+|raw_terminal \d+ id=\d+)[ \t]*$/;
688
541
 
689
- export function splitRecallRootBlocks(text) {
542
+ function splitRecallRootBlocks(text) {
690
543
  const value = String(text || '');
691
544
  if (!value.trim()) return { preamble: '', blocks: [] };
692
545
  const re = new RegExp(RECALL_ROOT_BLOCK_HEADER_RE.source, 'gm');
@@ -708,97 +561,3 @@ export function splitRecallRootBlocks(text) {
708
561
  return { preamble, blocks };
709
562
  }
710
563
 
711
- // Minimal-header summary-message wrapper for the smart-compact roots path.
712
- // Keeps the SUMMARY_PREFIX anchor (isSummaryMessage / selectCompactionWindow
713
- // / clear-preserve / TUI all key off startsWith(SUMMARY_PREFIX)) but skips the
714
- // full sha256/roleCounts header line that fitRecallFastTrackSummaryMessage
715
- // computes — smart-arrival replacement is a lightweight prefix swap, not the
716
- // anchored LLM-summary compact, so a heavy per-call header is unneeded cost.
717
- function makeRecallRootsSummaryMessageParts(oldHistory, rootsPart, priorPart, recallMeta = {}) {
718
- const header = `${SUMMARY_PREFIX}\nmessages=${(oldHistory || []).length} compact_type=${COMPACT_TYPE_RECALL_FASTTRACK} source=smart-arrival query_sha=${recallMeta.querySha || 'none'}`;
719
- const parts = [header];
720
- const priorBlock = formatPriorCompactedContextBlock(priorPart);
721
- if (priorBlock) parts.push(priorBlock);
722
- const roots = String(rootsPart || '').trim();
723
- if (roots) parts.push(roots);
724
- return makeSummaryMessage(parts.join('\n\n'));
725
- }
726
-
727
- // Root-block-aware fit for the smart-compact arrival path (Step1). Mirrors
728
- // fitRecallFastTrackSummaryMessage's prior-block binary-search fit, but the
729
- // recall body is fit at ROOT-BLOCK granularity: when the full set of root
730
- // blocks (kept in original time order) exceeds remainingTokens, the OLDEST
731
- // blocks are dropped WHOLE (never character-truncated mid-block) until the
732
- // remaining (newest-biased) suffix fits. Because dropping more leading
733
- // blocks can only shrink (never grow) the serialized size, the minimal-drop
734
- // threshold is found via binary search on the drop count.
735
- export function fitRecallRootsMessage(oldHistory, recallText, remainingTokens, recallMeta = {}, priorPart = '') {
736
- const prior = String(priorPart || '');
737
-
738
- let fittedPrior = prior;
739
- if (prior) {
740
- let lo = 0;
741
- let hi = prior.length;
742
- let bestPriorLen = 0;
743
- while (lo <= hi) {
744
- const mid = Math.floor((lo + hi) / 2);
745
- const candidate = makeRecallRootsSummaryMessageParts(oldHistory, '', prior.slice(0, mid), recallMeta);
746
- if (estimateMessagesTokens([candidate]) <= remainingTokens) {
747
- bestPriorLen = mid;
748
- lo = mid + 1;
749
- } else {
750
- hi = mid - 1;
751
- }
752
- }
753
- fittedPrior = prior.slice(0, bestPriorLen);
754
- if (!fittedPrior && prior) {
755
- const markerOnly = makeRecallRootsSummaryMessageParts(oldHistory, '', RECALL_TAIL_TRUNCATION_MARKER, recallMeta);
756
- if (estimateMessagesTokens([markerOnly]) <= remainingTokens) {
757
- fittedPrior = RECALL_TAIL_TRUNCATION_MARKER;
758
- }
759
- }
760
- }
761
-
762
- const minimal = makeRecallRootsSummaryMessageParts(oldHistory, '', fittedPrior, recallMeta);
763
- if (estimateMessagesTokens([minimal]) > remainingTokens) return null;
764
-
765
- const { preamble, blocks } = splitRecallRootBlocks(recallText);
766
- if (blocks.length === 0) {
767
- // No parseable root-block boundaries (empty / non-dump recallText) —
768
- // degrade to keep-whole-if-it-fits, else drop entirely. Never
769
- // mid-truncates: a non-block body is treated as a single atomic unit.
770
- const whole = String(recallText || '').trim();
771
- if (!whole) return minimal;
772
- const full = makeRecallRootsSummaryMessageParts(oldHistory, whole, fittedPrior, recallMeta);
773
- if (estimateMessagesTokens([full]) <= remainingTokens) return full;
774
- return minimal;
775
- }
776
-
777
- let loB = 0;
778
- let hiB = blocks.length;
779
- let bestLo = -1;
780
- while (loB <= hiB) {
781
- const mid = Math.floor((loB + hiB) / 2);
782
- const kept = blocks.slice(mid);
783
- const body = [preamble, ...kept].filter(Boolean).join('\n\n');
784
- const candidate = makeRecallRootsSummaryMessageParts(oldHistory, body, fittedPrior, recallMeta);
785
- if (estimateMessagesTokens([candidate]) <= remainingTokens) {
786
- bestLo = mid;
787
- hiB = mid - 1;
788
- } else {
789
- loB = mid + 1;
790
- }
791
- }
792
- if (bestLo >= 0) {
793
- const kept = blocks.slice(bestLo);
794
- const body = [preamble, ...kept].filter(Boolean).join('\n\n');
795
- return makeRecallRootsSummaryMessageParts(oldHistory, body, fittedPrior, recallMeta);
796
- }
797
- // Even zero root blocks (preamble alone) overflows alongside the fitted
798
- // prior — try preamble alone, else the no-recall minimal header.
799
- if (preamble) {
800
- const preambleOnly = makeRecallRootsSummaryMessageParts(oldHistory, preamble, fittedPrior, recallMeta);
801
- if (estimateMessagesTokens([preambleOnly]) <= remainingTokens) return preambleOnly;
802
- }
803
- return minimal;
804
- }
@@ -44,12 +44,6 @@ export {
44
44
  pruneToolOutputsUnanchored,
45
45
  } from './compact/budget.mjs';
46
46
 
47
- export {
48
- buildRecallFastTrackQuery,
49
- splitRecallRootBlocks,
50
- fitRecallRootsMessage,
51
- } from './compact/summary.mjs';
52
-
53
47
  export {
54
48
  semanticCompactMessages,
55
49
  recallFastTrackCompactMessages,