@cortexkit/opencode-magic-context 0.43.2 → 0.44.1

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 (297) hide show
  1. package/README.md +18 -2
  2. package/dist/agents/magic-context-prompt.d.ts +2 -0
  3. package/dist/agents/magic-context-prompt.d.ts.map +1 -1
  4. package/dist/{announcement-1a8bvswd.js → announcement-n8hs7kjw.js} +2 -2
  5. package/dist/config/index.d.ts +13 -0
  6. package/dist/config/index.d.ts.map +1 -1
  7. package/dist/config/live-child-output-cap.d.ts +18 -0
  8. package/dist/config/live-child-output-cap.d.ts.map +1 -0
  9. package/dist/config/project-security.d.ts +6 -3
  10. package/dist/config/project-security.d.ts.map +1 -1
  11. package/dist/config/schema/magic-context.d.ts +28 -1
  12. package/dist/config/schema/magic-context.d.ts.map +1 -1
  13. package/dist/{conflict-warning-hook-hyk9y29x.js → conflict-warning-hook-d14ah73v.js} +6 -6
  14. package/dist/{derive-budgets-b8ybssh9.js → derive-budgets-gd2270s0.js} +3 -3
  15. package/dist/features/magic-context/compaction-marker.d.ts.map +1 -1
  16. package/dist/features/magic-context/compartment-embedding.d.ts +3 -2
  17. package/dist/features/magic-context/compartment-embedding.d.ts.map +1 -1
  18. package/dist/features/magic-context/compartment-storage.d.ts.map +1 -1
  19. package/dist/features/magic-context/dreamer/classify.d.ts.map +1 -1
  20. package/dist/features/magic-context/dreamer/curate-category-rotation.d.ts.map +1 -1
  21. package/dist/features/magic-context/dreamer/curate-memory-safety.d.ts.map +1 -1
  22. package/dist/features/magic-context/dreamer/failed-invocation-evidence.d.ts +13 -0
  23. package/dist/features/magic-context/dreamer/failed-invocation-evidence.d.ts.map +1 -0
  24. package/dist/features/magic-context/dreamer/hidden-single-shot.d.ts.map +1 -1
  25. package/dist/features/magic-context/dreamer/lease.d.ts +5 -2
  26. package/dist/features/magic-context/dreamer/lease.d.ts.map +1 -1
  27. package/dist/features/magic-context/dreamer/map-memories.d.ts.map +1 -1
  28. package/dist/features/magic-context/dreamer/memory-claim-safety.d.ts.map +1 -1
  29. package/dist/features/magic-context/dreamer/module-apply.d.ts +1 -0
  30. package/dist/features/magic-context/dreamer/module-apply.d.ts.map +1 -1
  31. package/dist/features/magic-context/dreamer/open-opencode-db.d.ts +2 -0
  32. package/dist/features/magic-context/dreamer/open-opencode-db.d.ts.map +1 -1
  33. package/dist/features/magic-context/dreamer/primer-seed.d.ts +11 -5
  34. package/dist/features/magic-context/dreamer/primer-seed.d.ts.map +1 -1
  35. package/dist/features/magic-context/dreamer/refresh-primers.d.ts +2 -2
  36. package/dist/features/magic-context/dreamer/refresh-primers.d.ts.map +1 -1
  37. package/dist/features/magic-context/dreamer/retrospective-learnings.d.ts.map +1 -1
  38. package/dist/features/magic-context/dreamer/storage-dream-runs.d.ts +1 -1
  39. package/dist/features/magic-context/dreamer/storage-dream-runs.d.ts.map +1 -1
  40. package/dist/features/magic-context/dreamer/task-executor.d.ts.map +1 -1
  41. package/dist/features/magic-context/dreamer/task-scheduler.d.ts +2 -0
  42. package/dist/features/magic-context/dreamer/task-scheduler.d.ts.map +1 -1
  43. package/dist/features/magic-context/dreamer/verify.d.ts +19 -0
  44. package/dist/features/magic-context/dreamer/verify.d.ts.map +1 -1
  45. package/dist/features/magic-context/fail-closed-block.d.ts +7 -0
  46. package/dist/features/magic-context/fail-closed-block.d.ts.map +1 -1
  47. package/dist/features/magic-context/index.d.ts +1 -0
  48. package/dist/features/magic-context/index.d.ts.map +1 -1
  49. package/dist/features/magic-context/install-instance-id.d.ts +33 -0
  50. package/dist/features/magic-context/install-instance-id.d.ts.map +1 -0
  51. package/dist/features/magic-context/memory/constants.d.ts.map +1 -1
  52. package/dist/features/magic-context/memory/embedding-backfill.d.ts.map +1 -1
  53. package/dist/features/magic-context/memory/project-identity.d.ts +7 -0
  54. package/dist/features/magic-context/memory/project-identity.d.ts.map +1 -1
  55. package/dist/features/magic-context/memory/single-store-embedding-drain.d.ts +35 -0
  56. package/dist/features/magic-context/memory/single-store-embedding-drain.d.ts.map +1 -0
  57. package/dist/features/magic-context/memory/verification-paths.d.ts.map +1 -1
  58. package/dist/features/magic-context/message-index.d.ts +23 -0
  59. package/dist/features/magic-context/message-index.d.ts.map +1 -1
  60. package/dist/features/magic-context/migrations.d.ts +7 -0
  61. package/dist/features/magic-context/migrations.d.ts.map +1 -1
  62. package/dist/features/magic-context/mural/mural-font.generated.d.ts.map +1 -1
  63. package/dist/features/magic-context/overflow-detection.d.ts +31 -8
  64. package/dist/features/magic-context/overflow-detection.d.ts.map +1 -1
  65. package/dist/features/magic-context/project-embedding-registry.d.ts +40 -1
  66. package/dist/features/magic-context/project-embedding-registry.d.ts.map +1 -1
  67. package/dist/features/magic-context/search.d.ts.map +1 -1
  68. package/dist/features/magic-context/session-cache-ttl.d.ts +10 -0
  69. package/dist/features/magic-context/session-cache-ttl.d.ts.map +1 -0
  70. package/dist/features/magic-context/session-decision-calibration.d.ts.map +1 -1
  71. package/dist/features/magic-context/storage-db.d.ts +1 -1
  72. package/dist/features/magic-context/storage-db.d.ts.map +1 -1
  73. package/dist/features/magic-context/storage-meta-persisted.d.ts +20 -5
  74. package/dist/features/magic-context/storage-meta-persisted.d.ts.map +1 -1
  75. package/dist/features/magic-context/storage-meta.d.ts +1 -1
  76. package/dist/features/magic-context/storage-meta.d.ts.map +1 -1
  77. package/dist/features/magic-context/storage-notes.d.ts +1 -0
  78. package/dist/features/magic-context/storage-notes.d.ts.map +1 -1
  79. package/dist/features/magic-context/storage-primers.d.ts.map +1 -1
  80. package/dist/features/magic-context/storage-tags.d.ts.map +1 -1
  81. package/dist/features/magic-context/storage-unavailable-reason.d.ts +17 -0
  82. package/dist/features/magic-context/storage-unavailable-reason.d.ts.map +1 -0
  83. package/dist/features/magic-context/storage.d.ts +1 -1
  84. package/dist/features/magic-context/storage.d.ts.map +1 -1
  85. package/dist/features/magic-context/store-generation-rebase.d.ts +33 -1
  86. package/dist/features/magic-context/store-generation-rebase.d.ts.map +1 -1
  87. package/dist/features/magic-context/subagent-token-capture.d.ts.map +1 -1
  88. package/dist/features/magic-context/transform-decision-log.d.ts +1 -1
  89. package/dist/features/magic-context/transform-decision-log.d.ts.map +1 -1
  90. package/dist/features/magic-context/types.d.ts +8 -3
  91. package/dist/features/magic-context/types.d.ts.map +1 -1
  92. package/dist/features/magic-context/user-memory/storage-user-memory.d.ts.map +1 -1
  93. package/dist/hooks/magic-context/apply-operations.d.ts +105 -9
  94. package/dist/hooks/magic-context/apply-operations.d.ts.map +1 -1
  95. package/dist/hooks/magic-context/auto-search-runner.d.ts.map +1 -1
  96. package/dist/hooks/magic-context/compartment-parser.d.ts +2 -0
  97. package/dist/hooks/magic-context/compartment-parser.d.ts.map +1 -1
  98. package/dist/hooks/magic-context/compartment-runner-historian.d.ts +1 -0
  99. package/dist/hooks/magic-context/compartment-runner-historian.d.ts.map +1 -1
  100. package/dist/hooks/magic-context/compartment-runner-incremental.d.ts.map +1 -1
  101. package/dist/hooks/magic-context/compartment-runner-partial-recomp.d.ts.map +1 -1
  102. package/dist/hooks/magic-context/compartment-runner-recomp.d.ts.map +1 -1
  103. package/dist/hooks/magic-context/compartment-runner-types.d.ts +2 -0
  104. package/dist/hooks/magic-context/compartment-runner-types.d.ts.map +1 -1
  105. package/dist/hooks/magic-context/compartment-runner-validation.d.ts.map +1 -1
  106. package/dist/hooks/magic-context/context-limit-resolution.d.ts +31 -0
  107. package/dist/hooks/magic-context/context-limit-resolution.d.ts.map +1 -0
  108. package/dist/hooks/magic-context/embed-history-runner.d.ts +0 -1
  109. package/dist/hooks/magic-context/embed-history-runner.d.ts.map +1 -1
  110. package/dist/hooks/magic-context/event-handler.d.ts.map +1 -1
  111. package/dist/hooks/magic-context/event-resolvers.d.ts.map +1 -1
  112. package/dist/hooks/magic-context/execute-status.d.ts.map +1 -1
  113. package/dist/hooks/magic-context/final-wire-token-estimate.d.ts.map +1 -1
  114. package/dist/hooks/magic-context/format-embed-status.d.ts.map +1 -1
  115. package/dist/hooks/magic-context/heuristic-cleanup.d.ts.map +1 -1
  116. package/dist/hooks/magic-context/historian-host-runner.d.ts +233 -0
  117. package/dist/hooks/magic-context/historian-host-runner.d.ts.map +1 -0
  118. package/dist/hooks/magic-context/hook.d.ts +1 -3
  119. package/dist/hooks/magic-context/hook.d.ts.map +1 -1
  120. package/dist/hooks/magic-context/image-token-estimate.d.ts +9 -0
  121. package/dist/hooks/magic-context/image-token-estimate.d.ts.map +1 -1
  122. package/dist/hooks/magic-context/inject-compartments.d.ts +60 -1
  123. package/dist/hooks/magic-context/inject-compartments.d.ts.map +1 -1
  124. package/dist/hooks/magic-context/lkg-slot.d.ts +6 -0
  125. package/dist/hooks/magic-context/lkg-slot.d.ts.map +1 -1
  126. package/dist/hooks/magic-context/module-client.d.ts +21 -0
  127. package/dist/hooks/magic-context/module-client.d.ts.map +1 -0
  128. package/dist/hooks/magic-context/module-state-sync.d.ts +6 -2
  129. package/dist/hooks/magic-context/module-state-sync.d.ts.map +1 -1
  130. package/dist/hooks/magic-context/module-tool-backends.d.ts +47 -0
  131. package/dist/hooks/magic-context/module-tool-backends.d.ts.map +1 -0
  132. package/dist/hooks/magic-context/module-transport.d.ts +1 -1
  133. package/dist/hooks/magic-context/module-transport.d.ts.map +1 -1
  134. package/dist/hooks/magic-context/opencode-v1-store-fixture.d.ts +12 -0
  135. package/dist/hooks/magic-context/opencode-v1-store-fixture.d.ts.map +1 -0
  136. package/dist/hooks/magic-context/persist-filtered-noise.d.ts.map +1 -1
  137. package/dist/hooks/magic-context/read-session-chunk.d.ts +28 -0
  138. package/dist/hooks/magic-context/read-session-chunk.d.ts.map +1 -1
  139. package/dist/hooks/magic-context/read-session-db.d.ts +5 -1
  140. package/dist/hooks/magic-context/read-session-db.d.ts.map +1 -1
  141. package/dist/hooks/magic-context/read-session-raw.d.ts +10 -0
  142. package/dist/hooks/magic-context/read-session-raw.d.ts.map +1 -1
  143. package/dist/hooks/magic-context/rust-mode-transform.d.ts +35 -0
  144. package/dist/hooks/magic-context/rust-mode-transform.d.ts.map +1 -1
  145. package/dist/hooks/magic-context/rust-refusal-recovery.d.ts +18 -0
  146. package/dist/hooks/magic-context/rust-refusal-recovery.d.ts.map +1 -1
  147. package/dist/hooks/magic-context/rust-served-m0.d.ts +20 -0
  148. package/dist/hooks/magic-context/rust-served-m0.d.ts.map +1 -0
  149. package/dist/hooks/magic-context/store-ahead-refusal.d.ts +40 -0
  150. package/dist/hooks/magic-context/store-ahead-refusal.d.ts.map +1 -0
  151. package/dist/hooks/magic-context/strip-content.d.ts +5 -5
  152. package/dist/hooks/magic-context/strip-content.d.ts.map +1 -1
  153. package/dist/hooks/magic-context/system-prompt-hash.d.ts.map +1 -1
  154. package/dist/hooks/magic-context/tag-messages.d.ts +19 -0
  155. package/dist/hooks/magic-context/tag-messages.d.ts.map +1 -1
  156. package/dist/hooks/magic-context/tail-hygiene-walk.d.ts.map +1 -1
  157. package/dist/hooks/magic-context/tool-drop-target.d.ts +14 -0
  158. package/dist/hooks/magic-context/tool-drop-target.d.ts.map +1 -1
  159. package/dist/hooks/magic-context/tool-input-size.d.ts +21 -0
  160. package/dist/hooks/magic-context/tool-input-size.d.ts.map +1 -0
  161. package/dist/hooks/magic-context/tool-sweep-policy.d.ts.map +1 -1
  162. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts +124 -11
  163. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts.map +1 -1
  164. package/dist/hooks/magic-context/transform.d.ts +14 -0
  165. package/dist/hooks/magic-context/transform.d.ts.map +1 -1
  166. package/dist/{index-pa67brzn.js → index-0rp6pj54.js} +3 -3
  167. package/dist/{index-4b30nf6z.js → index-32b096cc.js} +1 -1
  168. package/dist/{index-wgzyeyf5.js → index-3bygzk2d.js} +23 -7
  169. package/dist/{index-jgnag7sa.js → index-a9vbtdzv.js} +4 -4
  170. package/dist/{index-bmzt6xgy.js → index-cz88kw0n.js} +13 -3
  171. package/dist/{index-6j8th2hd.js → index-d107az47.js} +2 -2
  172. package/dist/{index-g6hpfkqa.js → index-jtdrvmcn.js} +3290 -286
  173. package/dist/{index-9r1cbh9e.js → index-kr5qehbd.js} +1 -1
  174. package/dist/{index-febg06dy.js → index-kwe03yde.js} +1 -1
  175. package/dist/{index-tdrv6nd0.js → index-s6b7h12g.js} +352 -71
  176. package/dist/{index-6z9g64js.js → index-s70wtd8k.js} +4 -1
  177. package/dist/{index-0ccmyzbj.js → index-stb5fg12.js} +2 -2
  178. package/dist/index.d.ts.map +1 -1
  179. package/dist/index.js +5230 -5663
  180. package/dist/{message-time-backfill-0ccvyk9n.js → message-time-backfill-q374fxc5.js} +4 -4
  181. package/dist/plugin/dream-timer.d.ts +2 -0
  182. package/dist/plugin/dream-timer.d.ts.map +1 -1
  183. package/dist/plugin/hooks/create-session-hooks.d.ts.map +1 -1
  184. package/dist/plugin/messages-transform.d.ts.map +1 -1
  185. package/dist/plugin/native-compaction-guard.d.ts +22 -0
  186. package/dist/plugin/native-compaction-guard.d.ts.map +1 -0
  187. package/dist/plugin/rpc-handlers.d.ts +11 -0
  188. package/dist/plugin/rpc-handlers.d.ts.map +1 -1
  189. package/dist/{read-session-chunk-53a7qbrh.js → read-session-chunk-fkdv2g5b.js} +8 -4
  190. package/dist/{recomp-orchestrator-adsgqgse.js → recomp-orchestrator-k4h5n0p3.js} +9 -9
  191. package/dist/{safe-notification-target-vrkjrbgb.js → safe-notification-target-50gm9c58.js} +3 -3
  192. package/dist/{send-session-notification-e28r4xx2.js → send-session-notification-g2k03zyn.js} +5 -5
  193. package/dist/shared/cache-ttl-display.d.ts +3 -1
  194. package/dist/shared/cache-ttl-display.d.ts.map +1 -1
  195. package/dist/shared/harness.d.ts +11 -0
  196. package/dist/shared/harness.d.ts.map +1 -1
  197. package/dist/shared/index.d.ts +1 -0
  198. package/dist/shared/index.d.ts.map +1 -1
  199. package/dist/shared/logger.d.ts.map +1 -1
  200. package/dist/shared/model-cache-ttl.d.ts +9 -0
  201. package/dist/shared/model-cache-ttl.d.ts.map +1 -0
  202. package/dist/shared/model-suggestion-retry.d.ts +13 -1
  203. package/dist/shared/model-suggestion-retry.d.ts.map +1 -1
  204. package/dist/shared/prompt-async-transport.d.ts +25 -0
  205. package/dist/shared/prompt-async-transport.d.ts.map +1 -0
  206. package/dist/shared/rpc-server.d.ts +1 -0
  207. package/dist/shared/rpc-server.d.ts.map +1 -1
  208. package/dist/shared/rpc-types.d.ts +17 -1
  209. package/dist/shared/rpc-types.d.ts.map +1 -1
  210. package/dist/shared/rpc-utils.d.ts +3 -0
  211. package/dist/shared/rpc-utils.d.ts.map +1 -1
  212. package/dist/shared/sqlite-write-locker-test-support.d.ts +7 -0
  213. package/dist/shared/sqlite-write-locker-test-support.d.ts.map +1 -0
  214. package/dist/shared/status-summary.d.ts +9 -1
  215. package/dist/shared/status-summary.d.ts.map +1 -1
  216. package/dist/shared/status-view.d.ts +1 -1
  217. package/dist/shared/status-view.d.ts.map +1 -1
  218. package/dist/shared/tag-transcript.d.ts.map +1 -1
  219. package/dist/shared/user-facing-codes.d.ts +10 -5
  220. package/dist/shared/user-facing-codes.d.ts.map +1 -1
  221. package/dist/shared/window-geometry.d.ts +6 -3
  222. package/dist/shared/window-geometry.d.ts.map +1 -1
  223. package/dist/tools/ctx-expand/render.d.ts.map +1 -1
  224. package/dist/tools/ctx-memory/tools.d.ts.map +1 -1
  225. package/dist/tools/ctx-note/tools.d.ts.map +1 -1
  226. package/dist/tools/ctx-reduce/tools.d.ts.map +1 -1
  227. package/dist/tools/ctx-search/tools.d.ts.map +1 -1
  228. package/dist/v2/fold/boundary.d.ts +61 -0
  229. package/dist/v2/fold/boundary.d.ts.map +1 -0
  230. package/dist/v2/fold/restore.d.ts.map +1 -1
  231. package/dist/v2/hidden-completion.d.ts +16 -3
  232. package/dist/v2/hidden-completion.d.ts.map +1 -1
  233. package/dist/v2/hooks/context.d.ts +45 -14
  234. package/dist/v2/hooks/context.d.ts.map +1 -1
  235. package/dist/v2/hooks/hidden-child.d.ts +6 -0
  236. package/dist/v2/hooks/hidden-child.d.ts.map +1 -1
  237. package/dist/v2/hooks/payload.d.ts.map +1 -1
  238. package/dist/v2/hooks/rpc-live-state.d.ts +1 -1
  239. package/dist/v2/hooks/rpc-live-state.d.ts.map +1 -1
  240. package/dist/v2/hooks/rust-mode.d.ts +47 -0
  241. package/dist/v2/hooks/rust-mode.d.ts.map +1 -0
  242. package/dist/v2/hooks/session-project-backfill.d.ts +15 -0
  243. package/dist/v2/hooks/session-project-backfill.d.ts.map +1 -0
  244. package/dist/v2/hooks/storage-gate.d.ts +42 -0
  245. package/dist/v2/hooks/storage-gate.d.ts.map +1 -0
  246. package/dist/v2/hooks/storage-notice.d.ts +29 -0
  247. package/dist/v2/hooks/storage-notice.d.ts.map +1 -0
  248. package/dist/v2/hooks/store.d.ts +16 -0
  249. package/dist/v2/hooks/store.d.ts.map +1 -1
  250. package/dist/v2/hooks/tools.d.ts +11 -2
  251. package/dist/v2/hooks/tools.d.ts.map +1 -1
  252. package/dist/v2/hooks/types.d.ts +4 -0
  253. package/dist/v2/hooks/types.d.ts.map +1 -1
  254. package/dist/v2/hooks/usage-persist.d.ts +31 -0
  255. package/dist/v2/hooks/usage-persist.d.ts.map +1 -0
  256. package/dist/v2/server.js +27201 -22695
  257. package/dist/v2/store-reader.d.ts +9 -0
  258. package/dist/v2/store-reader.d.ts.map +1 -1
  259. package/dist/wrapup-orchestrator-35y56636.js +18 -0
  260. package/package.json +1 -1
  261. package/src/agents/magic-context-prompt.test.ts +125 -0
  262. package/src/agents/magic-context-prompt.ts +15 -10
  263. package/src/config/index.ts +40 -0
  264. package/src/config/live-child-output-cap.test.ts +75 -0
  265. package/src/config/live-child-output-cap.ts +70 -0
  266. package/src/config/live-run-config.test.ts +24 -11
  267. package/src/config/misplaced-agent-model.test.ts +61 -0
  268. package/src/config/project-security.test.ts +17 -0
  269. package/src/config/project-security.ts +28 -4
  270. package/src/config/schema/magic-context.test.ts +16 -1
  271. package/src/config/schema/magic-context.ts +35 -6
  272. package/src/shared/cache-ttl-display.ts +14 -20
  273. package/src/shared/harness.ts +14 -0
  274. package/src/shared/index.ts +1 -0
  275. package/src/shared/logger.test.ts +63 -2
  276. package/src/shared/logger.ts +23 -5
  277. package/src/shared/model-cache-ttl.test.ts +40 -0
  278. package/src/shared/model-cache-ttl.ts +58 -0
  279. package/src/shared/model-suggestion-retry.test.ts +115 -4
  280. package/src/shared/model-suggestion-retry.ts +57 -12
  281. package/src/shared/prompt-async-transport.test.ts +217 -0
  282. package/src/shared/prompt-async-transport.ts +242 -0
  283. package/src/shared/prompt-surface-a1-golden.md +17 -17
  284. package/src/shared/rpc-server.ts +13 -1
  285. package/src/shared/rpc-types.ts +18 -1
  286. package/src/shared/rpc-utils.ts +28 -0
  287. package/src/shared/sqlite-transaction-mode-guard.test.ts +198 -0
  288. package/src/shared/sqlite-write-locker-test-support.ts +62 -0
  289. package/src/shared/status-detail-text.test.ts +23 -0
  290. package/src/shared/status-summary.ts +25 -1
  291. package/src/shared/status-view.ts +1 -1
  292. package/src/shared/tag-transcript.ts +82 -19
  293. package/src/shared/user-facing-codes.ts +12 -5
  294. package/src/shared/window-geometry.ts +6 -3
  295. package/dist/v2/hooks/provider-admission.d.ts +0 -22
  296. package/dist/v2/hooks/provider-admission.d.ts.map +0 -1
  297. package/dist/wrapup-orchestrator-8xzbpvm8.js +0 -18
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  getHarness
3
- } from "./index-6z9g64js.js";
3
+ } from "./index-s70wtd8k.js";
4
4
  import {
5
5
  openCodeDbExists,
6
6
  withReadOnlySessionDb,
7
7
  getRawSessionMessageCountFromDb,
8
8
  getMessageTimesFromOpenCodeDb
9
- } from "./index-bmzt6xgy.js";
9
+ } from "./index-cz88kw0n.js";
10
10
  import {
11
11
  UNKNOWN_FIT_RATIO,
12
12
  resolveDecisionCalibration,
@@ -520,6 +520,23 @@ function estimateImageTokensFromDataUrl(url) {
520
520
  }
521
521
  return IMAGE_FALLBACK_TOKENS;
522
522
  }
523
+ function estimateToolAttachmentImageTokens(state) {
524
+ if (!state || typeof state !== "object")
525
+ return 0;
526
+ const attachments = state.attachments;
527
+ if (!Array.isArray(attachments))
528
+ return 0;
529
+ let tokens = 0;
530
+ for (const attachment of attachments) {
531
+ if (!attachment || typeof attachment !== "object")
532
+ continue;
533
+ const { mime, url } = attachment;
534
+ if (typeof mime !== "string" || !mime.startsWith("image/"))
535
+ continue;
536
+ tokens += typeof url === "string" && url.startsWith("data:") ? estimateImageTokensFromDataUrl(url) : IMAGE_FALLBACK_TOKENS;
537
+ }
538
+ return tokens;
539
+ }
523
540
  function clampImageTokens(n) {
524
541
  if (n < 1)
525
542
  return 1;
@@ -1260,7 +1277,7 @@ function measureTailHygiene(input) {
1260
1277
  if (isDropSentinel(output)) {
1261
1278
  parts.push(excludedSnapshot(`${key}\x00excludedOutput`, output));
1262
1279
  } else {
1263
- const tokens = memoizedTokens("toolOutput", output);
1280
+ const tokens = memoizedTokens("toolOutput", output) + (part.type === "tool" ? estimateToolAttachmentImageTokens(part.state) : 0);
1264
1281
  const measured = snapshot({
1265
1282
  key: `${key}\x00toolOutput`,
1266
1283
  kind: "toolOutput",
@@ -1562,10 +1579,15 @@ var S_URGENT = 0.6;
1562
1579
  var CHANNEL2_SEVERITY_THRESHOLD = 0.75;
1563
1580
  var CHANNEL2_FLOOR_TOKENS = 50000;
1564
1581
  var LEVEL_RANK = { gentle: 1, firm: 2, urgent: 3 };
1582
+ var DROP_SENTINELS = ["[dropped", "[truncated"];
1565
1583
  function channel1RefireTokens(tailTokens) {
1566
1584
  const scaled = Math.round(0.08 * Math.max(0, tailTokens));
1567
1585
  return Math.max(CHANNEL1_REFIRE_FLOOR_TOKENS, scaled);
1568
1586
  }
1587
+ function isDroppedToolOutput(output) {
1588
+ const head = output.trimStart().replace(/^§\d+§\s*/, "").slice(0, 16).toLowerCase();
1589
+ return DROP_SENTINELS.some((sentinel) => head.startsWith(sentinel));
1590
+ }
1569
1591
  function toolOutputTokens(output) {
1570
1592
  return estimateTokens(stripChannel1ReminderSpans(output));
1571
1593
  }
@@ -1809,7 +1831,7 @@ function buildChannel2Reminder(undroppedTokens, reclaimableToolOutputs, hint) {
1809
1831
  const summary = formatReclaimableOutputSummary(reclaimableToolOutputs, undroppedTokens);
1810
1832
  const hintText = formatOldestReclaimableHint(hint);
1811
1833
  return `<system-reminder>
1812
- ` + `Routine housekeeping: ${summary} are reclaimable — make a ctx_reduce pass at a natural stopping point.${hintText}
1834
+ ` + `Your next step: call ctx_reduce on the outputs you've already used (${summary}). Then continue your task.${hintText}
1813
1835
  ` + `</system-reminder>`;
1814
1836
  }
1815
1837
  var CHANNEL1_STICKY_REAL_USER_TURN_GAP = 5;
@@ -1820,19 +1842,19 @@ function buildChannel1Reminder(level, undroppedTokens, reclaimableToolOutputs, h
1820
1842
  return `
1821
1843
 
1822
1844
  <system-reminder>
1823
- Reminder: ${summary} are still reclaimable — ctx_reduce them at a natural stopping point.${hintText}
1845
+ Still unstamped: ${summary}. Stamp the ones you've used with ctx_reduce now.${hintText}
1824
1846
  </system-reminder>`;
1825
1847
  }
1826
1848
  let body;
1827
1849
  switch (level) {
1828
1850
  case "gentle":
1829
- body = `Housekeeping: ${summary} are reclaimable — drop the ones you have already processed with ctx_reduce at a natural stopping point.`;
1851
+ body = `Housekeeping: ${summary} are reclaimable. Stamp each output with ctx_reduce as soon as you've taken what you need from it; don't wait for the task to finish.`;
1830
1852
  break;
1831
1853
  case "firm":
1832
- body = `Housekeeping: ${summary} are reclaimable — make a ctx_reduce pass at a natural stopping point.`;
1854
+ body = `${summary} are reclaimable. Make a ctx_reduce pass now over the outputs you've already used, then continue.`;
1833
1855
  break;
1834
1856
  case "urgent":
1835
- body = `Housekeeping backlog: ${summary} are reclaimable — a ctx_reduce pass is due.`;
1857
+ body = `${summary} are still unstamped. Call ctx_reduce now, before your next tool call, on every output you've already used.`;
1836
1858
  break;
1837
1859
  }
1838
1860
  return `
@@ -2287,7 +2309,7 @@ function toTagEntry(row) {
2287
2309
  messageId: row.message_id,
2288
2310
  type,
2289
2311
  status,
2290
- dropMode: row.drop_mode === "truncated" ? "truncated" : row.drop_mode === "edit_marker" ? "edit_marker" : "full",
2312
+ dropMode: row.drop_mode === "truncated" ? "truncated" : row.drop_mode === "skeleton_real" ? "skeleton_real" : row.drop_mode === "skeleton_stripped" ? "skeleton_stripped" : row.drop_mode === "edit_marker" ? "edit_marker" : row.drop_mode === "edit_marker_stripped" ? "edit_marker_stripped" : "full",
2291
2313
  toolName: row.tool_name ?? null,
2292
2314
  inputByteSize: row.input_byte_size ?? 0,
2293
2315
  byteSize: row.byte_size,
@@ -2369,8 +2391,22 @@ function maxNullableNumber(a, b) {
2369
2391
  return b;
2370
2392
  return null;
2371
2393
  }
2394
+ var foldStatements = new WeakMap;
2395
+ function foldStatement(db, sql) {
2396
+ let statements = foldStatements.get(db);
2397
+ if (!statements) {
2398
+ statements = new Map;
2399
+ foldStatements.set(db, statements);
2400
+ }
2401
+ let statement = statements.get(sql);
2402
+ if (!statement) {
2403
+ statement = db.prepare(sql);
2404
+ statements.set(sql, statement);
2405
+ }
2406
+ return statement;
2407
+ }
2372
2408
  function mergeSizeAndTokenColumnsIntoSurvivor(db, sessionId, survivor, duplicate) {
2373
- db.prepare(`UPDATE tags
2409
+ foldStatement(db, `UPDATE tags
2374
2410
  SET byte_size = ?,
2375
2411
  reasoning_byte_size = ?,
2376
2412
  input_byte_size = ?,
@@ -2390,41 +2426,42 @@ function applyDroppedStatusIfNeeded(db, sessionId, survivor, duplicate) {
2390
2426
  return;
2391
2427
  if (duplicate.status !== "dropped")
2392
2428
  return;
2393
- db.prepare("UPDATE tags SET status = 'dropped' WHERE session_id = ? AND tag_number = ?").run(sessionId, survivor.tagNumber);
2429
+ foldStatement(db, "UPDATE tags SET status = 'dropped' WHERE session_id = ? AND tag_number = ?").run(sessionId, survivor.tagNumber);
2394
2430
  survivor.status = "dropped";
2395
2431
  }
2396
2432
  function retargetPendingOps(db, sessionId, fromTagNumber, toTagNumber) {
2397
- const rows = db.prepare(`SELECT id, operation
2398
- FROM pending_ops
2399
- WHERE session_id = ? AND tag_id = ?
2400
- ORDER BY id ASC`).all(sessionId, fromTagNumber).filter(isPendingOpIdentityRow);
2433
+ const rows = foldStatement(db, `SELECT id, operation
2434
+ FROM pending_ops
2435
+ WHERE session_id = ? AND tag_id = ?
2436
+ ORDER BY id ASC`).all(sessionId, fromTagNumber).filter(isPendingOpIdentityRow);
2401
2437
  for (const row of rows) {
2402
- const existing = db.prepare(`SELECT 1
2403
- FROM pending_ops
2404
- WHERE session_id = ? AND tag_id = ? AND operation = ?
2405
- LIMIT 1`).get(sessionId, toTagNumber, row.operation);
2438
+ const existing = foldStatement(db, `SELECT 1
2439
+ FROM pending_ops
2440
+ WHERE session_id = ? AND tag_id = ? AND operation = ?
2441
+ LIMIT 1`).get(sessionId, toTagNumber, row.operation);
2406
2442
  if (existing) {
2407
- db.prepare("DELETE FROM pending_ops WHERE session_id = ? AND id = ?").run(sessionId, row.id);
2443
+ foldStatement(db, "DELETE FROM pending_ops WHERE session_id = ? AND id = ?").run(sessionId, row.id);
2408
2444
  } else {
2409
- db.prepare("UPDATE pending_ops SET tag_id = ? WHERE session_id = ? AND id = ?").run(toTagNumber, sessionId, row.id);
2445
+ foldStatement(db, "UPDATE pending_ops SET tag_id = ? WHERE session_id = ? AND id = ?").run(toTagNumber, sessionId, row.id);
2410
2446
  }
2411
2447
  }
2412
- db.prepare("DELETE FROM pending_ops WHERE session_id = ? AND tag_id = ?").run(sessionId, fromTagNumber);
2448
+ foldStatement(db, "DELETE FROM pending_ops WHERE session_id = ? AND tag_id = ?").run(sessionId, fromTagNumber);
2413
2449
  }
2414
2450
  function deleteFoldedDuplicateTag(db, sessionId, tagNumber) {
2415
- db.prepare("DELETE FROM source_contents WHERE session_id = ? AND tag_id = ?").run(sessionId, tagNumber);
2416
- db.prepare("DELETE FROM tags WHERE session_id = ? AND tag_number = ?").run(sessionId, tagNumber);
2417
- db.prepare("DELETE FROM pending_ops WHERE session_id = ? AND tag_id = ?").run(sessionId, tagNumber);
2451
+ foldStatement(db, "DELETE FROM source_contents WHERE session_id = ? AND tag_id = ?").run(sessionId, tagNumber);
2452
+ foldStatement(db, "DELETE FROM tags WHERE session_id = ? AND tag_number = ?").run(sessionId, tagNumber);
2453
+ foldStatement(db, "DELETE FROM pending_ops WHERE session_id = ? AND tag_id = ?").run(sessionId, tagNumber);
2418
2454
  }
2419
- function foldDuplicateIntoSurvivor(db, sessionId, survivor, duplicate) {
2455
+ function foldDuplicateIntoSurvivor(db, sessionId, survivor, duplicate, duplicateMayHaveQueuedOps = true) {
2420
2456
  mergeSizeAndTokenColumnsIntoSurvivor(db, sessionId, survivor, duplicate);
2421
2457
  applyDroppedStatusIfNeeded(db, sessionId, survivor, duplicate);
2422
- retargetPendingOps(db, sessionId, duplicate.tagNumber, survivor.tagNumber);
2458
+ if (duplicateMayHaveQueuedOps) {
2459
+ retargetPendingOps(db, sessionId, duplicate.tagNumber, survivor.tagNumber);
2460
+ }
2423
2461
  deleteFoldedDuplicateTag(db, sessionId, duplicate.tagNumber);
2424
2462
  }
2425
- function readPartTagRows(db, sessionId, messageId) {
2426
- const prefix = `${messageId}:p`;
2427
- return db.prepare(`SELECT tag_number AS tagNumber,
2463
+ function readPartTagRowsByMessage(db, sessionId) {
2464
+ const rows = db.prepare(`SELECT tag_number AS tagNumber,
2428
2465
  message_id AS messageId,
2429
2466
  tool_owner_message_id AS toolOwnerMessageId,
2430
2467
  type,
@@ -2438,22 +2475,39 @@ function readPartTagRows(db, sessionId, messageId) {
2438
2475
  FROM tags
2439
2476
  WHERE session_id = ?
2440
2477
  AND type = 'message'
2441
- AND message_id LIKE ? ESCAPE '\\'
2442
- ORDER BY tag_number ASC`).all(sessionId, `${escapeLikePattern(messageId)}:p%`).filter(isPiFallbackFoldTagRow).flatMap((row) => {
2443
- const suffix = row.messageId.startsWith(prefix) ? row.messageId.slice(prefix.length) : "";
2478
+ ORDER BY tag_number ASC`).all(sessionId).filter(isPiFallbackFoldTagRow);
2479
+ const byMessage = new Map;
2480
+ for (const row of rows) {
2481
+ const marker = row.messageId.lastIndexOf(":p");
2482
+ if (marker < 0)
2483
+ continue;
2484
+ const suffix = row.messageId.slice(marker + 2);
2444
2485
  if (!/^\d+$/.test(suffix))
2445
- return [];
2446
- return [{ ...row, partIndex: Number.parseInt(suffix, 10) }];
2447
- }).sort((a, b) => a.partIndex - b.partIndex);
2486
+ continue;
2487
+ const messageId = row.messageId.slice(0, marker);
2488
+ const group = byMessage.get(messageId);
2489
+ const entry = { ...row, partIndex: Number.parseInt(suffix, 10) };
2490
+ if (group)
2491
+ group.push(entry);
2492
+ else
2493
+ byMessage.set(messageId, [entry]);
2494
+ }
2495
+ for (const group of byMessage.values())
2496
+ group.sort((a, b) => a.partIndex - b.partIndex);
2497
+ return byMessage;
2448
2498
  }
2449
- function tagNumbersWithQueuedDrop(db, sessionId, tagNumbers) {
2450
- if (tagNumbers.length === 0)
2451
- return new Set;
2452
- const placeholders = tagNumbers.map(() => "?").join(", ");
2453
- const rows = db.prepare(`SELECT DISTINCT tag_id AS tagNumber
2454
- FROM pending_ops
2455
- WHERE session_id = ? AND operation = 'drop' AND tag_id IN (${placeholders})`).all(sessionId, ...tagNumbers);
2456
- return new Set(rows.flatMap((row) => typeof row.tagNumber === "number" ? [row.tagNumber] : []));
2499
+ function readQueuedTagNumbers(db, sessionId) {
2500
+ const rows = db.prepare("SELECT tag_id AS tagNumber, operation FROM pending_ops WHERE session_id = ? AND tag_id IS NOT NULL").all(sessionId);
2501
+ const any = new Set;
2502
+ const drop = new Set;
2503
+ for (const row of rows) {
2504
+ if (typeof row.tagNumber !== "number")
2505
+ continue;
2506
+ any.add(row.tagNumber);
2507
+ if (row.operation === "drop")
2508
+ drop.add(row.tagNumber);
2509
+ }
2510
+ return { any, drop };
2457
2511
  }
2458
2512
  function foldShrunkPartTags(db, sessionId, messages) {
2459
2513
  const result = {
@@ -2461,17 +2515,25 @@ function foldShrunkPartTags(db, sessionId, messages) {
2461
2515
  rekeyedTagNumbers: [],
2462
2516
  discardedDropTagNumbers: []
2463
2517
  };
2518
+ if (messages.length === 0)
2519
+ return result;
2520
+ const rowsByMessage = readPartTagRowsByMessage(db, sessionId);
2521
+ const queuedTags = readQueuedTagNumbers(db, sessionId);
2522
+ const discardDrop = foldStatement(db, "DELETE FROM pending_ops WHERE session_id = ? AND tag_id = ? AND operation = 'drop'");
2523
+ const rekey = foldStatement(db, "UPDATE tags SET message_id = ? WHERE session_id = ? AND tag_number = ? AND type = 'message'");
2464
2524
  for (const { messageId, partCount } of messages) {
2465
- const rows = readPartTagRows(db, sessionId, messageId);
2525
+ const rows = rowsByMessage.get(messageId) ?? [];
2466
2526
  if (rows.length === 0)
2467
2527
  continue;
2468
2528
  const orphans = rows.filter((row) => row.partIndex >= partCount);
2469
2529
  if (orphans.length === 0)
2470
2530
  continue;
2471
- const queued = tagNumbersWithQueuedDrop(db, sessionId, rows.map((row) => row.tagNumber));
2472
- if (queued.size > 0 && queued.size < rows.length) {
2531
+ const queued = [
2532
+ ...new Set(rows.map((row) => row.tagNumber).filter((tag) => queuedTags.drop.has(tag)))
2533
+ ].sort((a, b) => a - b);
2534
+ if (queued.length > 0 && queued.length < rows.length) {
2473
2535
  for (const tagNumber of queued) {
2474
- db.prepare("DELETE FROM pending_ops WHERE session_id = ? AND tag_id = ? AND operation = 'drop'").run(sessionId, tagNumber);
2536
+ discardDrop.run(sessionId, tagNumber);
2475
2537
  result.discardedDropTagNumbers.push(tagNumber);
2476
2538
  }
2477
2539
  }
@@ -2480,14 +2542,14 @@ function foldShrunkPartTags(db, sessionId, messages) {
2480
2542
  const lowest = orphans[0];
2481
2543
  if (!lowest)
2482
2544
  continue;
2483
- db.prepare("UPDATE tags SET message_id = ? WHERE session_id = ? AND tag_number = ? AND type = 'message'").run(`${messageId}:p0`, sessionId, lowest.tagNumber);
2545
+ rekey.run(`${messageId}:p0`, sessionId, lowest.tagNumber);
2484
2546
  result.rekeyedTagNumbers.push(lowest.tagNumber);
2485
2547
  survivor = { ...lowest, messageId: `${messageId}:p0`, partIndex: 0 };
2486
2548
  }
2487
2549
  for (const orphan of orphans) {
2488
2550
  if (orphan.tagNumber === survivor.tagNumber)
2489
2551
  continue;
2490
- foldDuplicateIntoSurvivor(db, sessionId, survivor, orphan);
2552
+ foldDuplicateIntoSurvivor(db, sessionId, survivor, orphan, queuedTags.any.has(orphan.tagNumber));
2491
2553
  result.foldedTagNumbers.push(orphan.tagNumber);
2492
2554
  }
2493
2555
  }
@@ -2514,7 +2576,7 @@ function markTagsCompactedByMessageIds(db, sessionId, messageIds) {
2514
2576
  changed += update.all(sessionId, messageId, `${escaped}:p%`, `${escaped}:file%`, messageId).length;
2515
2577
  }
2516
2578
  return changed;
2517
- })();
2579
+ }).immediate();
2518
2580
  }
2519
2581
  function deleteTagsByMessageId(db, sessionId, messageId) {
2520
2582
  const deleteTransaction = db.transaction(() => {
@@ -2989,11 +3051,23 @@ function readRawSessionMessagesFromDb(db, sessionId) {
2989
3051
  });
2990
3052
  }
2991
3053
  function readRawSessionMessagePageFromDb(db, sessionId, afterOrdinal, limit, finalWatermark = Number.MAX_SAFE_INTEGER) {
3054
+ const messageRows = readRawMessagePageRows(db, sessionId, afterOrdinal, limit, finalWatermark);
3055
+ if (messageRows.length === 0)
3056
+ return [];
3057
+ const placeholders = messageRows.map(() => "?").join(", ");
3058
+ const partRows = db.prepare(`SELECT message_id, data, time_updated
3059
+ FROM part
3060
+ WHERE +session_id = ?
3061
+ AND likelihood(message_id IN (${placeholders}), 0.000001)
3062
+ ORDER BY message_id ASC, time_created ASC, id ASC`).all(sessionId, ...messageRows.map((row) => row.id)).filter(isRawPartRow);
3063
+ return assembleRawMessagePage(messageRows, partRows);
3064
+ }
3065
+ function readRawMessagePageRows(db, sessionId, afterOrdinal, limit, finalWatermark) {
2992
3066
  const remaining = Math.max(0, Math.floor(finalWatermark) - Math.floor(afterOrdinal));
2993
3067
  const pageSize = Math.min(Math.max(1, Math.floor(limit)), remaining);
2994
3068
  if (pageSize === 0)
2995
3069
  return [];
2996
- const messageRows = db.prepare(`SELECT id, data, time_created, time_updated
3070
+ return db.prepare(`SELECT id, data, time_created, time_updated
2997
3071
  FROM message
2998
3072
  WHERE session_id = ?
2999
3073
  AND NOT (
@@ -3009,14 +3083,8 @@ function readRawSessionMessagePageFromDb(db, sessionId, afterOrdinal, limit, fin
3009
3083
  ...row,
3010
3084
  ordinal: Math.floor(afterOrdinal) + index + 1
3011
3085
  }));
3012
- if (messageRows.length === 0)
3013
- return [];
3014
- const placeholders = messageRows.map(() => "?").join(", ");
3015
- const partRows = db.prepare(`SELECT message_id, data, time_updated
3016
- FROM part
3017
- WHERE +session_id = ?
3018
- AND likelihood(message_id IN (${placeholders}), 0.000001)
3019
- ORDER BY message_id ASC, time_created ASC, id ASC`).all(sessionId, ...messageRows.map((row) => row.id)).filter(isRawPartRow);
3086
+ }
3087
+ function assembleRawMessagePage(messageRows, partRows) {
3020
3088
  const partsByMessageId = new Map;
3021
3089
  for (const part of partRows) {
3022
3090
  const list = partsByMessageId.get(part.message_id) ?? [];
@@ -3035,6 +3103,49 @@ function readRawSessionMessagePageFromDb(db, sessionId, afterOrdinal, limit, fin
3035
3103
  };
3036
3104
  });
3037
3105
  }
3106
+ var RAW_SUMMARY_TEXT_MAX_CHARS = 8192;
3107
+ var RAW_SUMMARY_ARG_MAX_CHARS = 512;
3108
+ var RAW_SUMMARY_TOOL_INPUT_KEYS = [
3109
+ "description",
3110
+ "filePath",
3111
+ "path",
3112
+ "pattern",
3113
+ "query",
3114
+ "symbol",
3115
+ "module",
3116
+ "action"
3117
+ ];
3118
+ function summaryStringField(jsonPath) {
3119
+ return `CASE WHEN json_type(data, '${jsonPath}') = 'text' THEN substr(json_extract(data, '${jsonPath}'), 1, ${RAW_SUMMARY_ARG_MAX_CHARS}) END`;
3120
+ }
3121
+ var RAW_SUMMARY_PART_DATA_SQL = `CASE
3122
+ WHEN json_extract(data, '$.type') = 'text'
3123
+ THEN json_set(data, '$.text', substr(json_extract(data, '$.text'), 1, ${RAW_SUMMARY_TEXT_MAX_CHARS}))
3124
+ ELSE json_object(
3125
+ 'type', 'tool',
3126
+ 'tool', ${summaryStringField("$.tool")},
3127
+ 'callID', ${summaryStringField("$.callID")},
3128
+ 'state', json_object(
3129
+ 'status', ${summaryStringField("$.state.status")},
3130
+ 'input', json_object(${RAW_SUMMARY_TOOL_INPUT_KEYS.map((key) => `'${key}', ${summaryStringField(`$.state.input.${key}`)}`).join(", ")}),
3131
+ 'metadata', json_object('description', ${summaryStringField("$.state.metadata.description")})
3132
+ )
3133
+ )
3134
+ END`;
3135
+ function readRawSessionMessageSummaryPageFromDb(db, sessionId, afterOrdinal, limit, finalWatermark = Number.MAX_SAFE_INTEGER) {
3136
+ const messageRows = readRawMessagePageRows(db, sessionId, afterOrdinal, limit, finalWatermark);
3137
+ if (messageRows.length === 0)
3138
+ return [];
3139
+ const placeholders = messageRows.map(() => "?").join(", ");
3140
+ const partRows = db.prepare(`SELECT message_id, ${RAW_SUMMARY_PART_DATA_SQL} AS data, time_updated
3141
+ FROM part
3142
+ WHERE +session_id = ?
3143
+ AND likelihood(message_id IN (${placeholders}), 0.000001)
3144
+ AND json_valid(data) = 1
3145
+ AND json_extract(data, '$.type') IN ('text', 'tool')
3146
+ ORDER BY message_id ASC, time_created ASC, id ASC`).all(sessionId, ...messageRows.map((row) => row.id)).filter(isRawPartRow);
3147
+ return assembleRawMessagePage(messageRows, partRows);
3148
+ }
3038
3149
  function countRawSessionMessageOrdinalsFromDb(db, sessionId) {
3039
3150
  const row = db.prepare(`SELECT COUNT(*) AS count
3040
3151
  FROM message
@@ -4252,6 +4363,7 @@ function estimateMessageTokens(message) {
4252
4363
  toolCall += serializedTokens(p.state?.input ?? p.input ?? p.args);
4253
4364
  toolCall += serializedTokens(p.state?.output ?? p.state?.content ?? p.output ?? p.result ?? p.content);
4254
4365
  toolCall += serializedTokens(p.state?.error);
4366
+ toolCall += estimateToolAttachmentImageTokens(p.state);
4255
4367
  break;
4256
4368
  case "tool-call":
4257
4369
  toolCall += serializedTokens(p.input ?? p.args);
@@ -4348,6 +4460,28 @@ function hasCountableParts(message) {
4348
4460
  });
4349
4461
  }
4350
4462
 
4463
+ // src/hooks/magic-context/tool-input-size.ts
4464
+ var SKELETON_REAL_INPUT_MAX_BYTES = 1024;
4465
+ var encoder2 = new TextEncoder;
4466
+ function toolInputStringBytes(value) {
4467
+ const seen = new WeakSet;
4468
+ const visit = (candidate) => {
4469
+ if (typeof candidate === "string")
4470
+ return encoder2.encode(candidate).length;
4471
+ if (candidate === null || typeof candidate !== "object")
4472
+ return 0;
4473
+ if (seen.has(candidate))
4474
+ return 0;
4475
+ seen.add(candidate);
4476
+ let total = 0;
4477
+ const values = Array.isArray(candidate) ? candidate : Object.values(candidate);
4478
+ for (const item of values)
4479
+ total += visit(item);
4480
+ return total;
4481
+ };
4482
+ return visit(value);
4483
+ }
4484
+
4351
4485
  // src/hooks/magic-context/tool-drop-target.ts
4352
4486
  var DROP_PREFIX = "[dropped";
4353
4487
  var IGNORE_PART_TYPES = new Set([
@@ -4400,9 +4534,39 @@ function clampCloneInPlace(occurrence, clamp) {
4400
4534
  const clone = clonePart(occurrence.part);
4401
4535
  clamp(clone);
4402
4536
  const parts = occurrence.message.parts;
4403
- const index = parts.indexOf(occurrence.part);
4404
- if (index >= 0)
4537
+ const index = parts.indexOf(servedPart(occurrence));
4538
+ if (index >= 0) {
4405
4539
  parts[index] = clone;
4540
+ occurrence.served = clone;
4541
+ }
4542
+ }
4543
+ function servedPart(occurrence) {
4544
+ return occurrence.served ?? occurrence.part;
4545
+ }
4546
+ function skeletonRealToolPart(part, tagId, stripAttachments = false) {
4547
+ if (!isRecord(part))
4548
+ return;
4549
+ const sentinel = `[dropped §${tagId}§]`;
4550
+ if (part.type === "tool" && isRecord(part.state)) {
4551
+ part.state.output = sentinel;
4552
+ if (stripAttachments)
4553
+ part.state.attachments = [];
4554
+ return;
4555
+ }
4556
+ if (part.type === "tool_result") {
4557
+ part.content = sentinel;
4558
+ }
4559
+ }
4560
+ function readToolPartRawInput(part) {
4561
+ if (!isRecord(part))
4562
+ return;
4563
+ if (part.type === "tool" && isRecord(part.state))
4564
+ return part.state.input;
4565
+ if (part.type === "tool-invocation")
4566
+ return part.args;
4567
+ if (part.type === "tool_use")
4568
+ return part.input;
4569
+ return;
4406
4570
  }
4407
4571
  function truncateToolPart(part, tagId) {
4408
4572
  if (!isRecord(part))
@@ -4426,12 +4590,14 @@ function truncateToolPart(part, tagId) {
4426
4590
  part.input = droppedInputMarker(tagId);
4427
4591
  }
4428
4592
  }
4429
- function editMarkerToolPart(part, tagId) {
4593
+ function editMarkerToolPart(part, tagId, stripAttachments = false) {
4430
4594
  if (!isRecord(part))
4431
4595
  return;
4432
4596
  const sentinel = `[dropped §${tagId}§]`;
4433
4597
  if (part.type === "tool" && isRecord(part.state)) {
4434
4598
  part.state.output = sentinel;
4599
+ if (stripAttachments)
4600
+ part.state.attachments = [];
4435
4601
  if (isRecord(part.state.input))
4436
4602
  applyEditMarkerToInput(part.state.input);
4437
4603
  return;
@@ -4534,7 +4700,7 @@ class ToolMutationBatch {
4534
4700
  this.messages = messages;
4535
4701
  }
4536
4702
  markForRemoval(occurrence) {
4537
- this.partsToRemove.add(occurrence.part);
4703
+ this.partsToRemove.add(servedPart(occurrence));
4538
4704
  this.affectedMessages.add(occurrence.message);
4539
4705
  }
4540
4706
  wouldStrandConversationEnd(occurrences) {
@@ -4546,7 +4712,7 @@ class ToolMutationBatch {
4546
4712
  }
4547
4713
  if (!end || !occurrences.some((occurrence) => occurrence.message === end))
4548
4714
  return false;
4549
- const leaving = new Set(occurrences.map((occurrence) => occurrence.part));
4715
+ const leaving = new Set(occurrences.map(servedPart));
4550
4716
  const survives = (part) => !leaving.has(part) && !this.partsToRemove.has(part);
4551
4717
  return end.info.role === "assistant" ? !end.parts.some((part) => partHasCompletedResult(part) && survives(part)) : !end.parts.some((part) => hasMeaningfulPart(part) && survives(part));
4552
4718
  }
@@ -4597,7 +4763,7 @@ function createToolDropTarget(compositeKey, thinkingParts, index, batch, tagId)
4597
4763
  if (!entry.hasResult)
4598
4764
  return "incomplete";
4599
4765
  if (batch.wouldStrandConversationEnd(entry.occurrences))
4600
- return truncate();
4766
+ return skeletonReal();
4601
4767
  for (const occurrence of entry.occurrences) {
4602
4768
  batch.markForRemoval(occurrence);
4603
4769
  }
@@ -4617,14 +4783,50 @@ function createToolDropTarget(compositeKey, thinkingParts, index, batch, tagId)
4617
4783
  clearThinkingParts(thinkingParts);
4618
4784
  return "truncated";
4619
4785
  };
4620
- const editMarker = () => {
4786
+ const skeletonReal = () => {
4787
+ const entry = index.get(compositeKey);
4788
+ if (!entry || entry.occurrences.length === 0)
4789
+ return "absent";
4790
+ if (!entry.hasResult)
4791
+ return "incomplete";
4792
+ for (const occurrence of entry.occurrences) {
4793
+ clampCloneInPlace(occurrence, (part) => skeletonRealToolPart(part, tagId));
4794
+ }
4795
+ clearThinkingParts(thinkingParts);
4796
+ return "truncated";
4797
+ };
4798
+ const skeletonStripped = () => {
4621
4799
  const entry = index.get(compositeKey);
4622
4800
  if (!entry || entry.occurrences.length === 0)
4623
4801
  return "absent";
4624
4802
  if (!entry.hasResult)
4625
4803
  return "incomplete";
4626
4804
  for (const occurrence of entry.occurrences) {
4627
- clampCloneInPlace(occurrence, (part) => editMarkerToolPart(part, tagId));
4805
+ clampCloneInPlace(occurrence, (part) => skeletonRealToolPart(part, tagId, true));
4806
+ }
4807
+ clearThinkingParts(thinkingParts);
4808
+ return "truncated";
4809
+ };
4810
+ const hasAttachments = () => index.get(compositeKey)?.occurrences.some(({ part }) => isRecord(part) && isRecord(part.state) && Array.isArray(part.state.attachments) && part.state.attachments.length > 0) ?? false;
4811
+ const readRawInput = () => {
4812
+ const entry = index.get(compositeKey);
4813
+ if (!entry)
4814
+ return;
4815
+ for (const occurrence of entry.occurrences) {
4816
+ const input = readToolPartRawInput(occurrence.part);
4817
+ if (input !== undefined)
4818
+ return input;
4819
+ }
4820
+ return;
4821
+ };
4822
+ const applyEditMarker = (stripAttachments) => {
4823
+ const entry = index.get(compositeKey);
4824
+ if (!entry || entry.occurrences.length === 0)
4825
+ return "absent";
4826
+ if (!entry.hasResult)
4827
+ return "incomplete";
4828
+ for (const occurrence of entry.occurrences) {
4829
+ clampCloneInPlace(occurrence, (part) => editMarkerToolPart(part, tagId, stripAttachments));
4628
4830
  }
4629
4831
  clearThinkingParts(thinkingParts);
4630
4832
  return "truncated";
@@ -4640,7 +4842,7 @@ function createToolDropTarget(compositeKey, thinkingParts, index, batch, tagId)
4640
4842
  const before = count(parts);
4641
4843
  const retained = skeleton ? structuredClone(parts) : [];
4642
4844
  for (const part of retained)
4643
- truncateToolPart(part, tagId);
4845
+ skeletonRealToolPart(part, tagId);
4644
4846
  const after = count(retained);
4645
4847
  return {
4646
4848
  beforeTools: before.toolCall,
@@ -4671,7 +4873,23 @@ function createToolDropTarget(compositeKey, thinkingParts, index, batch, tagId)
4671
4873
  },
4672
4874
  drop,
4673
4875
  truncate,
4674
- editMarker,
4876
+ skeletonReal,
4877
+ skeletonStripped,
4878
+ hasAttachments,
4879
+ editMarker: () => applyEditMarker(false),
4880
+ editMarkerStripped: () => applyEditMarker(true),
4881
+ inputStringBytes: () => {
4882
+ const entry = index.get(compositeKey);
4883
+ if (!entry || entry.occurrences.length === 0)
4884
+ return null;
4885
+ return toolInputStringBytes(readRawInput());
4886
+ },
4887
+ wouldStrandConversationEnd: () => {
4888
+ const entry = index.get(compositeKey);
4889
+ if (!entry || entry.occurrences.length === 0)
4890
+ return false;
4891
+ return batch.wouldStrandConversationEnd(entry.occurrences);
4892
+ },
4675
4893
  canDrop: () => {
4676
4894
  const entry = index.get(compositeKey);
4677
4895
  return !!entry && entry.occurrences.length > 0 && entry.hasResult;
@@ -4832,6 +5050,45 @@ function readRawSessionMessageRangeFromSource(sessionId, fromOrdinal, toOrdinal)
4832
5050
  }
4833
5051
  return messages;
4834
5052
  }
5053
+ var RAW_MESSAGE_VISIT_PAGE_SIZE = 50;
5054
+ function visitRawSessionMessages2(sessionId, fromOrdinal, toOrdinal, visit, options = {}) {
5055
+ const from = Math.max(1, Math.floor(fromOrdinal));
5056
+ const to = Math.floor(toOrdinal);
5057
+ if (to < from)
5058
+ return;
5059
+ const provider = sessionProviders.get(sessionId);
5060
+ if (provider && !provider.readMessagePage) {
5061
+ for (const message of provider.readMessages()) {
5062
+ if (message.ordinal < from || message.ordinal > to)
5063
+ continue;
5064
+ if (!visit(message))
5065
+ return;
5066
+ }
5067
+ return;
5068
+ }
5069
+ if (!provider && !openCodeDbExists())
5070
+ return;
5071
+ const pageSize = Math.max(1, Math.floor(options.pageSize ?? RAW_MESSAGE_VISIT_PAGE_SIZE));
5072
+ let afterOrdinal = from - 1;
5073
+ while (afterOrdinal < to) {
5074
+ const limit = Math.min(pageSize, to - afterOrdinal);
5075
+ const cursor = afterOrdinal;
5076
+ const page = provider?.readMessagePage ? provider.readMessagePage(cursor, limit, to) : withReadOnlySessionDb((db) => options.summary ? readRawSessionMessageSummaryPageFromDb(db, sessionId, cursor, limit, to) : readRawSessionMessagePageFromDb(db, sessionId, cursor, limit, to));
5077
+ if (page.length === 0)
5078
+ return;
5079
+ let nextOrdinal = afterOrdinal;
5080
+ for (const message of page) {
5081
+ if (message.ordinal < from || message.ordinal > to)
5082
+ continue;
5083
+ if (!visit(message))
5084
+ return;
5085
+ nextOrdinal = Math.max(nextOrdinal, message.ordinal);
5086
+ }
5087
+ if (nextOrdinal <= afterOrdinal)
5088
+ return;
5089
+ afterOrdinal = nextOrdinal;
5090
+ }
5091
+ }
4835
5092
  function readRawSessionMessageRange2(sessionId, fromOrdinal, toOrdinal) {
4836
5093
  const from = Math.max(1, Math.floor(fromOrdinal));
4837
5094
  const to = Math.floor(toOrdinal);
@@ -5008,6 +5265,30 @@ function readRawSessionMessageOrdinalById2(sessionId, messageId) {
5008
5265
  return null;
5009
5266
  return withReadOnlySessionDb((db) => readRawSessionMessageOrdinalByIdFromDb(db, sessionId, messageId));
5010
5267
  }
5268
+ function compareRawSessionMessageOrder2(sessionId, leftId, rightId) {
5269
+ const provider = sessionProviders.get(sessionId);
5270
+ if (provider) {
5271
+ if (!provider.readMessageOrdinalById)
5272
+ return null;
5273
+ const left = provider.readMessageOrdinalById(leftId);
5274
+ const right = provider.readMessageOrdinalById(rightId);
5275
+ return left === null || right === null ? null : left - right;
5276
+ }
5277
+ if (!openCodeDbExists())
5278
+ return null;
5279
+ return withReadOnlySessionDb((db) => {
5280
+ const lookup = db.prepare("SELECT time_created, id FROM message WHERE session_id = ? AND id = ? LIMIT 1");
5281
+ const left = lookup.get(sessionId, leftId);
5282
+ const right = lookup.get(sessionId, rightId);
5283
+ if (typeof left?.time_created !== "number" || typeof right?.time_created !== "number" || typeof left.id !== "string" || typeof right.id !== "string") {
5284
+ return null;
5285
+ }
5286
+ if (left.time_created !== right.time_created) {
5287
+ return left.time_created - right.time_created;
5288
+ }
5289
+ return left.id < right.id ? -1 : left.id > right.id ? 1 : 0;
5290
+ });
5291
+ }
5011
5292
  function readRawSessionMessageById2(sessionId, messageId) {
5012
5293
  const provider = sessionProviders.get(sessionId);
5013
5294
  if (provider?.readMessageById) {
@@ -5406,4 +5687,4 @@ function readRawSessionSeedTail2(sessionId, boundaryId, onQuery) {
5406
5687
  });
5407
5688
  }
5408
5689
 
5409
- export { textMentionsRecentCommit, removeSystemReminders, hasMeaningfulUserText2, extractTexts2, extractToolCallSummaries, getTokenizerNativeMemoryStats, preloadTokenizer, estimateTokens, normalizeText, stableStringify, getCurrentToolSetHash, setDatabase, loadToolDefinitionMeasurements, recordToolDefinition, getMeasuredToolDefinitionTokens, CTX_REDUCE_KEEP, newestCtxReduceTagNumbers, stripWellFormedLeadingTagPrefix, stripPersistedAssistantText, byteSize, stripTagPrefix, peelLeadingMcTagNotation, prependTag, isThinkingPart, isRecord, estimateImageTokensFromDataUrl, normalizeTodoStateJson, buildSyntheticTodoPart, computeSyntheticCallId, isSyntheticTodoPart, countRealUserMessages, tailHygieneStructuralSignature, sameTailHygieneStructuralSignature, formatTailHygienePrefixMismatch, refreshTailHygieneBaseline, effectiveTailHygiene, assertTailHygieneContentUnchanged, CHANNEL1_SENTINEL, CHANNEL1_FLOOR_TOKENS, toolOutputTokens, decideChannel1, evaluateChannel2, formatChannel1Evaluation, formatChannel2Evaluation, reclaimableToolOutputCount, buildChannel2Reminder, buildChannel1Reminder, estimateEmergencyDropReclaimTokens, planEmergencyDrop, measureEmergencyTag, getRecentTagOwnerMessageIds, AGE_RECLAIM_MIN_TOKENS, getOldestActiveUnprotectedToolTags, getActiveToolTagsForAgeReclaim, getTriggerTagTokenUpperBound, getActiveTagTokenTotalsByMessage, getAllStatusTagTokenTotalsFlat, tagTokenCountIsNull, backfillTagTokenCounts, insertTag, updateTagStatus, markWhitespaceAssistantTagInert, getInertWhitespaceAssistantTags, updateTagDropMode, updateCavemanDepth, updateTagMessageId, foldShrunkPartTags, markTagsCompactedByMessageIds, deleteTagsByMessageId, getMaxTagNumberBySession, getTagNumberByMessageId, getAssignableTagNumberByMessageId, deriveTagLoadFloor, TAG_SELECT_COLUMNS, getTagsBySession, getActiveTagsBySession, getTailHygieneTags, getDroppedTagsBySession, getTagsByNumbers, getDroppedTagsByNumbers, getMaxDroppedTagNumber, getTagById, getToolTagNumberByOwner, getNullOwnerToolTag, adoptNullOwnerToolTag, getCandidateToolOwners, pickNearestPriorOwner, markHostUnservedRow, retreatPastHostUnservedRows, snapTerminalCompartmentToServedRow, isHostRenderedSystemMessage, isStrictGapHealingMessage, isRawCompactionSummaryInfo, extractInMemoryMessageViews, buildInMemoryTailRawMessages, completedToolArcCrossesBoundary, estimateTrueRawMessageTokens, buildToolArcs, fenceBoundaryForCompletedToolArcs, fenceBoundaryForToolArcs, buildTrueRawTokenIndex, computeRawRangeFingerprint, invalidateTrueRawTokenCache, isTextPart, isToolPartWithOutput, isFilePart, buildFileSourceContent, recordToolParameters, createDroppedInputGuard, assertExecutableToolInput, createDroppedInputToolExecuteBeforeHook, isEditTool, describeFinalWireTail, estimateMessageTokens, estimateFinalWireInputTokens, partHasCompletedResult, extractToolCallObservation, ToolMutationBatch, createToolDropTarget, resolveHostServedBoundaryId2, hasRawMessageProvider2, setRawMessageProvider2, setBoundedRawMessageProvider2, cleanUserText2, withRawSessionMessageCache2, readRawSessionMessages2, readRawSessionMessagePage2, getRawSessionMessageOrdinalCount2, readRawSessionMessageRange2, primeTailRawMessageCache2, getCachedAbsoluteMessageCount2, primeInMemoryTailRawMessageCache2, readRawSessionMessageOrdinalPage2, getRawSessionStoredMessageCount2, readRawSessionMessageIdOrdinalsForRange2, readRawSessionMessagePartsById2, hasRawSessionMessageById2, readRawSessionMessageOrdinalById2, readRawSessionMessageById2, getRawSessionMessageCount2, getRawSessionTagKeysThrough2, getLegacyProtectedTailStartOrdinal2, readSessionChunk2, readRawSessionSeedTail2 };
5690
+ export { textMentionsRecentCommit, removeSystemReminders, hasMeaningfulUserText2, extractTexts2, extractToolCallSummaries, getTokenizerNativeMemoryStats, preloadTokenizer, estimateTokens, normalizeText, stableStringify, getCurrentToolSetHash, setDatabase, loadToolDefinitionMeasurements, recordToolDefinition, getMeasuredToolDefinitionTokens, CTX_REDUCE_KEEP, newestCtxReduceTagNumbers, stripWellFormedLeadingTagPrefix, stripPersistedAssistantText, byteSize, stripTagPrefix, peelLeadingMcTagNotation, prependTag, isThinkingPart, isRecord, estimateImageTokensFromDataUrl, estimateToolAttachmentImageTokens, normalizeTodoStateJson, buildSyntheticTodoPart, computeSyntheticCallId, isSyntheticTodoPart, countRealUserMessages, tailHygieneStructuralSignature, sameTailHygieneStructuralSignature, formatTailHygienePrefixMismatch, refreshTailHygieneBaseline, effectiveTailHygiene, assertTailHygieneContentUnchanged, CHANNEL1_SENTINEL, CHANNEL1_FLOOR_TOKENS, isDroppedToolOutput, toolOutputTokens, decideChannel1, evaluateChannel2, formatChannel1Evaluation, formatChannel2Evaluation, reclaimableToolOutputCount, buildChannel2Reminder, buildChannel1Reminder, estimateEmergencyDropReclaimTokens, planEmergencyDrop, measureEmergencyTag, getRecentTagOwnerMessageIds, AGE_RECLAIM_MIN_TOKENS, getOldestActiveUnprotectedToolTags, getActiveToolTagsForAgeReclaim, getTriggerTagTokenUpperBound, getActiveTagTokenTotalsByMessage, getAllStatusTagTokenTotalsFlat, tagTokenCountIsNull, backfillTagTokenCounts, insertTag, updateTagStatus, markWhitespaceAssistantTagInert, getInertWhitespaceAssistantTags, updateTagDropMode, updateCavemanDepth, updateTagMessageId, foldShrunkPartTags, markTagsCompactedByMessageIds, deleteTagsByMessageId, getMaxTagNumberBySession, getTagNumberByMessageId, getAssignableTagNumberByMessageId, deriveTagLoadFloor, TAG_SELECT_COLUMNS, getTagsBySession, getActiveTagsBySession, getTailHygieneTags, getDroppedTagsBySession, getTagsByNumbers, getDroppedTagsByNumbers, getMaxDroppedTagNumber, getTagById, getToolTagNumberByOwner, getNullOwnerToolTag, adoptNullOwnerToolTag, getCandidateToolOwners, pickNearestPriorOwner, markHostUnservedRow, retreatPastHostUnservedRows, snapTerminalCompartmentToServedRow, isHostRenderedSystemMessage, isStrictGapHealingMessage, isRawCompactionSummaryInfo, extractInMemoryMessageViews, buildInMemoryTailRawMessages, completedToolArcCrossesBoundary, estimateTrueRawMessageTokens, buildToolArcs, fenceBoundaryForCompletedToolArcs, fenceBoundaryForToolArcs, buildTrueRawTokenIndex, computeRawRangeFingerprint, invalidateTrueRawTokenCache, isTextPart, isToolPartWithOutput, isFilePart, buildFileSourceContent, recordToolParameters, createDroppedInputGuard, assertExecutableToolInput, createDroppedInputToolExecuteBeforeHook, isEditTool, describeFinalWireTail, estimateMessageTokens, estimateFinalWireInputTokens, SKELETON_REAL_INPUT_MAX_BYTES, partHasCompletedResult, extractToolCallObservation, ToolMutationBatch, createToolDropTarget, resolveHostServedBoundaryId2, hasRawMessageProvider2, setRawMessageProvider2, setBoundedRawMessageProvider2, cleanUserText2, withRawSessionMessageCache2, readRawSessionMessages2, readRawSessionMessagePage2, getRawSessionMessageOrdinalCount2, visitRawSessionMessages2, readRawSessionMessageRange2, primeTailRawMessageCache2, getCachedAbsoluteMessageCount2, primeInMemoryTailRawMessageCache2, readRawSessionMessageOrdinalPage2, getRawSessionStoredMessageCount2, readRawSessionMessageIdOrdinalsForRange2, readRawSessionMessagePartsById2, hasRawSessionMessageById2, readRawSessionMessageOrdinalById2, compareRawSessionMessageOrder2, readRawSessionMessageById2, getRawSessionMessageCount2, getRawSessionTagKeysThrough2, getLegacyProtectedTailStartOrdinal2, readSessionChunk2, readRawSessionSeedTail2 };