@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
@@ -0,0 +1,20 @@
1
+ [
2
+ { "name": "own maximum wins over a later smaller tag", "tags": [[2, 10, 4], [3]], "target": 0, "watermark": 8, "cutoff": null, "percentage": 60, "age": 10, "eligible": false },
3
+ { "name": "own maximum at watermark", "tags": [[2, 10, 4], [30]], "target": 0, "watermark": 10, "cutoff": null, "percentage": 60, "age": 10, "eligible": true },
4
+ { "name": "first later tag not largest later tag", "tags": [[], [3], [20]], "target": 0, "watermark": 3, "cutoff": null, "percentage": 60, "age": 3, "eligible": true },
5
+ { "name": "first later message contributes its own maximum", "tags": [[], [2, 9], [3]], "target": 0, "watermark": 5, "cutoff": null, "percentage": 60, "age": 9, "eligible": false },
6
+ { "name": "skip empty and zero tags when looking forward", "tags": [[1], [], [0], [4]], "target": 1, "watermark": 4, "cutoff": null, "percentage": 60, "age": 4, "eligible": true },
7
+ { "name": "zero own tag inherits later positive", "tags": [[0], [7]], "target": 0, "watermark": 6, "cutoff": null, "percentage": 60, "age": 7, "eligible": false },
8
+ { "name": "preceding tag cannot age live tail", "tags": [[1], [], []], "target": 1, "watermark": 100, "cutoff": null, "percentage": 60, "age": null, "eligible": false },
9
+ { "name": "all untagged is ineligible", "tags": [[], []], "target": 0, "watermark": 100, "cutoff": null, "percentage": 60, "age": null, "eligible": false },
10
+ { "name": "watermark zero even with emergency", "tags": [[], [1]], "target": 0, "watermark": 0, "cutoff": 1, "percentage": 95, "age": 1, "eligible": false },
11
+ { "name": "age above watermark even with emergency", "tags": [[], [7]], "target": 0, "watermark": 6, "cutoff": 1, "percentage": 100, "age": 7, "eligible": false },
12
+ { "name": "cutoff inclusive at 94.99 percent", "tags": [[5], [8]], "target": 0, "watermark": 9, "cutoff": 5, "percentage": 94.99, "age": 5, "eligible": false },
13
+ { "name": "inside cutoff is a range not set membership", "tags": [[], [6]], "target": 0, "watermark": 9, "cutoff": 5, "percentage": 60, "age": 6, "eligible": false },
14
+ { "name": "below cutoff is eligible", "tags": [[4], [8]], "target": 0, "watermark": 9, "cutoff": 5, "percentage": 94.99, "age": 4, "eligible": true },
15
+ { "name": "exactly 95 waives cutoff", "tags": [[], [6]], "target": 0, "watermark": 9, "cutoff": 5, "percentage": 95, "age": 6, "eligible": true },
16
+ { "name": "above 95 waives cutoff", "tags": [[5], [8]], "target": 0, "watermark": 9, "cutoff": 5, "percentage": 95.01, "age": 5, "eligible": true },
17
+ { "name": "emergency cannot invent tail age", "tags": [[1], []], "target": 1, "watermark": 100, "cutoff": 1, "percentage": 100, "age": null, "eligible": false },
18
+ { "name": "own positive tag overrides later greater tag", "tags": [[2], [20]], "target": 0, "watermark": 2, "cutoff": 3, "percentage": 60, "age": 2, "eligible": true },
19
+ { "name": "last message with own tag is aged", "tags": [[1], [4]], "target": 1, "watermark": 4, "cutoff": null, "percentage": 60, "age": 4, "eligible": true }
20
+ ]
@@ -0,0 +1,19 @@
1
+ import { expect, test } from "bun:test";
2
+ import { createProcessedImageEligibility } from "./processed-image-eligibility";
3
+ import cases from "./processed-image-position-review.json";
4
+
5
+ // OpenCode, Rust and Pi can reuse these cases: each row supplies per-message
6
+ // tag numbers rather than provider-specific message objects or image encodings.
7
+ for (const row of cases) {
8
+ test(`independent image position table: ${row.name}`, () => {
9
+ const messages = row.tags.map((_, i) => `message-${i}`);
10
+ const tags = new Map(messages.map((message, i) => [message, Math.max(0, ...row.tags[i])]));
11
+ const policy = createProcessedImageEligibility(messages, tags, {
12
+ watermark: row.watermark,
13
+ protectedCutoff: row.cutoff,
14
+ contextPercentage: row.percentage,
15
+ });
16
+ expect(policy.ageTags.get(messages[row.target]) ?? null).toBe(row.age);
17
+ expect(policy.mayStrip(messages[row.target])).toBe(row.eligible);
18
+ });
19
+ }
@@ -20,6 +20,26 @@ export function projectDirectoryKey(directory: string): string {
20
20
  return path.resolve(directory);
21
21
  }
22
22
 
23
+ /**
24
+ * Whether two spellings name the same directory, judged by spelling alone.
25
+ *
26
+ * Hosts and the plugin do not agree on how to write a directory: OpenCode 2 on
27
+ * Windows stores a session's directory as `D:/work/app` while the plugin's own
28
+ * location is `D:\work\app`, and a drive letter can arrive in either case.
29
+ * Both sides go through `projectDirectoryKey`, so separators, Windows case,
30
+ * `\\?\` prefixes, trailing separators and `.`/`..` segments cannot make one
31
+ * directory look like two. POSIX paths keep their case. Symlinks are not
32
+ * resolved here; callers that must follow them use `canonicalProjectDirectory`.
33
+ *
34
+ * An empty spelling never matches anything: `path.resolve("")` is the process's
35
+ * working directory, and a session with no recorded directory must not be
36
+ * taken for one in the directory the process happens to run in.
37
+ */
38
+ export function sameProjectDirectory(a: string, b: string): boolean {
39
+ if (a.length === 0 || b.length === 0) return false;
40
+ return projectDirectoryKey(a) === projectDirectoryKey(b);
41
+ }
42
+
23
43
  let realpathForCanonicalDirectory: (directory: string) => string = (directory) =>
24
44
  realpathSync.native(directory);
25
45
 
@@ -1,3 +1,4 @@
1
+ import { createHash } from "node:crypto";
1
2
  import { readFileSync, statSync } from "node:fs";
2
3
  import { dirname, isAbsolute, resolve } from "node:path";
3
4
 
@@ -59,6 +60,17 @@ export function promptSurfaceHashMaterial(
59
60
  : `${systemContent}\n\0magic-context-prompt-surface:${preset}`;
60
61
  }
61
62
 
63
+ /**
64
+ * Hash system text after the caller resolves guidance and freezes host date lines.
65
+ * Keep the legacy MD5 hex encoding so existing cached heads retain their identity.
66
+ */
67
+ export function systemPromptFingerprint(
68
+ systemContent: string,
69
+ preset: PromptSurfacePreset = "full",
70
+ ): string {
71
+ return createHash("md5").update(promptSurfaceHashMaterial(systemContent, preset)).digest("hex");
72
+ }
73
+
62
74
  const PROMPT_SURFACE_TOOL_ID_SET = new Set<string>(ACTIVE_TOOL_IDS);
63
75
 
64
76
  export interface PromptSurfaceGuidanceSelection {
@@ -0,0 +1,111 @@
1
+ import { describe, expect, it } from "bun:test";
2
+ import {
3
+ farBehindToolBookmark,
4
+ isReclaimUserTurn,
5
+ type ReclaimDistanceEntry,
6
+ } from "./reclaim-distance";
7
+
8
+ const output = (tag: number, tokens = 1000): ReclaimDistanceEntry => ({
9
+ toolOutputTag: tag,
10
+ tokens,
11
+ });
12
+ const turn = (): ReclaimDistanceEntry => ({ userTurn: true, tokens: 10 });
13
+
14
+ describe("reclaim distance", () => {
15
+ it("repeated rebuilds cannot age the current task", () => {
16
+ const entries = [turn(), ...Array.from({ length: 28 }, (_, i) => output(i + 1))];
17
+ for (const count of [2, 3, 5]) {
18
+ let bookmark = 0;
19
+ for (let pass = 0; pass < count + 1; pass++) {
20
+ expect(bookmark).toBe(0);
21
+ bookmark = Math.max(bookmark, farBehindToolBookmark(entries, 200_000));
22
+ }
23
+ }
24
+ });
25
+
26
+ it("three newer user turns establish a bookmark, not two", () => {
27
+ const entries = [turn(), output(1), turn(), output(2), turn()];
28
+ expect(farBehindToolBookmark(entries, 200_000)).toBe(0);
29
+ expect(farBehindToolBookmark([...entries, turn()], 200_000)).toBe(1);
30
+ });
31
+
32
+ it("single-turn tool loop ages at exactly a quarter of the usable window", () => {
33
+ const entries = [turn(), output(1), output(2, 49_999)];
34
+ expect(farBehindToolBookmark(entries, 200_000)).toBe(0);
35
+ expect(farBehindToolBookmark([...entries, { tokens: 1 }], 200_000)).toBe(1);
36
+ expect(farBehindToolBookmark([turn(), output(1, 100_000)], 200_000)).toBe(0);
37
+ });
38
+
39
+ it("multipart outputs never age from their own trailing chunks", () => {
40
+ expect(farBehindToolBookmark([output(1), output(1, 60_000)], 200_000)).toBe(0);
41
+ });
42
+
43
+ it("unknown windows disable only token distance", () => {
44
+ expect(farBehindToolBookmark([output(1), output(2, 99_999)], 0)).toBe(0);
45
+ expect(farBehindToolBookmark([output(1), turn(), turn(), turn()], 0)).toBe(1);
46
+ });
47
+
48
+ it("excludes synthetic host wakes, MC reminders, heads and result carriers", () => {
49
+ expect(
50
+ isReclaimUserTurn({
51
+ role: "user",
52
+ parts: [
53
+ {
54
+ kind: "text",
55
+ synthetic: true,
56
+ text: "<system-reminder>Background task finished.</system-reminder>",
57
+ },
58
+ ],
59
+ }),
60
+ ).toBe(false);
61
+ expect(
62
+ isReclaimUserTurn({
63
+ role: "user",
64
+ parts: [
65
+ {
66
+ kind: "text",
67
+ text: "<system-reminder>Your next step: call ctx_reduce on the outputs you've already used (5).</system-reminder>",
68
+ },
69
+ ],
70
+ }),
71
+ ).toBe(false);
72
+ expect(
73
+ isReclaimUserTurn({
74
+ role: "user",
75
+ syntheticHead: true,
76
+ parts: [{ kind: "text", text: "history" }],
77
+ }),
78
+ ).toBe(false);
79
+ expect(
80
+ isReclaimUserTurn({ role: "user", parts: [{ kind: "tool_result", text: "output" }] }),
81
+ ).toBe(false);
82
+ expect(
83
+ isReclaimUserTurn({
84
+ role: "user",
85
+ parts: [
86
+ { kind: "tool_result", text: "output" },
87
+ { kind: "text", text: "continue" },
88
+ ],
89
+ }),
90
+ ).toBe(true);
91
+ });
92
+
93
+ it("counts an authored part even after synthetic or ignored parts", () => {
94
+ for (const provenance of [{ synthetic: true }, { ignored: true }]) {
95
+ expect(
96
+ isReclaimUserTurn({ role: "user", parts: [{ kind: "image", ...provenance }] }),
97
+ ).toBe(false);
98
+ expect(
99
+ isReclaimUserTurn({
100
+ role: "user",
101
+ parts: [{ kind: "text", text: "notice", ...provenance }, { kind: "image" }],
102
+ }),
103
+ ).toBe(true);
104
+ }
105
+ });
106
+
107
+ it("a young lower-tag result holds back distant higher tags", () => {
108
+ expect(farBehindToolBookmark([output(2), output(3, 50_000), output(1)], 200_000)).toBe(0);
109
+ expect(farBehindToolBookmark([output(1), output(3, 50_000), output(2)], 200_000)).toBe(1);
110
+ });
111
+ });
@@ -0,0 +1,91 @@
1
+ export const RECLAIM_DISTANCE_USER_TURNS = 3;
2
+ export const RECLAIM_DISTANCE_WINDOW_FRACTION = 0.25;
3
+
4
+ export interface ReclaimDistanceEntry {
5
+ /** Local content tokens, excluding Magic Context's history and reduction/note reminders. */
6
+ tokens: number;
7
+ /** One event per authored user-role message, after any folded tool results. */
8
+ userTurn?: boolean;
9
+ /** Durable identifier of the tool invocation whose result ends at this entry. */
10
+ toolOutputTag?: number;
11
+ }
12
+
13
+ /** Only authored content starts a user turn; host control notices do not. */
14
+ export function isReclaimUserTurn(args: {
15
+ role?: string;
16
+ syntheticHead?: boolean;
17
+ synthetic?: boolean;
18
+ ignored?: boolean;
19
+ parts: readonly { kind: string; text?: string; synthetic?: boolean; ignored?: boolean }[];
20
+ }): boolean {
21
+ return (
22
+ args.role === "user" &&
23
+ !args.syntheticHead &&
24
+ !args.synthetic &&
25
+ !args.ignored &&
26
+ args.parts.some((part) => {
27
+ if (part.synthetic || part.ignored) return false;
28
+ if (part.kind !== "text" && part.kind !== "image" && part.kind !== "file") return false;
29
+ if (part.kind !== "text") return true;
30
+ return stripReclaimMcText(part.text ?? "").trim().length > 0;
31
+ })
32
+ );
33
+ }
34
+
35
+ /** Remove Magic Context's reduction/note reminders, not generic host wake notices. */
36
+ export function stripReclaimMcText(text: string): string {
37
+ return text
38
+ .replace(/^§\d+§\s*/, "")
39
+ .replace(/<system-reminder>[\s\S]*?<\/system-reminder>/g, (reminder) =>
40
+ /^(?:Your next step: call ctx_reduce on the outputs you've already used|Still unstamped:|Housekeeping: .* are reclaimable\. Stamp each output with ctx_reduce|.* are reclaimable\. Make a ctx_reduce pass now|.* are still unstamped\. Call ctx_reduce now)/.test(
41
+ reminder.slice("<system-reminder>".length).trimStart(),
42
+ )
43
+ ? ""
44
+ : reminder,
45
+ )
46
+ .replace(/<instruction name="deferred_notes">[\s\S]*?<\/instruction>/g, "");
47
+ }
48
+
49
+ /**
50
+ * A free cache rebuild is not evidence that the model has moved on. An output
51
+ * is far behind only after three newer user turns or a quarter-window of newer
52
+ * content. Return a prefix of qualifying tags; callers drop against the PREVIOUS
53
+ * durable bookmark before advancing it, so distance must survive two rebuilds.
54
+ */
55
+ export function farBehindToolBookmark(
56
+ entries: readonly ReclaimDistanceEntry[],
57
+ usableWindow: number,
58
+ ): number {
59
+ let newerTurns = 0;
60
+ let newerTokens = 0;
61
+ const farTags: number[] = [];
62
+ let firstYoungTag = Infinity;
63
+ const seenOutputs = new Set<number>();
64
+ const tokenDistance =
65
+ usableWindow > 0 && Number.isFinite(usableWindow)
66
+ ? usableWindow * RECLAIM_DISTANCE_WINDOW_FRACTION
67
+ : Infinity;
68
+ for (let index = entries.length - 1; index >= 0; index--) {
69
+ const entry = entries[index];
70
+ if (!entry) continue;
71
+ const tag = entry.toolOutputTag;
72
+ // Multi-part outputs are positioned at their last result, not their call
73
+ // or first chunk: an output must never count its own remaining payload.
74
+ if (tag !== undefined && !seenOutputs.has(tag)) {
75
+ seenOutputs.add(tag);
76
+ if (newerTurns >= RECLAIM_DISTANCE_USER_TURNS || newerTokens >= tokenDistance) {
77
+ farTags.push(tag);
78
+ } else {
79
+ firstYoungTag = Math.min(firstYoungTag, tag);
80
+ }
81
+ }
82
+ if (entry.userTurn) newerTurns++;
83
+ if (Number.isFinite(entry.tokens) && entry.tokens > 0) newerTokens += entry.tokens;
84
+ }
85
+ // Tags follow call order, not result arrival. A late lower-tag sibling must
86
+ // hold the prefix even when a higher-tag result is already distant.
87
+ return farTags.reduce(
88
+ (bookmark, tag) => (tag < firstYoungTag ? Math.max(bookmark, tag) : bookmark),
89
+ 0,
90
+ );
91
+ }
@@ -0,0 +1,34 @@
1
+ import { expect, test } from "bun:test";
2
+ import { recoveryReasoningPrefixes } from "./recovery-reasoning-prefix";
3
+
4
+ for (const key of ["content", "parts"] as const) {
5
+ test(`recovery reasoning ${key}: exact preceding messages and same-message parts`, () => {
6
+ const messages = [
7
+ { role: "user", [key]: [{ type: "text", text: "original" }] },
8
+ {
9
+ role: "assistant",
10
+ [key]: [
11
+ { type: "text", text: "before" },
12
+ { type: "thinking", thinkingSignature: "first" },
13
+ { type: "text", text: "between" },
14
+ { type: "redacted_thinking", data: "opaque" },
15
+ { type: "text", text: "after" },
16
+ ],
17
+ },
18
+ ];
19
+ const original = recoveryReasoningPrefixes(messages, key);
20
+ expect(original).toHaveLength(2);
21
+ const edited = structuredClone(messages);
22
+ edited[0]![key]![0]!.text = "changed";
23
+ expect(recoveryReasoningPrefixes(edited, key)).not.toEqual(original);
24
+ const parts = structuredClone(messages);
25
+ parts[1]![key]![2]!.text = "changed";
26
+ expect(recoveryReasoningPrefixes(parts, key)[0]).toBe(original[0]);
27
+ expect(recoveryReasoningPrefixes(parts, key)[1]).not.toBe(original[1]);
28
+ const suffix = structuredClone(messages);
29
+ suffix[1]![key]![4]!.text = "changed";
30
+ expect(recoveryReasoningPrefixes(suffix, key)).toEqual(original);
31
+ suffix[1]![key]!.splice(3, 1);
32
+ expect(recoveryReasoningPrefixes(suffix, key)).not.toEqual(original);
33
+ });
34
+ }
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Serialize each request prefix ending at a thinking/reasoning part, including
3
+ * earlier messages and earlier parts of that message. Comparing these snapshots
4
+ * detects edits to bytes authenticated by a kept signature, or missing blocks.
5
+ * Include reasoning without a visible signature too: a host may carry its
6
+ * provider signature in fields this helper does not interpret.
7
+ */
8
+ export function recoveryReasoningPrefixes(
9
+ messages: readonly unknown[],
10
+ partsKey: "parts" | "content",
11
+ ): string[] {
12
+ const prefixes: string[] = [];
13
+ for (let index = 0; index < messages.length; index++) {
14
+ const message = messages[index] as Record<string, unknown> | null;
15
+ const parts = message?.[partsKey];
16
+ if (!Array.isArray(parts)) continue;
17
+ for (let p = 0; p < parts.length; p++) {
18
+ const type = (parts[p] as { type?: string } | null)?.type;
19
+ if (
20
+ type !== "thinking" &&
21
+ type !== "reasoning" &&
22
+ type !== "redactedThinking" &&
23
+ type !== "redacted_thinking"
24
+ )
25
+ continue;
26
+ prefixes.push(
27
+ JSON.stringify([
28
+ ...messages.slice(0, index),
29
+ { ...message, [partsKey]: parts.slice(0, p + 1) },
30
+ ]),
31
+ );
32
+ }
33
+ }
34
+ return prefixes;
35
+ }
@@ -0,0 +1,36 @@
1
+ import assert from "node:assert/strict";
2
+ import { AsyncLocalStorage } from "node:async_hooks";
3
+ import { setTimeout as delay, setImmediate as tick } from "node:timers/promises";
4
+ import { Worker } from "node:worker_threads";
5
+ import { inRootAsyncContext } from "./sqlite";
6
+
7
+ const scope = new AsyncLocalStorage();
8
+ const gc = globalThis.Bun ? () => Bun.gc(true) : globalThis.gc;
9
+ const references = {};
10
+ const resources = [];
11
+ const timerStores = {};
12
+ const ambientTick = () => { timerStores.ambient = scope.getStore() !== undefined; };
13
+ const rootTick = () => { timerStores.root = scope.getStore() !== undefined; };
14
+ function create(name, root, worker) {
15
+ const payload = { synthetic: name };
16
+ references[name] = new WeakRef(payload);
17
+ scope.run(payload, () => {
18
+ const make = worker
19
+ ? () => new Worker(new URL("worker.mjs", import.meta.url))
20
+ : () => setInterval(root ? rootTick : ambientTick, 5);
21
+ resources.push(root ? inRootAsyncContext(make) : make());
22
+ assert.equal(scope.getStore(), payload, "Root execution must restore the caller's store");
23
+ });
24
+ }
25
+ create("ambientWorker", false, true);
26
+ create("rootWorker", true, true);
27
+ create("ambientTimer", false, false);
28
+ create("rootTimer", true, false);
29
+ await delay(30);
30
+ for (let i = 0; i < 12; i++) { await tick(); gc(); await tick(); }
31
+ const retained = Object.fromEntries(Object.entries(references).map(([key, ref]) => [key, Number(ref.deref() !== undefined)]));
32
+ for (const resource of resources) {
33
+ if (resource instanceof Worker) await resource.terminate();
34
+ else clearInterval(resource);
35
+ }
36
+ console.log(JSON.stringify({ runtime: globalThis.Bun ? `Bun ${Bun.version}` : process.version, timerStores, retained }));
@@ -0,0 +1,49 @@
1
+ import { expect, test } from "bun:test";
2
+ import { rm, writeFile } from "node:fs/promises";
3
+ import { tmpdir } from "node:os";
4
+ import { join } from "node:path";
5
+ import { createTestTempDirFromPath } from "./test-temp-dir";
6
+
7
+ for (const runtime of ["Node", "Bun"] as const) {
8
+ test(`root resources do not inherit request stores (${runtime})`, async () => {
9
+ const directory = createTestTempDirFromPath(join(tmpdir(), "root-context-"));
10
+ try {
11
+ const entry = join(directory, "probe.mjs");
12
+ const build = await Bun.build({
13
+ entrypoints: [new URL("root-async-context.probe.mjs", import.meta.url).pathname],
14
+ target: "node",
15
+ format: "esm",
16
+ external: ["bun:sqlite", "node:sqlite"],
17
+ });
18
+ expect(build.success).toBe(true);
19
+ await writeFile(entry, await build.outputs[0].text());
20
+ await writeFile(
21
+ join(directory, "worker.mjs"),
22
+ `import { parentPort } from 'node:worker_threads'; parentPort.on('message', () => {});`,
23
+ );
24
+ const child = Bun.spawn(
25
+ [...(runtime === "Node" ? ["node", "--expose-gc"] : [process.execPath]), entry],
26
+ {
27
+ stdout: "pipe",
28
+ stderr: "pipe",
29
+ windowsHide: true,
30
+ },
31
+ );
32
+ const [stdout, stderr, exit] = await Promise.all([
33
+ new Response(child.stdout).text(),
34
+ new Response(child.stderr).text(),
35
+ child.exited,
36
+ ]);
37
+ expect(exit, stderr).toBe(0);
38
+ const result = JSON.parse(stdout);
39
+ console.log(`${runtime} ALS propagation: ${stdout.trim()}`);
40
+ expect(result.timerStores).toEqual({ ambient: true, root: false });
41
+ expect(result.retained.rootWorker).toBe(0);
42
+ expect(result.retained.rootTimer).toBe(0);
43
+ expect(result.retained.ambientTimer).toBe(1);
44
+ if (runtime === "Node") expect(result.retained.ambientWorker).toBe(1);
45
+ } finally {
46
+ await rm(directory, { recursive: true, force: true });
47
+ }
48
+ });
49
+ }
@@ -118,7 +118,7 @@ test("exhausted routed acquisition never enters the callback or multiplies privi
118
118
  db.close();
119
119
  rmSync(dir, { recursive: true, force: true });
120
120
  }
121
- });
121
+ }, 30_000);
122
122
 
123
123
  for (const mode of ["run", "get", "all", "exec"] as const) {
124
124
  test(`foreground ${mode} autocommit waits share one turn budget and restore production timeout`, () => {
@@ -147,7 +147,8 @@ for (const mode of ["run", "get", "all", "exec"] as const) {
147
147
  }
148
148
  expect(() => db.exec("BEGIN IMMEDIATE")).toThrow("acquisition remained busy");
149
149
  });
150
- expect(performance.now() - started).toBeLessThan(650);
150
+ expect(performance.now() - started).toBeGreaterThanOrEqual(1900);
151
+ expect(performance.now() - started).toBeLessThan(2600);
151
152
  expect(db.prepare("PRAGMA busy_timeout").get()).toEqual({ timeout: 5000 });
152
153
  expect(db.prepare("SELECT * FROM result").all()).toEqual([]);
153
154
  blocker.exec("ROLLBACK");
@@ -159,5 +160,5 @@ for (const mode of ["run", "get", "all", "exec"] as const) {
159
160
  db.close();
160
161
  rmSync(dir, { recursive: true, force: true });
161
162
  }
162
- });
163
+ }, 30_000);
163
164
  }