@retaw106/mmc-oc 2.2.1 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (285) hide show
  1. package/dist/cli.js +14 -3
  2. package/dist/config/deprecated-config.d.ts +4 -0
  3. package/dist/config/deprecated-config.d.ts.map +1 -0
  4. package/dist/config/index.d.ts.map +1 -1
  5. package/dist/config/project-security.d.ts +2 -2
  6. package/dist/config/schema/magic-context.d.ts +36 -3
  7. package/dist/config/schema/magic-context.d.ts.map +1 -1
  8. package/dist/config-init.js +14 -3
  9. package/dist/{context-mrvm92n8.js → context-c72brxe5.js} +2410 -1801
  10. package/dist/{derive-budgets-rjjz5f7y.js → derive-budgets-s1p37t2g.js} +2 -2
  11. package/dist/features/magic-context/compaction-marker.d.ts.map +1 -1
  12. package/dist/features/magic-context/historian-failure-reason.d.ts +7 -0
  13. package/dist/features/magic-context/historian-failure-reason.d.ts.map +1 -0
  14. package/dist/features/magic-context/memory-maintainer/launcher.d.ts +13 -4
  15. package/dist/features/magic-context/memory-maintainer/launcher.d.ts.map +1 -1
  16. package/dist/features/magic-context/memory-maintainer/manual-commands.d.ts.map +1 -1
  17. package/dist/features/magic-context/memory-maintainer/model-chain.d.ts +47 -0
  18. package/dist/features/magic-context/memory-maintainer/model-chain.d.ts.map +1 -0
  19. package/dist/features/magic-context/memory-maintainer/oc2-adapter.d.ts +17 -4
  20. package/dist/features/magic-context/memory-maintainer/oc2-adapter.d.ts.map +1 -1
  21. package/dist/features/magic-context/memory-maintainer/pipeline.d.ts +6 -0
  22. package/dist/features/magic-context/memory-maintainer/pipeline.d.ts.map +1 -1
  23. package/dist/features/magic-context/message-index-async.d.ts +21 -3
  24. package/dist/features/magic-context/message-index-async.d.ts.map +1 -1
  25. package/dist/features/magic-context/message-index.d.ts +7 -1
  26. package/dist/features/magic-context/message-index.d.ts.map +1 -1
  27. package/dist/features/magic-context/migrations.d.ts.map +1 -1
  28. package/dist/features/magic-context/pi-content-decisions.d.ts +7 -1
  29. package/dist/features/magic-context/pi-content-decisions.d.ts.map +1 -1
  30. package/dist/features/magic-context/search.d.ts +29 -0
  31. package/dist/features/magic-context/search.d.ts.map +1 -1
  32. package/dist/features/magic-context/storage-clone.d.ts +2 -0
  33. package/dist/features/magic-context/storage-clone.d.ts.map +1 -1
  34. package/dist/features/magic-context/storage-compartment-history-version.d.ts +4 -0
  35. package/dist/features/magic-context/storage-compartment-history-version.d.ts.map +1 -0
  36. package/dist/features/magic-context/storage-db.d.ts +1 -1
  37. package/dist/features/magic-context/storage-db.d.ts.map +1 -1
  38. package/dist/features/magic-context/storage-historian-runs.d.ts.map +1 -1
  39. package/dist/features/magic-context/storage-meta-persisted.d.ts +23 -5
  40. package/dist/features/magic-context/storage-meta-persisted.d.ts.map +1 -1
  41. package/dist/features/magic-context/storage-meta-session.d.ts +7 -1
  42. package/dist/features/magic-context/storage-meta-session.d.ts.map +1 -1
  43. package/dist/features/magic-context/storage-session-tables.d.ts +5 -1
  44. package/dist/features/magic-context/storage-session-tables.d.ts.map +1 -1
  45. package/dist/features/magic-context/storage-tag-identity-revision.d.ts +50 -0
  46. package/dist/features/magic-context/storage-tag-identity-revision.d.ts.map +1 -0
  47. package/dist/features/magic-context/storage-tags.d.ts +159 -5
  48. package/dist/features/magic-context/storage-tags.d.ts.map +1 -1
  49. package/dist/features/magic-context/tagger.d.ts +2 -0
  50. package/dist/features/magic-context/tagger.d.ts.map +1 -1
  51. package/dist/features/magic-context/transform-decision-log.d.ts +60 -2
  52. package/dist/features/magic-context/transform-decision-log.d.ts.map +1 -1
  53. package/dist/hooks/magic-context/__fixtures__/tail-hygiene-refresh.d.ts +34 -0
  54. package/dist/hooks/magic-context/__fixtures__/tail-hygiene-refresh.d.ts.map +1 -0
  55. package/dist/hooks/magic-context/active-anthropic-turn.d.ts +2 -0
  56. package/dist/hooks/magic-context/active-anthropic-turn.d.ts.map +1 -1
  57. package/dist/hooks/magic-context/apply-operations.d.ts +10 -1
  58. package/dist/hooks/magic-context/apply-operations.d.ts.map +1 -1
  59. package/dist/hooks/magic-context/auto-search-runner.d.ts +2 -2
  60. package/dist/hooks/magic-context/auto-search-runner.d.ts.map +1 -1
  61. package/dist/hooks/magic-context/compartment-runner-types.d.ts +2 -2
  62. package/dist/hooks/magic-context/compartment-runner-types.d.ts.map +1 -1
  63. package/dist/hooks/magic-context/compartment-runner.d.ts +4 -0
  64. package/dist/hooks/magic-context/compartment-runner.d.ts.map +1 -1
  65. package/dist/hooks/magic-context/compartment-trigger-error.d.ts +11 -0
  66. package/dist/hooks/magic-context/compartment-trigger-error.d.ts.map +1 -0
  67. package/dist/hooks/magic-context/compartment-trigger.d.ts +1 -1
  68. package/dist/hooks/magic-context/compartment-trigger.d.ts.map +1 -1
  69. package/dist/hooks/magic-context/ctx-reduce-nudge.d.ts +1 -0
  70. package/dist/hooks/magic-context/ctx-reduce-nudge.d.ts.map +1 -1
  71. package/dist/hooks/magic-context/degraded-pass-refusal.d.ts +2 -0
  72. package/dist/hooks/magic-context/degraded-pass-refusal.d.ts.map +1 -1
  73. package/dist/hooks/magic-context/edit-marker.d.ts +2 -0
  74. package/dist/hooks/magic-context/edit-marker.d.ts.map +1 -1
  75. package/dist/hooks/magic-context/final-wire-token-estimate.d.ts +2 -0
  76. package/dist/hooks/magic-context/final-wire-token-estimate.d.ts.map +1 -1
  77. package/dist/hooks/magic-context/heuristic-cleanup.d.ts.map +1 -1
  78. package/dist/hooks/magic-context/history-boundary-repair.d.ts +11 -2
  79. package/dist/hooks/magic-context/history-boundary-repair.d.ts.map +1 -1
  80. package/dist/hooks/magic-context/hook-handlers.d.ts.map +1 -1
  81. package/dist/hooks/magic-context/lkg-measured-request.d.ts +3 -1
  82. package/dist/hooks/magic-context/lkg-measured-request.d.ts.map +1 -1
  83. package/dist/hooks/magic-context/lkg-persist.d.ts +10 -13
  84. package/dist/hooks/magic-context/lkg-persist.d.ts.map +1 -1
  85. package/dist/hooks/magic-context/lkg-recovery-fence.d.ts +62 -0
  86. package/dist/hooks/magic-context/lkg-recovery-fence.d.ts.map +1 -0
  87. package/dist/hooks/magic-context/lkg-recovery-prefix.d.ts +38 -0
  88. package/dist/hooks/magic-context/lkg-recovery-prefix.d.ts.map +1 -0
  89. package/dist/hooks/magic-context/lkg-replay.d.ts +16 -9
  90. package/dist/hooks/magic-context/lkg-replay.d.ts.map +1 -1
  91. package/dist/hooks/magic-context/lkg-slot.d.ts +141 -2
  92. package/dist/hooks/magic-context/lkg-slot.d.ts.map +1 -1
  93. package/dist/hooks/magic-context/opaque-thinking.d.ts +12 -0
  94. package/dist/hooks/magic-context/opaque-thinking.d.ts.map +1 -0
  95. package/dist/hooks/magic-context/pass-outcome.d.ts +1 -0
  96. package/dist/hooks/magic-context/pass-outcome.d.ts.map +1 -1
  97. package/dist/hooks/magic-context/pending-drop-eligibility.d.ts +14 -0
  98. package/dist/hooks/magic-context/pending-drop-eligibility.d.ts.map +1 -0
  99. package/dist/hooks/magic-context/pending-materialization.d.ts +10 -0
  100. package/dist/hooks/magic-context/pending-materialization.d.ts.map +1 -0
  101. package/dist/hooks/magic-context/postprocess-read-cache.d.ts.map +1 -1
  102. package/dist/hooks/magic-context/provider-visible-parts.d.ts +51 -0
  103. package/dist/hooks/magic-context/provider-visible-parts.d.ts.map +1 -0
  104. package/dist/hooks/magic-context/read-session-chunk.d.ts +22 -1
  105. package/dist/hooks/magic-context/read-session-chunk.d.ts.map +1 -1
  106. package/dist/hooks/magic-context/read-session-db.d.ts +3 -0
  107. package/dist/hooks/magic-context/read-session-db.d.ts.map +1 -1
  108. package/dist/hooks/magic-context/read-session-formatting.d.ts +5 -0
  109. package/dist/hooks/magic-context/read-session-formatting.d.ts.map +1 -1
  110. package/dist/hooks/magic-context/read-session-raw.d.ts +123 -1
  111. package/dist/hooks/magic-context/read-session-raw.d.ts.map +1 -1
  112. package/dist/hooks/magic-context/read-session-true-raw-tokens.d.ts.map +1 -1
  113. package/dist/hooks/magic-context/reasoning-budget.d.ts.map +1 -1
  114. package/dist/hooks/magic-context/render-options.d.ts +19 -0
  115. package/dist/hooks/magic-context/render-options.d.ts.map +1 -0
  116. package/dist/hooks/magic-context/sentinel.d.ts +41 -1
  117. package/dist/hooks/magic-context/sentinel.d.ts.map +1 -1
  118. package/dist/hooks/magic-context/strict-thinking-prefix.d.ts +8 -0
  119. package/dist/hooks/magic-context/strict-thinking-prefix.d.ts.map +1 -0
  120. package/dist/hooks/magic-context/strip-content.d.ts +38 -24
  121. package/dist/hooks/magic-context/strip-content.d.ts.map +1 -1
  122. package/dist/hooks/magic-context/supersession-reclaim.d.ts +5 -3
  123. package/dist/hooks/magic-context/supersession-reclaim.d.ts.map +1 -1
  124. package/dist/hooks/magic-context/system-date-refresh.d.ts +29 -0
  125. package/dist/hooks/magic-context/system-date-refresh.d.ts.map +1 -0
  126. package/dist/hooks/magic-context/system-prompt-dates.d.ts +6 -0
  127. package/dist/hooks/magic-context/system-prompt-dates.d.ts.map +1 -0
  128. package/dist/hooks/magic-context/system-prompt-delivery.d.ts +47 -0
  129. package/dist/hooks/magic-context/system-prompt-delivery.d.ts.map +1 -0
  130. package/dist/hooks/magic-context/system-prompt-hash.d.ts +18 -5
  131. package/dist/hooks/magic-context/system-prompt-hash.d.ts.map +1 -1
  132. package/dist/hooks/magic-context/tag-messages.d.ts +19 -0
  133. package/dist/hooks/magic-context/tag-messages.d.ts.map +1 -1
  134. package/dist/hooks/magic-context/tag-owner-warmup.d.ts +14 -0
  135. package/dist/hooks/magic-context/tag-owner-warmup.d.ts.map +1 -0
  136. package/dist/hooks/magic-context/tail-hygiene-output-count.d.ts +18 -0
  137. package/dist/hooks/magic-context/tail-hygiene-output-count.d.ts.map +1 -0
  138. package/dist/hooks/magic-context/tail-hygiene-walk.d.ts +8 -4
  139. package/dist/hooks/magic-context/tail-hygiene-walk.d.ts.map +1 -1
  140. package/dist/hooks/magic-context/token-count-exact.d.ts +35 -0
  141. package/dist/hooks/magic-context/token-count-exact.d.ts.map +1 -0
  142. package/dist/hooks/magic-context/tool-drop-target.d.ts +2 -0
  143. package/dist/hooks/magic-context/tool-drop-target.d.ts.map +1 -1
  144. package/dist/hooks/magic-context/tool-reclaim.d.ts +5 -2
  145. package/dist/hooks/magic-context/tool-reclaim.d.ts.map +1 -1
  146. package/dist/hooks/magic-context/transform-compartment-phase.d.ts.map +1 -1
  147. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts +9 -0
  148. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts.map +1 -1
  149. package/dist/hooks/magic-context/transform.d.ts +21 -11
  150. package/dist/hooks/magic-context/transform.d.ts.map +1 -1
  151. package/dist/hooks/magic-context/unresolved-history-boundary.d.ts +5 -1
  152. package/dist/hooks/magic-context/unresolved-history-boundary.d.ts.map +1 -1
  153. package/dist/{index-g2z2k5m4.js → index-27ddyx39.js} +2 -2
  154. package/dist/{index-btp5tdc8.js → index-48e9znrc.js} +1248 -570
  155. package/dist/{index-5cep2r9n.js → index-5ty9rnbx.js} +60 -258
  156. package/dist/{index-z2g20msd.js → index-azbmnekv.js} +4 -4
  157. package/dist/{index-1j34a56j.js → index-dwh99z66.js} +293 -36
  158. package/dist/{index-qbkzdkk0.js → index-k59af64t.js} +6 -2
  159. package/dist/{index-5b7x80ec.js → index-kahkxcqw.js} +12532 -10348
  160. package/dist/{index-53g38ggt.js → index-kmbme1v1.js} +1 -1
  161. package/dist/{index-amycb7b1.js → index-r7s7d350.js} +3 -3
  162. package/dist/{index-33gprt9g.js → index-yjv8dpht.js} +1 -1
  163. package/dist/index-ykq24x1n.js +1477 -0
  164. package/dist/index.d.ts.map +1 -1
  165. package/dist/index.js +114 -2
  166. package/dist/{message-time-backfill-phrwp2fz.js → message-time-backfill-j96x1sab.js} +3 -3
  167. package/dist/model-resolution-cvyrrcjw.js +8 -0
  168. package/dist/plugin/rpc-handlers.d.ts.map +1 -1
  169. package/dist/{read-session-chunk-2xm4sc4y.js → read-session-chunk-t8bg6wkz.js} +6 -4
  170. package/dist/recomp-orchestrator-k760qy1n.js +21 -0
  171. package/dist/{safe-notification-target-ph3xd1ve.js → safe-notification-target-1jkf0m82.js} +2 -2
  172. package/dist/{send-session-notification-rnc4nrsr.js → send-session-notification-njjf3b4s.js} +5 -5
  173. package/dist/shared/auto-search-lifecycle.d.ts +14 -0
  174. package/dist/shared/auto-search-lifecycle.d.ts.map +1 -1
  175. package/dist/shared/logger.d.ts.map +1 -1
  176. package/dist/shared/model-suggestion-retry.d.ts +21 -0
  177. package/dist/shared/model-suggestion-retry.d.ts.map +1 -1
  178. package/dist/shared/models-dev-cache.d.ts.map +1 -1
  179. package/dist/shared/models-dev-temperature.d.ts +18 -0
  180. package/dist/shared/models-dev-temperature.d.ts.map +1 -0
  181. package/dist/shared/processed-image-eligibility.d.ts +22 -0
  182. package/dist/shared/processed-image-eligibility.d.ts.map +1 -0
  183. package/dist/shared/project-directory-key.d.ts +16 -0
  184. package/dist/shared/project-directory-key.d.ts.map +1 -1
  185. package/dist/shared/prompt-surface-runtime.d.ts +5 -0
  186. package/dist/shared/prompt-surface-runtime.d.ts.map +1 -1
  187. package/dist/shared/reclaim-distance.d.ts +33 -0
  188. package/dist/shared/reclaim-distance.d.ts.map +1 -0
  189. package/dist/shared/recovery-reasoning-prefix.d.ts +9 -0
  190. package/dist/shared/recovery-reasoning-prefix.d.ts.map +1 -0
  191. package/dist/shared/sqlite.d.ts +35 -1
  192. package/dist/shared/sqlite.d.ts.map +1 -1
  193. package/dist/shared/stable-json.d.ts +7 -0
  194. package/dist/shared/stable-json.d.ts.map +1 -1
  195. package/dist/shared/storage-file-mutex.d.ts +9 -0
  196. package/dist/shared/storage-file-mutex.d.ts.map +1 -0
  197. package/dist/shared/storage-permissions.d.ts +6 -0
  198. package/dist/shared/storage-permissions.d.ts.map +1 -1
  199. package/dist/shared/subagent-temperature.d.ts +46 -0
  200. package/dist/shared/subagent-temperature.d.ts.map +1 -0
  201. package/dist/shared/tag-owner-id.d.ts +1 -0
  202. package/dist/shared/tag-owner-id.d.ts.map +1 -1
  203. package/dist/shared/tag-transcript.d.ts +9 -0
  204. package/dist/shared/tag-transcript.d.ts.map +1 -1
  205. package/dist/shared/tail-hygiene-json.d.ts +22 -0
  206. package/dist/shared/tail-hygiene-json.d.ts.map +1 -0
  207. package/dist/shared/user-facing-codes.d.ts +2 -2
  208. package/dist/shared/window-geometry.d.ts +9 -66
  209. package/dist/shared/window-geometry.d.ts.map +1 -1
  210. package/dist/standalone-plugin-marker.d.ts +8 -0
  211. package/dist/standalone-plugin-marker.d.ts.map +1 -0
  212. package/dist/tools/ctx-expand/search-archive.d.ts +4 -0
  213. package/dist/tools/ctx-expand/search-archive.d.ts.map +1 -0
  214. package/dist/tools/ctx-expand/tools.d.ts.map +1 -1
  215. package/dist/tools/ctx-reduce/constants.d.ts +1 -2
  216. package/dist/tools/ctx-reduce/constants.d.ts.map +1 -1
  217. package/dist/tools/ctx-reduce/tools.d.ts +1 -1
  218. package/dist/tools/ctx-reduce/tools.d.ts.map +1 -1
  219. package/dist/v2/hidden-completion.d.ts +20 -1
  220. package/dist/v2/hidden-completion.d.ts.map +1 -1
  221. package/dist/v2/hooks/context.d.ts +1 -1
  222. package/dist/v2/hooks/context.d.ts.map +1 -1
  223. package/dist/v2/hooks/copied-tag-notation.d.ts +19 -0
  224. package/dist/v2/hooks/copied-tag-notation.d.ts.map +1 -0
  225. package/dist/v2/hooks/generate.d.ts +9 -2
  226. package/dist/v2/hooks/generate.d.ts.map +1 -1
  227. package/dist/v2/hooks/hidden-child.d.ts +22 -1
  228. package/dist/v2/hooks/hidden-child.d.ts.map +1 -1
  229. package/dist/v2/hooks/payload.d.ts.map +1 -1
  230. package/dist/v2/hooks/system-prompt-response.d.ts +5 -0
  231. package/dist/v2/hooks/system-prompt-response.d.ts.map +1 -0
  232. package/dist/v2/server.d.ts.map +1 -1
  233. package/dist/v2/server.js +26593 -21940
  234. package/dist/v2/store-reader.d.ts +27 -1
  235. package/dist/v2/store-reader.d.ts.map +1 -1
  236. package/dist/web/main.js +401 -23
  237. package/dist/{wrapup-orchestrator-yknks3ad.js → wrapup-orchestrator-b2gswatj.js} +10 -10
  238. package/package.json +1 -1
  239. package/src/config/deprecated-config.ts +18 -0
  240. package/src/config/index.test.ts +13 -37
  241. package/src/config/index.ts +2 -2
  242. package/src/config/latch-permanence-guard.test.ts +4 -0
  243. package/src/config/project-security.test.ts +17 -0
  244. package/src/config/project-security.ts +3 -3
  245. package/src/config/schema/magic-context.test.ts +50 -0
  246. package/src/config/schema/magic-context.ts +44 -7
  247. package/src/shared/auto-search-lifecycle.ts +43 -0
  248. package/src/shared/logger.ts +10 -2
  249. package/src/shared/model-suggestion-retry.ts +5 -1
  250. package/src/shared/models-dev-cache.ts +1 -7
  251. package/src/shared/models-dev-temperature.ts +107 -0
  252. package/src/shared/processed-image-eligibility.test.ts +68 -0
  253. package/src/shared/processed-image-eligibility.ts +41 -0
  254. package/src/shared/processed-image-position-review.json +20 -0
  255. package/src/shared/processed-image-position-review.test.ts +19 -0
  256. package/src/shared/project-directory-key.ts +20 -0
  257. package/src/shared/prompt-surface-runtime.ts +12 -0
  258. package/src/shared/reclaim-distance.test.ts +111 -0
  259. package/src/shared/reclaim-distance.ts +91 -0
  260. package/src/shared/recovery-reasoning-prefix.test.ts +34 -0
  261. package/src/shared/recovery-reasoning-prefix.ts +35 -0
  262. package/src/shared/root-async-context.probe.mjs +36 -0
  263. package/src/shared/root-async-context.test.ts +49 -0
  264. package/src/shared/sqlite-acquisition-routing.test.ts +4 -3
  265. package/src/shared/sqlite-busy-budget-review.test.ts +291 -0
  266. package/src/shared/sqlite-foreground-wait.test.ts +304 -0
  267. package/src/shared/sqlite-pass-scope.test.ts +4 -4
  268. package/src/shared/sqlite-writer-diagnostics.test.ts +52 -12
  269. package/src/shared/sqlite.ts +428 -46
  270. package/src/shared/stable-json.ts +79 -7
  271. package/src/shared/storage-file-mutex.test.ts +50 -0
  272. package/src/shared/storage-file-mutex.ts +130 -0
  273. package/src/shared/storage-permissions.ts +46 -0
  274. package/src/shared/subagent-temperature.ts +110 -0
  275. package/src/shared/tag-owner-id.ts +13 -0
  276. package/src/shared/tag-transcript.ts +118 -0
  277. package/src/shared/tail-hygiene-json.test.ts +117 -0
  278. package/src/shared/tail-hygiene-json.ts +217 -0
  279. package/src/shared/user-facing-codes.ts +2 -2
  280. package/src/shared/window-geometry.test.ts +102 -236
  281. package/src/shared/window-geometry.ts +23 -413
  282. package/dist/index-ramz5kkm.js +0 -514
  283. package/dist/model-resolution-wazv26n0.js +0 -6
  284. package/dist/recomp-orchestrator-frmwj9hz.js +0 -21
  285. package/src/shared/__fixtures__/window-overlay.v1.json +0 -337
@@ -5,17 +5,30 @@ import {
5
5
  hasMeasuredDecisionCalibration,
6
6
  providerMass
7
7
  } from "./index-x37vg474.js";
8
+ import {
9
+ getTagIdentityWriteGeneration
10
+ } from "./index-dwh99z66.js";
8
11
  import {
9
12
  getHarness,
10
13
  sessionLog
11
- } from "./index-qbkzdkk0.js";
14
+ } from "./index-k59af64t.js";
12
15
  import {
13
16
  isKnownAutocommit,
17
+ readRawSessionMessagesFromDb,
18
+ readRawSessionMessagePageFromDb,
19
+ readRawSessionMessageSummaryPageFromDb,
20
+ countRawSessionMessageOrdinalsFromDb,
21
+ readRawSessionMessageIdOrdinalsForRangeFromDb,
22
+ readRawSessionTailFromDb,
23
+ warmRawSessionOrdinalsForDb,
24
+ readRawSessionMessageOrdinalByIdFromDb,
25
+ readRawSessionMessageByIdFromDb,
26
+ hasRawSessionMessageByIdFromDb,
14
27
  openCodeDbExists,
15
28
  withReadOnlySessionDb,
16
29
  getRawSessionMessageCountFromDb,
17
30
  getMessageTimesFromOpenCodeDb
18
- } from "./index-ramz5kkm.js";
31
+ } from "./index-ykq24x1n.js";
19
32
 
20
33
  // src/shared/protected-tools-policy.ts
21
34
  var DEFAULT_PROTECTED_TOOLS = {
@@ -67,7 +80,7 @@ import { existsSync, readFileSync, realpathSync, statSync } from "node:fs";
67
80
  import { createRequire } from "node:module";
68
81
  import { homedir } from "node:os";
69
82
  import { dirname, join, resolve } from "node:path";
70
- import { pathToFileURL } from "node:url";
83
+ import { fileURLToPath, pathToFileURL } from "node:url";
71
84
 
72
85
  // src/shared/commit-detection.ts
73
86
  var HASH_HEX = "[0-9a-f]{7,12}";
@@ -92,6 +105,272 @@ function removeSystemReminders(text) {
92
105
  return text.replace(/<system-reminder>[\s\S]*?<\/system-reminder>/gi, "").trim();
93
106
  }
94
107
 
108
+ // src/hooks/magic-context/token-count-exact.ts
109
+ var NO_RANK = 4294967295;
110
+ var LONG_PIECE_BYTES = 256;
111
+ var MERGE_CACHE_GENERATION = 50000;
112
+ function hasInternals(tokenizer) {
113
+ const value = tokenizer;
114
+ return !!value && value.patternRegex instanceof RegExp && value.patternRegex.global && typeof value.stringRankEncoder === "object" && value.stringRankEncoder !== null && Array.isArray(value.binaryFirstByteIndex);
115
+ }
116
+ var textEncoder = new TextEncoder;
117
+ var textDecoder = new TextDecoder("utf-8");
118
+ function isValidUtf8(bytes) {
119
+ let index = 0;
120
+ while (index < bytes.length) {
121
+ const first = bytes[index];
122
+ let size = 0;
123
+ let codePoint = 0;
124
+ if (first <= 127) {
125
+ size = 1;
126
+ codePoint = first;
127
+ } else if ((first & 224) === 192) {
128
+ size = 2;
129
+ codePoint = first & 31;
130
+ if (first <= 193)
131
+ return false;
132
+ } else if ((first & 240) === 224) {
133
+ size = 3;
134
+ codePoint = first & 15;
135
+ } else if ((first & 248) === 240) {
136
+ size = 4;
137
+ codePoint = first & 7;
138
+ if (first > 244)
139
+ return false;
140
+ } else
141
+ return false;
142
+ if (index + size > bytes.length)
143
+ return false;
144
+ for (let offset = 1;offset < size; offset += 1) {
145
+ const byte = bytes[index + offset];
146
+ if ((byte & 192) !== 128)
147
+ return false;
148
+ codePoint = codePoint << 6 | byte & 63;
149
+ }
150
+ if (size === 2 && codePoint < 128)
151
+ return false;
152
+ if (size === 3 && codePoint < 2048)
153
+ return false;
154
+ if (size === 4 && codePoint < 65536)
155
+ return false;
156
+ if (codePoint >= 55296 && codePoint <= 57343)
157
+ return false;
158
+ if (codePoint > 1114111)
159
+ return false;
160
+ index += size;
161
+ }
162
+ return true;
163
+ }
164
+ function binarySearchBytes(sorted, key) {
165
+ let low = 0;
166
+ let high = sorted.length - 1;
167
+ while (low <= high) {
168
+ const mid = low + high >>> 1;
169
+ const midKey = sorted[mid][0];
170
+ let compare = 0;
171
+ const shared = Math.min(midKey.length, key.length);
172
+ for (let index = 0;index < shared; index += 1) {
173
+ compare = midKey[index] - key[index];
174
+ if (compare !== 0)
175
+ break;
176
+ }
177
+ if (compare === 0)
178
+ compare = midKey.length - key.length;
179
+ if (compare === 0)
180
+ return sorted[mid][1];
181
+ if (compare < 0)
182
+ low = mid + 1;
183
+ else
184
+ high = mid - 1;
185
+ }
186
+ return -1;
187
+ }
188
+ function rankOf(tokenizer, slice) {
189
+ if (isValidUtf8(slice)) {
190
+ const rank = tokenizer.stringRankEncoder[textDecoder.decode(slice)];
191
+ if (rank !== undefined)
192
+ return rank;
193
+ }
194
+ const bucket = tokenizer.binaryFirstByteIndex[slice[0]];
195
+ if (bucket !== null && bucket !== undefined) {
196
+ const rank = binarySearchBytes(bucket, slice);
197
+ if (rank !== -1)
198
+ return rank;
199
+ }
200
+ return NO_RANK;
201
+ }
202
+ function mergeByScanning(tokenizer, bytes) {
203
+ const starts = [];
204
+ const ranks = [];
205
+ const pairRank = (index) => {
206
+ const end = starts[index + 2];
207
+ return end === undefined ? NO_RANK : rankOf(tokenizer, bytes.subarray(starts[index], end));
208
+ };
209
+ for (let index = 0;index <= bytes.length; index += 1)
210
+ starts.push(index);
211
+ for (let index = 0;index < starts.length; index += 1)
212
+ ranks.push(pairRank(index));
213
+ while (starts.length > 1) {
214
+ let minRank = NO_RANK;
215
+ let minIndex = -1;
216
+ for (let index = 0;index < ranks.length - 1; index += 1) {
217
+ if (ranks[index] < minRank) {
218
+ minRank = ranks[index];
219
+ minIndex = index;
220
+ }
221
+ }
222
+ if (minIndex === -1)
223
+ break;
224
+ starts.splice(minIndex + 1, 1);
225
+ ranks.splice(minIndex, 1);
226
+ ranks[minIndex] = pairRank(minIndex);
227
+ if (minIndex > 0)
228
+ ranks[minIndex - 1] = pairRank(minIndex - 1);
229
+ }
230
+ const tokens = [];
231
+ for (let index = 0;index < starts.length - 1; index += 1) {
232
+ const rank = rankOf(tokenizer, bytes.subarray(starts[index], starts[index + 1]));
233
+ if (rank !== NO_RANK)
234
+ tokens.push(rank);
235
+ }
236
+ return tokens;
237
+ }
238
+ function mergeWithHeap(tokenizer, bytes) {
239
+ const length = bytes.length;
240
+ const next = new Int32Array(length + 1);
241
+ const prev = new Int32Array(length + 1);
242
+ const alive = new Uint8Array(length + 1).fill(1);
243
+ const rank = new Float64Array(length + 1).fill(NO_RANK);
244
+ for (let index = 0;index <= length; index += 1) {
245
+ next[index] = index + 1;
246
+ prev[index] = index - 1;
247
+ }
248
+ const heapRank = [];
249
+ const heapAt = [];
250
+ const less = (a, b) => heapRank[a] < heapRank[b] || heapRank[a] === heapRank[b] && heapAt[a] < heapAt[b];
251
+ const swap = (a, b) => {
252
+ [heapRank[a], heapRank[b]] = [heapRank[b], heapRank[a]];
253
+ [heapAt[a], heapAt[b]] = [heapAt[b], heapAt[a]];
254
+ };
255
+ const push = (value, at) => {
256
+ heapRank.push(value);
257
+ heapAt.push(at);
258
+ let child = heapRank.length - 1;
259
+ while (child > 0) {
260
+ const parent = child - 1 >> 1;
261
+ if (!less(child, parent))
262
+ break;
263
+ swap(child, parent);
264
+ child = parent;
265
+ }
266
+ };
267
+ const pop = () => {
268
+ const last = heapRank.length - 1;
269
+ swap(0, last);
270
+ heapRank.pop();
271
+ heapAt.pop();
272
+ let parent = 0;
273
+ for (;; ) {
274
+ const left = parent * 2 + 1;
275
+ const right = left + 1;
276
+ let smallest = parent;
277
+ if (left < heapRank.length && less(left, smallest))
278
+ smallest = left;
279
+ if (right < heapRank.length && less(right, smallest))
280
+ smallest = right;
281
+ if (smallest === parent)
282
+ break;
283
+ swap(parent, smallest);
284
+ parent = smallest;
285
+ }
286
+ };
287
+ const pairRank = (at) => {
288
+ const middle = next[at];
289
+ if (middle >= length)
290
+ return NO_RANK;
291
+ return rankOf(tokenizer, bytes.subarray(at, next[middle]));
292
+ };
293
+ const update = (at) => {
294
+ rank[at] = pairRank(at);
295
+ if (rank[at] !== NO_RANK)
296
+ push(rank[at], at);
297
+ };
298
+ for (let at = 0;at < length; at += 1)
299
+ update(at);
300
+ while (heapRank.length > 0) {
301
+ const value = heapRank[0];
302
+ const at = heapAt[0];
303
+ pop();
304
+ if (!alive[at] || rank[at] !== value)
305
+ continue;
306
+ const removed = next[at];
307
+ alive[removed] = 0;
308
+ next[at] = next[removed];
309
+ prev[next[removed]] = at;
310
+ update(at);
311
+ if (at > 0)
312
+ update(prev[at]);
313
+ }
314
+ const tokens = [];
315
+ for (let at = 0;at < length; at = next[at]) {
316
+ const value = rankOf(tokenizer, bytes.subarray(at, next[at]));
317
+ if (value !== NO_RANK)
318
+ tokens.push(value);
319
+ }
320
+ return tokens;
321
+ }
322
+ var mergeCaches = new WeakMap;
323
+ var mergedPieces = 0;
324
+ function mergePiece(tokenizer, piece) {
325
+ let cache = mergeCaches.get(tokenizer);
326
+ if (!cache) {
327
+ cache = { current: new Map, previous: new Map };
328
+ mergeCaches.set(tokenizer, cache);
329
+ }
330
+ let tokens = cache.current.get(piece);
331
+ if (tokens)
332
+ return tokens;
333
+ tokens = cache.previous.get(piece);
334
+ if (!tokens) {
335
+ const bytes = textEncoder.encode(piece);
336
+ mergedPieces += 1;
337
+ tokens = bytes.length > LONG_PIECE_BYTES ? mergeWithHeap(tokenizer, bytes) : mergeByScanning(tokenizer, bytes);
338
+ }
339
+ if (cache.current.size >= MERGE_CACHE_GENERATION) {
340
+ cache.previous = cache.current;
341
+ cache.current = new Map;
342
+ }
343
+ cache.current.set(piece, tokens);
344
+ return tokens;
345
+ }
346
+ function encodeTokensExactly(tokenizer, text) {
347
+ if (!hasInternals(tokenizer)) {
348
+ return tokenizer.encode(text, "all");
349
+ }
350
+ if (text.length < 10) {
351
+ const direct = tokenizer.stringRankEncoder[text];
352
+ if (direct !== undefined)
353
+ return [direct];
354
+ }
355
+ const tokens = [];
356
+ const regex = tokenizer.patternRegex;
357
+ regex.lastIndex = 0;
358
+ for (let match = regex.exec(text);match !== null; match = regex.exec(text)) {
359
+ const piece = match[0];
360
+ const direct = tokenizer.stringRankEncoder[piece];
361
+ if (direct !== undefined) {
362
+ tokens.push(direct);
363
+ continue;
364
+ }
365
+ for (const token of mergePiece(tokenizer, piece))
366
+ tokens.push(token);
367
+ }
368
+ return tokens;
369
+ }
370
+ function countTokensExactly(tokenizer, text) {
371
+ return encodeTokensExactly(tokenizer, text).length;
372
+ }
373
+
95
374
  // src/hooks/magic-context/read-session-formatting.ts
96
375
  var MAX_COMMITS_PER_BLOCK = 5;
97
376
  function hasMeaningfulUserText2(parts) {
@@ -204,22 +483,30 @@ var tokenizerSerializedTableBytes;
204
483
  function tokenizerPackageRoots() {
205
484
  const cwd = process.cwd();
206
485
  const openCodeCache = join(process.env.XDG_CACHE_HOME ?? join(homedir(), ".cache"), "opencode");
207
- const roots = [cwd, openCodeCache];
208
486
  const candidates = [];
209
- for (const root of roots) {
487
+ const probeRoot = (root) => {
210
488
  for (const packageDir of TOKENIZER_PACKAGE_DIRS) {
211
489
  candidates.push(join(root, "node_modules", ...packageDir, "node_modules", "ai-tokenizer"));
212
490
  }
213
491
  candidates.push(join(root, "node_modules", "ai-tokenizer"));
492
+ };
493
+ for (const root of [cwd, openCodeCache]) {
494
+ probeRoot(root);
214
495
  }
215
- let ancestor = process.argv[1] ? dirname(resolve(process.argv[1])) : cwd;
216
- while (true) {
217
- candidates.push(join(ancestor, "node_modules", "ai-tokenizer"));
218
- const parent = dirname(ancestor);
219
- if (parent === ancestor)
220
- break;
221
- ancestor = parent;
222
- }
496
+ const pushAncestors = (startDir) => {
497
+ let ancestor = startDir;
498
+ while (true) {
499
+ candidates.push(join(ancestor, "node_modules", "ai-tokenizer"));
500
+ const parent = dirname(ancestor);
501
+ if (parent === ancestor)
502
+ break;
503
+ ancestor = parent;
504
+ }
505
+ };
506
+ pushAncestors(process.argv[1] ? dirname(resolve(process.argv[1])) : cwd);
507
+ const ownDir = dirname(fileURLToPath(new URL(import.meta.url)));
508
+ pushAncestors(ownDir);
509
+ probeRoot(join(homedir(), ".omp", "plugins"));
223
510
  return [...new Set(candidates)];
224
511
  }
225
512
  function packageImportTarget(value) {
@@ -379,7 +666,7 @@ function estimateTokens(text) {
379
666
  if (!activeTokenizer)
380
667
  return estimateTokensHeuristically(text);
381
668
  try {
382
- return activeTokenizer.encode(text, "all").length;
669
+ return countTokensExactly(activeTokenizer, text);
383
670
  } catch (error) {
384
671
  tokenizer = undefined;
385
672
  tokenizerLoadAttempted = true;
@@ -500,10 +787,34 @@ function mergeCommitHashes(existing, next) {
500
787
  var encoder = new TextEncoder;
501
788
  var TAG_PREFIX_REGEX = /^(?:§\d+§\s*)+/;
502
789
  var MALFORMED_TAG_PREFIX_REGEX = /^(?:§\d+">§(?:\d+§)?\s*)+/;
790
+ var DANGLING_TAG_GLOBAL_REGEX = /\u00a7\d+(?!\.\d)[^\s\u00a7\w.]?/g;
503
791
  var DANGLING_TAG_PREFIX_REGEX = /^(?:\u00a7\d+(?!\.\d)[^\s\u00a7\w.]?\s*)+/;
792
+ var COMPLETE_TAG_PAIR_GLOBAL_REGEX = /\u00a7\d+\u00a7/g;
793
+ var MALFORMED_TAG_GLOBAL_REGEX = /\u00a7\d+">(?:\u00a7(?:\d+\u00a7)?)?/g;
794
+ var STRAY_SECTION_CHAR_REGEX = /\u00a7/g;
504
795
  function stripWellFormedLeadingTagPrefix(value) {
505
796
  return value.replace(/^(\u00a7\d+\u00a7\s*)+/, "");
506
797
  }
798
+ function stripCompleteTagPairsGlobally(value) {
799
+ return value.replace(COMPLETE_TAG_PAIR_GLOBAL_REGEX, "");
800
+ }
801
+ function stripMalformedTagNotationGlobally(value) {
802
+ return value.replace(MALFORMED_TAG_GLOBAL_REGEX, "");
803
+ }
804
+ function stripDanglingTagNotationGlobally(value) {
805
+ return value.replace(DANGLING_TAG_GLOBAL_REGEX, "");
806
+ }
807
+ function stripTagSectionCharacters(value) {
808
+ return value.replace(STRAY_SECTION_CHAR_REGEX, "");
809
+ }
810
+ function stripPersistedAssistantText(value) {
811
+ let text = stripWellFormedLeadingTagPrefix(value);
812
+ text = stripCompleteTagPairsGlobally(text);
813
+ text = stripMalformedTagNotationGlobally(text);
814
+ text = stripDanglingTagNotationGlobally(text);
815
+ text = stripTagSectionCharacters(text);
816
+ return text.trim();
817
+ }
507
818
  function byteSize(value) {
508
819
  return encoder.encode(value).length;
509
820
  }
@@ -536,6 +847,21 @@ function isThinkingPart(part) {
536
847
  return candidate.type === "thinking" || candidate.type === "reasoning";
537
848
  }
538
849
 
850
+ // src/hooks/magic-context/tail-hygiene-output-count.ts
851
+ var CURRENT_OUTPUT_COUNT = Symbol.for("magic-context.current-reclaimable-tool-output-count");
852
+ function countReclaimableToolOutputs(parts) {
853
+ return parts.filter((part) => part.kind === "toolOutput" && part.uTokens > 0).length;
854
+ }
855
+ function rememberCurrentToolOutputCount(baseline, measurement) {
856
+ return Object.assign(baseline, {
857
+ [CURRENT_OUTPUT_COUNT]: countReclaimableToolOutputs(measurement.parts)
858
+ });
859
+ }
860
+ function currentReclaimableToolOutputCount(baseline) {
861
+ if (!baseline || !Object.hasOwn(baseline, CURRENT_OUTPUT_COUNT))
862
+ return 0;
863
+ return baseline[CURRENT_OUTPUT_COUNT];
864
+ }
539
865
  // src/shared/record-type-guard.ts
540
866
  function isRecord(value) {
541
867
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -543,15 +869,34 @@ function isRecord(value) {
543
869
 
544
870
  // src/shared/stable-json.ts
545
871
  function stableStringify(value, seen = new WeakSet) {
546
- if (value === undefined)
547
- return "undefined";
548
- if (value === null || typeof value !== "object")
549
- return JSON.stringify(value) ?? String(value);
550
- if (seen.has(value))
551
- return '"[Circular]"';
872
+ const pieces = [];
873
+ writeStable(value, seen, (piece) => pieces.push(piece));
874
+ return pieces.join("");
875
+ }
876
+ function writeStable(value, seen, write) {
877
+ if (value === undefined) {
878
+ write("undefined");
879
+ return;
880
+ }
881
+ if (value === null || typeof value !== "object") {
882
+ write(JSON.stringify(value) ?? String(value));
883
+ return;
884
+ }
885
+ if (seen.has(value)) {
886
+ write('"[Circular]"');
887
+ return;
888
+ }
552
889
  seen.add(value);
553
890
  if (Array.isArray(value)) {
554
- return `[${value.map((item) => stableStringify(item, seen)).join(",")}]`;
891
+ write("[");
892
+ for (let index = 0;index < value.length; index += 1) {
893
+ if (index > 0)
894
+ write(",");
895
+ if (index in value)
896
+ writeStable(value[index], seen, write);
897
+ }
898
+ write("]");
899
+ return;
555
900
  }
556
901
  const entries = Object.entries(value).sort(([a], [b]) => {
557
902
  if (a < b)
@@ -560,10 +905,38 @@ function stableStringify(value, seen = new WeakSet) {
560
905
  return 1;
561
906
  return 0;
562
907
  });
563
- return `{${entries.map(([key, child]) => `${JSON.stringify(key)}:${stableStringify(child, seen)}`).join(",")}}`;
908
+ if (entries.length > 0 && entries.length <= 16 && entries.every(([key, child]) => key.length <= 4096 && !/^(0|[1-9]\d*)$/.test(key) && (child === null || typeof child === "number" || typeof child === "boolean" || typeof child === "string" && child.length <= 4096))) {
909
+ write(JSON.stringify(Object.fromEntries(entries)));
910
+ return;
911
+ }
912
+ write("{");
913
+ entries.forEach(([key, child], index) => {
914
+ if (index > 0)
915
+ write(",");
916
+ write(JSON.stringify(key));
917
+ write(":");
918
+ writeStable(child, seen, write);
919
+ });
920
+ write("}");
921
+ }
922
+ function stableStringifyHash(value, prefix = "") {
923
+ const sink = jsonHashSink(prefix);
924
+ writeStable(value, new WeakSet, sink.write);
925
+ return sink.digest();
926
+ }
927
+ function jsonHashSink(prefix = "") {
928
+ let hash = 2166136261;
929
+ const write = (piece) => {
930
+ for (let index = 0;index < piece.length; index++) {
931
+ hash = Math.imul(hash ^ piece.charCodeAt(index), 16777619);
932
+ }
933
+ };
934
+ write(prefix);
935
+ return { write, digest: () => (hash >>> 0).toString(16).padStart(8, "0") };
564
936
  }
565
937
 
566
938
  // src/shared/tag-owner-id.ts
939
+ var PI_FALLBACK_PREFIXES_JSON = JSON.stringify([..."pi-msg-"].reduce((prefixes, char) => prefixes.flatMap((prefix) => /[a-z]/.test(char) ? [prefix + char, prefix + char.toUpperCase()] : [prefix + char]), [""]));
567
940
  var POSITIONAL_CONTENT_SUFFIX = /:(?:p|file)\d+$/;
568
941
  var CONTENT_DERIVED_TEXT_SUFFIX = /:mc-text-v1:[0-9a-f]+:[0-9a-f]+:o\d+$/;
569
942
  function contentTagOwnerMessageId(contentId) {
@@ -576,6 +949,127 @@ function contentTagOwnerMessageId(contentId) {
576
949
  return contentId;
577
950
  }
578
951
 
952
+ // src/shared/tail-hygiene-json.ts
953
+ var MAX_MEMO_BYTES = 64 * 1024 * 1024;
954
+ var MAX_MEMO_ENTRIES = 1e4;
955
+
956
+ class TailHygieneJsonMemo {
957
+ entries = new Map;
958
+ bytes = 0;
959
+ passText = new WeakMap;
960
+ passHash = new WeakMap;
961
+ beginPass() {
962
+ this.passText = new WeakMap;
963
+ this.passHash = new WeakMap;
964
+ }
965
+ get(key, value, compute, fingerprint = false) {
966
+ const pass = fingerprint ? this.passHash : this.passText;
967
+ const object = value !== null && typeof value === "object" ? value : undefined;
968
+ const local = object ? pass.get(object) : undefined;
969
+ if (local !== undefined)
970
+ return local;
971
+ const previous = this.entries.get(key);
972
+ if (previous && sameJson(previous.snapshot, value)) {
973
+ if (object)
974
+ pass.set(object, previous.result);
975
+ return previous.result;
976
+ }
977
+ const result = compute();
978
+ if (previous) {
979
+ this.bytes -= previous.bytes;
980
+ this.entries.delete(key);
981
+ }
982
+ try {
983
+ const copy = copyJson(value);
984
+ const bytes = copy.bytes + (key.length + result.length) * 2;
985
+ if (bytes <= MAX_MEMO_BYTES) {
986
+ this.entries.set(key, { snapshot: copy.value, result, bytes });
987
+ this.bytes += bytes;
988
+ if (object)
989
+ pass.set(object, result);
990
+ }
991
+ } catch {}
992
+ while (this.bytes > MAX_MEMO_BYTES || this.entries.size > MAX_MEMO_ENTRIES) {
993
+ const oldest = this.entries.entries().next().value;
994
+ if (!oldest)
995
+ break;
996
+ this.bytes -= oldest[1].bytes;
997
+ this.entries.delete(oldest[0]);
998
+ }
999
+ return result;
1000
+ }
1001
+ }
1002
+ function copyJson(value) {
1003
+ const seen = new Map;
1004
+ let bytes = 0;
1005
+ const copy = (current) => {
1006
+ bytes += 16;
1007
+ if (typeof current === "string")
1008
+ bytes += current.length * 2;
1009
+ if (bytes > MAX_MEMO_BYTES)
1010
+ throw new Error("memo capacity");
1011
+ if (current === null || typeof current !== "object") {
1012
+ if (["function", "symbol", "bigint"].includes(typeof current))
1013
+ throw new Error("exotic");
1014
+ return current;
1015
+ }
1016
+ if (seen.has(current))
1017
+ return seen.get(current);
1018
+ const prototype = Object.getPrototypeOf(current);
1019
+ if (!Array.isArray(current) && prototype !== Object.prototype && prototype !== null)
1020
+ throw new Error("exotic");
1021
+ const result = Array.isArray(current) ? new Array(current.length) : Object.create(prototype);
1022
+ seen.set(current, result);
1023
+ for (const key of Object.keys(current)) {
1024
+ const descriptor = Object.getOwnPropertyDescriptor(current, key);
1025
+ if (!descriptor || !("value" in descriptor))
1026
+ throw new Error("accessor");
1027
+ bytes += key.length * 2 + 16;
1028
+ if (key === "__proto__") {
1029
+ Object.defineProperty(result, key, {
1030
+ value: copy(descriptor.value),
1031
+ enumerable: true,
1032
+ writable: true,
1033
+ configurable: true
1034
+ });
1035
+ } else
1036
+ result[key] = copy(descriptor.value);
1037
+ }
1038
+ return result;
1039
+ };
1040
+ return { value: copy(value), bytes };
1041
+ }
1042
+ function sameJson(before, after) {
1043
+ const forward = new Map;
1044
+ const reverse = new Set;
1045
+ const same = (left, right) => {
1046
+ if (left === null || right === null || typeof left !== "object" || typeof right !== "object")
1047
+ return Object.is(left, right);
1048
+ if (forward.has(left))
1049
+ return forward.get(left) === right;
1050
+ if (reverse.has(right) || Object.getPrototypeOf(left) !== Object.getPrototypeOf(right))
1051
+ return false;
1052
+ forward.set(left, right);
1053
+ reverse.add(right);
1054
+ if (Array.isArray(left) && (!Array.isArray(right) || left.length !== right.length))
1055
+ return false;
1056
+ const keys = Object.keys(left);
1057
+ const otherKeys = Object.keys(right);
1058
+ if (keys.length !== otherKeys.length)
1059
+ return false;
1060
+ for (let index = 0;index < keys.length; index++) {
1061
+ const key = keys[index];
1062
+ if (key !== otherKeys[index])
1063
+ return false;
1064
+ const descriptor = Object.getOwnPropertyDescriptor(right, key);
1065
+ if (!descriptor || !("value" in descriptor) || !same(left[key], descriptor.value))
1066
+ return false;
1067
+ }
1068
+ return true;
1069
+ };
1070
+ return same(before, after);
1071
+ }
1072
+
579
1073
  // src/hooks/magic-context/image-token-estimate.ts
580
1074
  var IMAGE_TOKEN_DIVISOR = 750;
581
1075
  var IMAGE_FALLBACK_TOKENS = 1200;
@@ -768,6 +1262,151 @@ function readUint32BE(b, offset) {
768
1262
  return (b[offset] << 24 | b[offset + 1] << 16 | b[offset + 2] << 8 | b[offset + 3]) >>> 0;
769
1263
  }
770
1264
 
1265
+ // src/hooks/magic-context/provider-visible-parts.ts
1266
+ function isRecord2(value) {
1267
+ return value !== null && typeof value === "object" && !Array.isArray(value);
1268
+ }
1269
+ var KEPT_TOOL_STATE_FIELDS = new Set([
1270
+ "status",
1271
+ "input",
1272
+ "output",
1273
+ "error",
1274
+ "attachments",
1275
+ "content"
1276
+ ]);
1277
+ var KEPT_TOOL_STATE_TIME_FIELD = "compacted";
1278
+ function tailProviderVisibleToolState(state, openCode1) {
1279
+ const view = {};
1280
+ for (const key of Object.keys(state)) {
1281
+ if (tailToolStateFieldIsKept(key, openCode1)) {
1282
+ view[key] = state[key];
1283
+ } else if (key === "time" && openCode1) {
1284
+ const value = state.time;
1285
+ if (isRecord2(value)) {
1286
+ view.time = value[KEPT_TOOL_STATE_TIME_FIELD] === undefined ? {} : { [KEPT_TOOL_STATE_TIME_FIELD]: value[KEPT_TOOL_STATE_TIME_FIELD] };
1287
+ }
1288
+ } else if (key === "metadata" && openCode1 && state.status === "error") {
1289
+ const metadata = state.metadata;
1290
+ if (isRecord2(metadata) && metadata.interrupted === true) {
1291
+ const output = metadata.output;
1292
+ if (typeof output === "string")
1293
+ view.metadata = { interrupted: true, output };
1294
+ }
1295
+ }
1296
+ }
1297
+ return view;
1298
+ }
1299
+ function tailToolStateFieldIsKept(key, openCode1) {
1300
+ return KEPT_TOOL_STATE_FIELDS.has(key) && (key !== "content" || !openCode1);
1301
+ }
1302
+ function tailToolStateIsReduced(state, openCode1) {
1303
+ for (const key of Object.keys(state)) {
1304
+ if (tailToolStateFieldIsKept(key, openCode1))
1305
+ continue;
1306
+ return false;
1307
+ }
1308
+ return true;
1309
+ }
1310
+ function providerVisiblePart(part) {
1311
+ if (!isRecord2(part) || part.type !== "tool" || !isRecord2(part.state))
1312
+ return part;
1313
+ if (toolStateIsReduced(part.state))
1314
+ return part;
1315
+ return { ...part, state: providerVisibleToolState(part.state) };
1316
+ }
1317
+ function providerVisiblePartForTailHygiene(part) {
1318
+ return providerVisiblePartForHost(part, true);
1319
+ }
1320
+ function providerVisiblePartForOpenCode2(part) {
1321
+ return providerVisiblePartForHost(part, false);
1322
+ }
1323
+ function providerVisiblePartForHost(part, openCode1) {
1324
+ if (!isRecord2(part))
1325
+ return part;
1326
+ if (part.type !== "tool") {
1327
+ if (!Object.hasOwn(part, "state"))
1328
+ return part;
1329
+ const view = {};
1330
+ for (const key of Object.keys(part)) {
1331
+ if (key !== "state")
1332
+ view[key] = part[key];
1333
+ }
1334
+ return view;
1335
+ }
1336
+ if (!isRecord2(part.state))
1337
+ return part;
1338
+ if (tailToolStateIsReduced(part.state, openCode1))
1339
+ return part;
1340
+ return { ...part, state: tailProviderVisibleToolState(part.state, openCode1) };
1341
+ }
1342
+ var KEPT_ERROR_METADATA_FIELDS = ["interrupted", "output"];
1343
+ function providerVisibleToolState(state) {
1344
+ const view = {};
1345
+ for (const key of Object.keys(state)) {
1346
+ const value = state[key];
1347
+ if (KEPT_TOOL_STATE_FIELDS.has(key)) {
1348
+ view[key] = value;
1349
+ } else if (key === "time" && isRecord2(value)) {
1350
+ view.time = value[KEPT_TOOL_STATE_TIME_FIELD] === undefined ? {} : { [KEPT_TOOL_STATE_TIME_FIELD]: value[KEPT_TOOL_STATE_TIME_FIELD] };
1351
+ } else if (key === "metadata" && state.status === "error" && isRecord2(value)) {
1352
+ const kept = {};
1353
+ for (const field of KEPT_ERROR_METADATA_FIELDS) {
1354
+ if (Object.hasOwn(value, field))
1355
+ kept[field] = value[field];
1356
+ }
1357
+ view.metadata = kept;
1358
+ }
1359
+ }
1360
+ return view;
1361
+ }
1362
+ function toolStateIsReduced(state) {
1363
+ for (const key of Object.keys(state)) {
1364
+ if (KEPT_TOOL_STATE_FIELDS.has(key))
1365
+ continue;
1366
+ const value = state[key];
1367
+ if (key === "time" && isRecord2(value)) {
1368
+ const keys = Object.keys(value);
1369
+ if (keys.length === 0)
1370
+ continue;
1371
+ if (keys.length === 1 && keys[0] === KEPT_TOOL_STATE_TIME_FIELD)
1372
+ continue;
1373
+ return false;
1374
+ }
1375
+ if (key === "metadata" && state.status === "error" && isRecord2(value)) {
1376
+ const extra = Object.keys(value).some((field) => !KEPT_ERROR_METADATA_FIELDS.includes(field));
1377
+ if (!extra)
1378
+ continue;
1379
+ }
1380
+ return false;
1381
+ }
1382
+ return true;
1383
+ }
1384
+ function providerVisibleMessage(message) {
1385
+ return projectMessage(message, providerVisiblePart);
1386
+ }
1387
+ function providerVisibleMessageForTailHygiene(message) {
1388
+ return projectMessage(message, providerVisiblePartForTailHygiene);
1389
+ }
1390
+ function providerVisibleMessageForOpenCode2(message) {
1391
+ return projectMessage(message, providerVisiblePartForOpenCode2);
1392
+ }
1393
+ function projectMessage(message, projectPart) {
1394
+ if (!isRecord2(message) || !Array.isArray(message.parts))
1395
+ return message;
1396
+ let parts;
1397
+ for (let index = 0;index < message.parts.length; index += 1) {
1398
+ const part = message.parts[index];
1399
+ const view = projectPart(part);
1400
+ if (view !== part) {
1401
+ parts ??= message.parts.slice(0, index);
1402
+ parts.push(view);
1403
+ } else if (parts) {
1404
+ parts.push(part);
1405
+ }
1406
+ }
1407
+ return parts ? { ...message, parts } : message;
1408
+ }
1409
+
771
1410
  // src/hooks/magic-context/todo-view.ts
772
1411
  import { createHash } from "node:crypto";
773
1412
  var TODO_STATUS_PENDING = "pending";
@@ -885,7 +1524,7 @@ function isTodoItem(value) {
885
1524
 
886
1525
  // src/hooks/magic-context/tail-hygiene-walk.ts
887
1526
  var MAX_CONTENT_MEMO_ENTRIES = 1e5;
888
- var MAX_CONTENT_MEMO_BYTES = 64 * 1024 * 1024;
1527
+ var MAX_CONTENT_MEMO_BYTES = 256 * 1024 * 1024;
889
1528
  var contentMemo = new Map;
890
1529
  var contentMemoOrder = new Set;
891
1530
  var contentMemoBytes = 0;
@@ -1069,41 +1708,46 @@ function stripChannel1ReminderSpans(output) {
1069
1708
  return stripped;
1070
1709
  }
1071
1710
  function isDropSentinel(content) {
1072
- const stripped = content.trimStart().replace(TAG_PREFIX, "").trimStart().toLowerCase();
1073
- return DROP_PREFIXES.some((prefix) => stripped.startsWith(prefix));
1074
- }
1075
- function toolOutputText(part) {
1711
+ let stripped = content.trimStart();
1712
+ const tag = TAG_PREFIX.exec(stripped);
1713
+ if (tag)
1714
+ stripped = stripped.slice(tag[0].length).trimStart();
1715
+ return DROP_PREFIXES.some((prefix) => stripped.slice(0, prefix.length).toLowerCase() === prefix);
1716
+ }
1717
+ function toolOutputText(part, key) {
1718
+ const serialize = (value) => partJsonMemo.get(key, value, () => safeStableStringify(value));
1076
1719
  if (part.type === "tool") {
1077
1720
  const state = isRecord(part.state) ? part.state : null;
1078
1721
  if (!state)
1079
1722
  return null;
1080
1723
  if (state.output !== undefined)
1081
- return safeStableStringify(state.output);
1724
+ return serialize(state.output);
1082
1725
  if (state.error !== undefined)
1083
- return safeStableStringify(state.error);
1726
+ return serialize(state.error);
1084
1727
  if (state.result !== undefined)
1085
- return safeStableStringify(state.result);
1728
+ return serialize(state.result);
1086
1729
  return null;
1087
1730
  }
1088
1731
  if (part.type === "tool_result") {
1089
1732
  const value = part.content ?? part.output ?? part.result;
1090
- return value === undefined ? null : safeStableStringify(value);
1733
+ return value === undefined ? null : serialize(value);
1091
1734
  }
1092
1735
  return null;
1093
1736
  }
1094
- function toolInputText(part) {
1737
+ function toolInputText(part, key) {
1738
+ const serialize = (value) => partJsonMemo.get(key, value, () => safeStableStringify(value));
1095
1739
  if (part.type === "tool") {
1096
1740
  const state = isRecord(part.state) ? part.state : null;
1097
1741
  if (!state || state.input === undefined)
1098
1742
  return null;
1099
- return safeStableStringify(state.input);
1743
+ return serialize(state.input);
1100
1744
  }
1101
1745
  if (part.type === "tool-invocation") {
1102
1746
  const value = part.args ?? part.input;
1103
- return value === undefined ? null : safeStableStringify(value);
1747
+ return value === undefined ? null : serialize(value);
1104
1748
  }
1105
1749
  if (part.type === "tool_use") {
1106
- return part.input === undefined ? null : safeStableStringify(part.input);
1750
+ return part.input === undefined ? null : serialize(part.input);
1107
1751
  }
1108
1752
  return null;
1109
1753
  }
@@ -1114,8 +1758,8 @@ function messageIdForTag(tag) {
1114
1758
  }
1115
1759
  function resolveProtectedTagNumbers(tags, protectedTagNumbersInput, protectedToolTags) {
1116
1760
  const protectedNumbers = new Set(protectedTagNumbersInput);
1117
- const protectedExemplars = protectedToolTags ?? protectedToolTagNumbers(tags);
1118
- for (const tagNumber of protectedExemplars)
1761
+ const protectedCtxReduceTags = protectedToolTags ?? protectedToolTagNumbers(tags);
1762
+ for (const tagNumber of protectedCtxReduceTags)
1119
1763
  protectedNumbers.add(tagNumber);
1120
1764
  return protectedNumbers;
1121
1765
  }
@@ -1230,17 +1874,28 @@ function snapshot(args) {
1230
1874
  queuedForDrop
1231
1875
  };
1232
1876
  }
1877
+ var partJsonMemo = new TailHygieneJsonMemo;
1233
1878
  function excludedSnapshot(key, part) {
1234
- const content = safeStableStringify(part);
1235
- return snapshot({
1879
+ const contentHash = partJsonMemo.get(key, part, () => {
1880
+ if (part === null || part === undefined || typeof part === "string")
1881
+ return memoizedContent("excluded", safeStableStringify(part)).hash;
1882
+ try {
1883
+ return stableStringifyHash(part, "excluded\x00");
1884
+ } catch {
1885
+ return memoizedContent("excluded", String(part)).hash;
1886
+ }
1887
+ }, true);
1888
+ return {
1236
1889
  key,
1890
+ contentHash,
1237
1891
  kind: "excluded",
1238
- content,
1239
1892
  tokens: 0,
1240
- tag: undefined,
1241
- protectedNumbers: new Set,
1242
- pendingDropTagNumbers: new Set
1243
- });
1893
+ uTokens: 0,
1894
+ tagNumber: null,
1895
+ tagStatus: null,
1896
+ protected: false,
1897
+ queuedForDrop: false
1898
+ };
1244
1899
  }
1245
1900
  function fileContentAndTokens(part) {
1246
1901
  const mime = typeof part.mime === "string" ? part.mime : "";
@@ -1280,12 +1935,12 @@ function structuralSize(value) {
1280
1935
  }
1281
1936
  return 0;
1282
1937
  }
1283
- function tailHygieneStructuralSignature(messages) {
1938
+ function tailHygieneStructuralSignature(messages, opencode2 = false) {
1284
1939
  const partCounts = [];
1285
1940
  let totalBytes = 0;
1286
1941
  for (const message of messages) {
1287
1942
  partCounts.push(message.parts.length);
1288
- totalBytes += structuralSize(message);
1943
+ totalBytes += structuralSize(opencode2 ? providerVisibleMessageForOpenCode2(message) : providerVisibleMessageForTailHygiene(message));
1289
1944
  }
1290
1945
  return { messageCount: messages.length, partCounts, totalBytes };
1291
1946
  }
@@ -1299,10 +1954,22 @@ function measureTailHygiene(input) {
1299
1954
  return measureWithReplay(input);
1300
1955
  }
1301
1956
  function measureWithReplay(input, replay) {
1957
+ partJsonMemo.beginPass();
1958
+ const projectPart = input.opencode2 ? providerVisiblePartForOpenCode2 : providerVisiblePartForTailHygiene;
1959
+ const views = new WeakMap;
1960
+ const excluded = (key, part) => {
1961
+ let view = part !== null && typeof part === "object" ? views.get(part) : undefined;
1962
+ if (view === undefined) {
1963
+ view = projectPart(part);
1964
+ if (part !== null && typeof part === "object")
1965
+ views.set(part, view);
1966
+ }
1967
+ return excludedSnapshot(key, view);
1968
+ };
1302
1969
  const pendingDropTagNumbers = input.pendingDropTagNumbers ?? new Set;
1303
1970
  const unchanged = input.messages.map((message, index) => {
1304
1971
  const previous = replay?.messages[index];
1305
- return previous !== undefined && sameReplayMessage(previous, message);
1972
+ return previous !== undefined && sameReplayMessage(previous, message, projectPart);
1306
1973
  });
1307
1974
  const toolIdentities = collectToolPartIdentities(input.messages);
1308
1975
  const attribution = buildTagAttribution({
@@ -1312,7 +1979,7 @@ function measureWithReplay(input, replay) {
1312
1979
  protectedTagNumbers: input.protectedTagNumbers,
1313
1980
  protectedToolTags: input.protectedToolTags
1314
1981
  });
1315
- const toolOutputs = input.messages.map((message, index) => message.parts.map((part, partIndex) => unchanged[index] ? replay?.measured.toolOutputs[index][partIndex] ?? null : isRecord(part) ? toolOutputText(part) : null));
1982
+ const toolOutputs = input.messages.map((message, index) => message.parts.map((part, partIndex) => unchanged[index] ? replay?.measured.toolOutputs[index][partIndex] ?? null : isRecord(part) ? toolOutputText(part, `${messageIdentity(message, index)}\x00${partIndex}\x00output`) : null));
1316
1983
  const outputByPart = new Map;
1317
1984
  input.messages.forEach((message, index) => {
1318
1985
  message.parts.forEach((part, partIndex) => {
@@ -1378,19 +2045,19 @@ function measureWithReplay(input, replay) {
1378
2045
  const part = message.parts[partIndex];
1379
2046
  const key = `${messageKey}\x00${partIndex}`;
1380
2047
  if (messageSynthetic || isSyntheticPart(part) || !isRecord(part)) {
1381
- parts.push(excludedSnapshot(`${key}\x00excluded`, part));
2048
+ parts.push(excluded(`${key}\x00excluded`, part));
1382
2049
  continue;
1383
2050
  }
1384
2051
  const type = typeof part.type === "string" ? part.type : "";
1385
2052
  if (type === "reasoning" || type === "thinking" || type === "redacted_thinking" || type === "signature") {
1386
- parts.push(excludedSnapshot(`${key}\x00excluded`, part));
2053
+ parts.push(excluded(`${key}\x00excluded`, part));
1387
2054
  continue;
1388
2055
  }
1389
2056
  if (type === "text") {
1390
2057
  const rawContent = firstString(part, ["text", "content"]);
1391
2058
  const content = rawContent === null ? null : stripChannel1ReminderSpans(rawContent);
1392
2059
  if (!content || isDropSentinel(content)) {
1393
- parts.push(excludedSnapshot(`${key}\x00excluded`, part));
2060
+ parts.push(excluded(`${key}\x00excluded`, part));
1394
2061
  continue;
1395
2062
  }
1396
2063
  const tokens = memoizedTokens("text", content);
@@ -1412,7 +2079,7 @@ function measureWithReplay(input, replay) {
1412
2079
  if (type === "file" || type.includes("image") || type === "source") {
1413
2080
  const file = fileContentAndTokens(part);
1414
2081
  if (!file.content || isDropSentinel(file.content)) {
1415
- parts.push(excludedSnapshot(`${key}\x00excluded`, part));
2082
+ parts.push(excluded(`${key}\x00excluded`, part));
1416
2083
  continue;
1417
2084
  }
1418
2085
  const tag = attribution.messageTags.get(`${message.info.id}:file${partIndex}`);
@@ -1434,11 +2101,11 @@ function measureWithReplay(input, replay) {
1434
2101
  if (toolIdentity) {
1435
2102
  const ownerKey = `${toolIdentity.ownerMessageId}\x00${toolIdentity.callId}`;
1436
2103
  if (droppedToolOwners.has(ownerKey)) {
1437
- parts.push(excludedSnapshot(`${key}\x00excluded`, part));
2104
+ parts.push(excluded(`${key}\x00excluded`, part));
1438
2105
  continue;
1439
2106
  }
1440
2107
  const tag = attribution.toolTagsByPart.get(part);
1441
- const inputText = toolInputText(part);
2108
+ const inputText = toolInputText(part, `${key}\x00input`);
1442
2109
  if (inputText !== null) {
1443
2110
  const tokens = memoizedTokens("toolInput", inputText);
1444
2111
  const measured = snapshot({
@@ -1458,7 +2125,7 @@ function measureWithReplay(input, replay) {
1458
2125
  if (rawOutput !== null) {
1459
2126
  const output = stripChannel1ReminderSpans(rawOutput);
1460
2127
  if (isDropSentinel(output)) {
1461
- parts.push(excludedSnapshot(`${key}\x00excludedOutput`, output));
2128
+ parts.push(excluded(`${key}\x00excludedOutput`, output));
1462
2129
  } else {
1463
2130
  const tokens = memoizedTokens("toolOutput", output) + (part.type === "tool" ? estimateToolAttachmentImageTokens(part.state) : 0);
1464
2131
  const measured = snapshot({
@@ -1476,11 +2143,11 @@ function measureWithReplay(input, replay) {
1476
2143
  }
1477
2144
  }
1478
2145
  if (inputText === null && rawOutput === null) {
1479
- parts.push(excludedSnapshot(`${key}\x00excluded`, part));
2146
+ parts.push(excluded(`${key}\x00excluded`, part));
1480
2147
  }
1481
2148
  continue;
1482
2149
  }
1483
- parts.push(excludedSnapshot(`${key}\x00excluded`, part));
2150
+ parts.push(excluded(`${key}\x00excluded`, part));
1484
2151
  }
1485
2152
  }
1486
2153
  return {
@@ -1621,16 +2288,19 @@ function sameNumbers(before, after) {
1621
2288
  return false;
1622
2289
  return true;
1623
2290
  }
1624
- function sameReplayMessage(left, right) {
1625
- return left.info.id === right.info.id && left.info.role === right.info.role && left.info.summary === right.info.summary && sameReplayValue(left.parts, right.parts);
2291
+ function sameReplayMessage(left, right, projectPart = providerVisiblePartForTailHygiene) {
2292
+ return left.info.id === right.info.id && left.info.role === right.info.role && left.info.summary === right.info.summary && sameReplayValue(left.parts, right.parts.map(projectPart));
1626
2293
  }
1627
- function sameReplayMessages(before, after) {
2294
+ function replaySnapshotParts(parts, projectPart = providerVisiblePartForTailHygiene) {
2295
+ return copyReplayValue(parts.map(projectPart));
2296
+ }
2297
+ function sameReplayMessages(before, after, projectPart = providerVisiblePartForTailHygiene) {
1628
2298
  if (before.length !== after.length)
1629
2299
  return false;
1630
2300
  for (let index = 0;index < before.length; index += 1) {
1631
2301
  const left = before[index];
1632
2302
  const right = after[index];
1633
- if (!sameReplayMessage(left, right))
2303
+ if (!sameReplayMessage(left, right, projectPart))
1634
2304
  return false;
1635
2305
  }
1636
2306
  return true;
@@ -1689,8 +2359,10 @@ function refreshTailHygieneBaseline(input) {
1689
2359
  protectedTagNumbers: new Set([...input.protectedTagNumbers, ...protectedToolTags])
1690
2360
  };
1691
2361
  const pendingDropTagNumbers = input.pendingDropTagNumbers ?? new Set;
1692
- const cached = input.previous ? baselineMeasurementMemo.get(input.previous.baselineParts) : undefined;
1693
- const hit = !input.cacheBusting && cached && sameReplayMessages(cached.messages, input.messages) && sameReplayValue(cached.tags, input.tags) && sameNumbers(cached.protectedTagNumbers, input.protectedTagNumbers) && sameNumbers(cached.pendingDropTagNumbers, pendingDropTagNumbers);
2362
+ const priorMemo = input.previous ? baselineMeasurementMemo.get(input.previous.baselineParts) : undefined;
2363
+ const cached = priorMemo?.opencode2 === !!input.opencode2 ? priorMemo : undefined;
2364
+ const projectPart = input.opencode2 ? providerVisiblePartForOpenCode2 : providerVisiblePartForTailHygiene;
2365
+ const hit = !input.cacheBusting && cached && sameReplayMessages(cached.messages, input.messages, projectPart) && sameReplayValue(cached.tags, input.tags) && sameNumbers(cached.protectedTagNumbers, input.protectedTagNumbers) && sameNumbers(cached.pendingDropTagNumbers, pendingDropTagNumbers);
1694
2366
  const rawMeasured = hit ? cached.measured : measureWithReplay(input, cached);
1695
2367
  const frozenCalibration = !input.cacheBusting && input.previous ? {
1696
2368
  toolsRatio: input.previous.toolsRatio,
@@ -1710,19 +2382,20 @@ function refreshTailHygieneBaseline(input) {
1710
2382
  })
1711
2383
  };
1712
2384
  const memo = hit ? cached : {
1713
- messages: input.messages.map((message, index) => cached?.messages[index] && sameReplayMessage(cached.messages[index], message) ? cached.messages[index] : {
2385
+ opencode2: !!input.opencode2,
2386
+ messages: input.messages.map((message, index) => cached?.messages[index] && sameReplayMessage(cached.messages[index], message, projectPart) ? cached.messages[index] : {
1714
2387
  info: {
1715
2388
  id: message.info.id,
1716
2389
  role: message.info.role,
1717
2390
  summary: message.info.summary
1718
2391
  },
1719
- parts: copyReplayValue(message.parts)
2392
+ parts: replaySnapshotParts(message.parts, projectPart)
1720
2393
  }),
1721
2394
  tags: structuredClone(input.tags),
1722
2395
  protectedTagNumbers: new Set(input.protectedTagNumbers),
1723
2396
  pendingDropTagNumbers: new Set(pendingDropTagNumbers),
1724
2397
  measured: rawMeasured,
1725
- size: 2 * structuralSize(input.messages) + 512 * input.tags.length
2398
+ size: 2 * structuralSize(input.messages.map(input.opencode2 ? providerVisibleMessageForOpenCode2 : providerVisibleMessageForTailHygiene)) + 512 * input.tags.length
1726
2399
  };
1727
2400
  if (!hit) {
1728
2401
  const owners = new Map;
@@ -1739,8 +2412,9 @@ function refreshTailHygieneBaseline(input) {
1739
2412
  const refrozen = (mismatch) => {
1740
2413
  const frozen = freezeTailHygieneMeasurement(measured);
1741
2414
  retainBaselineMeasurement(frozen.baselineParts, memo);
1742
- return {
2415
+ return rememberCurrentToolOutputCount({
1743
2416
  ...frozen,
2417
+ protectedToolsPolicy,
1744
2418
  hygieneUnitsVersion: frozenCalibration.hygieneUnitsVersion,
1745
2419
  toolsRatio: frozenCalibration.toolsRatio,
1746
2420
  proseRatio: frozenCalibration.proseRatio,
@@ -1750,9 +2424,8 @@ function refreshTailHygieneBaseline(input) {
1750
2424
  generationInvalidated: false,
1751
2425
  contentSignature: measured.contentSignature,
1752
2426
  channel1PostReduceGrace: input.previous?.channel1PostReduceGrace,
1753
- lastPrefixMismatch: mismatch,
1754
- protectedToolsPolicy
1755
- };
2427
+ lastPrefixMismatch: mismatch
2428
+ }, measured);
1756
2429
  };
1757
2430
  if (input.cacheBusting || !input.previous)
1758
2431
  return refrozen();
@@ -1768,7 +2441,7 @@ function refreshTailHygieneBaseline(input) {
1768
2441
  if (part.kind !== "toolOutput" || !part.protected)
1769
2442
  turnDeltaU += part.uTokens;
1770
2443
  }
1771
- return {
2444
+ return rememberCurrentToolOutputCount({
1772
2445
  ...input.previous,
1773
2446
  protectedToolsPolicy,
1774
2447
  turnDeltaU,
@@ -1777,7 +2450,7 @@ function refreshTailHygieneBaseline(input) {
1777
2450
  generationInvalidated: false,
1778
2451
  contentSignature: measured.contentSignature,
1779
2452
  lastPrefixMismatch: undefined
1780
- };
2453
+ }, measured);
1781
2454
  }
1782
2455
  function effectiveTailHygiene(baseline) {
1783
2456
  const t = Math.ceil(Math.max(0, baseline.baselineT + baseline.turnDeltaT));
@@ -2049,7 +2722,7 @@ function formatOldestReclaimableHint(hint) {
2049
2722
  oldest reclaimable: ${rendered}.` : "";
2050
2723
  }
2051
2724
  function reclaimableToolOutputCount(parts) {
2052
- return parts.filter((part) => part.kind === "toolOutput" && part.uTokens > 0).length;
2725
+ return countReclaimableToolOutputs(parts);
2053
2726
  }
2054
2727
  function formatReclaimableOutputSummary(count, tokens) {
2055
2728
  const outputCount = Math.max(0, Math.floor(count));
@@ -2392,6 +3065,117 @@ function removePendingOp(db, sessionId, tagId) {
2392
3065
  getRemovePendingOpStatement(db).run(sessionId, tagId);
2393
3066
  }
2394
3067
 
3068
+ // src/features/magic-context/storage-tag-identity-revision.ts
3069
+ var TAG_IDENTITY_REVISION_PREFIX = "tag_identity_revision:";
3070
+ var TAG_REVISION_PREFIX = "tag_revision:";
3071
+ var TAG_TOMBSTONE_OWNER_PREFIX = "tag_revision_owner:";
3072
+ var TAG_REVISION_INCARNATION_KEY = "tag_revision_incarnation";
3073
+ var tagRevisionIncarnationSql = (value) => `CASE WHEN INSTR(${value}, ':') > 0 THEN SUBSTR(${value}, 1, INSTR(${value}, ':') - 1) ELSE '0' END`;
3074
+ var tagRevisionCountSql = (value) => `CAST(CASE WHEN INSTR(${value}, ':') > 0 THEN SUBSTR(${value}, INSTR(${value}, ':') + 1) ELSE ${value} END AS INTEGER)`;
3075
+ var ADVANCE = (delta = "1") => `CASE
3076
+ WHEN ${tagRevisionCountSql("value")} <= 9223372036854775807 - ${delta}
3077
+ THEN (${tagRevisionIncarnationSql("value")}) || ':' || CAST(${tagRevisionCountSql("value")} + ${delta} AS TEXT)
3078
+ ELSE NULL END`;
3079
+ function tagTombstoneOwnerRange(sessionId) {
3080
+ const stem = `${TAG_TOMBSTONE_OWNER_PREFIX}${JSON.stringify(sessionId)}`;
3081
+ return [`${stem}:`, `${stem};`];
3082
+ }
3083
+ function tagTombstoneOwnerKey(sessionId, harness) {
3084
+ return `${tagTombstoneOwnerRange(sessionId)[0]}${harness}`;
3085
+ }
3086
+ function tagRevisionKey(sessionId) {
3087
+ return `${TAG_REVISION_PREFIX}${sessionId}`;
3088
+ }
3089
+ function tagIdentityRevisionKey(sessionId) {
3090
+ return `${TAG_IDENTITY_REVISION_PREFIX}${sessionId}`;
3091
+ }
3092
+ var BUMP = (session, prefix = TAG_IDENTITY_REVISION_PREFIX) => `INSERT INTO schema_migrations_meta (key, value)
3093
+ VALUES ('${prefix}' || ${session}, '1')
3094
+ ON CONFLICT(key) DO UPDATE SET value = ${ADVANCE()}`;
3095
+ var TAG_INSERT_CONFLICT_ROWS = `SELECT id, session_id, tag_number FROM tags WHERE id = NEW.id
3096
+ UNION SELECT id, session_id, tag_number FROM tags WHERE session_id = NEW.session_id AND tag_number = NEW.tag_number
3097
+ UNION SELECT id, session_id, tag_number FROM tags
3098
+ WHERE NEW.type = 'tool' AND NEW.tool_owner_message_id IS NOT NULL
3099
+ AND type = 'tool' AND tool_owner_message_id IS NOT NULL
3100
+ AND session_id = NEW.session_id AND message_id = NEW.message_id
3101
+ AND tool_owner_message_id = NEW.tool_owner_message_id`;
3102
+ var BUMP_INSERT_CONFLICTS = (prefix) => `INSERT INTO schema_migrations_meta (key, value)
3103
+ SELECT '${prefix}' || session_id, CAST(COUNT(*) AS TEXT)
3104
+ FROM (${TAG_INSERT_CONFLICT_ROWS}) GROUP BY session_id
3105
+ ON CONFLICT(key) DO UPDATE SET value = ${ADVANCE("CAST(excluded.value AS INTEGER)")}`;
3106
+ var TRIGGER_SQL = `CREATE TEMP TRIGGER IF NOT EXISTS mc_tag_identity_revision_au
3107
+ AFTER UPDATE OF id, session_id, message_id, tag_number, type, tool_owner_message_id, reasoning_token_count
3108
+ ON main.tags
3109
+ BEGIN
3110
+ ${BUMP("OLD.session_id")};
3111
+ INSERT INTO schema_migrations_meta (key, value)
3112
+ SELECT '${TAG_IDENTITY_REVISION_PREFIX}' || NEW.session_id, '1'
3113
+ WHERE NEW.session_id IS NOT OLD.session_id
3114
+ ON CONFLICT(key) DO UPDATE SET value = ${ADVANCE()};
3115
+ END`;
3116
+ function installTagIdentityRevisionTrigger(db) {
3117
+ db.exec(`DROP TRIGGER IF EXISTS temp.mc_tag_identity_revision_au;
3118
+ DROP TRIGGER IF EXISTS temp.mc_tag_revision_bi;
3119
+ DROP TRIGGER IF EXISTS temp.mc_tag_revision_ai;
3120
+ DROP TRIGGER IF EXISTS temp.mc_tag_revision_au;
3121
+ DROP TRIGGER IF EXISTS temp.mc_tag_revision_ad;
3122
+ DROP TRIGGER IF EXISTS temp.mc_tag_revision_seed_ai;`);
3123
+ db.exec(`CREATE TEMP TRIGGER mc_tag_revision_seed_ai AFTER INSERT ON main.schema_migrations_meta
3124
+ WHEN INSTR(NEW.value, ':') = 0 AND (
3125
+ SUBSTR(NEW.key, 1, ${TAG_REVISION_PREFIX.length}) = '${TAG_REVISION_PREFIX}'
3126
+ OR SUBSTR(NEW.key, 1, ${TAG_IDENTITY_REVISION_PREFIX.length}) = '${TAG_IDENTITY_REVISION_PREFIX}')
3127
+ BEGIN
3128
+ INSERT INTO schema_migrations_meta (key, value) VALUES ('${TAG_REVISION_INCARNATION_KEY}', '1')
3129
+ ON CONFLICT(key) DO UPDATE SET value = CAST(CASE
3130
+ WHEN CAST(value AS INTEGER) < 9223372036854775807 THEN CAST(value AS INTEGER) + 1
3131
+ ELSE NULL END AS TEXT);
3132
+ UPDATE schema_migrations_meta SET value =
3133
+ (SELECT value FROM schema_migrations_meta WHERE key = '${TAG_REVISION_INCARNATION_KEY}')
3134
+ || ':' || CAST(NEW.value AS TEXT) WHERE key = NEW.key;
3135
+ INSERT INTO schema_migrations_meta (key, value)
3136
+ SELECT '${TAG_REVISION_INCARNATION_KEY}', '1'
3137
+ WHERE SUBSTR(NEW.key, 1, ${TAG_REVISION_PREFIX.length}) = '${TAG_REVISION_PREFIX}'
3138
+ AND NOT EXISTS (SELECT 1 FROM schema_migrations_meta
3139
+ WHERE key = '${TAG_IDENTITY_REVISION_PREFIX}' || SUBSTR(NEW.key, ${TAG_REVISION_PREFIX.length + 1}))
3140
+ ON CONFLICT(key) DO UPDATE SET value = CAST(CASE
3141
+ WHEN CAST(value AS INTEGER) < 9223372036854775807 THEN CAST(value AS INTEGER) + 1
3142
+ ELSE NULL END AS TEXT);
3143
+ INSERT INTO schema_migrations_meta (key, value)
3144
+ SELECT '${TAG_IDENTITY_REVISION_PREFIX}' || SUBSTR(NEW.key, ${TAG_REVISION_PREFIX.length + 1}),
3145
+ (SELECT value FROM schema_migrations_meta WHERE key = '${TAG_REVISION_INCARNATION_KEY}') || ':0'
3146
+ WHERE SUBSTR(NEW.key, 1, ${TAG_REVISION_PREFIX.length}) = '${TAG_REVISION_PREFIX}'
3147
+ AND NOT EXISTS (SELECT 1 FROM schema_migrations_meta
3148
+ WHERE key = '${TAG_IDENTITY_REVISION_PREFIX}' || SUBSTR(NEW.key, ${TAG_REVISION_PREFIX.length + 1}));
3149
+ END;`);
3150
+ db.exec(TRIGGER_SQL);
3151
+ db.exec(`CREATE TEMP TRIGGER IF NOT EXISTS mc_tag_revision_bi BEFORE INSERT ON main.tags BEGIN
3152
+ ${BUMP_INSERT_CONFLICTS(TAG_REVISION_PREFIX)};
3153
+ ${BUMP_INSERT_CONFLICTS(TAG_IDENTITY_REVISION_PREFIX)};
3154
+ UPDATE session_meta SET tags_version = tags_version + 1
3155
+ WHERE session_id IN (SELECT session_id FROM (${TAG_INSERT_CONFLICT_ROWS}));
3156
+ END;`);
3157
+ db.exec(`CREATE TEMP TRIGGER IF NOT EXISTS mc_tag_revision_ai AFTER INSERT ON main.tags BEGIN
3158
+ ${BUMP("NEW.session_id", TAG_REVISION_PREFIX)};
3159
+ END;
3160
+ CREATE TEMP TRIGGER IF NOT EXISTS mc_tag_revision_au AFTER UPDATE ON main.tags BEGIN
3161
+ ${BUMP("OLD.session_id", TAG_REVISION_PREFIX)};
3162
+ INSERT INTO schema_migrations_meta (key, value)
3163
+ SELECT '${TAG_REVISION_PREFIX}' || NEW.session_id, '1'
3164
+ WHERE NEW.session_id IS NOT OLD.session_id
3165
+ ON CONFLICT(key) DO UPDATE SET value = ${ADVANCE()};
3166
+ END;
3167
+ CREATE TEMP TRIGGER IF NOT EXISTS mc_tag_revision_ad AFTER DELETE ON main.tags BEGIN
3168
+ ${BUMP("OLD.session_id", TAG_REVISION_PREFIX)};
3169
+ END;`);
3170
+ }
3171
+ function deleteTagIdentityRevisions(db, sessionIds) {
3172
+ const statement = db.prepare(`INSERT INTO schema_migrations_meta (key, value) VALUES (?, '1')
3173
+ ON CONFLICT(key) DO UPDATE SET value = ${ADVANCE()}`);
3174
+ for (const sessionId of sessionIds) {
3175
+ statement.run(tagIdentityRevisionKey(sessionId));
3176
+ }
3177
+ }
3178
+
2395
3179
  // src/features/magic-context/storage-tags.ts
2396
3180
  var insertTagStatements = new WeakMap;
2397
3181
  var updateTagStatusStatements = new WeakMap;
@@ -2610,8 +3394,41 @@ function getActiveTagTokenTotalsByMessage(db, sessionId, messageIds) {
2610
3394
  }
2611
3395
  var updateTagTokenCountStatements = new WeakMap;
2612
3396
  var updateTagInputTokenCountStatements = new WeakMap;
2613
- function getAllStatusTagTokenTotalsFlat(db, sessionId, floor = 0, calibration = { proseRatio: 1, toolsRatio: 1 }, options) {
2614
- const rows = floor > 0 ? db.prepare(`SELECT type, message_id, tool_owner_message_id, token_count, input_token_count, reasoning_token_count
3397
+ function getAllStatusTagTokenTotalsFlat(db, sessionId, floor = 0, calibration = { proseRatio: 1, toolsRatio: 1 }, options, ownerMessageIds) {
3398
+ const columns = "type, message_id, tool_owner_message_id, token_count, input_token_count, reasoning_token_count";
3399
+ const owners = ownerMessageIds ? new Set(ownerMessageIds) : undefined;
3400
+ let scanOrder = "id";
3401
+ if (owners) {
3402
+ const planStatement = db.prepare(`EXPLAIN QUERY PLAN SELECT ${columns} FROM tags WHERE session_id = ?${floor > 0 ? " AND tag_number >= ?" : ""}`);
3403
+ let plan;
3404
+ try {
3405
+ plan = planStatement.all(sessionId, ...floor > 0 ? [floor] : []);
3406
+ } finally {
3407
+ planStatement.finalize?.();
3408
+ }
3409
+ const index = plan.map((row) => /USING (?:COVERING )?INDEX (\S+)/.exec(row.detail)?.[1]).find(Boolean);
3410
+ if (index) {
3411
+ const keyStatement = db.prepare("SELECT name, coll, desc FROM pragma_index_xinfo(?) WHERE key = 1 ORDER BY seqno");
3412
+ let keys;
3413
+ try {
3414
+ keys = keyStatement.all(index);
3415
+ } finally {
3416
+ keyStatement.finalize?.();
3417
+ }
3418
+ scanOrder = [
3419
+ ...keys.map((key) => `"${(key.name ?? "id").replaceAll('"', '""')}" COLLATE "${key.coll.replaceAll('"', '""')}"${key.desc ? " DESC" : ""}`),
3420
+ "id"
3421
+ ].join(", ");
3422
+ }
3423
+ }
3424
+ const rows = owners ? db.prepare(`SELECT ${columns} FROM tags WHERE id IN (
3425
+ SELECT t.id FROM json_each(?) o CROSS JOIN tags t INDEXED BY idx_tags_session_message_id
3426
+ ON t.session_id = ? AND t.message_id >= o.value AND t.message_id < o.value || ';'
3427
+ UNION
3428
+ SELECT t.id FROM json_each(?) o CROSS JOIN tags t INDEXED BY idx_tags_pi_fallback_tool_owner
3429
+ ON t.session_id = ? AND t.tool_owner_message_id = o.value
3430
+ WHERE t.type = 'tool'
3431
+ ) AND tag_number >= ? ORDER BY ${scanOrder}`).all(JSON.stringify([...owners]), sessionId, JSON.stringify([...owners]), sessionId, floor) : floor > 0 ? db.prepare(`SELECT type, message_id, tool_owner_message_id, token_count, input_token_count, reasoning_token_count
2615
3432
  FROM tags
2616
3433
  WHERE session_id = ? AND tag_number >= ?`).all(sessionId, floor) : db.prepare(`SELECT type, message_id, tool_owner_message_id, token_count, input_token_count, reasoning_token_count
2617
3434
  FROM tags
@@ -2624,6 +3441,8 @@ function getAllStatusTagTokenTotalsFlat(db, sessionId, floor = 0, calibration =
2624
3441
  if (options?.excludeToolTags === true && row.type === "tool")
2625
3442
  continue;
2626
3443
  const owner = ownerMessageIdForTagRow(row);
3444
+ if (owners && !owners.has(owner))
3445
+ continue;
2627
3446
  if (row.token_count === null) {
2628
3447
  nullMessageIds.add(owner);
2629
3448
  totals.delete(owner);
@@ -2638,15 +3457,199 @@ function getAllStatusTagTokenTotalsFlat(db, sessionId, floor = 0, calibration =
2638
3457
  return { totals, nullMessageIds };
2639
3458
  }
2640
3459
  function getReasoningTokenEstimatesByMessage(db, sessionId, proseRatio) {
2641
- const rows = db.prepare(`SELECT type, message_id, tool_owner_message_id, reasoning_token_count FROM tags WHERE session_id = ? AND reasoning_token_count IS NOT NULL`).all(sessionId);
2642
- const totals = new Map;
2643
- for (const row of rows) {
2644
- if (row.type !== "message")
2645
- continue;
2646
- const id = ownerMessageIdForTagRow(row);
2647
- totals.set(id, Math.max(totals.get(id) ?? 0, row.reasoning_token_count * proseRatio));
3460
+ const summary = readTagOwnerSummary(db, sessionId, proseRatio);
3461
+ return summary.reasoningEstimatesByRatio.get(proseRatio) ?? new Map;
3462
+ }
3463
+ function tryGetReasoningTokenEstimatesByMessage(db, sessionId, ratio) {
3464
+ try {
3465
+ return getReasoningTokenEstimatesByMessage(db, sessionId, ratio);
3466
+ } catch (error) {
3467
+ if (error instanceof TagOwnerSummaryNotReady)
3468
+ return;
3469
+ throw error;
3470
+ }
3471
+ }
3472
+ function getMaxTagNumberByOwnerMessage(db, sessionId) {
3473
+ return readTagOwnerSummary(db, sessionId).maxTagByOwner;
3474
+ }
3475
+ var tagOwnerSummaries = new WeakMap;
3476
+ var MAX_CACHED_PROSE_RATIOS = 4;
3477
+ var TAG_OWNER_PAGE_LIMIT = 512;
3478
+
3479
+ class TagOwnerSummaryNotReady extends Error {
3480
+ constructor() {
3481
+ super("tag owner summary needs off-thread preparation");
3482
+ }
3483
+ }
3484
+ function scanTagOwnerSummary(db, sessionId, ratio, ratios = []) {
3485
+ db.exec("BEGIN");
3486
+ try {
3487
+ return readTagOwnerSummary(db, sessionId, ratio, ratios);
3488
+ } finally {
3489
+ db.exec("ROLLBACK");
3490
+ }
3491
+ }
3492
+ function isTagOwnerSummaryReady(db, sessionId, ratio) {
3493
+ try {
3494
+ readTagOwnerSummary(db, sessionId, ratio);
3495
+ return true;
3496
+ } catch (error) {
3497
+ if (error instanceof TagOwnerSummaryNotReady)
3498
+ return false;
3499
+ throw error;
3500
+ }
3501
+ }
3502
+ var tagOwnerRowsRead = 0;
3503
+ var tagOwnerShapeChecks = 0;
3504
+ function foldTagOwnerRow(summary, row, newRow = true) {
3505
+ summary.lastRowId = Math.max(summary.lastRowId, row.id);
3506
+ if (newRow)
3507
+ summary.rowCount += 1;
3508
+ if (row.type === "tool" && typeof row.tool_owner_message_id !== "string")
3509
+ summary.unownedToolRows.add(row.id);
3510
+ else
3511
+ summary.unownedToolRows.delete(row.id);
3512
+ const owner = row.type === "tool" ? typeof row.tool_owner_message_id === "string" ? row.tool_owner_message_id : null : typeof row.message_id === "string" ? contentTagOwnerMessageId(row.message_id) : null;
3513
+ if (owner) {
3514
+ summary.maxTagByOwner.set(owner, Math.max(summary.maxTagByOwner.get(owner) ?? 0, row.tag_number));
3515
+ }
3516
+ if (row.type !== "message" || row.reasoning_token_count === null)
3517
+ return;
3518
+ const reasoningOwner = ownerMessageIdForTagRow({
3519
+ type: row.type,
3520
+ message_id: row.message_id,
3521
+ tool_owner_message_id: row.tool_owner_message_id
3522
+ });
3523
+ for (const [ratio, estimates] of summary.reasoningEstimatesByRatio) {
3524
+ estimates.set(reasoningOwner, Math.max(estimates.get(reasoningOwner) ?? 0, row.reasoning_token_count * ratio));
3525
+ }
3526
+ }
3527
+ var TAG_OWNER_COLUMNS = "id, type, message_id, tool_owner_message_id, tag_number, reasoning_token_count";
3528
+ function connectionInTransaction(db) {
3529
+ try {
3530
+ const state = db;
3531
+ return state.inTransaction !== false && state.isTransaction !== false;
3532
+ } catch {
3533
+ return true;
3534
+ }
3535
+ }
3536
+ var TAG_OWNER_APPENDED_WITH_SHAPE_SQL = `SELECT ${TAG_OWNER_COLUMNS}, 0 AS shape, NULL AS tag_count, NULL AS max_id, NULL AS revision
3537
+ FROM tags WHERE id > ? AND +session_id = ?
3538
+ UNION ALL
3539
+ SELECT NULL, NULL, NULL, NULL, NULL, NULL, 1, COUNT(*), MAX(id), (SELECT value FROM schema_migrations_meta WHERE key = ?)
3540
+ FROM tags WHERE session_id = ?`;
3541
+ function readTagIdentityRevision(db, sessionId) {
3542
+ const row = db.prepare("SELECT value FROM schema_migrations_meta WHERE key = ?").get(tagIdentityRevisionKey(sessionId));
3543
+ return typeof row?.value === "string" ? row.value : null;
3544
+ }
3545
+ function captureInitialTagOwnerRevision(db, sessionId, cached, appendedRows) {
3546
+ if (cached.identityRevision !== null || appendedRows === 0)
3547
+ return true;
3548
+ const revision = readTagIdentityRevision(db, sessionId);
3549
+ if (revision !== null && !/^[1-9]\d*:0$/.test(revision))
3550
+ return false;
3551
+ cached.identityRevision = revision;
3552
+ return true;
3553
+ }
3554
+ function appendedSinceForeignCommit(db, sessionId, cached) {
3555
+ tagOwnerShapeChecks += 1;
3556
+ const rows = db.prepare(TAG_OWNER_APPENDED_WITH_SHAPE_SQL).all(cached.globalLastRowId, sessionId, tagIdentityRevisionKey(sessionId), sessionId);
3557
+ const shape = rows.find((row) => row.shape === 1);
3558
+ const appended = rows.filter((row) => row.shape === 0);
3559
+ const highest = appended.reduce((max, row) => Math.max(max, row.id), cached.lastRowId);
3560
+ if (!shape || (shape.revision ?? null) !== cached.identityRevision || shape.tag_count !== cached.rowCount + appended.length || (shape.max_id ?? 0) !== highest)
3561
+ return null;
3562
+ return appended;
3563
+ }
3564
+ function adoptedSinceForeignCommit(db, cached) {
3565
+ if (cached.unownedToolRows.size === 0)
3566
+ return [];
3567
+ return db.prepare(`SELECT ${TAG_OWNER_COLUMNS} FROM tags
3568
+ WHERE id IN (SELECT value FROM json_each(?)) AND tool_owner_message_id IS NOT NULL LIMIT ${TAG_OWNER_PAGE_LIMIT + 1}`).all(JSON.stringify([...cached.unownedToolRows]));
3569
+ }
3570
+ function readTagOwnerSummary(db, sessionId, proseRatio, extraRatios = []) {
3571
+ const inTransaction = connectionInTransaction(db);
3572
+ const versions = inTransaction ? null : db.prepare("SELECT data_version AS dataVersion, (SELECT schema_version FROM pragma_schema_version) AS schemaVersion FROM pragma_data_version").get();
3573
+ const dataVersion = versions?.dataVersion ?? -1;
3574
+ const schemaVersion = versions?.schemaVersion ?? -1;
3575
+ const generation = getTagIdentityWriteGeneration();
3576
+ const sessions = tagOwnerSummaries.get(db) ?? new Map;
3577
+ const cached = inTransaction ? undefined : sessions.get(sessionId);
3578
+ if (cached && (cached.generation === generation || cached.identityRevision === readTagIdentityRevision(db, sessionId)) && cached.schemaVersion === schemaVersion && (proseRatio === undefined || cached.reasoningEstimatesByRatio.has(proseRatio))) {
3579
+ let rows;
3580
+ let globalLastRowId = db.prepare("SELECT COALESCE(MAX(id), 0) AS id FROM tags").get().id;
3581
+ if (cached.dataVersion === dataVersion && cached.generation === generation) {
3582
+ const statement = db.prepare(`SELECT ${TAG_OWNER_COLUMNS} FROM tags WHERE id > ? AND +session_id = ? ORDER BY id LIMIT ${TAG_OWNER_PAGE_LIMIT + 1}`);
3583
+ rows = statement.all(cached.globalLastRowId, sessionId);
3584
+ let page = rows;
3585
+ while (page.length === TAG_OWNER_PAGE_LIMIT + 1) {
3586
+ page = statement.all(page[page.length - 1].id, sessionId);
3587
+ rows.push(...page);
3588
+ }
3589
+ if (!captureInitialTagOwnerRevision(db, sessionId, cached, rows.length)) {
3590
+ rows = null;
3591
+ }
3592
+ } else {
3593
+ try {
3594
+ globalLastRowId = db.prepare("SELECT COALESCE(MAX(id),0) AS id FROM tags").get().id;
3595
+ rows = appendedSinceForeignCommit(db, sessionId, cached);
3596
+ const adopted = rows ? adoptedSinceForeignCommit(db, cached) : [];
3597
+ if (!rows || rows.length > TAG_OWNER_PAGE_LIMIT || adopted.length > TAG_OWNER_PAGE_LIMIT) {
3598
+ rows = null;
3599
+ } else {
3600
+ tagOwnerRowsRead += rows.length + adopted.length;
3601
+ for (const row of rows)
3602
+ foldTagOwnerRow(cached, row);
3603
+ for (const row of adopted)
3604
+ foldTagOwnerRow(cached, row, false);
3605
+ cached.dataVersion = dataVersion;
3606
+ cached.generation = generation;
3607
+ cached.globalLastRowId = globalLastRowId;
3608
+ return cached;
3609
+ }
3610
+ } catch {
3611
+ rows = null;
3612
+ }
3613
+ }
3614
+ if (rows) {
3615
+ const adopted = cached.dataVersion === dataVersion ? [] : adoptedSinceForeignCommit(db, cached);
3616
+ tagOwnerRowsRead += rows.length + adopted.length;
3617
+ for (const row of rows)
3618
+ foldTagOwnerRow(cached, row);
3619
+ for (const row of adopted)
3620
+ foldTagOwnerRow(cached, row, false);
3621
+ cached.dataVersion = dataVersion;
3622
+ cached.generation = generation;
3623
+ cached.globalLastRowId = globalLastRowId;
3624
+ return cached;
3625
+ }
3626
+ }
3627
+ const ratios = [
3628
+ ...new Set([...cached?.reasoningEstimatesByRatio.keys() ?? [], ...extraRatios])
3629
+ ];
3630
+ if (proseRatio !== undefined && !ratios.includes(proseRatio))
3631
+ ratios.push(proseRatio);
3632
+ const summary = {
3633
+ dataVersion,
3634
+ schemaVersion,
3635
+ generation,
3636
+ lastRowId: 0,
3637
+ globalLastRowId: db.prepare("SELECT COALESCE(MAX(id), 0) AS id FROM tags").get().id,
3638
+ rowCount: 0,
3639
+ unownedToolRows: new Set,
3640
+ identityRevision: readTagIdentityRevision(db, sessionId),
3641
+ maxTagByOwner: new Map,
3642
+ reasoningEstimatesByRatio: new Map(ratios.slice(-MAX_CACHED_PROSE_RATIOS).map((ratio) => [ratio, new Map]))
3643
+ };
3644
+ const rows = db.prepare(`SELECT ${TAG_OWNER_COLUMNS} FROM tags WHERE session_id = ? ORDER BY id`).all(sessionId);
3645
+ tagOwnerRowsRead += rows.length;
3646
+ for (const row of rows)
3647
+ foldTagOwnerRow(summary, row);
3648
+ if (!inTransaction) {
3649
+ sessions.set(sessionId, summary);
3650
+ tagOwnerSummaries.set(db, sessions);
2648
3651
  }
2649
- return totals;
3652
+ return summary;
2650
3653
  }
2651
3654
  function tagTokenCountIsNull(db, sessionId, tagNumber) {
2652
3655
  const row = db.prepare("SELECT token_count FROM tags WHERE session_id = ? AND tag_number = ?").get(sessionId, tagNumber);
@@ -2689,7 +3692,7 @@ function getTagNumberByMessageIdStatement(db) {
2689
3692
  function getAssignableTagNumberByMessageIdStatement(db) {
2690
3693
  let stmt = getAssignableTagNumberByMessageIdStatements.get(db);
2691
3694
  if (!stmt) {
2692
- stmt = db.prepare(`SELECT tag_number FROM tags
3695
+ stmt = db.prepare(`SELECT tag_number FROM tags INDEXED BY idx_tags_session_message_id
2693
3696
  WHERE session_id = ?
2694
3697
  AND message_id = ?
2695
3698
  AND NOT (
@@ -2750,6 +3753,19 @@ function insertTag(db, sessionId, messageId, type, byteSize, tagNumber, reasonin
2750
3753
  function updateTagStatus(db, sessionId, tagId, status) {
2751
3754
  getUpdateTagStatusStatement(db).run(status, sessionId, tagId);
2752
3755
  }
3756
+ var droppedTagStatements = new WeakMap;
3757
+ function markTagDropped(db, sessionId, tagId, mode) {
3758
+ if (!mode) {
3759
+ updateTagStatus(db, sessionId, tagId, "dropped");
3760
+ return;
3761
+ }
3762
+ let statement = droppedTagStatements.get(db);
3763
+ if (!statement) {
3764
+ statement = db.prepare("UPDATE tags SET status = ?, drop_mode = ? WHERE session_id = ? AND tag_number = ?");
3765
+ droppedTagStatements.set(db, statement);
3766
+ }
3767
+ statement.run("dropped", mode, sessionId, tagId);
3768
+ }
2753
3769
  var inertWhitespaceStatements = new WeakMap;
2754
3770
  function markWhitespaceAssistantTagInert(db, sessionId, tagNumber, contentId) {
2755
3771
  db.prepare(`UPDATE tags
@@ -2787,6 +3803,28 @@ function getInertWhitespaceAssistantTags(db, sessionId, messageIds) {
2787
3803
  return contentId.length > 0 ? [{ tagNumber: row.tagNumber, contentId }] : [];
2788
3804
  });
2789
3805
  }
3806
+ var inertWhitespaceByNumberStatements = new WeakMap;
3807
+ function getInertWhitespaceAssistantTagsByNumbers(db, sessionId, tagNumbers) {
3808
+ if (tagNumbers.length === 0)
3809
+ return [];
3810
+ let statement = inertWhitespaceByNumberStatements.get(db);
3811
+ if (!statement) {
3812
+ statement = db.prepare(`SELECT tags.tag_number AS tagNumber, tags.entry_fingerprint AS entryFingerprint
3813
+ FROM json_each(?) AS wanted CROSS JOIN tags
3814
+ WHERE tags.session_id = ?
3815
+ AND tags.tag_number = wanted.value
3816
+ AND tags.type = 'message'
3817
+ AND tags.status = 'compacted'
3818
+ AND tags.entry_fingerprint LIKE ?
3819
+ ORDER BY tags.tag_number, tags.id`);
3820
+ inertWhitespaceByNumberStatements.set(db, statement);
3821
+ }
3822
+ const rows = statement.all(JSON.stringify([...new Set(tagNumbers)]), sessionId, `${WHITESPACE_ASSISTANT_INERT_FINGERPRINT_PREFIX}%`);
3823
+ return rows.flatMap((row) => {
3824
+ const contentId = row.entryFingerprint.slice(WHITESPACE_ASSISTANT_INERT_FINGERPRINT_PREFIX.length);
3825
+ return contentId.length > 0 ? [{ tagNumber: row.tagNumber, contentId }] : [];
3826
+ });
3827
+ }
2790
3828
  function updateTagDropMode(db, sessionId, tagNumber, dropMode) {
2791
3829
  getUpdateTagDropModeStatement(db).run(dropMode, sessionId, tagNumber);
2792
3830
  }
@@ -3013,7 +4051,8 @@ function markTagsCompactedByMessageIds(db, sessionId, messageIds, eligibleTagNum
3013
4051
  SELECT value AS source_id, lower(value) AS folded_id FROM json_each(?)
3014
4052
  )
3015
4053
  SELECT id, tag_number, message_id, tool_owner_message_id FROM tags INDEXED BY ${tagOrderConstraintIndex(db)}
3016
- WHERE session_id = ? AND status IN ('active', 'dropped') AND (
4054
+ WHERE session_id = ? ${eligibleTagNumbers ? "AND tag_number IN (SELECT value FROM json_each(?))" : ""}
4055
+ AND status IN ('active', 'dropped') AND (
3017
4056
  message_id IN (SELECT source_id FROM ids)
3018
4057
  OR tool_owner_message_id IN (SELECT source_id FROM ids)
3019
4058
  OR (instr(lower(message_id), ':p') > 0 AND
@@ -3022,8 +4061,8 @@ function markTagsCompactedByMessageIds(db, sessionId, messageIds, eligibleTagNum
3022
4061
  lower(substr(message_id, 1, instr(lower(message_id), ':file') - 1)) IN (SELECT folded_id FROM ids))
3023
4062
  OR (? AND instr(message_id, ':') > 0)
3024
4063
  OR ?
3025
- )`).all(JSON.stringify(Array.from(ids)), sessionId, Array.from(ids).some((id) => id.includes(":")) ? 1 : 0, nulPrefixes.size > 0 ? 1 : 0);
3026
- const candidates = rows.filter((row) => (eligibleTagNumbers === undefined || eligibleTagNumbers.has(row.tag_number)) && matches(row.message_id, row.tool_owner_message_id));
4064
+ )`).all(JSON.stringify(Array.from(ids)), sessionId, ...eligibleTagNumbers ? [JSON.stringify([...eligibleTagNumbers])] : [], Array.from(ids).some((id) => id.includes(":")) ? 1 : 0, nulPrefixes.size > 0 ? 1 : 0);
4065
+ const candidates = rows.filter((row) => matches(row.message_id, row.tool_owner_message_id));
3027
4066
  if (candidates.length === 0)
3028
4067
  return 0;
3029
4068
  const update = db.prepare(`UPDATE tags SET status = 'compacted'
@@ -3177,7 +4216,7 @@ function getNewestToolTagNumbers(db, sessionId, limit) {
3177
4216
  let statement = newestToolTagNumberStatements.get(db);
3178
4217
  if (!statement) {
3179
4218
  statement = db.prepare(`SELECT tag_number FROM tags
3180
- WHERE session_id = ? AND type = 'tool'
4219
+ WHERE session_id = ? AND +type = 'tool'
3181
4220
  AND typeof(message_id) = 'text'
3182
4221
  AND typeof(status) = 'text'
3183
4222
  AND typeof(byte_size) IN ('integer', 'real')
@@ -3685,423 +4724,6 @@ function isHostRenderedSystemMessage(message) {
3685
4724
  return (typeof id !== "string" || id.length === 0) && message.info.role === "system";
3686
4725
  }
3687
4726
 
3688
- // src/hooks/magic-context/read-session-raw.ts
3689
- function isStrictGapHealingMessage(message) {
3690
- if (message.storeType === "synthetic")
3691
- return true;
3692
- let sawTool = false;
3693
- for (const part of message.parts) {
3694
- if (!part || typeof part !== "object" || Array.isArray(part))
3695
- return false;
3696
- const record = part;
3697
- const type = typeof record.type === "string" ? record.type : "";
3698
- if (type === "tool" || type === "tool_use" || type === "tool_result") {
3699
- sawTool = true;
3700
- continue;
3701
- }
3702
- const text = typeof record.text === "string" ? record.text : typeof record.content === "string" ? record.content : "";
3703
- if (text.trim().length > 0 || type.length > 0)
3704
- return false;
3705
- }
3706
- return sawTool;
3707
- }
3708
- var RAW_MESSAGE_PARTS_BY_ID_SQL = "SELECT message_id, data, time_updated FROM part WHERE +session_id = ? AND likelihood(message_id = ?, 0.000001) ORDER BY time_created ASC, id ASC";
3709
- function isRawMessageRow(row) {
3710
- if (row === null || typeof row !== "object")
3711
- return false;
3712
- const candidate = row;
3713
- return typeof candidate.id === "string" && typeof candidate.data === "string";
3714
- }
3715
- function isRawPartRow(row) {
3716
- if (row === null || typeof row !== "object")
3717
- return false;
3718
- const candidate = row;
3719
- return typeof candidate.message_id === "string" && typeof candidate.data === "string";
3720
- }
3721
- function parseJsonRecord(value) {
3722
- try {
3723
- const parsed = JSON.parse(value);
3724
- if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
3725
- return null;
3726
- }
3727
- return parsed;
3728
- } catch {
3729
- return null;
3730
- }
3731
- }
3732
- function isRawCompactionSummaryInfo(info) {
3733
- if (info === null || typeof info !== "object" || Array.isArray(info))
3734
- return false;
3735
- const candidate = info;
3736
- return candidate.summary === true && candidate.finish === "stop";
3737
- }
3738
- function parseJsonUnknown(value) {
3739
- try {
3740
- return JSON.parse(value);
3741
- } catch {
3742
- return null;
3743
- }
3744
- }
3745
- function attachRawPartVersion(value, timeUpdated) {
3746
- if (value === null || typeof value !== "object" || Array.isArray(value))
3747
- return value;
3748
- if (typeof timeUpdated !== "number")
3749
- return value;
3750
- try {
3751
- Object.defineProperty(value, "__magicContextPartUpdatedAt", {
3752
- value: timeUpdated,
3753
- enumerable: false,
3754
- configurable: true
3755
- });
3756
- } catch {}
3757
- return value;
3758
- }
3759
- function readRawSessionMessagesFromDb(db, sessionId) {
3760
- const messageRows = db.prepare("SELECT id, data, time_created, time_updated FROM message WHERE session_id = ? ORDER BY time_created ASC, id ASC").all(sessionId).filter(isRawMessageRow);
3761
- const partsByMessageId = new Map;
3762
- const partMessageBatchSize = 128;
3763
- for (let offset = 0;offset < messageRows.length; offset += partMessageBatchSize) {
3764
- const messageIds = messageRows.slice(offset, offset + partMessageBatchSize).map((row) => row.id);
3765
- if (messageIds.length === 0)
3766
- continue;
3767
- const placeholders = messageIds.map(() => "?").join(", ");
3768
- const partRows = db.prepare(`SELECT message_id, data, time_updated
3769
- FROM part
3770
- WHERE +session_id = ?
3771
- AND likelihood(message_id IN (${placeholders}), 0.000001)
3772
- ORDER BY message_id ASC, time_created ASC, id ASC`).all(sessionId, ...messageIds).filter(isRawPartRow);
3773
- for (const part of partRows) {
3774
- const list = partsByMessageId.get(part.message_id) ?? [];
3775
- list.push(attachRawPartVersion(parseJsonUnknown(part.data), part.time_updated));
3776
- partsByMessageId.set(part.message_id, list);
3777
- }
3778
- }
3779
- const filtered = messageRows.filter((row) => !isRawCompactionSummaryInfo(parseJsonRecord(row.data)));
3780
- return filtered.flatMap((row, index) => {
3781
- const info = parseJsonRecord(row.data);
3782
- if (!info)
3783
- return [];
3784
- const role = typeof info.role === "string" ? info.role : "unknown";
3785
- return {
3786
- ordinal: index + 1,
3787
- id: row.id,
3788
- role,
3789
- parts: partsByMessageId.get(row.id) ?? [],
3790
- createdAt: row.time_created ?? null,
3791
- version: row.time_updated ?? null
3792
- };
3793
- });
3794
- }
3795
- function readRawSessionMessagePageFromDb(db, sessionId, afterOrdinal, limit, finalWatermark = Number.MAX_SAFE_INTEGER, after) {
3796
- const messageRows = readRawMessagePageRows(db, sessionId, afterOrdinal, limit, finalWatermark, after);
3797
- if (messageRows.length === 0)
3798
- return [];
3799
- const placeholders = messageRows.map(() => "?").join(", ");
3800
- const partRows = db.prepare(`SELECT message_id, data, time_updated
3801
- FROM part
3802
- WHERE +session_id = ?
3803
- AND likelihood(message_id IN (${placeholders}), 0.000001)
3804
- ORDER BY message_id ASC, time_created ASC, id ASC`).all(sessionId, ...messageRows.map((row) => row.id)).filter(isRawPartRow);
3805
- return assembleRawMessagePage(messageRows, partRows);
3806
- }
3807
- function readRawMessagePageRows(db, sessionId, afterOrdinal, limit, finalWatermark, after) {
3808
- const remaining = Math.max(0, Math.floor(finalWatermark) - Math.floor(afterOrdinal));
3809
- const pageSize = Math.min(Math.max(1, Math.floor(limit)), remaining);
3810
- if (pageSize === 0)
3811
- return [];
3812
- const parameters = [sessionId];
3813
- if (after)
3814
- parameters.push(after.timeCreated, after.timeCreated, after.timeCreated, after.id);
3815
- parameters.push(pageSize);
3816
- if (!after)
3817
- parameters.push(Math.max(0, Math.floor(afterOrdinal)));
3818
- return db.prepare(`SELECT id, data, time_created, time_updated
3819
- FROM message
3820
- WHERE session_id = ?
3821
- ${after ? "AND time_created >= ? AND (time_created > ? OR (time_created = ? AND id > ?))" : ""}
3822
- AND NOT (
3823
- CASE WHEN json_valid(data) = 1
3824
- THEN COALESCE(json_extract(data, '$.summary'), 0)
3825
- ELSE 0 END = 1
3826
- AND CASE WHEN json_valid(data) = 1
3827
- THEN COALESCE(json_extract(data, '$.finish'), '')
3828
- ELSE '' END = 'stop'
3829
- )
3830
- ORDER BY time_created ASC, id ASC
3831
- LIMIT ? ${after ? "" : "OFFSET ?"}`).all(...parameters).filter(isRawMessageRow).map((row, index) => ({
3832
- ...row,
3833
- ordinal: Math.floor(afterOrdinal) + index + 1
3834
- }));
3835
- }
3836
- function assembleRawMessagePage(messageRows, partRows) {
3837
- const partsByMessageId = new Map;
3838
- for (const part of partRows) {
3839
- const list = partsByMessageId.get(part.message_id) ?? [];
3840
- list.push(attachRawPartVersion(parseJsonUnknown(part.data), part.time_updated));
3841
- partsByMessageId.set(part.message_id, list);
3842
- }
3843
- return messageRows.map((row) => {
3844
- const info = parseJsonRecord(row.data);
3845
- return {
3846
- ordinal: row.ordinal,
3847
- id: row.id,
3848
- role: typeof info?.role === "string" ? info.role : "unknown",
3849
- parts: partsByMessageId.get(row.id) ?? [],
3850
- createdAt: row.time_created ?? null,
3851
- version: row.time_updated ?? null
3852
- };
3853
- });
3854
- }
3855
- var RAW_SUMMARY_TEXT_MAX_CHARS = 8192;
3856
- var RAW_SUMMARY_ARG_MAX_CHARS = 512;
3857
- var RAW_SUMMARY_TOOL_INPUT_KEYS = [
3858
- "description",
3859
- "filePath",
3860
- "path",
3861
- "pattern",
3862
- "query",
3863
- "symbol",
3864
- "module",
3865
- "action"
3866
- ];
3867
- function summaryStringField(jsonPath) {
3868
- return `CASE WHEN json_type(data, '${jsonPath}') = 'text' THEN substr(json_extract(data, '${jsonPath}'), 1, ${RAW_SUMMARY_ARG_MAX_CHARS}) END`;
3869
- }
3870
- var RAW_SUMMARY_PART_DATA_SQL = `CASE
3871
- WHEN json_extract(data, '$.type') = 'text'
3872
- THEN json_set(data, '$.text', substr(json_extract(data, '$.text'), 1, ${RAW_SUMMARY_TEXT_MAX_CHARS}))
3873
- ELSE json_object(
3874
- 'type', 'tool',
3875
- 'tool', ${summaryStringField("$.tool")},
3876
- 'callID', ${summaryStringField("$.callID")},
3877
- 'state', json_object(
3878
- 'status', ${summaryStringField("$.state.status")},
3879
- 'input', json_object(${RAW_SUMMARY_TOOL_INPUT_KEYS.map((key) => `'${key}', ${summaryStringField(`$.state.input.${key}`)}`).join(", ")}),
3880
- 'metadata', json_object('description', ${summaryStringField("$.state.metadata.description")})
3881
- )
3882
- )
3883
- END`;
3884
- function readRawSessionMessageSummaryPageFromDb(db, sessionId, afterOrdinal, limit, finalWatermark = Number.MAX_SAFE_INTEGER, after) {
3885
- const messageRows = readRawMessagePageRows(db, sessionId, afterOrdinal, limit, finalWatermark, after);
3886
- if (messageRows.length === 0)
3887
- return [];
3888
- const placeholders = messageRows.map(() => "?").join(", ");
3889
- const partRows = db.prepare(`SELECT message_id, ${RAW_SUMMARY_PART_DATA_SQL} AS data, time_updated
3890
- FROM part
3891
- WHERE +session_id = ?
3892
- AND likelihood(message_id IN (${placeholders}), 0.000001)
3893
- AND json_valid(data) = 1
3894
- AND json_extract(data, '$.type') IN ('text', 'tool')
3895
- ORDER BY message_id ASC, time_created ASC, id ASC`).all(sessionId, ...messageRows.map((row) => row.id)).filter(isRawPartRow);
3896
- return assembleRawMessagePage(messageRows, partRows);
3897
- }
3898
- function countRawSessionMessageOrdinalsFromDb(db, sessionId) {
3899
- const row = db.prepare(`SELECT COUNT(*) AS count
3900
- FROM message
3901
- WHERE session_id = ?
3902
- AND NOT (
3903
- CASE WHEN json_valid(data) = 1
3904
- THEN COALESCE(json_extract(data, '$.summary'), 0)
3905
- ELSE 0 END = 1
3906
- AND CASE WHEN json_valid(data) = 1
3907
- THEN COALESCE(json_extract(data, '$.finish'), '')
3908
- ELSE '' END = 'stop'
3909
- )`).get(sessionId);
3910
- return typeof row?.count === "number" ? row.count : 0;
3911
- }
3912
- function readRawSessionMessageIdOrdinalsForRangeFromDb(db, sessionId, fromOrdinal, toOrdinal) {
3913
- const from = Math.max(1, Math.floor(fromOrdinal));
3914
- const to = Math.floor(toOrdinal);
3915
- if (to < from)
3916
- return new Map;
3917
- const rows = db.prepare(`
3918
- SELECT id, data FROM message WHERE session_id = ?
3919
- AND CASE WHEN json_valid(data) THEN NOT (
3920
- COALESCE(json_type(data, '$.summary'), '') = 'true'
3921
- AND COALESCE(json_extract(data, '$.finish'), '') = 'stop'
3922
- ) ELSE 1 END
3923
- ORDER BY time_created, id LIMIT ? OFFSET ?
3924
- `).all(sessionId, to - from + 1, from - 1).filter(isRawMessageRow);
3925
- const result = new Map;
3926
- for (const [index, row] of rows.entries()) {
3927
- if (parseJsonRecord(row.data))
3928
- result.set(row.id, from + index);
3929
- }
3930
- return result;
3931
- }
3932
- function isAnchorRow(row) {
3933
- return row !== null && typeof row === "object" && typeof row.time_created === "number" && typeof row.id === "string";
3934
- }
3935
- function readRawSessionTailFromDb(db, sessionId, baseOrdinal, anchorMessageId) {
3936
- const anchorRow = db.prepare("SELECT time_created, id, data FROM message WHERE id = ? AND session_id = ?").get(anchorMessageId, sessionId);
3937
- if (!isAnchorRow(anchorRow))
3938
- return null;
3939
- const anchorInfo = parseJsonRecord(anchorRow.data ?? "");
3940
- if (anchorInfo?.summary === true && anchorInfo?.finish === "stop")
3941
- return null;
3942
- const messageRows = db.prepare(`SELECT id, data, time_created, time_updated FROM message
3943
- WHERE session_id = ?
3944
- AND (time_created > ? OR (time_created = ? AND id >= ?))
3945
- ORDER BY time_created ASC, id ASC`).all(sessionId, anchorRow.time_created, anchorRow.time_created, anchorRow.id).filter(isRawMessageRow);
3946
- const filtered = messageRows.filter((row) => {
3947
- const info = parseJsonRecord(row.data);
3948
- return !(info?.summary === true && info?.finish === "stop");
3949
- });
3950
- const ids = filtered.map((row) => row.id);
3951
- const partsByMessageId = new Map;
3952
- if (ids.length > 0) {
3953
- const CHUNK = 800;
3954
- for (let i = 0;i < ids.length; i += CHUNK) {
3955
- const slice = ids.slice(i, i + CHUNK);
3956
- const placeholders = slice.map(() => "?").join(",");
3957
- const partRows = db.prepare(`SELECT message_id, data, time_updated FROM part WHERE +session_id = ? AND likelihood(message_id IN (${placeholders}), 0.000001) ORDER BY time_created ASC, id ASC`).all(sessionId, ...slice).filter(isRawPartRow);
3958
- for (const part of partRows) {
3959
- const list = partsByMessageId.get(part.message_id) ?? [];
3960
- list.push(attachRawPartVersion(parseJsonUnknown(part.data), part.time_updated));
3961
- partsByMessageId.set(part.message_id, list);
3962
- }
3963
- }
3964
- }
3965
- const messages = [];
3966
- let ord = baseOrdinal;
3967
- for (const row of filtered) {
3968
- const info = parseJsonRecord(row.data);
3969
- if (!info) {
3970
- ord += 1;
3971
- continue;
3972
- }
3973
- messages.push({
3974
- ordinal: ord,
3975
- id: row.id,
3976
- role: typeof info.role === "string" ? info.role : "unknown",
3977
- parts: partsByMessageId.get(row.id) ?? [],
3978
- createdAt: row.time_created ?? null,
3979
- version: row.time_updated ?? null
3980
- });
3981
- ord += 1;
3982
- }
3983
- return { messages, absoluteMessageCount: Math.max(0, ord - 1) };
3984
- }
3985
- function extractInMemoryMessageViews(messages) {
3986
- return messages.map((m) => {
3987
- const info = m.info ?? {};
3988
- return {
3989
- id: typeof info.id === "string" ? info.id : "",
3990
- role: typeof info.role === "string" ? info.role : "unknown",
3991
- parts: Array.isArray(m.parts) ? m.parts : [],
3992
- summary: info.summary === true ? true : undefined,
3993
- finish: typeof info.finish === "string" ? info.finish : undefined
3994
- };
3995
- });
3996
- }
3997
- function buildInMemoryTailRawMessages(args) {
3998
- const { messages, lastCompartmentEnd, anchorMessageId } = args;
3999
- const filtered = messages.filter((m) => !(m.summary === true && m.finish === "stop"));
4000
- if (filtered.length === 0)
4001
- return null;
4002
- let startIndex = 0;
4003
- let baseOrdinal;
4004
- let anchorFound = false;
4005
- if (anchorMessageId) {
4006
- const anchorIndex = filtered.findIndex((m) => m.id === anchorMessageId);
4007
- if (anchorIndex >= 0) {
4008
- anchorFound = true;
4009
- startIndex = anchorIndex;
4010
- baseOrdinal = lastCompartmentEnd;
4011
- } else {
4012
- baseOrdinal = Math.max(1, lastCompartmentEnd + 1);
4013
- }
4014
- } else {
4015
- baseOrdinal = Math.max(1, lastCompartmentEnd + 1);
4016
- }
4017
- const out = [];
4018
- let ord = baseOrdinal;
4019
- for (let i = startIndex;i < filtered.length; i += 1) {
4020
- const m = filtered[i];
4021
- if (!m.id || typeof m.id !== "string") {
4022
- ord += 1;
4023
- continue;
4024
- }
4025
- out.push({
4026
- ordinal: ord,
4027
- id: m.id,
4028
- role: typeof m.role === "string" ? m.role : "unknown",
4029
- parts: m.parts ?? [],
4030
- version: null
4031
- });
4032
- ord += 1;
4033
- }
4034
- return { messages: out, absoluteMessageCount: Math.max(0, ord - 1), anchorFound };
4035
- }
4036
- function readRawSessionMessageOrdinalByIdFromDb(db, sessionId, messageId) {
4037
- const row = db.prepare(`SELECT COUNT(candidate.id) AS ordinal
4038
- FROM message AS target
4039
- JOIN message AS candidate
4040
- ON candidate.session_id = target.session_id
4041
- AND NOT (
4042
- CASE WHEN json_valid(candidate.data) = 1
4043
- THEN COALESCE(json_extract(candidate.data, '$.summary'), 0)
4044
- ELSE 0 END = 1
4045
- AND CASE WHEN json_valid(candidate.data) = 1
4046
- THEN COALESCE(json_extract(candidate.data, '$.finish'), '')
4047
- ELSE '' END = 'stop'
4048
- )
4049
- AND (candidate.time_created < target.time_created
4050
- OR (candidate.time_created = target.time_created AND candidate.id <= target.id))
4051
- WHERE target.session_id = ?
4052
- AND target.id = ?
4053
- AND NOT (
4054
- CASE WHEN json_valid(target.data) = 1
4055
- THEN COALESCE(json_extract(target.data, '$.summary'), 0)
4056
- ELSE 0 END = 1
4057
- AND CASE WHEN json_valid(target.data) = 1
4058
- THEN COALESCE(json_extract(target.data, '$.finish'), '')
4059
- ELSE '' END = 'stop'
4060
- )`).get(sessionId, messageId);
4061
- const ordinal = row?.ordinal;
4062
- return typeof ordinal === "number" && ordinal > 0 ? ordinal : null;
4063
- }
4064
- function readRawSessionMessageByIdFromDb(db, sessionId, messageId) {
4065
- const row = db.prepare("SELECT id, data, time_created, time_updated FROM message WHERE session_id = ? AND id = ?").get(sessionId, messageId);
4066
- if (!row || !isRawMessageRow(row) || typeof row.time_created !== "number") {
4067
- return null;
4068
- }
4069
- const info = parseJsonRecord(row.data);
4070
- if (!info || isRawCompactionSummaryInfo(info)) {
4071
- return null;
4072
- }
4073
- const ordinalRow = db.prepare(`SELECT COUNT(*) AS ordinal FROM message
4074
- WHERE session_id = ?
4075
- AND NOT (COALESCE(json_extract(data, '$.summary'), 0) = 1
4076
- AND COALESCE(json_extract(data, '$.finish'), '') = 'stop')
4077
- AND (time_created < ? OR (time_created = ? AND id <= ?))`).get(sessionId, row.time_created, row.time_created, messageId);
4078
- const ordinal = typeof ordinalRow?.ordinal === "number" ? ordinalRow.ordinal : 0;
4079
- if (ordinal <= 0) {
4080
- return null;
4081
- }
4082
- const partRows = db.prepare(RAW_MESSAGE_PARTS_BY_ID_SQL).all(sessionId, messageId).filter(isRawPartRow);
4083
- const role = typeof info.role === "string" ? info.role : "unknown";
4084
- return {
4085
- ordinal,
4086
- id: row.id,
4087
- role,
4088
- parts: partRows.map((part) => attachRawPartVersion(parseJsonUnknown(part.data), part.time_updated)),
4089
- createdAt: row.time_created,
4090
- version: row.time_updated ?? null
4091
- };
4092
- }
4093
- function hasRawSessionMessageByIdFromDb(db, sessionId, messageId) {
4094
- const row = db.prepare("SELECT id, data, time_created FROM message WHERE session_id = ? AND id = ?").get(sessionId, messageId);
4095
- if (!row || !isRawMessageRow(row) || typeof row.time_created !== "number")
4096
- return false;
4097
- const info = parseJsonRecord(row.data);
4098
- if (!info || isRawCompactionSummaryInfo(info))
4099
- return false;
4100
- if (info.summary === 1 && info.finish === "stop")
4101
- return readRawSessionMessageByIdFromDb(db, sessionId, messageId) !== null;
4102
- return true;
4103
- }
4104
-
4105
4727
  // src/hooks/magic-context/read-session-true-raw-tokens.ts
4106
4728
  function completedToolArcCrossesBoundary(invOrdinal, resOrdinal, boundary) {
4107
4729
  return invOrdinal < boundary && boundary <= resOrdinal;
@@ -4239,7 +4861,7 @@ function callIdFromPart2(part) {
4239
4861
  const state = isRecord(part.state) ? part.state : null;
4240
4862
  return state ? firstStringField(state, ["callID", "callId", "toolCallId", "tool_call_id", "id"]) ?? "" : "";
4241
4863
  }
4242
- function toolSignalFromPart(part) {
4864
+ function toolSignalFromPart(part, withText = true) {
4243
4865
  if (!isRecord(part))
4244
4866
  return null;
4245
4867
  const type = partType(part);
@@ -4258,8 +4880,8 @@ function toolSignalFromPart(part) {
4258
4880
  callId,
4259
4881
  hasInput: hasInput || openInvocation,
4260
4882
  hasOutput,
4261
- inputText: hasInput && state ? stringValue(state.input) : "",
4262
- outputText: hasOutput ? stringValue(outputValue) : ""
4883
+ inputText: withText && hasInput && state ? stringValue(state.input) : "",
4884
+ outputText: withText && hasOutput ? stringValue(outputValue) : ""
4263
4885
  };
4264
4886
  }
4265
4887
  if (type === "tool-invocation") {
@@ -4268,7 +4890,7 @@ function toolSignalFromPart(part) {
4268
4890
  callId,
4269
4891
  hasInput: args !== undefined,
4270
4892
  hasOutput: false,
4271
- inputText: args !== undefined ? stringValue(args) : "",
4893
+ inputText: withText && args !== undefined ? stringValue(args) : "",
4272
4894
  outputText: ""
4273
4895
  };
4274
4896
  }
@@ -4278,7 +4900,7 @@ function toolSignalFromPart(part) {
4278
4900
  callId,
4279
4901
  hasInput: input !== undefined,
4280
4902
  hasOutput: false,
4281
- inputText: input !== undefined ? stringValue(input) : "",
4903
+ inputText: withText && input !== undefined ? stringValue(input) : "",
4282
4904
  outputText: ""
4283
4905
  };
4284
4906
  }
@@ -4289,7 +4911,7 @@ function toolSignalFromPart(part) {
4289
4911
  hasInput: false,
4290
4912
  hasOutput: content !== undefined,
4291
4913
  inputText: "",
4292
- outputText: content !== undefined ? textFromToolResultContent(content) : ""
4914
+ outputText: withText && content !== undefined ? textFromToolResultContent(content) : ""
4293
4915
  };
4294
4916
  }
4295
4917
  return null;
@@ -4299,7 +4921,7 @@ function partCheapFingerprint(part) {
4299
4921
  return `${typeof part}:${recursiveByteLength(part)}`;
4300
4922
  const version = rawPartVersion(part);
4301
4923
  const type = typeof part.type === "string" ? part.type : "";
4302
- return `${type}:${String(version)}:${recursiveByteLength(part)}`;
4924
+ return `${type}:${String(version)}:${recursiveByteLength(providerVisiblePart(part))}`;
4303
4925
  }
4304
4926
  function messageCacheKey(message, options) {
4305
4927
  const namespace = "cacheNamespace" in options ? options.cacheNamespace : "estimate";
@@ -4419,7 +5041,7 @@ function buildToolArcs(messages) {
4419
5041
  const arcs = [];
4420
5042
  for (const message of messages) {
4421
5043
  for (const part of message.parts) {
4422
- const signal = toolSignalFromPart(part);
5044
+ const signal = toolSignalFromPart(part, false);
4423
5045
  if (!signal || signal.callId.length === 0)
4424
5046
  continue;
4425
5047
  if (signal.hasInput && signal.hasOutput) {
@@ -4787,11 +5409,11 @@ function containsDroppedInputPlaceholder(value) {
4787
5409
  };
4788
5410
  return visit(value);
4789
5411
  }
4790
- function isRecord2(value) {
5412
+ function isRecord3(value) {
4791
5413
  return value !== null && typeof value === "object";
4792
5414
  }
4793
5415
  function isOptionalZodField(field) {
4794
- if (!isRecord2(field))
5416
+ if (!isRecord3(field))
4795
5417
  return false;
4796
5418
  const isOptional = field.isOptional;
4797
5419
  if (typeof isOptional === "function") {
@@ -4803,10 +5425,10 @@ function isOptionalZodField(field) {
4803
5425
  return internals?.optin === "optional";
4804
5426
  }
4805
5427
  function toolParameterNames(schema) {
4806
- if (!isRecord2(schema))
5428
+ if (!isRecord3(schema))
4807
5429
  return;
4808
5430
  const properties = schema.properties;
4809
- if (isRecord2(properties) && !Array.isArray(properties)) {
5431
+ if (isRecord3(properties) && !Array.isArray(properties)) {
4810
5432
  const names = Object.keys(properties);
4811
5433
  const requiredList = Array.isArray(schema.required) ? schema.required : [];
4812
5434
  const required = new Set(requiredList.filter((name) => typeof name === "string"));
@@ -4821,7 +5443,7 @@ function toolParameterNames(schema) {
4821
5443
  } catch {
4822
5444
  shape = undefined;
4823
5445
  }
4824
- if (isRecord2(shape) && !Array.isArray(shape)) {
5446
+ if (isRecord3(shape) && !Array.isArray(shape)) {
4825
5447
  const result = { required: [], optional: [] };
4826
5448
  for (const [name, field] of Object.entries(shape)) {
4827
5449
  (isOptionalZodField(field) ? result.optional : result.required).push(name);
@@ -4939,6 +5561,12 @@ function safeSlice(str, maxLen) {
4939
5561
  function isEditTool(name) {
4940
5562
  return name === "edit" || name === "write";
4941
5563
  }
5564
+ function needsEditMarker(input) {
5565
+ return Object.keys(input).some((key) => {
5566
+ const value = input[key];
5567
+ return DIFF_KEYS.has(key) && typeof value === "string" && value.length > EDIT_REGION_HINT_LEN && !value.endsWith(TRUNCATION_SENTINEL);
5568
+ });
5569
+ }
4942
5570
  function applyEditMarkerToInput(input) {
4943
5571
  for (const key of Object.keys(input)) {
4944
5572
  if (PATH_KEYS.has(key))
@@ -5100,6 +5728,17 @@ function serializedTokens(value, bounded = false) {
5100
5728
  return Buffer.byteLength(serialized);
5101
5729
  return serialized ? wireTextTokens(serialized) : 0;
5102
5730
  }
5731
+ function estimatePartImageTokens(raw) {
5732
+ if (!raw || typeof raw !== "object")
5733
+ return 0;
5734
+ const part = raw;
5735
+ if (part.ignored)
5736
+ return 0;
5737
+ if (part.type === "file" && part.mime?.startsWith("image/")) {
5738
+ return typeof part.url === "string" && part.url.startsWith("data:") ? estimateImageTokensFromDataUrl(part.url) : 1200;
5739
+ }
5740
+ return part.type === "tool" ? estimateToolAttachmentImageTokens(part.state) : 0;
5741
+ }
5103
5742
  function visitWireContent(message, visit) {
5104
5743
  for (const part of message.parts) {
5105
5744
  if (!part || typeof part !== "object")
@@ -5128,15 +5767,13 @@ function visitWireContent(message, visit) {
5128
5767
  text(p.data);
5129
5768
  break;
5130
5769
  case "file":
5131
- if (typeof p.mime === "string" && p.mime.startsWith("image/")) {
5132
- visit.image("conversation", typeof p.url === "string" && p.url.startsWith("data:") ? estimateImageTokensFromDataUrl(p.url) : 1200);
5133
- }
5770
+ visit.image("conversation", estimatePartImageTokens(part));
5134
5771
  break;
5135
5772
  case "tool":
5136
5773
  tool(p.state?.input ?? p.input ?? p.args);
5137
5774
  tool(p.state?.output ?? p.state?.content ?? p.output ?? p.result ?? p.content);
5138
5775
  tool(p.state?.error);
5139
- visit.image("toolCall", estimateToolAttachmentImageTokens(p.state));
5776
+ visit.image("toolCall", estimatePartImageTokens(part));
5140
5777
  break;
5141
5778
  case "tool-call":
5142
5779
  tool(p.input ?? p.args);
@@ -5680,6 +6317,15 @@ function makeWholeMessageSentinel(providerID) {
5680
6317
  text: modelAcceptsEmptyContent(providerID) ? "" : WHOLE_MESSAGE_PLACEHOLDER_TEXT
5681
6318
  };
5682
6319
  }
6320
+ function wholeMessageNeutralizationRemoves(message, providerID) {
6321
+ return message.info.role === "system" && modelAcceptsEmptyContent(providerID);
6322
+ }
6323
+ function neutralizeWholeMessage(message, providerID) {
6324
+ message.parts.length = 0;
6325
+ if (!wholeMessageNeutralizationRemoves(message, providerID)) {
6326
+ message.parts.push(makeWholeMessageSentinel(providerID));
6327
+ }
6328
+ }
5683
6329
  function isSentinel(part) {
5684
6330
  if (!isRecord(part))
5685
6331
  return false;
@@ -5707,8 +6353,9 @@ function replaySentinelByMessageIds(messages, ids, providerID, hiddenSeamIds = n
5707
6353
  }
5708
6354
  if (msg.parts.length === 1 && isSentinel(msg.parts[0]))
5709
6355
  continue;
5710
- msg.parts.length = 0;
5711
- msg.parts.push(makeWholeMessageSentinel(providerID));
6356
+ if (wholeMessageNeutralizationRemoves(msg, providerID) && msg.parts.length === 0)
6357
+ continue;
6358
+ neutralizeWholeMessage(msg, providerID);
5712
6359
  replayed += 1;
5713
6360
  }
5714
6361
  const missingIds = [];
@@ -5776,24 +6423,18 @@ function setToolContent(part, content) {
5776
6423
  }
5777
6424
  }
5778
6425
  function clonePart(part) {
5779
- if (part === null || typeof part !== "object")
5780
- return part;
5781
- try {
5782
- return structuredClone(part);
5783
- } catch {
5784
- try {
5785
- return JSON.parse(JSON.stringify(part));
5786
- } catch {
5787
- return part;
5788
- }
5789
- }
6426
+ return {
6427
+ ...part,
6428
+ ...isRecord(part.state) ? { state: { ...part.state } } : {}
6429
+ };
5790
6430
  }
5791
6431
  function clampCloneInPlace(occurrence, clamp) {
5792
- const clone = clonePart(occurrence.part);
5793
- clamp(clone);
5794
6432
  const parts = occurrence.message.parts;
5795
6433
  const index = parts.indexOf(servedPart(occurrence));
5796
6434
  if (index >= 0) {
6435
+ const clone = clamp(occurrence.part);
6436
+ if (clone === servedPart(occurrence))
6437
+ return;
5797
6438
  parts[index] = clone;
5798
6439
  occurrence.served = clone;
5799
6440
  }
@@ -5803,17 +6444,24 @@ function servedPart(occurrence) {
5803
6444
  }
5804
6445
  function skeletonRealToolPart(part, tagId, stripAttachments = false) {
5805
6446
  if (!isRecord(part))
5806
- return;
6447
+ return part;
5807
6448
  const sentinel = `[dropped §${tagId}§]`;
5808
6449
  if (part.type === "tool" && isRecord(part.state)) {
5809
- part.state.output = sentinel;
6450
+ if (part.state.output === sentinel && !needsAttachmentStrip(part.state, stripAttachments))
6451
+ return part;
6452
+ const clone = clonePart(part);
6453
+ const state = clone.state;
6454
+ state.output = sentinel;
5810
6455
  if (stripAttachments)
5811
- part.state.attachments = [];
5812
- return;
5813
- }
5814
- if (part.type === "tool_result") {
5815
- part.content = sentinel;
6456
+ state.attachments = [];
6457
+ return clone;
5816
6458
  }
6459
+ if (part.type === "tool_result" && part.content !== sentinel)
6460
+ return { ...part, content: sentinel };
6461
+ return part;
6462
+ }
6463
+ function needsAttachmentStrip(state, strip) {
6464
+ return strip && (!Array.isArray(state.attachments) || state.attachments.length !== 0);
5817
6465
  }
5818
6466
  function readToolPartRawInput(part) {
5819
6467
  if (!isRecord(part))
@@ -5826,51 +6474,62 @@ function readToolPartRawInput(part) {
5826
6474
  return part.input;
5827
6475
  return;
5828
6476
  }
6477
+ function isDroppedInput(input, sentinel) {
6478
+ return isRecord(input) && Object.keys(input).length === 1 && Object.hasOwn(input, "dropped") && input.dropped === sentinel;
6479
+ }
5829
6480
  function truncateToolPart(part, tagId) {
5830
6481
  if (!isRecord(part))
5831
- return;
6482
+ return part;
5832
6483
  const sentinel = `[dropped §${tagId}§]`;
5833
6484
  if (part.type === "tool" && isRecord(part.state)) {
5834
- const state = part.state;
6485
+ if (part.state.output === sentinel && isDroppedInput(part.state.input, sentinel))
6486
+ return part;
6487
+ const clone = clonePart(part);
6488
+ const state = clone.state;
5835
6489
  state.output = sentinel;
5836
6490
  state.input = droppedInputMarker(tagId);
5837
- return;
6491
+ return clone;
5838
6492
  }
5839
6493
  if (part.type === "tool_result") {
5840
- part.content = sentinel;
5841
- return;
6494
+ return part.content === sentinel ? part : { ...part, content: sentinel };
5842
6495
  }
5843
6496
  if (part.type === "tool-invocation") {
5844
- part.args = droppedInputMarker(tagId);
5845
- return;
6497
+ return isDroppedInput(part.args, sentinel) ? part : { ...part, args: droppedInputMarker(tagId) };
5846
6498
  }
5847
6499
  if (part.type === "tool_use") {
5848
- part.input = droppedInputMarker(tagId);
6500
+ return isDroppedInput(part.input, sentinel) ? part : { ...part, input: droppedInputMarker(tagId) };
5849
6501
  }
6502
+ return part;
5850
6503
  }
5851
6504
  function editMarkerToolPart(part, tagId, stripAttachments = false) {
5852
6505
  if (!isRecord(part))
5853
- return;
6506
+ return part;
5854
6507
  const sentinel = `[dropped §${tagId}§]`;
6508
+ const input = readToolPartInput(part);
6509
+ const rewriteInput = input !== null && needsEditMarker(input);
5855
6510
  if (part.type === "tool" && isRecord(part.state)) {
5856
- part.state.output = sentinel;
6511
+ if (part.state.output === sentinel && !rewriteInput && !needsAttachmentStrip(part.state, stripAttachments))
6512
+ return part;
6513
+ const clone = clonePart(part);
6514
+ const state = clone.state;
6515
+ state.output = sentinel;
5857
6516
  if (stripAttachments)
5858
- part.state.attachments = [];
5859
- if (isRecord(part.state.input))
5860
- applyEditMarkerToInput(part.state.input);
5861
- return;
6517
+ state.attachments = [];
6518
+ if (rewriteInput) {
6519
+ state.input = { ...input };
6520
+ applyEditMarkerToInput(state.input);
6521
+ }
6522
+ return clone;
5862
6523
  }
5863
6524
  if (part.type === "tool_result") {
5864
- part.content = sentinel;
5865
- return;
5866
- }
5867
- if (part.type === "tool-invocation" && isRecord(part.args)) {
5868
- applyEditMarkerToInput(part.args);
5869
- return;
6525
+ return part.content === sentinel ? part : { ...part, content: sentinel };
5870
6526
  }
5871
- if (part.type === "tool_use" && isRecord(part.input)) {
5872
- applyEditMarkerToInput(part.input);
6527
+ if (rewriteInput) {
6528
+ const markedInput = { ...input };
6529
+ applyEditMarkerToInput(markedInput);
6530
+ return { ...part, [part.type === "tool-invocation" ? "args" : "input"]: markedInput };
5873
6531
  }
6532
+ return part;
5874
6533
  }
5875
6534
  function readToolPartInput(part) {
5876
6535
  if (!isRecord(part))
@@ -6099,9 +6758,7 @@ function createToolDropTarget(compositeKey, thinkingParts, index, batch, tagId)
6099
6758
  parts
6100
6759
  });
6101
6760
  const before = count(parts);
6102
- const retained = skeleton ? structuredClone(parts) : [];
6103
- for (const part of retained)
6104
- skeletonRealToolPart(part, tagId);
6761
+ const retained = skeleton ? parts.map((part) => skeletonRealToolPart(part, tagId)) : [];
6105
6762
  const after = count(retained);
6106
6763
  return {
6107
6764
  beforeTools: before.toolCall,
@@ -6149,6 +6806,10 @@ function createToolDropTarget(compositeKey, thinkingParts, index, batch, tagId)
6149
6806
  return false;
6150
6807
  return batch.wouldStrandConversationEnd(entry.occurrences);
6151
6808
  },
6809
+ prepareDrop: () => {
6810
+ const entry = index.get(compositeKey);
6811
+ return !!entry && entry.occurrences.length > 0 && entry.hasResult;
6812
+ },
6152
6813
  canDrop: () => {
6153
6814
  const entry = index.get(compositeKey);
6154
6815
  return !!entry && entry.occurrences.length > 0 && entry.hasResult && !entry.occurrences.some((occurrence) => toolPartHasUserAnswer(occurrence.part));
@@ -6422,6 +7083,14 @@ function readRawSessionMessageRange2(sessionId, fromOrdinal, toOrdinal) {
6422
7083
  }
6423
7084
  readRawSessionMessages2.readPage = readRawSessionMessagePage2;
6424
7085
  readRawSessionMessages2.getCount = getRawSessionMessageOrdinalCount2;
7086
+ readRawSessionMessages2.prepare = prepareRawSessionOrdinals2;
7087
+ async function prepareRawSessionOrdinals2(sessionId) {
7088
+ if (sessionProviders.get(sessionId)?.provider)
7089
+ return true;
7090
+ if (!openCodeDbExists())
7091
+ return true;
7092
+ return withReadOnlySessionDb((db) => warmRawSessionOrdinalsForDb(db, sessionId));
7093
+ }
6425
7094
  function primeTailRawMessageCache2(args) {
6426
7095
  const { sessionId, lastCompartmentEnd, anchorMessageId } = args;
6427
7096
  if (!activeRawMessageCache)
@@ -6573,6 +7242,7 @@ function readRawSessionMessageById2(sessionId, messageId) {
6573
7242
  return null;
6574
7243
  return withReadOnlySessionDb((db) => readRawSessionMessageByIdFromDb(db, sessionId, messageId));
6575
7244
  }
7245
+ readRawSessionMessageById2.prepare = prepareRawSessionOrdinals2;
6576
7246
  function readRawSessionMessagesFromSource(sessionId) {
6577
7247
  const provider = sessionProviders.get(sessionId)?.provider;
6578
7248
  if (provider)
@@ -6953,6 +7623,14 @@ function readSessionChunk2(sessionId, tokenBudget, offset = 1, eligibleEndOrdina
6953
7623
  pinComponentWhenFormattedBudgetCrosses(msg.ordinal, text);
6954
7624
  }
6955
7625
  if (flushCurrentBlock() && pendingNoiseMeta.length > 0) {
7626
+ const lastNoise = pendingNoiseMeta[pendingNoiseMeta.length - 1];
7627
+ if (messagesProcessed > 0 && lastNoise) {
7628
+ lineMeta.push(...pendingNoiseMeta);
7629
+ messagesProcessed += pendingNoiseMeta.length;
7630
+ lastOrdinal = lastNoise.ordinal;
7631
+ lastMessageId = lastNoise.messageId;
7632
+ pendingNoiseMeta = [];
7633
+ }
6956
7634
  highestScannedOrdinal = Math.max(highestScannedOrdinal, pendingNoiseMeta[pendingNoiseMeta.length - 1]?.ordinal ?? highestScannedOrdinal);
6957
7635
  }
6958
7636
  const toolOnlyRanges = [];
@@ -6990,4 +7668,4 @@ function readSessionChunk2(sessionId, tokenBudget, offset = 1, eligibleEndOrdina
6990
7668
  toolResultBoundaries
6991
7669
  };
6992
7670
  }
6993
- export { toolTemplateError, DEFAULT_PROTECTED_TOOLS, normalizeProtectedToolName, mergeProtectedTools, isRecord, detectLatestTurnThinkingMismatch, isPrefixBoundThinkingModel, detectOverflow, protectedToolTagNumbers, protectedToolTokenCount, textMentionsRecentCommit, removeSystemReminders, hasMeaningfulUserText2, extractTexts2, getTokenizerNativeMemoryStats, preloadTokenizer, estimateTokens, estimateFixedPromptTokens, stripWellFormedLeadingTagPrefix, byteSize, stripTagPrefix, peelLeadingMcTagNotation, prependTag, isThinkingPart, stableStringify, contentTagOwnerMessageId, estimateImageTokensFromDataUrl, estimateToolAttachmentImageTokens, normalizeTodoStateJson, buildSyntheticTodoPart, isSyntheticTodoPart, countRealUserMessages, tailHygieneStructuralSignature, sameTailHygieneStructuralSignature, formatTailHygienePrefixMismatch, refreshTailHygieneBaseline, effectiveTailHygiene, assertTailHygieneContentUnchangedIfEnabled, CHANNEL1_SENTINEL, CHANNEL1_FLOOR_TOKENS, isDroppedToolOutput, toolOutputTokens, decideChannel1, evaluateChannel2, formatChannel1Evaluation, formatChannel2Evaluation, reclaimableToolOutputCount, buildChannel2Reminder, buildChannel1Reminder, estimateEmergencyDropReclaimTokens, planEmergencyDrop, measureEmergencyTag, installV3PerfSchema, queuePendingOp, queuePendingDropForUnchangedTag, getPendingOps, getPendingOpsCount, clearPendingOps, removePendingOp, getRecentTagOwnerMessageIds, AGE_RECLAIM_MIN_TOKENS, getOldestActiveUnprotectedToolTags, getActiveToolTagsForAgeReclaim, getTriggerTagTokenUpperBound, getActiveTagTokenTotalsByMessage, getAllStatusTagTokenTotalsFlat, getReasoningTokenEstimatesByMessage, tagTokenCountIsNull, backfillTagTokenCounts, insertTag, updateTagStatus, markWhitespaceAssistantTagInert, getInertWhitespaceAssistantTags, updateTagDropMode, updateCavemanDepth, updateTagMessageId, foldShrunkPartTags, markTagsCompactedByMessageIds, getMaxTagNumberBySession, getTagNumberByMessageId, getAssignableTagNumberByMessageId, deriveTagLoadFloor, TAG_SELECT_COLUMNS, getTagsBySession, getActiveTagsBySession, getTailHygieneTags, getTagsByNumbers, getNewestToolTagNumbers, getDroppedTagsByNumbers, getMaxDroppedTagNumber, getTagById, getToolTagNumberByOwner, getNullOwnerToolTag, adoptNullOwnerToolTag, getCandidateToolOwners, pickNearestPriorOwner, expandToolPart, markHostUnservedRow, retreatPastHostUnservedRows, snapTerminalCompartmentToServedRow, isHostRenderedSystemMessage, isStrictGapHealingMessage, extractInMemoryMessageViews, buildInMemoryTailRawMessages, completedToolArcCrossesBoundary, estimateTrueRawMessageTokens, buildToolArcs, fenceBoundaryForCompletedToolArcs, fenceBoundaryForToolArcs, buildTrueRawTokenIndex, computeRawRangeFingerprint, stripSystemInjection, isTextPart, isToolPartWithOutput, isFilePart, buildFileSourceContent, toolPartHasUserAnswer, recordToolParameters, createDroppedInputGuard, assertExecutableToolInput, isEditTool, getCurrentToolSetHash, setDatabase, loadToolDefinitionMeasurements, recordToolDefinition, getMeasuredToolDefinitionTokens, describeFinalWireTail, estimateMessageTokens, wireContentBytes, createFinalWireUsageTracker, estimateFinalWireInputTokens, modelAcceptsEmptyContent, isAnthropicFamilyRoute, neutralizeDroppedReasoningPart, restoreNeutralizedReasoningPart, isNeutralizedReasoningPart, neutralizedReasoningSource, variantChangeBustsProviderCache, makeSentinel, makeWholeMessageSentinel, isSentinel, replaySentinelByMessageIds, SKELETON_REAL_INPUT_MAX_BYTES, partHasCompletedResult, extractToolCallObservation, ToolMutationBatch, createToolDropTarget, resolveHostServedBoundaryId2, hasRawMessageProvider2, setBoundedRawMessageProvider2, cleanUserText2, withRawSessionMessageCache2, readRawSessionMessages2, readRawSessionMessagePage2, getRawSessionMessageOrdinalCount2, visitRawSessionMessages2, readRawSessionMessageRange2, primeTailRawMessageCache2, getCachedAbsoluteMessageCount2, primeInMemoryTailRawMessageCache2, readRawSessionMessageIdOrdinalsForRange2, hasRawSessionMessageById2, readRawSessionMessageOrdinalById2, compareRawSessionMessageOrder2, readRawSessionMessageById2, getRawSessionMessageCount2, getRawSessionTagKeysThrough2, getLegacyProtectedTailStartOrdinal2, readSessionChunk2 };
7671
+ export { toolTemplateError, DEFAULT_PROTECTED_TOOLS, normalizeProtectedToolName, mergeProtectedTools, detectLatestTurnThinkingMismatch, isPrefixBoundThinkingModel, detectOverflow, stripWellFormedLeadingTagPrefix, stripPersistedAssistantText, byteSize, stripTagPrefix, peelLeadingMcTagNotation, prependTag, isThinkingPart, isRecord, protectedToolTagNumbers, protectedToolTokenCount, textMentionsRecentCommit, removeSystemReminders, hasMeaningfulUserText2, extractTexts2, getTokenizerNativeMemoryStats, preloadTokenizer, estimateTokens, estimateFixedPromptTokens, currentReclaimableToolOutputCount, stableStringify, contentTagOwnerMessageId, estimateImageTokensFromDataUrl, estimateToolAttachmentImageTokens, providerVisibleMessage, normalizeTodoStateJson, buildSyntheticTodoPart, isSyntheticTodoPart, countRealUserMessages, tailHygieneStructuralSignature, sameTailHygieneStructuralSignature, formatTailHygienePrefixMismatch, refreshTailHygieneBaseline, effectiveTailHygiene, assertTailHygieneContentUnchangedIfEnabled, CHANNEL1_SENTINEL, CHANNEL1_FLOOR_TOKENS, isDroppedToolOutput, toolOutputTokens, decideChannel1, evaluateChannel2, formatChannel1Evaluation, formatChannel2Evaluation, reclaimableToolOutputCount, buildChannel2Reminder, buildChannel1Reminder, estimateEmergencyDropReclaimTokens, planEmergencyDrop, measureEmergencyTag, installV3PerfSchema, queuePendingOp, queuePendingDropForUnchangedTag, getPendingOps, getPendingOpsCount, clearPendingOps, removePendingOp, tagTombstoneOwnerRange, tagTombstoneOwnerKey, tagRevisionKey, tagIdentityRevisionKey, installTagIdentityRevisionTrigger, deleteTagIdentityRevisions, getRecentTagOwnerMessageIds, AGE_RECLAIM_MIN_TOKENS, getOldestActiveUnprotectedToolTags, getActiveToolTagsForAgeReclaim, getTriggerTagTokenUpperBound, getActiveTagTokenTotalsByMessage, getAllStatusTagTokenTotalsFlat, getReasoningTokenEstimatesByMessage, tryGetReasoningTokenEstimatesByMessage, getMaxTagNumberByOwnerMessage, scanTagOwnerSummary, isTagOwnerSummaryReady, tagTokenCountIsNull, backfillTagTokenCounts, insertTag, updateTagStatus, markTagDropped, markWhitespaceAssistantTagInert, getInertWhitespaceAssistantTags, getInertWhitespaceAssistantTagsByNumbers, updateTagDropMode, updateCavemanDepth, updateTagMessageId, foldShrunkPartTags, markTagsCompactedByMessageIds, getMaxTagNumberBySession, getTagNumberByMessageId, getAssignableTagNumberByMessageId, deriveTagLoadFloor, TAG_SELECT_COLUMNS, getTagsBySession, getActiveTagsBySession, getTailHygieneTags, getTagsByNumbers, getNewestToolTagNumbers, getDroppedTagsByNumbers, getMaxDroppedTagNumber, getTagById, getToolTagNumberByOwner, getNullOwnerToolTag, adoptNullOwnerToolTag, getCandidateToolOwners, pickNearestPriorOwner, expandToolPart, markHostUnservedRow, retreatPastHostUnservedRows, snapTerminalCompartmentToServedRow, isHostRenderedSystemMessage, completedToolArcCrossesBoundary, estimateTrueRawMessageTokens, buildToolArcs, fenceBoundaryForCompletedToolArcs, fenceBoundaryForToolArcs, buildTrueRawTokenIndex, computeRawRangeFingerprint, stripSystemInjection, isTextPart, isToolPartWithOutput, isFilePart, buildFileSourceContent, toolPartHasUserAnswer, recordToolParameters, createDroppedInputGuard, assertExecutableToolInput, isEditTool, getCurrentToolSetHash, setDatabase, loadToolDefinitionMeasurements, recordToolDefinition, getMeasuredToolDefinitionTokens, describeFinalWireTail, estimatePartImageTokens, estimateMessageTokens, wireContentBytes, createFinalWireUsageTracker, estimateFinalWireInputTokens, modelAcceptsEmptyContent, isAnthropicFamilyRoute, neutralizeDroppedReasoningPart, restoreNeutralizedReasoningPart, isNeutralizedReasoningPart, neutralizedReasoningSource, variantChangeBustsProviderCache, makeSentinel, makeWholeMessageSentinel, neutralizeWholeMessage, isSentinel, replaySentinelByMessageIds, SKELETON_REAL_INPUT_MAX_BYTES, partHasCompletedResult, extractToolCallObservation, ToolMutationBatch, createToolDropTarget, resolveHostServedBoundaryId2, hasRawMessageProvider2, setBoundedRawMessageProvider2, cleanUserText2, withRawSessionMessageCache2, readRawSessionMessages2, readRawSessionMessagePage2, getRawSessionMessageOrdinalCount2, visitRawSessionMessages2, readRawSessionMessageRange2, prepareRawSessionOrdinals2, primeTailRawMessageCache2, getCachedAbsoluteMessageCount2, primeInMemoryTailRawMessageCache2, readRawSessionMessageIdOrdinalsForRange2, hasRawSessionMessageById2, readRawSessionMessageOrdinalById2, compareRawSessionMessageOrder2, readRawSessionMessageById2, getRawSessionMessageCount2, getRawSessionTagKeysThrough2, getLegacyProtectedTailStartOrdinal2, readSessionChunk2 };