@cortexkit/opencode-magic-context 0.45.0 → 0.46.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (396) hide show
  1. package/README.md +26 -0
  2. package/dist/{announcement-f75t58v9.js → announcement-y35wzg2r.js} +1 -1
  3. package/dist/config/index.d.ts.map +1 -1
  4. package/dist/config/live-run-config.d.ts.map +1 -1
  5. package/dist/config/migrate-config-location.d.ts.map +1 -1
  6. package/dist/config/schema/magic-context.d.ts +13 -7
  7. package/dist/config/schema/magic-context.d.ts.map +1 -1
  8. package/dist/{conflict-warning-hook-5yrz2r24.js → conflict-warning-hook-7fj2b9jw.js} +6 -5
  9. package/dist/context-sh2m2vde.js +4525 -0
  10. package/dist/{derive-budgets-a63zsm5c.js → derive-budgets-7nj7r1rv.js} +2 -2
  11. package/dist/embedding-worker.js +4 -4
  12. package/dist/features/magic-context/checkout-claim-fake-subc.test-support.d.ts +45 -0
  13. package/dist/features/magic-context/checkout-claim-fake-subc.test-support.d.ts.map +1 -0
  14. package/dist/features/magic-context/checkout-claim.d.ts +155 -0
  15. package/dist/features/magic-context/checkout-claim.d.ts.map +1 -0
  16. package/dist/features/magic-context/compaction-marker.d.ts +20 -3
  17. package/dist/features/magic-context/compaction-marker.d.ts.map +1 -1
  18. package/dist/features/magic-context/compartment-storage.d.ts +23 -2
  19. package/dist/features/magic-context/compartment-storage.d.ts.map +1 -1
  20. package/dist/features/magic-context/dreamer/classify.d.ts.map +1 -1
  21. package/dist/features/magic-context/dreamer/evaluate-smart-notes.d.ts.map +1 -1
  22. package/dist/features/magic-context/dreamer/provider-output-failure.d.ts +6 -2
  23. package/dist/features/magic-context/dreamer/provider-output-failure.d.ts.map +1 -1
  24. package/dist/features/magic-context/dreamer/provider-output-failure.test-support.d.ts +30 -0
  25. package/dist/features/magic-context/dreamer/provider-output-failure.test-support.d.ts.map +1 -0
  26. package/dist/features/magic-context/dreamer/storage-dream-runs.d.ts.map +1 -1
  27. package/dist/features/magic-context/dreamer/task-executor.d.ts +9 -0
  28. package/dist/features/magic-context/dreamer/task-executor.d.ts.map +1 -1
  29. package/dist/features/magic-context/dreamer/task-gates.d.ts.map +1 -1
  30. package/dist/features/magic-context/dreamer/task-scheduler.d.ts.map +1 -1
  31. package/dist/features/magic-context/dreamer/verify-diff.d.ts.map +1 -1
  32. package/dist/features/magic-context/dreamer/verify-gate.d.ts.map +1 -1
  33. package/dist/features/magic-context/dreamer/verify.d.ts.map +1 -1
  34. package/dist/features/magic-context/git-commits/search-git-commits.d.ts.map +1 -1
  35. package/dist/features/magic-context/memory/embedding-local.d.ts.map +1 -1
  36. package/dist/features/magic-context/memory/project-identity-cache.d.ts.map +1 -1
  37. package/dist/features/magic-context/memory/storage-memory-verifications.d.ts.map +1 -1
  38. package/dist/features/magic-context/memory/storage-memory.d.ts +3 -0
  39. package/dist/features/magic-context/memory/storage-memory.d.ts.map +1 -1
  40. package/dist/features/magic-context/memory/verification-paths.d.ts +2 -2
  41. package/dist/features/magic-context/memory/verification-paths.d.ts.map +1 -1
  42. package/dist/features/magic-context/merged-reasoning-decisions.d.ts.map +1 -1
  43. package/dist/features/magic-context/message-index-async.d.ts +3 -3
  44. package/dist/features/magic-context/message-index-async.d.ts.map +1 -1
  45. package/dist/features/magic-context/message-index.d.ts +2 -0
  46. package/dist/features/magic-context/message-index.d.ts.map +1 -1
  47. package/dist/features/magic-context/migration-v95-perf-indexes.d.ts +12 -0
  48. package/dist/features/magic-context/migration-v95-perf-indexes.d.ts.map +1 -0
  49. package/dist/features/magic-context/migration-worker-client.d.ts +4 -4
  50. package/dist/features/magic-context/migration-worker-client.d.ts.map +1 -1
  51. package/dist/features/magic-context/migrations.d.ts +1 -0
  52. package/dist/features/magic-context/migrations.d.ts.map +1 -1
  53. package/dist/features/magic-context/mural/render-trigger.d.ts.map +1 -1
  54. package/dist/features/magic-context/mural/resolve-mural.d.ts +15 -4
  55. package/dist/features/magic-context/mural/resolve-mural.d.ts.map +1 -1
  56. package/dist/features/magic-context/mural/source-revision.d.ts +7 -0
  57. package/dist/features/magic-context/mural/source-revision.d.ts.map +1 -0
  58. package/dist/features/magic-context/mural/storage-mural-cues.d.ts.map +1 -1
  59. package/dist/features/magic-context/reclaim-protection.d.ts +15 -10
  60. package/dist/features/magic-context/reclaim-protection.d.ts.map +1 -1
  61. package/dist/features/magic-context/session-cache-ttl.d.ts +4 -2
  62. package/dist/features/magic-context/session-cache-ttl.d.ts.map +1 -1
  63. package/dist/features/magic-context/smart-notes/capabilities.d.ts +3 -0
  64. package/dist/features/magic-context/smart-notes/capabilities.d.ts.map +1 -1
  65. package/dist/features/magic-context/smart-notes/compiler.d.ts.map +1 -1
  66. package/dist/features/magic-context/smart-notes/github-token.d.ts +5 -0
  67. package/dist/features/magic-context/smart-notes/github-token.d.ts.map +1 -0
  68. package/dist/features/magic-context/smart-notes/runner.d.ts +1 -0
  69. package/dist/features/magic-context/smart-notes/runner.d.ts.map +1 -1
  70. package/dist/features/magic-context/smart-notes/sandbox-runner.d.ts +12 -0
  71. package/dist/features/magic-context/smart-notes/sandbox-runner.d.ts.map +1 -1
  72. package/dist/features/magic-context/smart-notes/ssrf-guard.d.ts +6 -0
  73. package/dist/features/magic-context/smart-notes/ssrf-guard.d.ts.map +1 -1
  74. package/dist/features/magic-context/smart-notes/storage.d.ts.map +1 -1
  75. package/dist/features/magic-context/smart-notes/types.d.ts +2 -0
  76. package/dist/features/magic-context/smart-notes/types.d.ts.map +1 -1
  77. package/dist/features/magic-context/storage-clone.d.ts.map +1 -1
  78. package/dist/features/magic-context/storage-db.d.ts +6 -9
  79. package/dist/features/magic-context/storage-db.d.ts.map +1 -1
  80. package/dist/features/magic-context/storage-meta-shared.d.ts +1 -1
  81. package/dist/features/magic-context/storage-meta-shared.d.ts.map +1 -1
  82. package/dist/features/magic-context/storage-ops.d.ts +8 -1
  83. package/dist/features/magic-context/storage-ops.d.ts.map +1 -1
  84. package/dist/features/magic-context/storage-replay-document.d.ts +7 -0
  85. package/dist/features/magic-context/storage-replay-document.d.ts.map +1 -1
  86. package/dist/features/magic-context/storage-schema-helpers.d.ts +2 -0
  87. package/dist/features/magic-context/storage-schema-helpers.d.ts.map +1 -1
  88. package/dist/features/magic-context/storage-session-tables.d.ts.map +1 -1
  89. package/dist/features/magic-context/storage-source.d.ts.map +1 -1
  90. package/dist/features/magic-context/storage-tags.d.ts +11 -3
  91. package/dist/features/magic-context/storage-tags.d.ts.map +1 -1
  92. package/dist/features/magic-context/storage.d.ts +2 -2
  93. package/dist/features/magic-context/storage.d.ts.map +1 -1
  94. package/dist/features/magic-context/temporal-decisions.d.ts +10 -0
  95. package/dist/features/magic-context/temporal-decisions.d.ts.map +1 -0
  96. package/dist/features/magic-context/tool-definition-tokens.d.ts +2 -0
  97. package/dist/features/magic-context/tool-definition-tokens.d.ts.map +1 -1
  98. package/dist/features/magic-context/transform-decision-log.d.ts.map +1 -1
  99. package/dist/features/magic-context/types.d.ts +7 -6
  100. package/dist/features/magic-context/types.d.ts.map +1 -1
  101. package/dist/features/magic-context/window-report-ledger.d.ts.map +1 -1
  102. package/dist/hooks/auto-update-checker/index.d.ts.map +1 -1
  103. package/dist/hooks/magic-context/apply-operations.d.ts +8 -0
  104. package/dist/hooks/magic-context/apply-operations.d.ts.map +1 -1
  105. package/dist/hooks/magic-context/cache-busting-signals.d.ts +6 -3
  106. package/dist/hooks/magic-context/cache-busting-signals.d.ts.map +1 -1
  107. package/dist/hooks/magic-context/channel2-cycle.d.ts +2 -0
  108. package/dist/hooks/magic-context/channel2-cycle.d.ts.map +1 -1
  109. package/dist/hooks/magic-context/compaction-marker-manager.d.ts +7 -0
  110. package/dist/hooks/magic-context/compaction-marker-manager.d.ts.map +1 -1
  111. package/dist/hooks/magic-context/compartment-prompt.d.ts +2 -2
  112. package/dist/hooks/magic-context/compartment-prompt.d.ts.map +1 -1
  113. package/dist/hooks/magic-context/compartment-render-epoch.d.ts +8 -0
  114. package/dist/hooks/magic-context/compartment-render-epoch.d.ts.map +1 -1
  115. package/dist/hooks/magic-context/compartment-runner-drop-queue.d.ts +18 -4
  116. package/dist/hooks/magic-context/compartment-runner-drop-queue.d.ts.map +1 -1
  117. package/dist/hooks/magic-context/compartment-runner-incremental.d.ts.map +1 -1
  118. package/dist/hooks/magic-context/compartment-runner-partial-recomp.d.ts.map +1 -1
  119. package/dist/hooks/magic-context/compartment-runner-recomp.d.ts.map +1 -1
  120. package/dist/hooks/magic-context/ctx-reduce-availability.d.ts +12 -0
  121. package/dist/hooks/magic-context/ctx-reduce-availability.d.ts.map +1 -1
  122. package/dist/hooks/magic-context/decision-calibration.d.ts +3 -0
  123. package/dist/hooks/magic-context/decision-calibration.d.ts.map +1 -1
  124. package/dist/hooks/magic-context/default-protection-pressure.test-support.d.ts +37 -0
  125. package/dist/hooks/magic-context/default-protection-pressure.test-support.d.ts.map +1 -0
  126. package/dist/hooks/magic-context/drop-stale-reduce-calls.d.ts +4 -0
  127. package/dist/hooks/magic-context/drop-stale-reduce-calls.d.ts.map +1 -1
  128. package/dist/hooks/magic-context/edit-marker.d.ts.map +1 -1
  129. package/dist/hooks/magic-context/emergency-drop.d.ts +2 -0
  130. package/dist/hooks/magic-context/emergency-drop.d.ts.map +1 -1
  131. package/dist/hooks/magic-context/emergency-fail-closed.d.ts +21 -1
  132. package/dist/hooks/magic-context/emergency-fail-closed.d.ts.map +1 -1
  133. package/dist/hooks/magic-context/event-handler.d.ts +5 -0
  134. package/dist/hooks/magic-context/event-handler.d.ts.map +1 -1
  135. package/dist/hooks/magic-context/final-wire-token-estimate.d.ts +30 -1
  136. package/dist/hooks/magic-context/final-wire-token-estimate.d.ts.map +1 -1
  137. package/dist/hooks/magic-context/heuristic-cleanup.d.ts +2 -0
  138. package/dist/hooks/magic-context/heuristic-cleanup.d.ts.map +1 -1
  139. package/dist/hooks/magic-context/historian-prompt-fit.d.ts +4 -2
  140. package/dist/hooks/magic-context/historian-prompt-fit.d.ts.map +1 -1
  141. package/dist/hooks/magic-context/hook.d.ts +2 -1
  142. package/dist/hooks/magic-context/hook.d.ts.map +1 -1
  143. package/dist/hooks/magic-context/inject-compartments.d.ts +9 -10
  144. package/dist/hooks/magic-context/inject-compartments.d.ts.map +1 -1
  145. package/dist/hooks/magic-context/lkg-measured-request.d.ts +69 -0
  146. package/dist/hooks/magic-context/lkg-measured-request.d.ts.map +1 -0
  147. package/dist/hooks/magic-context/lkg-persist.d.ts +2 -0
  148. package/dist/hooks/magic-context/lkg-persist.d.ts.map +1 -1
  149. package/dist/hooks/magic-context/lkg-replay-fit.d.ts +14 -0
  150. package/dist/hooks/magic-context/lkg-replay-fit.d.ts.map +1 -1
  151. package/dist/hooks/magic-context/lkg-replay.d.ts +10 -1
  152. package/dist/hooks/magic-context/lkg-replay.d.ts.map +1 -1
  153. package/dist/hooks/magic-context/lkg-slot.d.ts +4 -0
  154. package/dist/hooks/magic-context/lkg-slot.d.ts.map +1 -1
  155. package/dist/hooks/magic-context/module-state-sync.d.ts +2 -0
  156. package/dist/hooks/magic-context/module-state-sync.d.ts.map +1 -1
  157. package/dist/hooks/magic-context/module-transport.d.ts.map +1 -1
  158. package/dist/hooks/magic-context/module-wire.d.ts.map +1 -1
  159. package/dist/hooks/magic-context/note-nudger.d.ts +17 -5
  160. package/dist/hooks/magic-context/note-nudger.d.ts.map +1 -1
  161. package/dist/hooks/magic-context/read-session-chunk.d.ts +1 -1
  162. package/dist/hooks/magic-context/read-session-chunk.d.ts.map +1 -1
  163. package/dist/hooks/magic-context/read-session-db.d.ts +1 -0
  164. package/dist/hooks/magic-context/read-session-db.d.ts.map +1 -1
  165. package/dist/hooks/magic-context/read-session-formatting.d.ts +7 -0
  166. package/dist/hooks/magic-context/read-session-formatting.d.ts.map +1 -1
  167. package/dist/hooks/magic-context/read-session-raw.d.ts +4 -0
  168. package/dist/hooks/magic-context/read-session-raw.d.ts.map +1 -1
  169. package/dist/hooks/magic-context/read-session-true-raw-tokens.d.ts.map +1 -1
  170. package/dist/hooks/magic-context/recomp-orchestrator.d.ts +2 -0
  171. package/dist/hooks/magic-context/recomp-orchestrator.d.ts.map +1 -1
  172. package/dist/hooks/magic-context/reference-retrieval.d.ts +27 -17
  173. package/dist/hooks/magic-context/reference-retrieval.d.ts.map +1 -1
  174. package/dist/hooks/magic-context/request-hook-order.d.ts +56 -0
  175. package/dist/hooks/magic-context/request-hook-order.d.ts.map +1 -0
  176. package/dist/hooks/magic-context/rust-mode-transform.d.ts +22 -3
  177. package/dist/hooks/magic-context/rust-mode-transform.d.ts.map +1 -1
  178. package/dist/hooks/magic-context/strip-content.d.ts +4 -2
  179. package/dist/hooks/magic-context/strip-content.d.ts.map +1 -1
  180. package/dist/hooks/magic-context/supersession-reclaim.d.ts +4 -0
  181. package/dist/hooks/magic-context/supersession-reclaim.d.ts.map +1 -1
  182. package/dist/hooks/magic-context/system-prompt-hash.d.ts +7 -0
  183. package/dist/hooks/magic-context/system-prompt-hash.d.ts.map +1 -1
  184. package/dist/hooks/magic-context/tail-hygiene-walk.d.ts +12 -3
  185. package/dist/hooks/magic-context/tail-hygiene-walk.d.ts.map +1 -1
  186. package/dist/hooks/magic-context/temporal-awareness.d.ts +6 -3
  187. package/dist/hooks/magic-context/temporal-awareness.d.ts.map +1 -1
  188. package/dist/hooks/magic-context/temporal-served-projection.d.ts +4 -0
  189. package/dist/hooks/magic-context/temporal-served-projection.d.ts.map +1 -0
  190. package/dist/hooks/magic-context/tool-drop-target.d.ts.map +1 -1
  191. package/dist/hooks/magic-context/tool-reclaim.d.ts +2 -0
  192. package/dist/hooks/magic-context/tool-reclaim.d.ts.map +1 -1
  193. package/dist/hooks/magic-context/transform-message-helpers.d.ts +5 -0
  194. package/dist/hooks/magic-context/transform-message-helpers.d.ts.map +1 -1
  195. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts +41 -17
  196. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts.map +1 -1
  197. package/dist/hooks/magic-context/transform.d.ts +12 -0
  198. package/dist/hooks/magic-context/transform.d.ts.map +1 -1
  199. package/dist/hooks/magic-context/wrapup-orchestrator.d.ts.map +1 -1
  200. package/dist/{index-vvtfyw1z.js → index-0d3g3461.js} +5 -13
  201. package/dist/index-1bc61ans.js +154 -0
  202. package/dist/{index-n96ag4rk.js → index-1zx87sdm.js} +5 -1
  203. package/dist/{index-4krbw8z9.js → index-3h0ybwah.js} +608 -102
  204. package/dist/{index-gd5qx1j9.js → index-5eqk6z3s.js} +62 -1
  205. package/dist/index-5gq3b2ya.js +494 -0
  206. package/dist/{index-8fgkmxmy.js → index-5p8jdswx.js} +4 -3
  207. package/dist/{index-75zjgwga.js → index-7qw742ev.js} +1 -1
  208. package/dist/{index-f85teqck.js → index-8da2zjhz.js} +3 -256
  209. package/dist/{index-q7yesyk9.js → index-8x2v7gg9.js} +25 -24
  210. package/dist/{index-w9jwmntv.js → index-b35pxds2.js} +9 -1
  211. package/dist/{v2/server-a4m2b1yv.js → index-fg34g6a5.js} +55 -1
  212. package/dist/index-hpecdzec.js +28506 -0
  213. package/dist/{index-2ntg5sd4.js → index-k5bdx1bx.js} +9 -5
  214. package/dist/{index-bmzf7zxv.js → index-majxda46.js} +23 -5
  215. package/dist/{index-2aq21j41.js → index-pkbcrdqs.js} +418 -127
  216. package/dist/{index-remp7e2g.js → index-q4yp4b52.js} +16 -1
  217. package/dist/{index-fr2z4qy8.js → index-r5hmbx3t.js} +132 -169
  218. package/dist/index-sfnj6h8h.js +259 -0
  219. package/dist/{index-xgt9k6c6.js → index-sgthv3f7.js} +2 -1
  220. package/dist/index-sj29b3z2.js +30 -0
  221. package/dist/{index-16ny736w.js → index-sjthx78w.js} +20526 -19817
  222. package/dist/index.d.ts.map +1 -1
  223. package/dist/index.js +1983 -33118
  224. package/dist/{message-time-backfill-an311pmk.js → message-time-backfill-68gj6t3e.js} +2 -2
  225. package/dist/migration-worker.js +12 -7
  226. package/dist/plugin/dream-timer.d.ts +25 -1
  227. package/dist/plugin/dream-timer.d.ts.map +1 -1
  228. package/dist/plugin/hooks/create-session-hooks.d.ts +2 -1
  229. package/dist/plugin/hooks/create-session-hooks.d.ts.map +1 -1
  230. package/dist/plugin/messages-transform.d.ts +13 -0
  231. package/dist/plugin/messages-transform.d.ts.map +1 -1
  232. package/dist/plugin/rpc-handlers.d.ts +4 -0
  233. package/dist/plugin/rpc-handlers.d.ts.map +1 -1
  234. package/dist/plugin/subagent-tool-policy.d.ts +14 -0
  235. package/dist/plugin/subagent-tool-policy.d.ts.map +1 -0
  236. package/dist/plugin/tool-registry.d.ts +1 -0
  237. package/dist/plugin/tool-registry.d.ts.map +1 -1
  238. package/dist/{read-session-chunk-8rxs0tc9.js → read-session-chunk-egz7r68d.js} +8 -8
  239. package/dist/{recomp-orchestrator-nzamtw29.js → recomp-orchestrator-y15j0rb9.js} +15 -15
  240. package/dist/{send-session-notification-nqpv7cne.js → send-session-notification-dyw42dtr.js} +4 -4
  241. package/dist/shared/announcement.d.ts.map +1 -1
  242. package/dist/shared/cache-ttl-display.d.ts +6 -4
  243. package/dist/shared/cache-ttl-display.d.ts.map +1 -1
  244. package/dist/shared/model-cache-ttl.d.ts +1 -1
  245. package/dist/shared/model-cache-ttl.d.ts.map +1 -1
  246. package/dist/shared/model-suggestion-retry.d.ts +2 -0
  247. package/dist/shared/model-suggestion-retry.d.ts.map +1 -1
  248. package/dist/shared/models-dev-cache.d.ts.map +1 -1
  249. package/dist/shared/protected-tools-policy.d.ts +6 -0
  250. package/dist/shared/protected-tools-policy.d.ts.map +1 -0
  251. package/dist/shared/quota-diagnostic.d.ts +4 -0
  252. package/dist/shared/quota-diagnostic.d.ts.map +1 -0
  253. package/dist/shared/rpc-server.d.ts.map +1 -1
  254. package/dist/shared/sqlite-context-pragmas.d.ts +12 -0
  255. package/dist/shared/sqlite-context-pragmas.d.ts.map +1 -0
  256. package/dist/shared/sqlite-helpers.d.ts +9 -0
  257. package/dist/shared/sqlite-helpers.d.ts.map +1 -1
  258. package/dist/shared/sqlite.d.ts +10 -0
  259. package/dist/shared/sqlite.d.ts.map +1 -1
  260. package/dist/shared/status-summary.d.ts +1 -0
  261. package/dist/shared/status-summary.d.ts.map +1 -1
  262. package/dist/shared/status-view-check.d.ts.map +1 -1
  263. package/dist/shared/status-view.d.ts +4 -0
  264. package/dist/shared/status-view.d.ts.map +1 -1
  265. package/dist/shared/storage-permissions.d.ts +24 -0
  266. package/dist/shared/storage-permissions.d.ts.map +1 -1
  267. package/dist/shared/temporal-upgrade-fixture.d.ts +19 -0
  268. package/dist/shared/temporal-upgrade-fixture.d.ts.map +1 -0
  269. package/dist/shared/user-facing-codes.d.ts +5 -0
  270. package/dist/shared/user-facing-codes.d.ts.map +1 -1
  271. package/dist/shared/write-transaction-timing.d.ts +8 -1
  272. package/dist/shared/write-transaction-timing.d.ts.map +1 -1
  273. package/dist/tools/ctx-expand/render.d.ts.map +1 -1
  274. package/dist/tools/ctx-memory/tools.d.ts.map +1 -1
  275. package/dist/tools/ctx-reduce/constants.d.ts +2 -0
  276. package/dist/tools/ctx-reduce/constants.d.ts.map +1 -1
  277. package/dist/tools/ctx-reduce/tools.d.ts +4 -4
  278. package/dist/tools/ctx-reduce/tools.d.ts.map +1 -1
  279. package/dist/{transform-postprocess-phase-414phndq.js → transform-postprocess-phase-bqhz6vdr.js} +15 -15
  280. package/dist/v2/context-zecmzk5s.js +52209 -0
  281. package/dist/v2/{derive-budgets-v0krf3t7.js → derive-budgets-kdgp4s3r.js} +4 -3
  282. package/dist/v2/embedding-worker.js +6 -5
  283. package/dist/v2/fold/boundary.d.ts +2 -0
  284. package/dist/v2/fold/boundary.d.ts.map +1 -1
  285. package/dist/v2/fold/owner.d.ts.map +1 -1
  286. package/dist/v2/hidden-child-native.d.ts +7 -0
  287. package/dist/v2/hidden-child-native.d.ts.map +1 -1
  288. package/dist/v2/hidden-child-record.d.ts +8 -0
  289. package/dist/v2/hidden-child-record.d.ts.map +1 -1
  290. package/dist/v2/hidden-completion.d.ts.map +1 -1
  291. package/dist/v2/hooks/channel2.d.ts +2 -0
  292. package/dist/v2/hooks/channel2.d.ts.map +1 -1
  293. package/dist/v2/hooks/context.d.ts +2 -2
  294. package/dist/v2/hooks/context.d.ts.map +1 -1
  295. package/dist/v2/hooks/dream-timer.d.ts +39 -0
  296. package/dist/v2/hooks/dream-timer.d.ts.map +1 -0
  297. package/dist/v2/hooks/dream-trigger.d.ts +15 -1
  298. package/dist/v2/hooks/dream-trigger.d.ts.map +1 -1
  299. package/dist/v2/hooks/hidden-child.d.ts +54 -3
  300. package/dist/v2/hooks/hidden-child.d.ts.map +1 -1
  301. package/dist/v2/hooks/payload.d.ts.map +1 -1
  302. package/dist/v2/hooks/store.d.ts.map +1 -1
  303. package/dist/v2/hooks/tools.d.ts +1 -1
  304. package/dist/v2/hooks/tools.d.ts.map +1 -1
  305. package/dist/v2/hooks/types.d.ts +12 -1
  306. package/dist/v2/hooks/types.d.ts.map +1 -1
  307. package/dist/v2/hooks/update-check.d.ts.map +1 -1
  308. package/dist/v2/{message-time-backfill-0n93vrd7.js → message-time-backfill-r6qkem1x.js} +3 -3
  309. package/dist/v2/migration-worker.js +13 -8
  310. package/dist/v2/{read-session-chunk-hjza38hr.js → read-session-chunk-8vjp6581.js} +9 -9
  311. package/dist/v2/recomp-orchestrator-8ejxvrzz.js +39 -0
  312. package/dist/v2/{safe-notification-target-wtj0bbc2.js → safe-notification-target-eb1n1vfb.js} +2 -2
  313. package/dist/v2/{send-session-notification-mq9frrtm.js → send-session-notification-qs0j78v6.js} +6 -6
  314. package/dist/v2/server-14vq4kpm.js +30 -0
  315. package/dist/v2/server-1bc61ans.js +154 -0
  316. package/dist/v2/{server-n96ag4rk.js → server-1zx87sdm.js} +5 -1
  317. package/dist/v2/server-3n4q9xme.js +79 -0
  318. package/dist/v2/{server-rhdgxp1t.js → server-51dv1pr5.js} +63 -2
  319. package/dist/v2/{server-5317ykaf.js → server-6r257mf5.js} +1 -1
  320. package/dist/v2/server-84w6rvvf.js +14 -0
  321. package/dist/v2/{server-qpg6wf72.js → server-ajzeteqw.js} +9 -1
  322. package/dist/v2/server-c5gz8wph.js +3892 -0
  323. package/dist/v2/{server-v5xgft5v.js → server-e29d7p7c.js} +188 -3533
  324. package/dist/{index-a4m2b1yv.js → v2/server-fg34g6a5.js} +55 -1
  325. package/dist/v2/{server-e36nf2p1.js → server-frbm99q5.js} +1595 -1599
  326. package/dist/v2/{server-remp7e2g.js → server-g0fjrkta.js} +16 -1
  327. package/dist/v2/{server-c4g2y1z8.js → server-jc7y02q0.js} +2816 -5392
  328. package/dist/v2/{server-z19x7eqz.js → server-mcfawjgc.js} +4 -4
  329. package/dist/v2/{server-hfjfbg59.js → server-qp5hx1ad.js} +608 -105
  330. package/dist/v2/server-vs5gpnd4.js +493 -0
  331. package/dist/v2/{server-w99cyt6a.js → server-wvjvfhck.js} +14 -6
  332. package/dist/v2/server-xa4xe3rv.js +3351 -0
  333. package/dist/v2/{server-0jqw05sa.js → server-y8maxeft.js} +6 -84
  334. package/dist/v2/server.d.ts.map +1 -1
  335. package/dist/v2/server.js +104 -49288
  336. package/dist/v2/store-reader.d.ts +39 -1
  337. package/dist/v2/store-reader.d.ts.map +1 -1
  338. package/dist/v2/tool-result.d.ts +8 -0
  339. package/dist/v2/tool-result.d.ts.map +1 -0
  340. package/dist/v2/tui/index.d.ts.map +1 -1
  341. package/dist/v2/{wrapup-orchestrator-tbyx78dz.js → wrapup-orchestrator-0snhvwcv.js} +20 -16
  342. package/dist/wrapup-orchestrator-39amhv9s.js +26 -0
  343. package/package.json +26 -10
  344. package/src/config/index.ts +21 -4
  345. package/src/config/latch-permanence-guard.test.ts +6 -1
  346. package/src/config/live-run-config.ts +1 -0
  347. package/src/config/migrate-config-location.test.ts +31 -1
  348. package/src/config/migrate-config-location.ts +8 -41
  349. package/src/config/protected-tools.test.ts +70 -0
  350. package/src/config/raw-loader.test.ts +15 -0
  351. package/src/config/raw-loader.ts +1 -1
  352. package/src/config/removed-agent-source-fence.test.ts +10 -1
  353. package/src/config/schema/magic-context.test.ts +20 -1
  354. package/src/config/schema/magic-context.ts +26 -7
  355. package/src/shared/announcement.ts +6 -5
  356. package/src/shared/cache-ttl-display.test.ts +1 -1
  357. package/src/shared/cache-ttl-display.ts +17 -16
  358. package/src/shared/fold-render-lock-fence.test.ts +84 -0
  359. package/src/shared/fold-render-lock-fixtures.test.ts +276 -0
  360. package/src/shared/model-cache-ttl.test.ts +2 -2
  361. package/src/shared/model-cache-ttl.ts +8 -4
  362. package/src/shared/model-suggestion-retry.test.ts +104 -1
  363. package/src/shared/model-suggestion-retry.ts +63 -6
  364. package/src/shared/models-dev-cache.ts +3 -11
  365. package/src/shared/protected-tools-policy.ts +23 -0
  366. package/src/shared/quota-diagnostic.ts +9 -0
  367. package/src/shared/rpc-server.ts +6 -54
  368. package/src/shared/sqlite-context-pragmas.test.ts +105 -0
  369. package/src/shared/sqlite-context-pragmas.ts +24 -0
  370. package/src/shared/sqlite-helpers.ts +17 -0
  371. package/src/shared/sqlite.ts +75 -0
  372. package/src/shared/status-detail-text.test.ts +18 -1
  373. package/src/shared/status-summary.ts +11 -0
  374. package/src/shared/status-view-check.ts +5 -0
  375. package/src/shared/status-view.test.ts +11 -2
  376. package/src/shared/status-view.ts +12 -1
  377. package/src/shared/storage-permissions.test.ts +204 -0
  378. package/src/shared/storage-permissions.ts +192 -0
  379. package/src/shared/temporal-upgrade-fixture.ts +50 -0
  380. package/src/shared/user-facing-codes.ts +6 -0
  381. package/src/shared/write-transaction-timing.test.ts +39 -0
  382. package/src/shared/write-transaction-timing.ts +25 -1
  383. package/src/tui/dialogs/status-dialog-render.test.ts +1 -1
  384. package/src/tui/index.tsx +3 -1
  385. package/src/tui/startup-order.test.ts +16 -0
  386. package/src/tui-compiled/index.tsx +3 -1
  387. package/src/v2/tui/index.ts +9 -2
  388. package/dist/index-anq4nn6f.js +0 -131
  389. package/dist/index-e44zzy84.js +0 -10
  390. package/dist/index-x23gah8c.js +0 -16
  391. package/dist/v2/recomp-orchestrator-1aq7h44c.js +0 -36
  392. package/dist/v2/server-e44zzy84.js +0 -10
  393. package/dist/v2/server-fgmxwrgy.js +0 -16
  394. package/dist/v2/server-r7cmye3k.js +0 -131
  395. package/dist/wrapup-orchestrator-h28bqsy6.js +0 -26
  396. package/dist/v2/{server-ckpc8pxy.js → server-1qbnzc80.js} +8 -8
@@ -9,6 +9,25 @@ import {
9
9
  } from "./magic-context";
10
10
 
11
11
  describe("MagicContextConfigSchema", () => {
12
+ it("documents that Rust transform mode always keeps the shared data directory private", () => {
13
+ const inputSchema = MagicContextConfigSchema._def.in as unknown as {
14
+ shape: {
15
+ storage: {
16
+ unwrap: () => {
17
+ shape: {
18
+ enforce_private_permissions: { description?: string };
19
+ };
20
+ };
21
+ };
22
+ };
23
+ };
24
+ const description =
25
+ inputSchema.shape.storage.unwrap().shape.enforce_private_permissions.description ?? "";
26
+ expect(description).toContain("Rust transform mode");
27
+ expect(description).toContain("always keeps the shared data directory owner-only 0700");
28
+ expect(description).toContain("regardless of this setting");
29
+ });
30
+
12
31
  describe("defaults", () => {
13
32
  it("applies defaults for an empty config", () => {
14
33
  const result = MagicContextConfigSchema.parse({});
@@ -166,7 +185,7 @@ describe("MagicContextConfigSchema", () => {
166
185
 
167
186
  const result = MagicContextConfigSchema.parse(input);
168
187
 
169
- expect(result).toEqual(input);
188
+ expect(result).toEqual({ ...input, protected_tools: { todowrite: 1, ctx_reduce: 3 } });
170
189
  });
171
190
 
172
191
  it("accepts a boolean storage permission policy and rejects non-booleans", () => {
@@ -8,6 +8,7 @@ import type {
8
8
  } from "../../features/magic-context/dreamer/task-registry";
9
9
  import { toolTemplateError } from "../../shared/historian-tool-template";
10
10
  import { isValidPromptSurfaceModelKey } from "../../shared/prompt-surface";
11
+ import { DEFAULT_PROTECTED_TOOLS, mergeProtectedTools } from "../../shared/protected-tools-policy";
11
12
  import { AgentOverrideConfigSchema } from "./agent-overrides";
12
13
 
13
14
  export const DEFAULT_EXECUTE_THRESHOLD_PERCENTAGE = 65;
@@ -640,6 +641,10 @@ const AgentMetadataSchema = AgentOverrideConfigSchema.pick({
640
641
 
641
642
  /** Combined dreamer metadata plus independent strict execution blocks. */
642
643
  export const DreamerConfigSchema = AgentMetadataSchema.extend({
644
+ // Its own node rather than the one shared with the historian through
645
+ // AgentMetadataSchema: `dreamer.disable` is a live-reload key and the
646
+ // historian's is not, and the live marker is set on the schema node.
647
+ disable: z.boolean().optional().describe("Disable this agent"),
643
648
  runner: z
644
649
  .enum(["broca", "host"])
645
650
  .optional()
@@ -918,6 +923,8 @@ export interface MuralConfig {
918
923
  }
919
924
 
920
925
  export interface MagicContextConfig {
926
+ /** The loader sets this to distinguish an explicit `5m` from the built-in default; users do not configure it. */
927
+ cacheTtlConfigured?: boolean;
921
928
  enabled: boolean;
922
929
  /** User-level setting that lets a session in the canonical home directory use project memory. */
923
930
  allow_home_project: boolean;
@@ -955,6 +962,7 @@ export interface MagicContextConfig {
955
962
  execute_threshold_tokens?: { default?: number; [modelKey: string]: number | undefined };
956
963
  protected_tokens?: number;
957
964
  protected_tags?: number;
965
+ protected_tools: Record<string, number>;
958
966
  clear_reasoning_age: number;
959
967
  history_budget_percentage: number;
960
968
  historian_timeout_ms: number;
@@ -1038,7 +1046,8 @@ export interface MagicContextConfig {
1038
1046
  * on its own; when off, the messages sent to the model are byte-identical to
1039
1047
  * the age-based-only behavior. Experimental, opt-in, default off until cache
1040
1048
  * stability is proven. */
1041
- smart_drops: boolean;
1049
+ /** Deprecated and ignored: supersession reclaim is always on. */
1050
+ smart_drops?: unknown;
1042
1051
  /**
1043
1052
  * Age-tier caveman compression for long user/assistant text parts.
1044
1053
  * Graduated from `experimental.caveman_text_compression`; opt-in, default off.
@@ -1187,7 +1196,7 @@ export const MagicContextConfigSchema = z
1187
1196
  .union([z.string(), z.object({ default: z.string() }).catchall(z.string())])
1188
1197
  .default("5m")
1189
1198
  .describe(
1190
- 'How long Magic Context assumes the provider\'s cached prefix stays valid. This is MC\'s own deferral gate — it does not change the provider\'s actual cache lifetime. String (e.g. "5m", "1h", "30s") or per-model object ({ default: "5m", "provider/model": "1h", "provider/*": "never" }); keys resolve most-specific first (exact provider/model, bare model ID, shorter dash-prefixes, then the provider/* wildcard). Explicit per-model entries win; otherwise GPT-5.6 and later (including gpt-6*, through any provider prefix) use a built-in 30m lifetime before the object default or 5m fallback. An unset or global "5m" opts into built-in defaults; any other global string is an explicit policy and wins. Policy is frozen per session, including across restarts; a model switch resolves against that frozen policy. /ctx-status shows the effective value and source. OpenAI documents at least 30 minutes since the latest write or reuse: https://developers.openai.com/api/docs/guides/prompt-caching (Cache lifetime and Summary of model differences). Set to "never" to mean MC never assumes expiry (for lanes kept warm externally by a cache-keep tool) — disables the idle-TTL heuristic so MC never initiates a rebuild based on elapsed time. Provider-side extended TTL is a separate request-level concern (cache_control: { ttl } in the request body).',
1199
+ 'How long Magic Context assumes the provider\'s cached prefix stays valid. This is MC\'s own deferral gate — it does not change the provider\'s actual cache lifetime. String (e.g. "5m", "1h", "30s") or per-model object ({ default: "5m", "provider/model": "1h", "provider/*": "never" }); keys resolve most-specific first (exact provider/model, bare model ID, shorter dash-prefixes, then the provider/* wildcard, then default). User and project settings, including an explicit "5m" or object default, apply on the next pass. Only built-in defaults are frozen per session, including across restarts: when unset, GPT-5.6 and later (including gpt-6*, through any provider prefix) use 30m, other models use 5m. /ctx-status shows the effective TTL and whether it comes from your config or a frozen built-in default. Editing the TTL does not itself rewrite prompt bytes; a lowered TTL rebuilds only after normal idle expiry. OpenAI documents at least 30 minutes since the latest write or reuse: https://developers.openai.com/api/docs/guides/prompt-caching (Cache lifetime and Summary of model differences). Set to "never" to mean MC never assumes expiry (for lanes kept warm externally by a cache-keep tool) — disables the idle-TTL heuristic so MC never initiates a rebuild based on elapsed time. Provider-side extended TTL is a separate request-level concern (cache_control: { ttl } in the request body).',
1191
1200
  ),
1192
1201
  prompt_surface: PromptSurfaceConfigSchema.default({ default: "full" }).describe(
1193
1202
  "Prompt-surface presets: default is full; models use bare model IDs, provider/model, or provider/* routing keys. Guidance and tool-description overrides are user-level only. OpenCode 1.x, Pi, and OMP register tool descriptions once per process (they follow the default preset). OpenCode 2 rewrites the five ctx_* descriptions per request from the draft model.",
@@ -1346,12 +1355,12 @@ export const MagicContextConfigSchema = z
1346
1355
  .boolean()
1347
1356
  .default(true)
1348
1357
  .describe(
1349
- "When true (default), Magic Context creates and re-tightens its storage directories to owner-only 0700 and storage files to owner-only 0600. Set false only for a deliberate trusted-group deployment whose operator manages directory, database, WAL/SHM, cache, and RPC file permissions externally; Magic Context then never chmods or supplies restrictive creation modes. USER-LEVEL ONLY — ignored in project config for security. On Windows, POSIX chmod modes are already meaningless, so this setting is a no-op.",
1358
+ "When true (default), Magic Context creates and re-tightens its TypeScript-mode storage directories to owner-only 0700 and storage files to owner-only 0600. Set false only for a deliberate trusted-group deployment whose operator manages those files externally; in TypeScript mode Magic Context then skips its own creation modes and recursive tightening. In Rust transform mode, ck-mc's store library always keeps the shared data directory owner-only 0700, regardless of this setting. USER-LEVEL ONLY — ignored in project config for security. On Windows, POSIX chmod modes are already meaningless, so this setting is a no-op.",
1350
1359
  ),
1351
1360
  })
1352
1361
  .default({ enforce_private_permissions: true })
1353
1362
  .describe(
1354
- "Storage permission policy. The default keeps session content and memories owner-private. Disabling enforcement is for trusted shared-group storage managed externally; every group member able to read the storage can read all stored session content and memories.",
1363
+ "Storage permission policy. The default keeps session content and memories owner-private. Disabling enforcement is for trusted shared-group storage managed externally; TypeScript mode follows that policy, but Rust transform mode always keeps its shared data directory owner-only because ck-mc's store library enforces it.",
1355
1364
  ),
1356
1365
  embedding: EmbeddingConfigSchema.default({
1357
1366
  provider: "local",
@@ -1438,10 +1447,18 @@ export const MagicContextConfigSchema = z
1438
1447
  "Pi-only child-process extension controls. This setting is user-level only; project configuration cannot choose which extensions a user's subagent children load.",
1439
1448
  ),
1440
1449
  smart_drops: z
1441
- .boolean()
1442
- .default(false)
1450
+ .unknown()
1451
+ .optional()
1452
+ .describe(
1453
+ "Deprecated: ignored. Content-aware supersession reclaim is always on, only on passes already rebuilding the cache. Remove this key; it no longer does anything.",
1454
+ )
1455
+ .meta({ deprecated: true }),
1456
+ protected_tools: z
1457
+ .record(z.string(), z.number().int().nonnegative())
1458
+ .default({ ...DEFAULT_PROTECTED_TOOLS })
1459
+ .transform((map) => mergeProtectedTools(map))
1443
1460
  .describe(
1444
- "Content-aware reclaim of provably-superseded tool output, layered on the existing execute-pass auto-drop. When on: superseded todowrite (keep newest 1), spent ctx_reduce (keep newest 3), and zero-value meta (bash_status, bash_kill, ctx_note read/dismiss) outputs are dropped; older edits to a file are compressed to a filePath-preserving marker while the newest edit per file stays full. Only acts on passes already busting the cache, so it never originates a cache bust. Honors the protected-tag reserve. Experimental: opt-in, default off until cache stability is proven; when off the wire is byte-identical to the positional-only reclaim. Requires a restart.",
1461
+ "Keep each tool's newest N still-active results in every automatic drop lane (issue 621). User and project maps merge over defaults {todowrite: 1, ctx_reduce: 3}; 0 turns protection off. Names are case-insensitive and ignore leading mcp_. Holds even at 95% pressure, with no byte cap: large protected outputs can reach refusal sooner. Queued drops, from the agent or historian publication, are held until newer calls displace the result and a later cache-rebuilding pass applies them. The historian's summary is unaffected; the raw result leaves at the next fold. Frozen strips are unaffected. Changes and rotation never originate a bust; dropped results are never restored.",
1445
1462
  ),
1446
1463
  caveman_text_compression: z
1447
1464
  .object({
@@ -1571,6 +1588,7 @@ export const MagicContextConfigSchema = z
1571
1588
 
1572
1589
  /** Settings whose fresh values can be used by later agent runs without changing rendered prompt bytes. */
1573
1590
  export const LIVE_RELOAD_CONFIG_PATHS = [
1591
+ "cache_ttl",
1574
1592
  "mural.model",
1575
1593
  "toast_duration_ms",
1576
1594
  "historian.opencode.model",
@@ -1589,6 +1607,7 @@ export const LIVE_RELOAD_CONFIG_PATHS = [
1589
1607
  "commit_cluster_trigger.enabled",
1590
1608
  "commit_cluster_trigger.min_clusters",
1591
1609
  "memory.auto_promote",
1610
+ "dreamer.disable",
1592
1611
  "dreamer.maxTokens",
1593
1612
  "dreamer.opencode.model",
1594
1613
  "dreamer.opencode.fallback_models",
@@ -15,10 +15,11 @@
15
15
  * Leave both empty (`""` and `[]`) to skip the dialog entirely.
16
16
  */
17
17
 
18
- import * as fs from "node:fs";
18
+ import { existsSync, readFileSync } from "node:fs";
19
19
  import * as path from "node:path";
20
20
  import { compareSemverCore } from "../hooks/auto-update-checker/semver";
21
21
  import { getMagicContextStorageDir } from "./data-path";
22
+ import { ensureStorageDirectorySync, writeStorageFileAtomicSync } from "./storage-permissions";
22
23
 
23
24
  /**
24
25
  * Bump only when there are user-visible changes worth a startup dialog.
@@ -60,8 +61,8 @@ type AnnouncementStateRead =
60
61
  function readAnnouncementState(): AnnouncementStateRead {
61
62
  try {
62
63
  const file = getStateFilePath();
63
- if (!fs.existsSync(file)) return { status: "missing" };
64
- const version = fs.readFileSync(file, "utf-8").trim();
64
+ if (!existsSync(file)) return { status: "missing" };
65
+ const version = readFileSync(file, "utf-8").trim();
65
66
  if (!version) return { status: "error" };
66
67
  return { status: "valid", version };
67
68
  } catch {
@@ -88,8 +89,8 @@ export function markAnnouncementSeen(version: string): void {
88
89
  if (!version) return;
89
90
  try {
90
91
  const dir = getMagicContextStorageDir();
91
- fs.mkdirSync(dir, { recursive: true });
92
- fs.writeFileSync(getStateFilePath(), version);
92
+ ensureStorageDirectorySync(dir);
93
+ writeStorageFileAtomicSync(getStateFilePath(), version);
93
94
  } catch {
94
95
  // best-effort
95
96
  }
@@ -45,7 +45,7 @@ describe("resolveCacheTtlDisplay", () => {
45
45
  });
46
46
 
47
47
  expect(configured.source).toBe("config");
48
- expect(session).toEqual({ value: "45m", source: "session", modelKey });
48
+ expect(session).toEqual({ value: "1h", source: "config", modelKey });
49
49
  expect(fallback).toEqual({ value: "5m", source: "default", modelKey });
50
50
  });
51
51
 
@@ -10,7 +10,7 @@ export interface CacheTtlDisplay {
10
10
  }
11
11
 
12
12
  export interface ResolveCacheTtlDisplayArgs {
13
- frozen?: ResolvedCacheTtl;
13
+ frozen?: ResolvedCacheTtl & { builtInDefault?: ResolvedCacheTtl };
14
14
  configured: MagicContextConfig["cache_ttl"];
15
15
  configuredExplicitly: boolean;
16
16
  modelKey: string | undefined;
@@ -20,12 +20,22 @@ export interface ResolveCacheTtlDisplayArgs {
20
20
  }
21
21
 
22
22
  /**
23
- * Resolve status-only TTL text without changing the scheduler's persisted truth.
24
- * Use the session value only when its persisted model key matches the model being
25
- * displayed; otherwise use live config because the session value may be for another model.
23
+ * Resolve the lifetime shown in status without changing the value saved for the scheduler.
24
+ * The next pass uses current settings; a saved built-in lifetime applies only to the same
25
+ * model, even after an override is removed.
26
26
  */
27
27
  export function resolveCacheTtlDisplay(args: ResolveCacheTtlDisplayArgs): CacheTtlDisplay {
28
- if (args.frozen) return args.frozen;
28
+ const resolved = resolveModelCacheTtl(
29
+ args.configured,
30
+ args.modelKey,
31
+ args.configuredExplicitly,
32
+ );
33
+ if (resolved.source === "config") return resolved;
34
+ if (args.frozen && (!args.modelKey || args.frozen.modelKey === args.modelKey)) {
35
+ return args.frozen.source === "config"
36
+ ? (args.frozen.builtInDefault ?? resolved)
37
+ : args.frozen;
38
+ }
29
39
  if (
30
40
  (args.sessionModelKey && (!args.modelKey || args.sessionModelKey === args.modelKey)) ||
31
41
  (!args.modelKey && !args.sessionModelKey && args.sessionValue !== "5m")
@@ -37,22 +47,13 @@ export function resolveCacheTtlDisplay(args: ResolveCacheTtlDisplayArgs): CacheT
37
47
  };
38
48
  }
39
49
 
40
- const resolved = resolveModelCacheTtl(args.configured, args.modelKey);
41
- if (
42
- resolved.source === "default" &&
43
- typeof args.configured === "string" &&
44
- args.configuredExplicitly
45
- )
46
- return { ...resolved, source: "config" };
47
50
  return resolved;
48
51
  }
49
52
 
50
53
  export function formatCacheTtlDisplay(display: CacheTtlDisplay): string {
51
- if (display.source === "OpenAI GPT-5.6+ default")
52
- return `Cache TTL: ${display.value} (${display.source})`;
53
54
  if (display.source === "session") return `Cache TTL: ${display.value} (session)`;
54
55
  if (display.source === "config") {
55
- return `Cache TTL: ${display.value} (config for ${display.modelKey ?? "current model"})`;
56
+ return `Cache TTL: ${display.value} (your config)`;
56
57
  }
57
- return `Cache TTL: ${display.value} (default — no cache_ttl for ${display.modelKey ?? "unknown model"})`;
58
+ return `Cache TTL: ${display.value} (built-in default, frozen for this session)`;
58
59
  }
@@ -0,0 +1,84 @@
1
+ import { expect, test } from "bun:test";
2
+ import { readFileSync } from "node:fs";
3
+ import { resolve } from "node:path";
4
+ import ts from "typescript";
5
+
6
+ const root = resolve(import.meta.dir, "../../../../");
7
+
8
+ for (const [host, path, functions] of [
9
+ [
10
+ "OpenCode",
11
+ "packages/plugin/src/hooks/magic-context/inject-compartments.ts",
12
+ ["materializeM0", "softRefreshCachedM1"],
13
+ ],
14
+ [
15
+ "Pi",
16
+ "packages/pi-plugin/src/inject-compartments-pi.ts",
17
+ ["materializeM0Pi", "softRefreshCachedM1Pi"],
18
+ ],
19
+ ] as const) {
20
+ test(`${host} fold and refresh render m[1] inside their writer section`, () => {
21
+ const source = ts.createSourceFile(
22
+ path,
23
+ readFileSync(resolve(root, path), "utf8"),
24
+ ts.ScriptTarget.Latest,
25
+ true,
26
+ );
27
+ const inspected: string[] = [];
28
+ const violations: string[] = [];
29
+ function visit(node: ts.Node): void {
30
+ if (
31
+ ts.isFunctionDeclaration(node) &&
32
+ node.name &&
33
+ functions.some((name) => name === node.name?.text)
34
+ ) {
35
+ inspected.push(node.name.text);
36
+ const calls: ts.CallExpression[] = [];
37
+ function collect(child: ts.Node): void {
38
+ if (ts.isCallExpression(child)) calls.push(child);
39
+ ts.forEachChild(child, collect);
40
+ }
41
+ collect(node);
42
+ const admission = calls.find(
43
+ (call) =>
44
+ call.expression.getText(source).endsWith(".exec") &&
45
+ call.arguments[0]?.getText(source) === '"BEGIN IMMEDIATE"',
46
+ );
47
+ expect(admission).toBeDefined();
48
+ const commit = calls.find(
49
+ (call) =>
50
+ admission &&
51
+ call.pos > admission.pos &&
52
+ call.expression.getText(source).endsWith(".exec") &&
53
+ call.arguments[0]?.getText(source) === '"COMMIT"',
54
+ );
55
+ expect(commit).toBeDefined();
56
+ const renders = calls.filter((call) =>
57
+ /^renderM1(?:Pi)?WithMetadata$/.test(call.expression.getText(source)),
58
+ );
59
+ expect(renders).toHaveLength(1);
60
+ for (const render of renders) {
61
+ if (
62
+ !admission ||
63
+ !commit ||
64
+ render.pos < admission.pos ||
65
+ render.pos > commit.pos
66
+ )
67
+ violations.push(`${node.name.text}: m[1] render outside writer`);
68
+ }
69
+ for (const call of calls) {
70
+ if (
71
+ call.expression.getText(source).endsWith("onFoldPrepare") &&
72
+ admission &&
73
+ call.pos > admission.pos
74
+ )
75
+ violations.push(`${node.name.text}: wire preparation inside writer`);
76
+ }
77
+ }
78
+ ts.forEachChild(node, visit);
79
+ }
80
+ visit(source);
81
+ expect(inspected.sort()).toEqual([...functions].sort());
82
+ expect(violations).toEqual([]);
83
+ });
84
+ }
@@ -0,0 +1,276 @@
1
+ import { expect, test } from "bun:test";
2
+ import { rmSync } from "node:fs";
3
+ import { tmpdir } from "node:os";
4
+ import { join } from "node:path";
5
+ import { appendCompartments } from "../features/magic-context/compartment-storage";
6
+ import {
7
+ insertMemory,
8
+ setMemoryClassification,
9
+ updateMemorySeenCount,
10
+ updateMemoryVerification,
11
+ } from "../features/magic-context/memory/storage-memory";
12
+ import {
13
+ recordIndexedMessageTime,
14
+ recordMessageFtsRowid,
15
+ } from "../features/magic-context/message-fts-rowid-map";
16
+ import { runMigrations } from "../features/magic-context/migrations";
17
+ import { getOrCreateSessionMeta } from "../features/magic-context/storage";
18
+ import { initializeDatabase } from "../features/magic-context/storage-db";
19
+ import { recoverUnresolvedCompartments } from "../features/magic-context/store-generation-rebase";
20
+ import { renderMemoryBlockV2 } from "../hooks/magic-context/inject-compartments";
21
+ import { estimateTokens } from "../hooks/magic-context/read-session-formatting";
22
+ import { Database } from "./sqlite";
23
+ import { createTestTempDirFromPath } from "./test-temp-dir";
24
+
25
+ export interface LockedDeltaFixture {
26
+ db: Database;
27
+ sibling: Database;
28
+ directory: string;
29
+ sessionId: string;
30
+ projectPath: string;
31
+ close: () => void;
32
+ }
33
+
34
+ export function createLockedDeltaFixture(
35
+ label: string,
36
+ open?: (path: string) => Database,
37
+ ): LockedDeltaFixture {
38
+ const directory = createTestTempDirFromPath(join(tmpdir(), `mc-locked-delta-${label}-`));
39
+ const path = join(directory, "context.db");
40
+ const db = open ? open(path) : new Database(path);
41
+ if (!open) {
42
+ initializeDatabase(db);
43
+ runMigrations(db);
44
+ }
45
+ db.exec("PRAGMA journal_mode=WAL");
46
+ const sibling = new Database(path);
47
+ const sessionId = label;
48
+ const projectPath = "git:locked-delta";
49
+ getOrCreateSessionMeta(db, sessionId);
50
+ return {
51
+ db,
52
+ sibling,
53
+ directory,
54
+ sessionId,
55
+ projectPath,
56
+ close: () => {
57
+ sibling.close();
58
+ db.close();
59
+ rmSync(directory, { recursive: true, force: true });
60
+ },
61
+ };
62
+ }
63
+ export interface LockedDeltaOptions {
64
+ memoryBudget?: number;
65
+ temporalAwareness?: boolean;
66
+ }
67
+ interface LockedDeltaDriver<Markers> {
68
+ host: string;
69
+ create: (label: string) => LockedDeltaFixture;
70
+ materialize: (fixture: LockedDeltaFixture, options: LockedDeltaOptions) => Markers;
71
+ refresh: (
72
+ fixture: LockedDeltaFixture,
73
+ options: LockedDeltaOptions,
74
+ beforeAdmission: () => void,
75
+ ) => void;
76
+ render: (fixture: LockedDeltaFixture, options: LockedDeltaOptions, markers: Markers) => string;
77
+ temporalHeadings?: boolean;
78
+ }
79
+ function compartment() {
80
+ return {
81
+ sequence: 0,
82
+ startMessage: 1,
83
+ endMessage: 2,
84
+ startMessageId: "a",
85
+ endMessageId: "b",
86
+ title: "locked history",
87
+ content: "locked history",
88
+ p1: "locked history",
89
+ p2: "summary",
90
+ p3: "outcome",
91
+ p4: "anchor",
92
+ legacy: 0,
93
+ };
94
+ }
95
+ function persistedDelta(f: LockedDeltaFixture): string {
96
+ return getOrCreateSessionMeta(f.db, f.sessionId).cachedM1Bytes?.toString("utf8") ?? "";
97
+ }
98
+ function refreshAtAdmission<Markers>(
99
+ driver: LockedDeltaDriver<Markers>,
100
+ f: LockedDeltaFixture,
101
+ options: LockedDeltaOptions,
102
+ write: () => void,
103
+ ) {
104
+ let admissions = 0;
105
+ let hooks = 0;
106
+ const exec = f.db.exec.bind(f.db);
107
+ f.db.exec = (sql) => {
108
+ if (sql === "BEGIN IMMEDIATE") admissions++;
109
+ return exec(sql);
110
+ };
111
+ try {
112
+ driver.refresh(f, options, () => {
113
+ expect(admissions).toBe(0);
114
+ hooks++;
115
+ write();
116
+ });
117
+ expect(hooks).toBe(1);
118
+ expect(admissions).toBe(1);
119
+ } finally {
120
+ f.db.exec = exec;
121
+ }
122
+ }
123
+
124
+ /** These fixtures use real sibling writes, then compare persisted bytes to an independent live render. */
125
+ export function registerLockedDeltaRegressions<Markers>(driver: LockedDeltaDriver<Markers>): void {
126
+ for (const change of ["importance", "reinforcement", "verification"] as const) {
127
+ test(`${driver.host} m[1] reads memory ${change} under its writer`, () => {
128
+ const f = driver.create(`${driver.host}-${change}`);
129
+ try {
130
+ const sample = insertMemory(f.db, {
131
+ projectPath: "git:budget-only",
132
+ category: "ARCHITECTURE",
133
+ content: "candidate A ".repeat(40),
134
+ });
135
+ const options = {
136
+ memoryBudget:
137
+ 4 * (estimateTokens(renderMemoryBlockV2([sample], "new-memories")) + 2),
138
+ };
139
+ const markers = driver.materialize(f, options);
140
+ const a = insertMemory(f.db, {
141
+ projectPath: f.projectPath,
142
+ category: "ARCHITECTURE",
143
+ content: "candidate A ".repeat(40),
144
+ });
145
+ const b = insertMemory(f.db, {
146
+ projectPath: f.projectPath,
147
+ category: "ARCHITECTURE",
148
+ content: "candidate B ".repeat(40),
149
+ });
150
+ setMemoryClassification(f.db, a.id, { importance: 50 });
151
+ setMemoryClassification(f.db, b.id, { importance: 50 });
152
+ f.db
153
+ .prepare(
154
+ "UPDATE memories SET last_seen_at = CASE WHEN id = ? THEN 1000 ELSE 0 END, verified_at = NULL WHERE id IN (?, ?)",
155
+ )
156
+ .run(a.id, a.id, b.id);
157
+ const before = driver.render(f, options, markers);
158
+ expect(before).toContain("candidate A");
159
+ expect(before).not.toContain("candidate B");
160
+ refreshAtAdmission(driver, f, options, () => {
161
+ if (change === "importance")
162
+ setMemoryClassification(f.sibling, b.id, { importance: 100 });
163
+ else if (change === "reinforcement") updateMemorySeenCount(f.sibling, b.id);
164
+ else updateMemoryVerification(f.sibling, b.id, "verified");
165
+ });
166
+ const fresh = driver.render(f, options, markers);
167
+ expect(fresh).toContain("candidate B");
168
+ expect(fresh).not.toContain("candidate A");
169
+ expect(persistedDelta(f)).toBe(fresh);
170
+ expect(persistedDelta(f)).not.toBe(before);
171
+ } finally {
172
+ f.close();
173
+ }
174
+ });
175
+ }
176
+
177
+ test(`${driver.host} m[1] reads in-place recovered compartment ranges under its writer`, () => {
178
+ const f = driver.create(`${driver.host}-ranges`);
179
+ try {
180
+ const options = {};
181
+ const markers = driver.materialize(f, options);
182
+ appendCompartments(f.db, f.sessionId, [compartment()]);
183
+ f.db
184
+ .prepare(
185
+ "UPDATE compartments SET rebase_status = 'unresolved' WHERE session_id = ?",
186
+ )
187
+ .run(f.sessionId);
188
+ const before = driver.render(f, options, markers);
189
+ expect(before).toContain("## 1-2");
190
+ const revision = f.db
191
+ .prepare("SELECT version FROM compartment_history_versions WHERE session_id = ?")
192
+ .get(f.sessionId) as { version: number };
193
+ refreshAtAdmission(driver, f, options, () => {
194
+ const recovered = recoverUnresolvedCompartments({
195
+ db: f.sibling,
196
+ sessionId: f.sessionId,
197
+ resolveOrdinal: (id) => (id === "a" ? 3 : id === "b" ? 4 : undefined),
198
+ reason: "Recovered fixture anchors",
199
+ });
200
+ expect(recovered.rowsRewritten).toBe(1);
201
+ });
202
+ const updated = f.db
203
+ .prepare("SELECT version FROM compartment_history_versions WHERE session_id = ?")
204
+ .get(f.sessionId) as { version: number };
205
+ expect(updated.version).toBeGreaterThan(revision.version);
206
+ const fresh = driver.render(f, options, markers);
207
+ expect(fresh).toContain("## 3-4");
208
+ expect(fresh).not.toContain("## 1-2");
209
+ expect(persistedDelta(f)).toBe(fresh);
210
+ } finally {
211
+ f.close();
212
+ }
213
+ });
214
+
215
+ test(`${driver.host} m[1] uses the baseline cutoff for a newly expired additive memory`, () => {
216
+ const f = driver.create(`${driver.host}-expiry`);
217
+ const realNow = Date.now;
218
+ let now = 1000;
219
+ Date.now = () => now;
220
+ try {
221
+ const options = {};
222
+ const markers = driver.materialize(f, options);
223
+ now = 2000;
224
+ const before = driver.render(f, options, markers);
225
+ expect(before).not.toContain("eligible at the baseline cutoff");
226
+ refreshAtAdmission(driver, f, options, () => {
227
+ insertMemory(f.sibling, {
228
+ projectPath: f.projectPath,
229
+ category: "ARCHITECTURE",
230
+ content: "Memory eligible at the baseline cutoff",
231
+ expiresAt: 2500,
232
+ });
233
+ now = 3000;
234
+ });
235
+ const fresh = driver.render(f, options, markers);
236
+ expect(fresh).toContain("eligible at the baseline cutoff");
237
+ expect(persistedDelta(f)).toBe(fresh);
238
+ } finally {
239
+ Date.now = realNow;
240
+ f.close();
241
+ }
242
+ });
243
+
244
+ if (driver.temporalHeadings) {
245
+ test(`${driver.host} m[1] reads indexed temporal headings under its writer`, () => {
246
+ const f = driver.create(`${driver.host}-dates`);
247
+ const originalXdgDataHome = process.env.XDG_DATA_HOME;
248
+ process.env.XDG_DATA_HOME = f.directory;
249
+ try {
250
+ const options = { temporalAwareness: true };
251
+ const markers = driver.materialize(f, options);
252
+ appendCompartments(f.db, f.sessionId, [compartment()]);
253
+ for (const ordinal of [1, 2])
254
+ recordMessageFtsRowid(f.db, f.sessionId, ordinal, ordinal);
255
+ const before = driver.render(f, options, markers);
256
+ expect(before).not.toContain("2025-01-01");
257
+ refreshAtAdmission(driver, f, options, () => {
258
+ for (const ordinal of [1, 2])
259
+ recordIndexedMessageTime(
260
+ f.sibling,
261
+ f.sessionId,
262
+ ordinal,
263
+ Date.UTC(2025, 0, 1),
264
+ );
265
+ });
266
+ const fresh = driver.render(f, options, markers);
267
+ expect(fresh).toContain("2025-01-01");
268
+ expect(persistedDelta(f)).toBe(fresh);
269
+ } finally {
270
+ if (originalXdgDataHome === undefined) delete process.env.XDG_DATA_HOME;
271
+ else process.env.XDG_DATA_HOME = originalXdgDataHome;
272
+ f.close();
273
+ }
274
+ });
275
+ }
276
+ }
@@ -29,8 +29,8 @@ describe("known model cache TTL", () => {
29
29
  expect(resolveCacheTtl("5m", "openai/gpt-6")).toBe("30m");
30
30
  expect(resolveCacheTtl("10m", "openai/gpt-6")).toBe("10m");
31
31
  });
32
- it("honors per-model entries before built-ins and built-ins before object defaults", () => {
33
- expect(resolveCacheTtl({ default: "10m" }, "openai/gpt-6")).toBe("30m");
32
+ it("honors per-model entries and configured defaults before built-ins", () => {
33
+ expect(resolveCacheTtl({ default: "10m" }, "openai/gpt-6")).toBe("10m");
34
34
  expect(resolveCacheTtl({ default: "10m", "gpt-6": "5m" }, "openai/gpt-6")).toBe("5m");
35
35
  expect(resolveCacheTtl({ default: "10m", "openai/*": "never" }, "openai/gpt-6")).toBe(
36
36
  "never",
@@ -28,6 +28,8 @@ const MODEL_CACHE_LIFETIMES = [
28
28
  export function resolveModelCacheTtl(
29
29
  config: CacheTtlConfig | undefined,
30
30
  modelKey: string | undefined,
31
+ configuredExplicitly = typeof config === "object" ||
32
+ (typeof config === "string" && config !== "5m"),
31
33
  ): ResolvedCacheTtl {
32
34
  if (config && typeof config !== "string") {
33
35
  const match =
@@ -37,11 +39,13 @@ export function resolveModelCacheTtl(
37
39
  modelKey !== "default"
38
40
  ? config[modelKey]
39
41
  : resolveModelConfigValue(config, modelKey)?.value;
40
- if (match !== undefined) return { value: match, source: "config", modelKey };
42
+ const value = match ?? config.default;
43
+ if (value !== undefined && configuredExplicitly)
44
+ return { value, source: "config", modelKey };
41
45
  }
42
- // A non-5m global string is an explicit policy. The generic 5m default is
43
- // not evidence of provider eviction: documented lifetimes avoid paid rewrites.
44
- if (typeof config === "string" && config !== "5m")
46
+ // The loader supplies provenance: an explicit 5m is policy too. Older callers
47
+ // without that bit still distinguish non-default strings from the schema's 5m.
48
+ if (typeof config === "string" && configuredExplicitly)
45
49
  return { value: config, source: "config", modelKey };
46
50
  const model =
47
51
  canonicalModelIdentity(modelKey ?? "")