@cortexkit/opencode-magic-context 0.46.1 → 0.48.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 (462) hide show
  1. package/dist/agents/magic-context-prompt.d.ts +1 -1
  2. package/dist/agents/magic-context-prompt.d.ts.map +1 -1
  3. package/dist/{announcement-y35wzg2r.js → announcement-fp14dw0n.js} +3 -2
  4. package/dist/auto-search-worker.js +112 -0
  5. package/dist/config/index.d.ts.map +1 -1
  6. package/dist/config/live-run-config.d.ts.map +1 -1
  7. package/dist/config/migrate-config-location.d.ts.map +1 -1
  8. package/dist/config/mural-model-deprecation.d.ts +15 -0
  9. package/dist/config/mural-model-deprecation.d.ts.map +1 -0
  10. package/dist/config/project-security.d.ts +0 -3
  11. package/dist/config/project-security.d.ts.map +1 -1
  12. package/dist/config/schema/magic-context.d.ts +21 -9
  13. package/dist/config/schema/magic-context.d.ts.map +1 -1
  14. package/dist/{conflict-warning-hook-7fj2b9jw.js → conflict-warning-hook-w8cykrnf.js} +12 -9
  15. package/dist/{context-sh2m2vde.js → context-m0cy262m.js} +1785 -913
  16. package/dist/{derive-budgets-7nj7r1rv.js → derive-budgets-sg0xsq7s.js} +4 -3
  17. package/dist/embedding-activity-g1dhes6g.js +10 -0
  18. package/dist/embedding-backfill-9rcm1mfy.js +21 -0
  19. package/dist/embedding-cache-mgyr73ef.js +16 -0
  20. package/dist/embedding-worker.js +11 -9
  21. package/dist/features/magic-context/compaction-marker.d.ts.map +1 -1
  22. package/dist/features/magic-context/dreamer/evaluate-smart-notes.d.ts +1 -0
  23. package/dist/features/magic-context/dreamer/evaluate-smart-notes.d.ts.map +1 -1
  24. package/dist/features/magic-context/dreamer/task-config.d.ts +3 -3
  25. package/dist/features/magic-context/dreamer/task-config.d.ts.map +1 -1
  26. package/dist/features/magic-context/dreamer/task-executor.d.ts +1 -1
  27. package/dist/features/magic-context/dreamer/task-executor.d.ts.map +1 -1
  28. package/dist/features/magic-context/dreamer/task-gates.d.ts.map +1 -1
  29. package/dist/features/magic-context/dreamer/task-registry.d.ts +1 -0
  30. package/dist/features/magic-context/dreamer/task-registry.d.ts.map +1 -1
  31. package/dist/features/magic-context/dreamer/verify.d.ts.map +1 -1
  32. package/dist/features/magic-context/message-index-async.d.ts +16 -3
  33. package/dist/features/magic-context/message-index-async.d.ts.map +1 -1
  34. package/dist/features/magic-context/message-index-bounded.d.ts +17 -0
  35. package/dist/features/magic-context/message-index-bounded.d.ts.map +1 -0
  36. package/dist/features/magic-context/message-index.d.ts +7 -1
  37. package/dist/features/magic-context/message-index.d.ts.map +1 -1
  38. package/dist/features/magic-context/mural/render-trigger.d.ts +7 -4
  39. package/dist/features/magic-context/mural/render-trigger.d.ts.map +1 -1
  40. package/dist/features/magic-context/overflow-detection.d.ts +2 -0
  41. package/dist/features/magic-context/overflow-detection.d.ts.map +1 -1
  42. package/dist/features/magic-context/pi-content-decisions.d.ts +7 -1
  43. package/dist/features/magic-context/pi-content-decisions.d.ts.map +1 -1
  44. package/dist/features/magic-context/project-embedding-registry.d.ts +7 -0
  45. package/dist/features/magic-context/project-embedding-registry.d.ts.map +1 -1
  46. package/dist/features/magic-context/search.d.ts +31 -0
  47. package/dist/features/magic-context/search.d.ts.map +1 -1
  48. package/dist/features/magic-context/session-activity.d.ts.map +1 -1
  49. package/dist/features/magic-context/session-project-storage.d.ts +8 -2
  50. package/dist/features/magic-context/session-project-storage.d.ts.map +1 -1
  51. package/dist/features/magic-context/smart-notes/runner.d.ts +1 -0
  52. package/dist/features/magic-context/smart-notes/runner.d.ts.map +1 -1
  53. package/dist/features/magic-context/storage-db.d.ts.map +1 -1
  54. package/dist/features/magic-context/storage-historian-runs.d.ts +2 -5
  55. package/dist/features/magic-context/storage-historian-runs.d.ts.map +1 -1
  56. package/dist/features/magic-context/storage-meta-persisted.d.ts +12 -0
  57. package/dist/features/magic-context/storage-meta-persisted.d.ts.map +1 -1
  58. package/dist/features/magic-context/storage-meta-session.d.ts +6 -0
  59. package/dist/features/magic-context/storage-meta-session.d.ts.map +1 -1
  60. package/dist/features/magic-context/storage-tag-identity-revision.d.ts +30 -0
  61. package/dist/features/magic-context/storage-tag-identity-revision.d.ts.map +1 -0
  62. package/dist/features/magic-context/storage-tags.d.ts +148 -3
  63. package/dist/features/magic-context/storage-tags.d.ts.map +1 -1
  64. package/dist/features/magic-context/storage.d.ts +1 -0
  65. package/dist/features/magic-context/storage.d.ts.map +1 -1
  66. package/dist/features/magic-context/subagent-token-capture.d.ts.map +1 -1
  67. package/dist/features/magic-context/transform-decision-log.d.ts +4 -2
  68. package/dist/features/magic-context/transform-decision-log.d.ts.map +1 -1
  69. package/dist/harness-e4avh192.js +10 -0
  70. package/dist/hooks/magic-context/active-anthropic-turn.d.ts +10 -0
  71. package/dist/hooks/magic-context/active-anthropic-turn.d.ts.map +1 -0
  72. package/dist/hooks/magic-context/apply-operations.d.ts.map +1 -1
  73. package/dist/hooks/magic-context/auto-search-blocking.fixture.d.ts +2 -0
  74. package/dist/hooks/magic-context/auto-search-blocking.fixture.d.ts.map +1 -0
  75. package/dist/hooks/magic-context/auto-search-deadline.d.ts +7 -0
  76. package/dist/hooks/magic-context/auto-search-deadline.d.ts.map +1 -1
  77. package/dist/hooks/magic-context/auto-search-host-review.fixture.d.ts +3 -0
  78. package/dist/hooks/magic-context/auto-search-host-review.fixture.d.ts.map +1 -0
  79. package/dist/hooks/magic-context/auto-search-lock-review.fixture.d.ts +2 -0
  80. package/dist/hooks/magic-context/auto-search-lock-review.fixture.d.ts.map +1 -0
  81. package/dist/hooks/magic-context/auto-search-long-lock-review.fixture.d.ts +2 -0
  82. package/dist/hooks/magic-context/auto-search-long-lock-review.fixture.d.ts.map +1 -0
  83. package/dist/hooks/magic-context/auto-search-omp-host-review.fixture.d.ts +4 -0
  84. package/dist/hooks/magic-context/auto-search-omp-host-review.fixture.d.ts.map +1 -0
  85. package/dist/hooks/magic-context/auto-search-omp-loader.fixture.d.ts +3 -0
  86. package/dist/hooks/magic-context/auto-search-omp-loader.fixture.d.ts.map +1 -0
  87. package/dist/hooks/magic-context/auto-search-runner.d.ts +1 -1
  88. package/dist/hooks/magic-context/auto-search-runner.d.ts.map +1 -1
  89. package/dist/hooks/magic-context/auto-search-snapshot.fixture.d.ts +4 -0
  90. package/dist/hooks/magic-context/auto-search-snapshot.fixture.d.ts.map +1 -0
  91. package/dist/hooks/magic-context/auto-search-worker-client.d.ts +98 -0
  92. package/dist/hooks/magic-context/auto-search-worker-client.d.ts.map +1 -0
  93. package/dist/hooks/magic-context/auto-search-worker.d.ts +2 -0
  94. package/dist/hooks/magic-context/auto-search-worker.d.ts.map +1 -0
  95. package/dist/hooks/magic-context/caveman-cleanup.d.ts.map +1 -1
  96. package/dist/hooks/magic-context/command-handler.d.ts +1 -0
  97. package/dist/hooks/magic-context/command-handler.d.ts.map +1 -1
  98. package/dist/hooks/magic-context/compartment-runner-incremental.d.ts.map +1 -1
  99. package/dist/hooks/magic-context/compartment-runner-recomp.d.ts.map +1 -1
  100. package/dist/hooks/magic-context/compartment-runner-types.d.ts +3 -5
  101. package/dist/hooks/magic-context/compartment-runner-types.d.ts.map +1 -1
  102. package/dist/hooks/magic-context/compartment-runner.d.ts +2 -1
  103. package/dist/hooks/magic-context/compartment-runner.d.ts.map +1 -1
  104. package/dist/hooks/magic-context/compartment-trigger.d.ts +3 -1
  105. package/dist/hooks/magic-context/compartment-trigger.d.ts.map +1 -1
  106. package/dist/hooks/magic-context/event-handler.d.ts +1 -1
  107. package/dist/hooks/magic-context/event-handler.d.ts.map +1 -1
  108. package/dist/hooks/magic-context/event-resolvers.d.ts.map +1 -1
  109. package/dist/hooks/magic-context/execute-status.d.ts.map +1 -1
  110. package/dist/hooks/magic-context/final-wire-token-estimate.d.ts +2 -0
  111. package/dist/hooks/magic-context/final-wire-token-estimate.d.ts.map +1 -1
  112. package/dist/hooks/magic-context/heuristic-cleanup.d.ts.map +1 -1
  113. package/dist/hooks/magic-context/historian-drain-gate.d.ts +11 -0
  114. package/dist/hooks/magic-context/historian-drain-gate.d.ts.map +1 -0
  115. package/dist/hooks/magic-context/hook.d.ts +3 -2
  116. package/dist/hooks/magic-context/hook.d.ts.map +1 -1
  117. package/dist/hooks/magic-context/inject-compartments.d.ts.map +1 -1
  118. package/dist/hooks/magic-context/latest-assistant-turn.d.ts +25 -0
  119. package/dist/hooks/magic-context/latest-assistant-turn.d.ts.map +1 -0
  120. package/dist/hooks/magic-context/latest-thinking-recovery.d.ts +61 -0
  121. package/dist/hooks/magic-context/latest-thinking-recovery.d.ts.map +1 -0
  122. package/dist/hooks/magic-context/lkg-persist.d.ts +4 -3
  123. package/dist/hooks/magic-context/lkg-persist.d.ts.map +1 -1
  124. package/dist/hooks/magic-context/lkg-replay.d.ts +13 -8
  125. package/dist/hooks/magic-context/lkg-replay.d.ts.map +1 -1
  126. package/dist/hooks/magic-context/lkg-slot.d.ts +139 -2
  127. package/dist/hooks/magic-context/lkg-slot.d.ts.map +1 -1
  128. package/dist/hooks/magic-context/message-search-accepting-silent-worker.fixture.d.ts +2 -0
  129. package/dist/hooks/magic-context/message-search-accepting-silent-worker.fixture.d.ts.map +1 -0
  130. package/dist/hooks/magic-context/module-wire.d.ts.map +1 -1
  131. package/dist/hooks/magic-context/oc-stall-r2-warmup-worker.fixture.d.ts +2 -0
  132. package/dist/hooks/magic-context/oc-stall-r2-warmup-worker.fixture.d.ts.map +1 -0
  133. package/dist/hooks/magic-context/oc-stall-search-review.fixture.d.ts +2 -0
  134. package/dist/hooks/magic-context/oc-stall-search-review.fixture.d.ts.map +1 -0
  135. package/dist/hooks/magic-context/opencode-proven-floor.d.ts +6 -0
  136. package/dist/hooks/magic-context/opencode-proven-floor.d.ts.map +1 -0
  137. package/dist/hooks/magic-context/opencode1-to-model-messages.fixture.d.ts +63 -0
  138. package/dist/hooks/magic-context/opencode1-to-model-messages.fixture.d.ts.map +1 -0
  139. package/dist/hooks/magic-context/pass-outcome.d.ts.map +1 -1
  140. package/dist/hooks/magic-context/protected-tail-boundary.d.ts.map +1 -1
  141. package/dist/hooks/magic-context/provider-visible-parts.d.ts +45 -0
  142. package/dist/hooks/magic-context/provider-visible-parts.d.ts.map +1 -0
  143. package/dist/hooks/magic-context/raw-ordinal-warmup-silent-worker.fixture.d.ts +2 -0
  144. package/dist/hooks/magic-context/raw-ordinal-warmup-silent-worker.fixture.d.ts.map +1 -0
  145. package/dist/hooks/magic-context/raw-ordinal-warmup-worker.d.ts +2 -0
  146. package/dist/hooks/magic-context/raw-ordinal-warmup-worker.d.ts.map +1 -0
  147. package/dist/hooks/magic-context/raw-ordinal-warmup.d.ts +87 -0
  148. package/dist/hooks/magic-context/raw-ordinal-warmup.d.ts.map +1 -0
  149. package/dist/hooks/magic-context/read-session-chunk.d.ts +12 -0
  150. package/dist/hooks/magic-context/read-session-chunk.d.ts.map +1 -1
  151. package/dist/hooks/magic-context/read-session-db.d.ts.map +1 -1
  152. package/dist/hooks/magic-context/read-session-formatting.d.ts +5 -0
  153. package/dist/hooks/magic-context/read-session-formatting.d.ts.map +1 -1
  154. package/dist/hooks/magic-context/read-session-raw.d.ts +83 -1
  155. package/dist/hooks/magic-context/read-session-raw.d.ts.map +1 -1
  156. package/dist/hooks/magic-context/read-session-true-raw-tokens.d.ts.map +1 -1
  157. package/dist/hooks/magic-context/reasoning-budget-status.d.ts +15 -0
  158. package/dist/hooks/magic-context/reasoning-budget-status.d.ts.map +1 -0
  159. package/dist/hooks/magic-context/reasoning-budget.d.ts +40 -0
  160. package/dist/hooks/magic-context/reasoning-budget.d.ts.map +1 -0
  161. package/dist/hooks/magic-context/reasoning-removal.d.ts +6 -6
  162. package/dist/hooks/magic-context/reasoning-removal.d.ts.map +1 -1
  163. package/dist/hooks/magic-context/rust-mode-transform.d.ts.map +1 -1
  164. package/dist/hooks/magic-context/sentinel.d.ts +45 -1
  165. package/dist/hooks/magic-context/sentinel.d.ts.map +1 -1
  166. package/dist/hooks/magic-context/strip-content.d.ts +21 -5
  167. package/dist/hooks/magic-context/strip-content.d.ts.map +1 -1
  168. package/dist/hooks/magic-context/system-prompt-hash.d.ts +1 -0
  169. package/dist/hooks/magic-context/system-prompt-hash.d.ts.map +1 -1
  170. package/dist/hooks/magic-context/tag-messages.d.ts +21 -0
  171. package/dist/hooks/magic-context/tag-messages.d.ts.map +1 -1
  172. package/dist/hooks/magic-context/tag-owner-warmup.d.ts +6 -0
  173. package/dist/hooks/magic-context/tag-owner-warmup.d.ts.map +1 -0
  174. package/dist/hooks/magic-context/tail-hygiene-walk.d.ts.map +1 -1
  175. package/dist/hooks/magic-context/token-count-exact.d.ts +35 -0
  176. package/dist/hooks/magic-context/token-count-exact.d.ts.map +1 -0
  177. package/dist/hooks/magic-context/tool-drop-target.d.ts +5 -0
  178. package/dist/hooks/magic-context/tool-drop-target.d.ts.map +1 -1
  179. package/dist/hooks/magic-context/transform-compartment-phase.d.ts +3 -28
  180. package/dist/hooks/magic-context/transform-compartment-phase.d.ts.map +1 -1
  181. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts +28 -6
  182. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts.map +1 -1
  183. package/dist/hooks/magic-context/transform.d.ts +11 -3
  184. package/dist/hooks/magic-context/transform.d.ts.map +1 -1
  185. package/dist/hooks/magic-context/wrapup-orchestrator.d.ts.map +1 -1
  186. package/dist/{index-hpecdzec.js → index-0an7742d.js} +6820 -6587
  187. package/dist/index-0qhce371.js +120 -0
  188. package/dist/{index-q6hef7fh.js → index-0sahzkwr.js} +6 -19
  189. package/dist/{index-k5bdx1bx.js → index-0w56v4fm.js} +3 -5
  190. package/dist/index-14cjxt20.js +819 -0
  191. package/dist/{v2/server-51dv1pr5.js → index-1qb0z7wa.js} +301 -27
  192. package/dist/index-2bvekkfy.js +11 -0
  193. package/dist/{index-sj29b3z2.js → index-2y0s2hep.js} +3 -3
  194. package/dist/index-4dhv7mqz.js +131 -0
  195. package/dist/{index-b35pxds2.js → index-58e3y90n.js} +1 -18
  196. package/dist/index-5zygecde.js +152 -0
  197. package/dist/{index-sjthx78w.js → index-692jzy0p.js} +16879 -22907
  198. package/dist/index-72nhv486.js +2307 -0
  199. package/dist/index-7jzrrxap.js +931 -0
  200. package/dist/index-7mx8v0pw.js +3591 -0
  201. package/dist/index-8ajstryz.js +18 -0
  202. package/dist/{index-sfpzqvdz.js → index-8cd2j99z.js} +2 -3
  203. package/dist/{index-hybnrwq0.js → index-8j7gqj40.js} +131 -128
  204. package/dist/index-bdckkfw6.js +3261 -0
  205. package/dist/{index-8x2v7gg9.js → index-bhvjj0ys.js} +158 -2455
  206. package/dist/index-c43kr12f.js +3030 -0
  207. package/dist/index-cb7emxgj.js +984 -0
  208. package/dist/index-d9vfe7xq.js +16 -0
  209. package/dist/{index-5gq3b2ya.js → index-db7zwa3v.js} +147 -209
  210. package/dist/index-dhwzyd54.js +1142 -0
  211. package/dist/{index-8da2zjhz.js → index-eeezr5zz.js} +9 -7
  212. package/dist/{index-pkbcrdqs.js → index-f0h6xwqm.js} +3412 -4552
  213. package/dist/index-fb3zxn06.js +13 -0
  214. package/dist/index-fbv1dn35.js +171 -0
  215. package/dist/index-fr0wbhdn.js +43 -0
  216. package/dist/{index-mc22ayvf.js → index-ghc9f0n7.js} +11 -9
  217. package/dist/{index-fzbvakh0.js → index-jcbd3znx.js} +3 -3
  218. package/dist/{index-5p8jdswx.js → index-k1xb52kd.js} +20 -13
  219. package/dist/index-k9nnwad5.js +3532 -0
  220. package/dist/{v2/server-fg34g6a5.js → index-kb9nn0a0.js} +309 -52
  221. package/dist/index-knh4y330.js +566 -0
  222. package/dist/{index-q4yp4b52.js → index-mfkzp7qj.js} +28 -28
  223. package/dist/{index-sgthv3f7.js → index-mmyh6d8f.js} +4 -4
  224. package/dist/index-pavzsdc6.js +17 -0
  225. package/dist/{index-0d3g3461.js → index-pdecwzrd.js} +19 -16
  226. package/dist/index-pg50n748.js +1060 -0
  227. package/dist/index-q2tqeqde.js +2106 -0
  228. package/dist/index-q7h7csab.js +3469 -0
  229. package/dist/index-qt1qqasc.js +22 -0
  230. package/dist/{index-majxda46.js → index-ty64eqcn.js} +28 -18
  231. package/dist/{index-7qw742ev.js → index-yq8n9qcb.js} +25 -44
  232. package/dist/{index-sfnj6h8h.js → index-z8e0psj8.js} +20 -20
  233. package/dist/index.d.ts.map +1 -1
  234. package/dist/index.js +1061 -260
  235. package/dist/logger-d3wex3dz.js +20 -0
  236. package/dist/message-index-bounded-7ezbgddp.js +124 -0
  237. package/dist/{v2/message-time-backfill-r6qkem1x.js → message-time-backfill-brbd63hv.js} +8 -6
  238. package/dist/migration-worker.js +25 -16
  239. package/dist/{model-resolution-xhfmyyvy.js → model-resolution-nx97z3x7.js} +1 -1
  240. package/dist/plugin/dream-timer.d.ts +1 -1
  241. package/dist/plugin/dream-timer.d.ts.map +1 -1
  242. package/dist/plugin/hooks/create-session-hooks.d.ts +3 -1
  243. package/dist/plugin/hooks/create-session-hooks.d.ts.map +1 -1
  244. package/dist/plugin/host-stall-profiler-report.d.ts +2 -0
  245. package/dist/plugin/host-stall-profiler-report.d.ts.map +1 -0
  246. package/dist/plugin/host-stall-profiler.d.ts +3 -0
  247. package/dist/plugin/host-stall-profiler.d.ts.map +1 -0
  248. package/dist/plugin/messages-transform.d.ts +21 -19
  249. package/dist/plugin/messages-transform.d.ts.map +1 -1
  250. package/dist/plugin/rpc-handlers.d.ts.map +1 -1
  251. package/dist/plugin/tool-registry.d.ts.map +1 -1
  252. package/dist/project-embedding-registry-7qzptcw7.js +88 -0
  253. package/dist/raw-ordinal-warmup-worker.js +60 -0
  254. package/dist/{read-session-chunk-egz7r68d.js → read-session-chunk-6k83m4fj.js} +15 -9
  255. package/dist/read-session-raw-3g9qy1xa.js +58 -0
  256. package/dist/recomp-orchestrator-d3fp1cy0.js +57 -0
  257. package/dist/{v2/safe-notification-target-eb1n1vfb.js → safe-notification-target-5ffqq32m.js} +4 -2
  258. package/dist/search-epax1ecv.js +45 -0
  259. package/dist/{v2/send-session-notification-qs0j78v6.js → send-session-notification-erecz4y4.js} +10 -6
  260. package/dist/shared/auto-search-lifecycle.d.ts +7 -0
  261. package/dist/shared/auto-search-lifecycle.d.ts.map +1 -0
  262. package/dist/shared/conflict-detector.d.ts.map +1 -1
  263. package/dist/shared/historian-tool-expansions.d.ts +1 -1
  264. package/dist/shared/historian-tool-expansions.d.ts.map +1 -1
  265. package/dist/shared/historian-tool-template.d.ts +2 -2
  266. package/dist/shared/historian-tool-template.d.ts.map +1 -1
  267. package/dist/shared/host-stall-profiler-bun.d.ts +46 -0
  268. package/dist/shared/host-stall-profiler-bun.d.ts.map +1 -0
  269. package/dist/shared/host-stall-profiler-common.d.ts +58 -0
  270. package/dist/shared/host-stall-profiler-common.d.ts.map +1 -0
  271. package/dist/shared/host-stall-profiler-node.d.ts +36 -0
  272. package/dist/shared/host-stall-profiler-node.d.ts.map +1 -0
  273. package/dist/shared/host-stall-profiler-report.d.ts +68 -0
  274. package/dist/shared/host-stall-profiler-report.d.ts.map +1 -0
  275. package/dist/shared/host-stall-profiler.d.ts +5 -0
  276. package/dist/shared/host-stall-profiler.d.ts.map +1 -0
  277. package/dist/shared/model-resolution.d.ts +2 -3
  278. package/dist/shared/model-resolution.d.ts.map +1 -1
  279. package/dist/shared/sqlite.d.ts +46 -1
  280. package/dist/shared/sqlite.d.ts.map +1 -1
  281. package/dist/shared/stable-json.d.ts.map +1 -1
  282. package/dist/shared/status-view.d.ts.map +1 -1
  283. package/dist/shared/user-facing-codes.d.ts +0 -5
  284. package/dist/shared/user-facing-codes.d.ts.map +1 -1
  285. package/dist/shared/window-geometry.d.ts +4 -0
  286. package/dist/shared/window-geometry.d.ts.map +1 -1
  287. package/dist/sqlite-context-pragmas-mv9jqwjh.js +6 -0
  288. package/dist/sqlite-mhjkerzq.js +46 -0
  289. package/dist/storage-memory-07fx57k6.js +71 -0
  290. package/dist/storage-tags-d3b0v2ss.js +131 -0
  291. package/dist/{task-config-v81k8jvk.js → task-config-cgpg0nvh.js} +2 -2
  292. package/dist/tools/ctx-expand/render.d.ts.map +1 -1
  293. package/dist/tools/ctx-expand/tools.d.ts.map +1 -1
  294. package/dist/tools/ctx-note/constants.d.ts +4 -0
  295. package/dist/tools/ctx-note/constants.d.ts.map +1 -1
  296. package/dist/tools/ctx-note/tools.d.ts +1 -0
  297. package/dist/tools/ctx-note/tools.d.ts.map +1 -1
  298. package/dist/tools/ctx-search/tools.d.ts.map +1 -1
  299. package/dist/tools/parameter-descriptions.d.ts +2 -2
  300. package/dist/tools/parameter-descriptions.d.ts.map +1 -1
  301. package/dist/{transform-postprocess-phase-bqhz6vdr.js → transform-postprocess-phase-spcy2qre.js} +35 -17
  302. package/dist/transformers-node-wasm.js +18415 -18415
  303. package/dist/v2/auto-search-worker.js +112 -0
  304. package/dist/v2/{context-zecmzk5s.js → context-sf98kstd.js} +8378 -8530
  305. package/dist/v2/{derive-budgets-kdgp4s3r.js → derive-budgets-3vc0y84t.js} +4 -3
  306. package/dist/v2/embedding-activity-g1dhes6g.js +10 -0
  307. package/dist/v2/embedding-backfill-vn8g1nh1.js +21 -0
  308. package/dist/v2/embedding-cache-mgyr73ef.js +16 -0
  309. package/dist/v2/embedding-worker.js +12 -9
  310. package/dist/v2/fold/host-media.d.ts +4 -0
  311. package/dist/v2/fold/host-media.d.ts.map +1 -1
  312. package/dist/v2/fold/memory-cache.d.ts +70 -0
  313. package/dist/v2/fold/memory-cache.d.ts.map +1 -0
  314. package/dist/v2/fold/native-codec.d.ts +10 -0
  315. package/dist/v2/fold/native-codec.d.ts.map +1 -0
  316. package/dist/v2/fold/native-replay.d.ts +58 -0
  317. package/dist/v2/fold/native-replay.d.ts.map +1 -0
  318. package/dist/v2/fold/policy.d.ts +24 -0
  319. package/dist/v2/fold/policy.d.ts.map +1 -0
  320. package/dist/v2/harness-e4avh192.js +10 -0
  321. package/dist/v2/hidden-completion.d.ts.map +1 -1
  322. package/dist/v2/hooks/context.d.ts +2 -2
  323. package/dist/v2/hooks/context.d.ts.map +1 -1
  324. package/dist/v2/hooks/dream-manual.d.ts +1 -1
  325. package/dist/v2/hooks/dream-manual.d.ts.map +1 -1
  326. package/dist/v2/hooks/dream-timer.d.ts.map +1 -1
  327. package/dist/v2/hooks/dream-trigger.d.ts +1 -2
  328. package/dist/v2/hooks/dream-trigger.d.ts.map +1 -1
  329. package/dist/v2/hooks/payload.d.ts.map +1 -1
  330. package/dist/v2/hooks/tools.d.ts.map +1 -1
  331. package/dist/v2/hooks/types.d.ts +6 -0
  332. package/dist/v2/hooks/types.d.ts.map +1 -1
  333. package/dist/v2/logger-mxd0ym09.js +19 -0
  334. package/dist/v2/message-index-bounded-dy3s2k1e.js +123 -0
  335. package/dist/{message-time-backfill-68gj6t3e.js → v2/message-time-backfill-gtx1pwk1.js} +7 -7
  336. package/dist/v2/migration-worker.js +24 -15
  337. package/dist/v2/{model-resolution-xhfmyyvy.js → model-resolution-nx97z3x7.js} +1 -1
  338. package/dist/v2/project-embedding-registry-1tgba5dv.js +86 -0
  339. package/dist/v2/raw-ordinal-warmup-worker.js +60 -0
  340. package/dist/v2/{read-session-chunk-8vjp6581.js → read-session-chunk-rh4khdkv.js} +14 -8
  341. package/dist/v2/read-session-raw-bsbmf0vj.js +57 -0
  342. package/dist/v2/recomp-orchestrator-az61rfcg.js +57 -0
  343. package/dist/{safe-notification-target-43r8jsxw.js → v2/safe-notification-target-73ax1p5v.js} +3 -3
  344. package/dist/v2/search-nzkwrc6n.js +45 -0
  345. package/dist/{send-session-notification-dyw42dtr.js → v2/send-session-notification-6km439kn.js} +9 -7
  346. package/dist/{index-5eqk6z3s.js → v2/server-1r6pmz4f.js} +301 -27
  347. package/dist/v2/server-2bvekkfy.js +11 -0
  348. package/dist/v2/server-2fbhp79z.js +3205 -0
  349. package/dist/v2/{server-ajzeteqw.js → server-2ra6pwf3.js} +1 -18
  350. package/dist/v2/server-4dhv7mqz.js +131 -0
  351. package/dist/v2/{server-xa4xe3rv.js → server-4k748ke6.js} +11 -1053
  352. package/dist/v2/{server-vs5gpnd4.js → server-52awr2mw.js} +81 -145
  353. package/dist/v2/{server-1qbnzc80.js → server-5m3dt5r1.js} +136 -148
  354. package/dist/v2/server-686jg6eb.js +3508 -0
  355. package/dist/v2/server-7jzrrxap.js +931 -0
  356. package/dist/v2/server-7wwc2nga.js +3023 -0
  357. package/dist/v2/server-8ajstryz.js +18 -0
  358. package/dist/v2/{server-sfpzqvdz.js → server-8cd2j99z.js} +2 -3
  359. package/dist/v2/server-8pyt7hev.js +3408 -0
  360. package/dist/v2/server-8tqanswc.js +984 -0
  361. package/dist/v2/{server-14vq4kpm.js → server-aan4q8mx.js} +3 -3
  362. package/dist/v2/server-d9vfe7xq.js +16 -0
  363. package/dist/v2/server-e0vdaae2.js +3591 -0
  364. package/dist/v2/server-ezhze64f.js +1048 -0
  365. package/dist/v2/server-fb3zxn06.js +13 -0
  366. package/dist/v2/server-fr0wbhdn.js +43 -0
  367. package/dist/v2/server-g5r0n3b6.js +1137 -0
  368. package/dist/v2/server-gjcr4w98.js +154 -0
  369. package/dist/v2/server-k228xhjg.js +171 -0
  370. package/dist/v2/{server-jc7y02q0.js → server-k8x2rbxc.js} +5119 -10948
  371. package/dist/{index-fg34g6a5.js → v2/server-kb9nn0a0.js} +309 -52
  372. package/dist/v2/{server-g0fjrkta.js → server-mfkzp7qj.js} +28 -28
  373. package/dist/v2/server-pavzsdc6.js +17 -0
  374. package/dist/v2/server-psqc7e9n.js +2106 -0
  375. package/dist/v2/server-qt1qqasc.js +22 -0
  376. package/dist/v2/server-qye6ykf7.js +120 -0
  377. package/dist/v2/{server-qdjnb2z1.js → server-r5p3b1wy.js} +11 -9
  378. package/dist/v2/server-sggvvzhb.js +759 -0
  379. package/dist/v2/{server-y8maxeft.js → server-v06jcv0w.js} +16 -13
  380. package/dist/v2/server-vqpf3167.js +1048 -0
  381. package/dist/v2/{server-c5gz8wph.js → server-x2g40a71.js} +2048 -2059
  382. package/dist/v2/{server-wvjvfhck.js → server-xdfwt6kh.js} +20 -16
  383. package/dist/v2/{server-mcfawjgc.js → server-xxm59eww.js} +25 -44
  384. package/dist/v2/server-yczc713m.js +564 -0
  385. package/dist/v2/{server-3n4q9xme.js → server-z2037m6z.js} +4 -4
  386. package/dist/v2/{server-e29d7p7c.js → server-zm570tr2.js} +166 -160
  387. package/dist/v2/{server-6r257mf5.js → server-zxhgvsf9.js} +3 -3
  388. package/dist/v2/server.js +16 -14
  389. package/dist/v2/sqlite-context-pragmas-mv9jqwjh.js +6 -0
  390. package/dist/v2/sqlite-mhjkerzq.js +46 -0
  391. package/dist/v2/storage-memory-07fx57k6.js +71 -0
  392. package/dist/v2/storage-tags-w4tv77sn.js +130 -0
  393. package/dist/v2/store-reader.d.ts +16 -0
  394. package/dist/v2/store-reader.d.ts.map +1 -1
  395. package/dist/v2/{task-config-tbndqyny.js → task-config-x0hq3qfd.js} +2 -2
  396. package/dist/v2/transformers-node-wasm.js +18415 -18415
  397. package/dist/v2/tui/index.d.ts.map +1 -1
  398. package/dist/v2/tui/types.d.ts +1 -10
  399. package/dist/v2/tui/types.d.ts.map +1 -1
  400. package/dist/v2/{wrapup-orchestrator-0snhvwcv.js → wrapup-orchestrator-mz7efs7w.js} +51 -27
  401. package/dist/wrapup-orchestrator-amzta1t4.js +44 -0
  402. package/package.json +4 -3
  403. package/src/agents/magic-context-prompt.ts +27 -2
  404. package/src/agents/smart-notes-enabled.test.ts +294 -0
  405. package/src/agents/smart-notes-on.golden.json +70 -0
  406. package/src/config/index.test.ts +67 -1
  407. package/src/config/index.ts +8 -0
  408. package/src/config/latch-permanence-guard.test.ts +4 -0
  409. package/src/config/live-run-config.test.ts +37 -1
  410. package/src/config/live-run-config.ts +28 -0
  411. package/src/config/migrate-config-location.ts +10 -3
  412. package/src/config/mural-model-deprecation.ts +24 -0
  413. package/src/config/project-security.hostile-matrix.test.ts +4 -44
  414. package/src/config/project-security.test.ts +9 -14
  415. package/src/config/project-security.ts +13 -55
  416. package/src/config/schema/magic-context.test.ts +6 -5
  417. package/src/config/schema/magic-context.ts +34 -16
  418. package/src/features/magic-context/dreamer/task-registry.ts +6 -0
  419. package/src/shared/auto-search-lifecycle.ts +27 -0
  420. package/src/shared/conflict-detector.test.ts +56 -0
  421. package/src/shared/conflict-detector.ts +16 -5
  422. package/src/shared/historian-tool-defaults.json +6 -6
  423. package/src/shared/historian-tool-expansions.ts +65 -8
  424. package/src/shared/historian-tool-preview-defaults.json +13 -0
  425. package/src/shared/historian-tool-template.ts +48 -14
  426. package/src/shared/host-stall-profiler-bun.ts +358 -0
  427. package/src/shared/host-stall-profiler-common.ts +159 -0
  428. package/src/shared/host-stall-profiler-node.test.ts +234 -0
  429. package/src/shared/host-stall-profiler-node.ts +274 -0
  430. package/src/shared/host-stall-profiler-report.ts +248 -0
  431. package/src/shared/host-stall-profiler.ts +57 -0
  432. package/src/shared/model-resolution.test.ts +54 -17
  433. package/src/shared/model-resolution.ts +6 -17
  434. package/src/shared/sqlite-640-review-r2.test.ts +136 -0
  435. package/src/shared/sqlite-640-review.test.ts +183 -0
  436. package/src/shared/sqlite-acquisition-routing.test.ts +18 -0
  437. package/src/shared/sqlite.test.ts +52 -0
  438. package/src/shared/sqlite.ts +423 -37
  439. package/src/shared/stable-json-linear.test.ts +109 -0
  440. package/src/shared/stable-json.ts +37 -7
  441. package/src/shared/status-view.test.ts +6 -1
  442. package/src/shared/status-view.ts +15 -1
  443. package/src/shared/tag-transcript.ts +6 -0
  444. package/src/shared/user-facing-codes.ts +2 -6
  445. package/src/shared/window-geometry.ts +10 -0
  446. package/src/shared/write-transaction-attribution.test.ts +2 -2
  447. package/src/v2/tui/host-contract.test.ts +41 -67
  448. package/src/v2/tui/index.ts +6 -214
  449. package/src/v2/tui/types.ts +5 -17
  450. package/dist/features/magic-context/checkout-claim-fake-subc.test-support.d.ts +0 -45
  451. package/dist/features/magic-context/checkout-claim-fake-subc.test-support.d.ts.map +0 -1
  452. package/dist/features/magic-context/checkout-claim.d.ts +0 -155
  453. package/dist/features/magic-context/checkout-claim.d.ts.map +0 -1
  454. package/dist/index-3h0ybwah.js +0 -6540
  455. package/dist/index-r5hmbx3t.js +0 -7773
  456. package/dist/recomp-orchestrator-y15j0rb9.js +0 -39
  457. package/dist/v2/recomp-orchestrator-8ejxvrzz.js +0 -39
  458. package/dist/v2/server-frbm99q5.js +0 -7698
  459. package/dist/v2/server-qp5hx1ad.js +0 -6366
  460. package/dist/wrapup-orchestrator-39amhv9s.js +0 -26
  461. /package/dist/{index-en1k8h8m.js → index-2pp04pmg.js} +0 -0
  462. /package/dist/v2/{index-en1k8h8m.js → index-2pp04pmg.js} +0 -0
@@ -11,10 +11,7 @@ import {
11
11
  withLiveDreamerOutputCap,
12
12
  renderUserFacingFailure,
13
13
  userFacingFailureCode,
14
- advanceSessionActivity,
15
- backfillSessionActivity,
16
14
  invalidateAutoEmbedSession,
17
- deleteChunkEmbedBackoffForSession,
18
15
  acquireCompartmentLease,
19
16
  releaseCompartmentLeaseBestEffort,
20
17
  isCompartmentLeaseHeld,
@@ -60,6 +57,7 @@ import {
60
57
  HiddenChildHook,
61
58
  parseProviderModel,
62
59
  toModelEntry,
60
+ CTX_NOTE_LIGHT_DESCRIPTION,
63
61
  ACTIVE_TOOL_IDS,
64
62
  createPromptSurfaceRuntime,
65
63
  runTokenLog,
@@ -69,17 +67,19 @@ import {
69
67
  resetPrefixTrimFallbackState,
70
68
  resolveOpenCodeProtectedTailBoundary,
71
69
  getActiveCompartmentRun
72
- } from "./index-sjthx78w.js";
70
+ } from "./index-692jzy0p.js";
73
71
  import"./index-sd3egckz.js";
74
72
  import {
75
- getHarness,
73
+ getHarness2
74
+ } from "./index-pavzsdc6.js";
75
+ import {
76
76
  getDataDir,
77
77
  getMagicContextStorageDir
78
- } from "./index-q6hef7fh.js";
78
+ } from "./index-0sahzkwr.js";
79
79
  import {
80
- log,
81
- sessionLog
82
- } from "./index-hybnrwq0.js";
80
+ log2,
81
+ sessionLog2
82
+ } from "./index-8j7gqj40.js";
83
83
  import {
84
84
  isSaneLimit,
85
85
  setOutputReserveConfig,
@@ -89,9 +89,9 @@ import {
89
89
  deriveHistorianChunkTokens2,
90
90
  resolveKnownHistorianContextLimit2,
91
91
  resolveHistorianContextLimit2
92
- } from "./index-0d3g3461.js";
93
- import"./index-8x2v7gg9.js";
94
- import"./index-q4yp4b52.js";
92
+ } from "./index-pdecwzrd.js";
93
+ import"./index-bhvjj0ys.js";
94
+ import"./index-mfkzp7qj.js";
95
95
  import {
96
96
  CANONICAL_DREAM_TASKS,
97
97
  DREAM_TASK_CAPABILITIES,
@@ -99,66 +99,86 @@ import {
99
99
  isCanonicalDreamTask,
100
100
  buildDreamTaskRuntimeConfigs2,
101
101
  userMemoryCollectionEnabled2
102
- } from "./index-mc22ayvf.js";
102
+ } from "./index-ghc9f0n7.js";
103
103
  import {
104
104
  resolveHistorianModel2
105
- } from "./index-sfpzqvdz.js";
105
+ } from "./index-8cd2j99z.js";
106
106
  import {
107
107
  formatFailClosedBlockingMessage,
108
108
  formatFailClosedBlockingSummary,
109
109
  createFailClosedBlockingError,
110
110
  isFailClosedBlockingError,
111
- setHomeProjectPermission,
112
- resolveProjectIdentityForSession,
113
- scheduleAfterBootQuiet,
114
111
  startBootDeadline,
115
112
  BOOT_SQLITE_BUSY_TIMEOUT_MS,
116
113
  openCurrentDatabase,
117
114
  openDatabaseAsync,
118
115
  isDatabasePersisted,
119
116
  getDatabasePersistenceError
120
- } from "./index-r5hmbx3t.js";
117
+ } from "./index-q7h7csab.js";
118
+ import {
119
+ setHomeProjectPermission,
120
+ resolveProjectIdentityForSession,
121
+ scheduleAfterBootQuiet
122
+ } from "./index-knh4y330.js";
121
123
  import {
122
- isDroppedToolOutput,
123
- evaluateChannel2,
124
- reclaimableToolOutputCount,
125
- buildChannel2Reminder,
126
124
  markHostUnservedRow,
127
125
  DreamTokenBudgetExceeded,
128
126
  createDreamTokenBudget,
129
127
  recordToolParameters,
130
128
  createDroppedInputGuard,
131
129
  assertExecutableToolInput,
130
+ estimateFinalWireInputTokens,
132
131
  detectOverflow,
132
+ modelAcceptsEmptyContent,
133
133
  hasRawMessageProvider2,
134
134
  setBoundedRawMessageProvider2,
135
135
  cleanUserText2,
136
136
  readRawSessionMessageIdOrdinalsForRange2,
137
137
  readRawSessionMessageOrdinalById2
138
- } from "./index-3h0ybwah.js";
138
+ } from "./index-bdckkfw6.js";
139
139
  import {
140
140
  hasMeaningfulUserText2,
141
141
  preloadTokenizer,
142
142
  estimateTokens
143
- } from "./index-5eqk6z3s.js";
143
+ } from "./index-1qb0z7wa.js";
144
+ import"./index-72nhv486.js";
145
+ import {
146
+ withSqliteTransformPass2,
147
+ withoutSqliteTransformPass2,
148
+ isTransientSqliteError2,
149
+ withAsyncPrivilegedWriter2
150
+ } from "./index-kb9nn0a0.js";
151
+ import"./index-fbv1dn35.js";
152
+ import {
153
+ deleteChunkEmbedBackoffForSession
154
+ } from "./index-pg50n748.js";
144
155
  import {
145
- withSqliteTransformPass,
146
- withoutSqliteTransformPass,
147
- isTransientSqliteError,
148
- withAsyncPrivilegedWriter
149
- } from "./index-fg34g6a5.js";
156
+ advanceSessionActivity,
157
+ backfillSessionActivity
158
+ } from "./index-14cjxt20.js";
159
+ import"./index-db7zwa3v.js";
160
+ import"./index-1zx87sdm.js";
161
+ import {
162
+ isDroppedToolOutput,
163
+ evaluateChannel2,
164
+ reclaimableToolOutputCount,
165
+ buildChannel2Reminder
166
+ } from "./index-k9nnwad5.js";
167
+ import"./index-dhwzyd54.js";
168
+ import"./index-58e3y90n.js";
169
+ import"./index-ty64eqcn.js";
150
170
  import {
151
171
  getCurrentToolSetHash,
152
172
  recordToolDefinition
153
- } from "./index-5gq3b2ya.js";
154
- import"./index-1zx87sdm.js";
155
- import"./index-b35pxds2.js";
156
- import"./index-majxda46.js";
173
+ } from "./index-0qhce371.js";
174
+ import"./index-fr0wbhdn.js";
175
+ import"./index-7mx8v0pw.js";
176
+ import"./index-fb3zxn06.js";
177
+ import"./index-c43kr12f.js";
178
+ import"./index-cb7emxgj.js";
157
179
  import {
158
- createSubcCheckoutClaimGate,
159
180
  runSessionProjectBackfill,
160
181
  createLiveSessionState,
161
- getDefaultSubcConnectionFile,
162
182
  RETROSPECTIVE_MAX_USER_MESSAGE_CHARS,
163
183
  RETROSPECTIVE_MESSAGE_TRUNCATION_MARKER,
164
184
  createDreamTaskExecutor,
@@ -176,6 +196,9 @@ import {
176
196
  createToolExecuteAfterHook,
177
197
  recordHiddenVariantWarning,
178
198
  registerRpcHandlers,
199
+ armLatestThinkingRecoveryFromError,
200
+ lkgReplayLimit,
201
+ measureLkgReplay,
179
202
  STORAGE_BUSY_MESSAGE,
180
203
  StorageBusyRefusalError,
181
204
  UnmanagedOverWindowError,
@@ -185,42 +208,50 @@ import {
185
208
  createModuleToolBackends,
186
209
  createRustRefusalRecovery,
187
210
  createSystemPromptHashHandler,
211
+ tryMessagesTransformLkgReplay,
188
212
  createMessagesTransformHandler,
189
213
  subagentToolRefusal,
190
214
  hideSubagentTools,
191
215
  createCtxExpandTools,
192
216
  createCtxMemoryTools,
193
217
  createCtxMemoryListTools,
218
+ CTX_NOTE_DESCRIPTION,
219
+ withoutSmartNoteText,
194
220
  createCtxNoteTools,
195
221
  createCtxReduceTools,
196
222
  createCtxSearchTools,
197
223
  applyJsonSchemaParameterDescriptions,
198
224
  MagicContextRpcServer
199
- } from "./index-hpecdzec.js";
225
+ } from "./index-0an7742d.js";
200
226
  import {
201
227
  createTagger,
202
228
  setCtxReduceRegisteredGlobally,
203
229
  resolveCtxReduceAvailabilityFromMessages,
204
- DegradedPassRefusalError,
205
230
  EmergencyFailClosedError,
231
+ DegradedPassRefusalError,
206
232
  isSyntheticHeadMessage2
207
- } from "./index-pkbcrdqs.js";
208
- import"./index-7qw742ev.js";
233
+ } from "./index-f0h6xwqm.js";
234
+ import"./index-qt1qqasc.js";
235
+ import"./index-4dhv7mqz.js";
236
+ import"./index-5zygecde.js";
237
+ import"./index-7jzrrxap.js";
209
238
  import {
210
239
  pushNotification2,
211
240
  isTuiConnected2
212
241
  } from "./index-x8a7jmkh.js";
213
- import"./index-fzbvakh0.js";
214
- import"./index-sgthv3f7.js";
215
- import"./index-k5bdx1bx.js";
242
+ import"./index-jcbd3znx.js";
243
+ import"./index-yq8n9qcb.js";
244
+ import"./index-mmyh6d8f.js";
245
+ import"./index-0w56v4fm.js";
216
246
  import {
217
247
  detectConflicts
218
- } from "./index-8da2zjhz.js";
248
+ } from "./index-eeezr5zz.js";
249
+ import"./index-q2tqeqde.js";
219
250
  import"./index-fmsr7v69.js";
220
251
  import {
221
252
  getErrorMessage
222
253
  } from "./index-y8v6yerm.js";
223
- import"./index-sj29b3z2.js";
254
+ import"./index-2y0s2hep.js";
224
255
 
225
256
  // src/hooks/magic-context/history-boundary-repair.ts
226
257
  function readBaseline(db, sessionId) {
@@ -296,7 +327,7 @@ function repairMissingHistoryBoundary(args) {
296
327
  if (anchor === "unknown")
297
328
  return { kind: "unknown" };
298
329
  if (anchor === null) {
299
- sessionLog(sessionId, `history boundary unresolved: ${problem} and no older compartment end is in the host store; nothing to re-anchor on`);
330
+ sessionLog2(sessionId, `history boundary unresolved: ${problem} and no older compartment end is in the host store; nothing to re-anchor on`);
300
331
  return { kind: "unresolved", reason: "no-anchor", missingEndMessageId: missing };
301
332
  }
302
333
  if (getActiveCompartmentRun(sessionId) !== undefined) {
@@ -318,7 +349,7 @@ function repairMissingHistoryBoundary(args) {
318
349
  invalidateAutoEmbedSession(sessionId);
319
350
  forgetCachedPrefix(sessionId);
320
351
  const range = dropped.length === 0 ? "none" : `${dropped[0]}-${dropped[dropped.length - 1]} (${dropped.length})`;
321
- sessionLog(sessionId, `history boundary repair: ${problem}; re-anchored on compartment ${anchor.sequence} ending at ${anchor.endMessageId} (ordinal ${anchor.endMessage}); removed compartments ${range} for the historian to rebuild; the cached prefix is rebuilt on this pass`);
352
+ sessionLog2(sessionId, `history boundary repair: ${problem}; re-anchored on compartment ${anchor.sequence} ending at ${anchor.endMessageId} (ordinal ${anchor.endMessage}); removed compartments ${range} for the historian to rebuild; the cached prefix is rebuilt on this pass`);
322
353
  return {
323
354
  kind: "repaired",
324
355
  missingEndMessageId: missing,
@@ -334,7 +365,7 @@ function repairMissingHistoryBoundary(args) {
334
365
  return { kind: "intact" };
335
366
  clearCachedM0M1(db, sessionId);
336
367
  forgetCachedPrefix(sessionId);
337
- sessionLog(sessionId, `history boundary repair: the cached prefix boundary ${baseline.boundary} is not in the host store; rebuilding it on this pass against compartment end ${latestEnd}`);
368
+ sessionLog2(sessionId, `history boundary repair: the cached prefix boundary ${baseline.boundary} is not in the host store; rebuilding it on this pass against compartment end ${latestEnd}`);
338
369
  return {
339
370
  kind: "baseline-reset",
340
371
  anchorEndMessageId: latestEnd,
@@ -407,7 +438,7 @@ function createV2RustCompactionMarkerStrategy(findBoundaryUserMessage) {
407
438
  targetEndMessageId: pending.endMessageId
408
439
  };
409
440
  setPersistedCompactionMarkerState(db, sessionId, state);
410
- sessionLog(sessionId, `v2 boundary recorded at ordinal ${pending.ordinal}, boundary message ${boundary.id}`);
441
+ sessionLog2(sessionId, `v2 boundary recorded at ordinal ${pending.ordinal}, boundary message ${boundary.id}`);
411
442
  return { kind: "applied", markerOrdinal: pending.ordinal };
412
443
  }
413
444
  };
@@ -539,7 +570,8 @@ function hostUsesMediaAssets() {
539
570
  schemaUsesAssets.set(messageClass, uses);
540
571
  return uses;
541
572
  }
542
- function decodeThroughHostSchema(source) {
573
+ function decodeThroughHostSchema(encoded) {
574
+ const source = encoded.source;
543
575
  const messageClass = rememberedMessageClass;
544
576
  if (!messageClass)
545
577
  return "no host message class seen";
@@ -559,7 +591,7 @@ function decodeThroughHostSchema(source) {
559
591
  const run = decode?.run;
560
592
  if (typeof run !== "function")
561
593
  return "host media schema has no decode transformation";
562
- const result = run.call(decode, { _tag: "Some", value: { source } }, {});
594
+ const result = run.call(decode, { _tag: "Some", value: encoded }, {});
563
595
  const option = result?._tag === "Success" ? result.value : undefined;
564
596
  const asset = option?._tag === "Some" ? option.value : undefined;
565
597
  if (!isClassInstance(asset) || asset.source !== source)
@@ -567,18 +599,30 @@ function decodeThroughHostSchema(source) {
567
599
  return asset;
568
600
  }
569
601
  function hostMediaAsset(data, mediaType) {
570
- const source = { type: "base64", data, mediaType };
602
+ return hostMediaFromEncoded({ source: { type: "base64", data, mediaType } });
603
+ }
604
+ function hostMediaFromEncoded(value) {
605
+ if (!isRecord(value.source))
606
+ return "missing Media.Asset source";
607
+ const encoded = structuredClone(value);
608
+ if (encoded.source.type === "bytes") {
609
+ if (typeof encoded.source.data !== "string")
610
+ return "bytes media has no JSON codec payload";
611
+ encoded.source.data = new Uint8Array(Buffer.from(encoded.source.data, "base64"));
612
+ }
613
+ if (!["bytes", "base64", "url", "ref"].includes(String(encoded.source.type)))
614
+ return "unknown Media.Asset source";
571
615
  let first = "no Media.Asset seen in this process";
572
616
  if (rememberedAssetClass) {
573
617
  try {
574
- return new rememberedAssetClass({ source });
618
+ return new rememberedAssetClass(encoded);
575
619
  } catch (error) {
576
620
  first = `remembered asset class threw: ${String(error)}`;
577
621
  }
578
622
  }
579
623
  let second;
580
624
  try {
581
- const decoded = decodeThroughHostSchema(source);
625
+ const decoded = decodeThroughHostSchema(encoded);
582
626
  if (typeof decoded !== "string")
583
627
  return decoded;
584
628
  second = decoded;
@@ -588,6 +632,9 @@ function hostMediaAsset(data, mediaType) {
588
632
  return `${first}; ${second}`;
589
633
  }
590
634
 
635
+ // src/v2/fold/memory-cache.ts
636
+ import { randomUUID } from "node:crypto";
637
+
591
638
  // src/v2/fold/owner.ts
592
639
  import { createHash } from "node:crypto";
593
640
  var foldDigest = (value) => createHash("sha256").update(value).digest("hex");
@@ -670,122 +717,777 @@ class FoldOwner {
670
717
  }
671
718
  }
672
719
 
673
- // src/v2/fold/restore.ts
674
- import { fileURLToPath } from "node:url";
720
+ // src/v2/fold/memory-cache.ts
721
+ var DEFAULT_NATIVE_FOLD_BUDGET = Object.freeze({
722
+ maxSessionBytes: 16 * 1024 * 1024,
723
+ maxSessions: 16
724
+ });
725
+ var stringBytes = (value) => (value?.length ?? 0) * 2;
675
726
 
676
- // src/v2/hooks/storage-notice.ts
677
- var STORAGE_NOTICE_PREFIX = "[Magic Context storage notice] ";
678
- function formatStorageRefusalNotice(reason) {
679
- return `${STORAGE_NOTICE_PREFIX}This turn was not sent to the model. ${formatFailClosedBlockingSummary(reason)}`;
727
+ class NativeFoldCache {
728
+ resolveDB;
729
+ sourceID = randomUUID();
730
+ tails = new Map;
731
+ nativeRows = new Map;
732
+ admissions = new Map;
733
+ retention = new Map;
734
+ evictionListeners = new Set;
735
+ budget;
736
+ constructor(resolveDB, budget = DEFAULT_NATIVE_FOLD_BUDGET) {
737
+ this.resolveDB = resolveDB;
738
+ if (!Number.isSafeInteger(budget.maxSessionBytes) || budget.maxSessionBytes < 1 || !Number.isSafeInteger(budget.maxSessions) || budget.maxSessions < 1)
739
+ throw new Error("Native fold cache budgets must be positive integers");
740
+ this.budget = { ...budget };
741
+ }
742
+ onEvict(listener) {
743
+ this.evictionListeners.add(listener);
744
+ }
745
+ touch(sessionID) {
746
+ const state = this.retention.get(sessionID) ?? { active: 0, bytes: 0, replayBytes: 0 };
747
+ this.retention.delete(sessionID);
748
+ this.retention.set(sessionID, state);
749
+ return state;
750
+ }
751
+ hold(sessionID) {
752
+ const state = this.touch(sessionID);
753
+ state.active++;
754
+ return () => {
755
+ state.active--;
756
+ this.enforceBudget();
757
+ };
758
+ }
759
+ accountReplay(sessionID, bytes) {
760
+ this.touch(sessionID).replayBytes = bytes;
761
+ this.recount(sessionID);
762
+ }
763
+ usage() {
764
+ return {
765
+ sessions: this.retention.size,
766
+ bytes: [...this.retention.values()].reduce((total, state) => total + state.bytes, 0)
767
+ };
768
+ }
769
+ recount(sessionID) {
770
+ const state = this.touch(sessionID);
771
+ let bytes = 256 + stringBytes(sessionID) + state.replayBytes;
772
+ const tail = this.tails.get(sessionID);
773
+ if (tail)
774
+ bytes += 128 + stringBytes(tail.data) + stringBytes(tail.digest);
775
+ for (const row of this.nativeRows.get(sessionID)?.values() ?? [])
776
+ bytes += 256 + stringBytes(row.id) + stringBytes(row.type) + stringBytes(row.data) + stringBytes(row.digest);
777
+ for (const row of this.admissions.get(sessionID)?.values() ?? [])
778
+ bytes += 256 + stringBytes(row.admission_id) + stringBytes(row.status) + stringBytes(row.owner_token) + stringBytes(row.data) + stringBytes(row.payload) + stringBytes(row.digest);
779
+ state.bytes = bytes;
780
+ this.enforceBudget();
781
+ }
782
+ enforceBudget() {
783
+ for (const [id, state] of this.retention)
784
+ if (!state.active && state.bytes > this.budget.maxSessionBytes)
785
+ this.evict(id);
786
+ for (const [id, state] of this.retention) {
787
+ if (this.retention.size <= this.budget.maxSessions)
788
+ break;
789
+ if (!state.active)
790
+ this.evict(id);
791
+ }
792
+ }
793
+ evict(sessionID) {
794
+ this.tails.delete(sessionID);
795
+ this.nativeRows.delete(sessionID);
796
+ this.admissions.delete(sessionID);
797
+ this.retention.delete(sessionID);
798
+ for (const listener of this.evictionListeners)
799
+ listener(sessionID);
800
+ }
801
+ get db() {
802
+ return this.resolveDB();
803
+ }
804
+ tail(sessionID) {
805
+ const record = this.tails.get(sessionID);
806
+ if (record)
807
+ this.touch(sessionID);
808
+ return record && { ...record };
809
+ }
810
+ async saveTail(sessionID, data, rows) {
811
+ this.tails.set(sessionID, {
812
+ revision: (this.tails.get(sessionID)?.revision ?? -1) + 1,
813
+ data,
814
+ digest: foldDigest(data)
815
+ });
816
+ const kept = this.nativeRows.get(sessionID) ?? new Map;
817
+ for (const row of rows)
818
+ kept.set(row.id, Object.freeze({ ...row, revision: (kept.get(row.id)?.revision ?? -1) + 1 }));
819
+ this.nativeRows.set(sessionID, kept);
820
+ this.recount(sessionID);
821
+ }
822
+ replaceRows(sessionID, through, rows, after = -1) {
823
+ const kept = this.nativeRows.get(sessionID) ?? new Map;
824
+ for (const [id, row] of kept)
825
+ if (row.seq > after && row.seq <= through)
826
+ kept.delete(id);
827
+ for (const row of rows)
828
+ kept.set(row.id, Object.freeze({ ...row, revision: 0 }));
829
+ this.nativeRows.set(sessionID, kept);
830
+ this.recount(sessionID);
831
+ }
832
+ truncate(sessionID, through) {
833
+ const kept = this.nativeRows.get(sessionID);
834
+ if (kept) {
835
+ for (const [id, row] of kept)
836
+ if (row.seq > through)
837
+ kept.delete(id);
838
+ }
839
+ if (kept)
840
+ this.recount(sessionID);
841
+ }
842
+ sequenceForID(sessionID, id) {
843
+ return this.nativeRows.get(sessionID)?.get(id)?.seq;
844
+ }
845
+ containsRows(sessionID, ids) {
846
+ const kept = this.nativeRows.get(sessionID);
847
+ return ids.every((id) => kept?.has(id));
848
+ }
849
+ rows(sessionID, after, through) {
850
+ if (this.retention.has(sessionID))
851
+ this.touch(sessionID);
852
+ return [...this.nativeRows.get(sessionID)?.values() ?? []].filter((row) => row.seq > after && row.seq <= through).sort((a, b) => a.seq - b.seq).map((row) => ({ ...row }));
853
+ }
854
+ admission(sessionID, id) {
855
+ const record = this.admissions.get(sessionID)?.get(id);
856
+ if (record)
857
+ this.touch(sessionID);
858
+ return record && { ...record };
859
+ }
860
+ put(sessionID, id, record) {
861
+ const kept = this.admissions.get(sessionID) ?? new Map;
862
+ kept.set(id, Object.freeze({ ...record }));
863
+ this.admissions.set(sessionID, kept);
864
+ this.recount(sessionID);
865
+ }
866
+ async supply(sessionID, id, payload) {
867
+ const old = this.admission(sessionID, id);
868
+ this.put(sessionID, id, {
869
+ admission_id: id,
870
+ revision: (old?.revision ?? -1) + 1,
871
+ status: old?.status ?? "supplied",
872
+ owner_token: old?.owner_token ?? null,
873
+ data: old?.data ?? "{}",
874
+ payload,
875
+ digest: foldDigest(payload),
876
+ logged_at: old?.logged_at ?? null
877
+ });
878
+ }
879
+ latestAttempt(sessionID) {
880
+ const record = [...this.admissions.get(sessionID)?.values() ?? []].reverse().find((row) => JSON.parse(row.data).after !== undefined);
881
+ return record && { ...record };
882
+ }
883
+ async claim(sessionID, id, data, owner, _now) {
884
+ const old = this.admission(sessionID, id);
885
+ if (old?.owner_token || old?.logged_at !== null && old?.logged_at !== undefined)
886
+ return false;
887
+ this.put(sessionID, id, {
888
+ admission_id: id,
889
+ revision: 0,
890
+ status: "pending",
891
+ owner_token: owner,
892
+ data,
893
+ payload: old?.payload ?? null,
894
+ digest: old?.digest ?? null,
895
+ logged_at: null
896
+ });
897
+ return true;
898
+ }
899
+ async finish(sessionID, id, owner, status, now) {
900
+ const old = this.admission(sessionID, id);
901
+ if (!old || old.owner_token !== owner || old.status !== "pending")
902
+ return false;
903
+ this.put(sessionID, id, { ...old, status, owner_token: null, logged_at: now });
904
+ return true;
905
+ }
906
+ async forget(sessionID) {
907
+ this.evict(sessionID);
908
+ }
680
909
  }
681
- function formatStorageRecoveryNotice(hiddenWorkRecovered) {
682
- return hiddenWorkRecovered ? `${STORAGE_NOTICE_PREFIX}Magic Context storage is available again and turns are sent to the model. The historian and dreamer are running again. Restart OpenCode to enable Magic Context's tools.` : `${STORAGE_NOTICE_PREFIX}Magic Context storage is available again and turns are sent to the model. Restart OpenCode to enable Magic Context's tools, historian and dreamer.`;
910
+ function nativeFoldCache(db, budget) {
911
+ return new NativeFoldCache(typeof db === "function" ? db : () => db, budget);
683
912
  }
684
- function isStorageNoticeText(text) {
685
- return typeof text === "string" && text.startsWith(STORAGE_NOTICE_PREFIX);
913
+
914
+ // src/v2/tool-result.ts
915
+ function isToolError(part) {
916
+ const result = part.result;
917
+ return part.resultType === "error" || result?.type === "error" || result !== null && typeof result === "object" && "error" in result;
686
918
  }
687
- function hasStorageNoticeShape(message) {
688
- if (message.role !== "user" || typeof message.id !== "string")
689
- return false;
690
- if (message.content.length !== 1)
691
- return false;
692
- const part = message.content[0];
693
- return part?.type === "text" && isStorageNoticeText(part.text);
919
+ function toolErrorText(result) {
920
+ const value = result.value === undefined ? result : result.value;
921
+ return typeof value === "string" ? value : JSON.stringify(value);
694
922
  }
695
- async function dropStorageNotices(messages, isAdmittedSynthetic) {
696
- const drop = new Set;
697
- for (const message of messages) {
698
- if (!hasStorageNoticeShape(message))
923
+ function toolStateContent(state) {
924
+ if (typeof state.output === "string")
925
+ return state.output;
926
+ if (state.status === "error")
927
+ return toolErrorText({ error: state.error, content: state.content ?? [] });
928
+ if (typeof state.content === "string")
929
+ return state.content;
930
+ if (!Array.isArray(state.content))
931
+ return "";
932
+ return state.content.map((part) => {
933
+ if (typeof part === "string")
934
+ return part;
935
+ if (!part || typeof part !== "object")
936
+ return "";
937
+ const value = part;
938
+ if (typeof value.text === "string")
939
+ return value.text;
940
+ if (typeof value.value === "string")
941
+ return value.value;
942
+ return "";
943
+ }).filter(Boolean).join(`
944
+ `);
945
+ }
946
+
947
+ // src/v2/hooks/payload.ts
948
+ var HEAD_IDS = ["__magic_context_v2_m0__", "__magic_context_v2_m1__"];
949
+ var HOST_CONTENT_TYPES = new Set([
950
+ "text",
951
+ "media",
952
+ "tool-call",
953
+ "tool-result",
954
+ "reasoning",
955
+ "compaction",
956
+ "effort"
957
+ ]);
958
+ function rejectContentPart(message, part, reason) {
959
+ const type = typeof part.type === "string" ? part.type : "<missing>";
960
+ const text = `v2 context omitted a content part the host would reject: type=${type} message=${String(message.info.id ?? "<head>")} reason=${reason}`;
961
+ if (typeof message.info.sessionID === "string")
962
+ sessionLog2(message.info.sessionID, text);
963
+ else
964
+ log2(text);
965
+ }
966
+ var emptyTextOmissionLogged = new Set;
967
+ function placeCacheHint(content, hint) {
968
+ if (content.length === 0 || content.some((part) => part.cache !== undefined))
969
+ return;
970
+ let lastText = content.length - 1;
971
+ while (lastText >= 0 && content[lastText]?.type !== "text")
972
+ lastText -= 1;
973
+ const index = lastText >= 0 ? lastText : content.length - 1;
974
+ content[index] = { ...content[index], cache: hint };
975
+ }
976
+ function removeEmptyTextParts(content, rendered) {
977
+ let hint;
978
+ let removed = 0;
979
+ for (let index = content.length - 1;index >= 0; index -= 1) {
980
+ const part = content[index];
981
+ if (part?.type !== "text" || part.text !== "")
699
982
  continue;
700
- if (await isAdmittedSynthetic(message.id))
701
- drop.add(message);
983
+ if (hint === undefined)
984
+ hint = part.cache;
985
+ content.splice(index, 1);
986
+ removed += 1;
702
987
  }
703
- if (drop.size === 0)
704
- return 0;
705
- const kept = messages.filter((message) => !drop.has(message));
706
- messages.splice(0, messages.length, ...kept);
707
- return drop.size;
988
+ if (hint !== undefined) {
989
+ const target = content.length > 0 ? content : rendered.at(-1)?.content;
990
+ if (target)
991
+ placeCacheHint(target, hint);
992
+ }
993
+ return removed;
708
994
  }
709
-
710
- // src/v2/fold/restore.ts
711
- function unavailableAttachmentNote(name, mediaType) {
712
- return `[Attachment ${name ? `"${name}" ` : ""}(${mediaType}) is not available in this restored history]`;
995
+ function isHostInstance(value) {
996
+ if (!value || typeof value !== "object" || Array.isArray(value))
997
+ return false;
998
+ const prototype = Object.getPrototypeOf(value);
999
+ return prototype !== Object.prototype && prototype !== null;
713
1000
  }
714
- var imageMimes = new Set(["image/png", "image/jpeg", "image/gif", "image/webp"]);
715
- function attachmentParts(files, rowID, media) {
716
- const seen = new Map;
717
- return files.flatMap((file) => {
718
- if (imageMimes.has(file.mime) && file.source.type === "inline" && file.mention?.text) {
719
- const key = JSON.stringify([
720
- file.mime,
721
- file.name ?? null,
722
- file.description ?? null,
723
- file.mention.text
724
- ]);
725
- const payloads = seen.get(key) ?? new Set;
726
- if (payloads.has(file.data))
727
- return [];
728
- payloads.add(file.data);
729
- seen.set(key, payloads);
730
- }
731
- const uri = file.source.type === "uri" ? file.source.uri : undefined;
732
- const location = uri?.startsWith("file:") ? fileURLToPath(uri) : undefined;
733
- if (file.mime === "text/plain" || file.mime === "application/x-directory") {
734
- const directory = file.mime === "application/x-directory";
735
- return [
736
- {
737
- type: "text",
738
- text: `
739
-
740
- ${[
741
- directory ? `Attached directory: ${location ?? file.name ?? uri ?? "directory"}` : `Attached file: ${file.name ?? uri ?? "inline attachment"}`,
742
- file.description === undefined ? undefined : `Description: ${file.description}`,
743
- directory && !file.data.length ? undefined : "",
744
- directory && !file.data.length ? undefined : Buffer.from(file.data, "base64").toString("utf8")
745
- ].filter((line) => line !== undefined).join(`
746
- `)}`,
747
- metadata: {
748
- attachment: {
749
- source: file.source,
750
- name: file.name,
751
- description: file.description
752
- }
753
- }
754
- }
755
- ];
1001
+ function containsHostInstance(value) {
1002
+ if (isHostInstance(value))
1003
+ return true;
1004
+ if (Array.isArray(value))
1005
+ return value.some(containsHostInstance);
1006
+ if (value && typeof value === "object")
1007
+ return Object.values(value).some(containsHostInstance);
1008
+ return false;
1009
+ }
1010
+ function clonePreservingInstances(value) {
1011
+ if (isHostInstance(value))
1012
+ return value;
1013
+ if (Array.isArray(value))
1014
+ return value.map(clonePreservingInstances);
1015
+ if (value && typeof value === "object") {
1016
+ const copy = {};
1017
+ for (const [key, entry] of Object.entries(value))
1018
+ copy[key] = clonePreservingInstances(entry);
1019
+ return copy;
1020
+ }
1021
+ return value;
1022
+ }
1023
+ function contentKey(value) {
1024
+ const plain = (entry) => {
1025
+ if (ArrayBuffer.isView(entry)) {
1026
+ return {
1027
+ bytes: Buffer.from(entry.buffer, entry.byteOffset, entry.byteLength).toString("base64")
1028
+ };
756
1029
  }
757
- if (!imageMimes.has(file.mime) && file.mime !== "application/pdf")
758
- return [];
759
- const metadata = file.description === undefined ? undefined : { description: file.description };
760
- const located = location ? [{ type: "text", text: `Attached file: ${location}` }] : [];
761
- if (!media)
762
- return [
763
- ...located,
764
- {
765
- type: "media",
766
- mediaType: file.mime,
767
- data: file.data,
768
- filename: file.name,
769
- metadata
770
- }
771
- ];
772
- const asset = media.asset(file.data, file.mime);
773
- if (typeof asset === "string") {
774
- media.unavailable({ rowID, name: file.name, mediaType: file.mime, reason: asset });
775
- return [
776
- ...located,
777
- { type: "text", text: unavailableAttachmentNote(file.name, file.mime) }
778
- ];
1030
+ if (Array.isArray(entry))
1031
+ return entry.map(plain);
1032
+ if (entry && typeof entry === "object") {
1033
+ return Object.fromEntries(Object.entries(entry).map(([key, nested]) => [key, plain(nested)]));
779
1034
  }
780
- return [...located, { type: "media", media: asset, filename: file.name, metadata }];
781
- });
1035
+ return entry;
1036
+ };
1037
+ return JSON.stringify(plain(value));
782
1038
  }
783
- function restoreRow(row, model, media) {
784
- const data = row.data;
785
- const make = (role, content, metadata = data.metadata) => ({
786
- id: row.id,
787
- role,
788
- content,
1039
+ function fileContentValue(result) {
1040
+ const value = result?.value;
1041
+ if (result?.type !== "content" || !Array.isArray(value))
1042
+ return;
1043
+ return value.some((item) => item?.type === "file") ? value : undefined;
1044
+ }
1045
+ function contentValueText(value) {
1046
+ return value.filter((item) => item?.type === "text" && typeof item.text === "string").map((item) => item.text).join(`
1047
+ `);
1048
+ }
1049
+ function contentValueAttachments(value) {
1050
+ return value.filter((item) => item?.type === "file").map((item) => ({
1051
+ type: "file",
1052
+ mime: item.mime,
1053
+ url: item.uri,
1054
+ ...typeof item.name === "string" ? { filename: item.name } : {}
1055
+ }));
1056
+ }
1057
+ function rebuildFileContent(value, output) {
1058
+ if (isDroppedToolOutput(output))
1059
+ return { type: "text", value: output };
1060
+ const rebuilt = [];
1061
+ let placed = false;
1062
+ for (const item of value) {
1063
+ if (item?.type !== "text") {
1064
+ rebuilt.push(item);
1065
+ continue;
1066
+ }
1067
+ if (placed)
1068
+ continue;
1069
+ placed = true;
1070
+ rebuilt.push({ ...item, text: output });
1071
+ }
1072
+ if (!placed && output)
1073
+ rebuilt.unshift({ type: "text", text: output });
1074
+ return { type: "content", value: rebuilt };
1075
+ }
1076
+ function adaptPayload(draft, admittedIDs = new Set) {
1077
+ const existingHeads = new Map(draft.messages.filter((m) => HEAD_IDS.some((id) => m.id === id)).map((m) => [m.id, m]));
1078
+ const source = draft.messages.filter((m) => !existingHeads.has(m.id));
1079
+ const results = new Map;
1080
+ const hostParts = new Map;
1081
+ const hostPartTypes = new Set;
1082
+ for (const message of source) {
1083
+ for (const part of message.content) {
1084
+ if (part.type !== "tool-call" && part.type !== "tool-result" && part.type !== "tool" && containsHostInstance(part)) {
1085
+ const key = contentKey(part);
1086
+ if (!hostParts.has(key))
1087
+ hostParts.set(key, part);
1088
+ hostPartTypes.add(part.type);
1089
+ }
1090
+ if (part.type === "tool-result" && typeof part.id === "string") {
1091
+ const queue = results.get(part.id) ?? [];
1092
+ queue.push({ part, message });
1093
+ results.set(part.id, queue);
1094
+ }
1095
+ }
1096
+ }
1097
+ const paired = new Set;
1098
+ const bridges = new Map;
1099
+ const originals = new Map;
1100
+ const bridgesByMessageID = new Map;
1101
+ const bridgesByCarrier = new Map;
1102
+ const originalsByID = new Map;
1103
+ const bridgesFor = (message) => typeof message.info.id === "string" ? bridgesByMessageID.get(message.info.id) : bridgesByCarrier.get(message);
1104
+ const nativeTool = (call, result) => {
1105
+ const hostResult = result?.part.result;
1106
+ const failed = result !== undefined && isToolError(result.part);
1107
+ const value = hostResult?.value;
1108
+ const files = fileContentValue(hostResult);
1109
+ const output = failed && hostResult ? toolErrorText(hostResult) : files ? contentValueText(files) : typeof value === "string" ? value : value === undefined ? "" : JSON.stringify(value);
1110
+ const part = {
1111
+ type: "tool",
1112
+ callID: call?.id ?? result?.part.id,
1113
+ tool: call?.name ?? result?.part.name,
1114
+ state: {
1115
+ input: structuredClone(call?.input ?? {}),
1116
+ status: failed ? "error" : result ? "completed" : "running",
1117
+ ...result ? { output } : {},
1118
+ ...result && (call?.name ?? result.part.name) === "question" ? { metadata: { userAnswer: true } } : {},
1119
+ ...files ? { attachments: contentValueAttachments(files) } : {}
1120
+ }
1121
+ };
1122
+ bridges.set(part, {
1123
+ call,
1124
+ result: result?.part,
1125
+ resultMessage: result?.message,
1126
+ output,
1127
+ files
1128
+ });
1129
+ if (result)
1130
+ paired.add(result.part);
1131
+ return part;
1132
+ };
1133
+ const convertedTool = (source) => {
1134
+ const sourceState = source.state && typeof source.state === "object" ? source.state : {};
1135
+ const output = toolStateContent(sourceState);
1136
+ const { content: _content, ...projectedState } = structuredClone(sourceState);
1137
+ const part = {
1138
+ type: "tool",
1139
+ callID: source.callID ?? source.id,
1140
+ tool: source.tool ?? source.name,
1141
+ state: { ...projectedState, output }
1142
+ };
1143
+ bridges.set(part, { native: source, output });
1144
+ return part;
1145
+ };
1146
+ const callParts = new Map;
1147
+ for (const message of source) {
1148
+ for (const part of message.content) {
1149
+ if (part.type === "tool-call") {
1150
+ callParts.set(part, nativeTool(part, results.get(String(part.id))?.shift()));
1151
+ } else if (part.type === "tool") {
1152
+ callParts.set(part, convertedTool(part));
1153
+ }
1154
+ }
1155
+ }
1156
+ const messages = [];
1157
+ for (const message of source) {
1158
+ const parts = [];
1159
+ for (const content of message.content) {
1160
+ if (paired.has(content))
1161
+ continue;
1162
+ const part = callParts.get(content) ?? (content.type === "tool-result" ? nativeTool(undefined, { part: content, message }) : clonePreservingInstances(content));
1163
+ if (message.id && admittedIDs.has(message.id))
1164
+ part.synthetic = true;
1165
+ parts.push(part);
1166
+ }
1167
+ if (!parts.length && message.content.length)
1168
+ continue;
1169
+ const byCallID = new Map;
1170
+ for (const part of parts) {
1171
+ const bridge = bridges.get(part);
1172
+ if (bridge && typeof part.callID === "string")
1173
+ byCallID.set(part.callID, bridge);
1174
+ }
1175
+ if (typeof message.id === "string") {
1176
+ bridgesByMessageID.set(message.id, byCallID);
1177
+ originalsByID.set(message.id, message);
1178
+ }
1179
+ const mapped = {
1180
+ info: {
1181
+ id: message.id,
1182
+ sessionID: draft.sessionID,
1183
+ role: message.role,
1184
+ ...{
1185
+ providerID: draft.model.providerID,
1186
+ modelID: draft.model.id,
1187
+ agent: draft.agent
1188
+ }
1189
+ },
1190
+ parts
1191
+ };
1192
+ originals.set(mapped, message);
1193
+ if (typeof message.id !== "string")
1194
+ bridgesByCarrier.set(mapped, byCallID);
1195
+ messages.push(mapped);
1196
+ }
1197
+ return {
1198
+ messages,
1199
+ commit() {
1200
+ let head = 0;
1201
+ const rendered = [];
1202
+ const emptyTextGuard = modelAcceptsEmptyContent(draft.model.providerID);
1203
+ let omitted = 0;
1204
+ let emptyTextParts = 0;
1205
+ for (const message of messages) {
1206
+ const original = originals.get(message) ?? (typeof message.info.id === "string" ? originalsByID.get(message.info.id) : undefined);
1207
+ const id = message.info.syntheticHead ? HEAD_IDS[head++] : original?.id;
1208
+ const content = [];
1209
+ const following = [];
1210
+ for (const candidate of message.parts) {
1211
+ const part = candidate;
1212
+ const bridge = bridges.get(part) ?? (part.type === "tool" && typeof part.callID === "string" ? bridgesFor(message)?.get(part.callID) : undefined);
1213
+ if (!bridge) {
1214
+ if (part.type === "tool") {
1215
+ const state = part.state;
1216
+ if (typeof part.callID !== "string" || typeof part.tool !== "string" || !state || typeof state !== "object") {
1217
+ rejectContentPart(message, part, "tool has no call ID, name, or state");
1218
+ continue;
1219
+ }
1220
+ content.push({
1221
+ type: "tool-call",
1222
+ id: part.callID,
1223
+ name: part.tool,
1224
+ input: state.input
1225
+ });
1226
+ if (state.status === "completed" || state.status === "error") {
1227
+ following.push({
1228
+ role: "tool",
1229
+ content: [
1230
+ {
1231
+ type: "tool-result",
1232
+ id: part.callID,
1233
+ name: part.tool,
1234
+ result: {
1235
+ type: state.status === "error" ? "error" : "text",
1236
+ value: toolStateContent(state)
1237
+ }
1238
+ }
1239
+ ]
1240
+ });
1241
+ }
1242
+ continue;
1243
+ }
1244
+ if (part.type === "file") {
1245
+ const mime = part.mime;
1246
+ const url = part.url;
1247
+ const prefix = `data:${mime};base64,`;
1248
+ if (typeof mime !== "string" || !/^image\/(png|jpeg|gif|webp)$/.test(mime) || typeof url !== "string" || !url.startsWith(prefix)) {
1249
+ rejectContentPart(message, part, "file is not an inline supported image");
1250
+ continue;
1251
+ }
1252
+ const asset = hostMediaAsset(url.slice(prefix.length), mime);
1253
+ if (typeof asset === "string") {
1254
+ rejectContentPart(message, part, `host media unavailable: ${asset}`);
1255
+ continue;
1256
+ }
1257
+ content.push({ type: "media", media: asset });
1258
+ continue;
1259
+ }
1260
+ if (!HOST_CONTENT_TYPES.has(String(part.type))) {
1261
+ rejectContentPart(message, part, "unknown host content type");
1262
+ continue;
1263
+ }
1264
+ const { synthetic: _synthetic, ...clean } = part;
1265
+ const original = hostPartTypes.has(clean.type) && !containsHostInstance(clean) ? hostParts.get(contentKey(clean)) : undefined;
1266
+ content.push(original ?? clean);
1267
+ continue;
1268
+ }
1269
+ const state = part.state;
1270
+ if (bridge.native) {
1271
+ const native = bridge.native;
1272
+ const callID = String(native.id ?? native.callID ?? part.callID);
1273
+ const name = String(native.name ?? native.tool ?? part.tool);
1274
+ content.push({ type: "tool-call", id: callID, name, input: state.input });
1275
+ if (state.status === "completed" || state.status === "error") {
1276
+ following.push({
1277
+ role: "tool",
1278
+ content: [
1279
+ {
1280
+ type: "tool-result",
1281
+ id: callID,
1282
+ name,
1283
+ result: {
1284
+ type: state.status === "error" ? "error" : "text",
1285
+ value: state.output
1286
+ }
1287
+ }
1288
+ ]
1289
+ });
1290
+ }
1291
+ continue;
1292
+ }
1293
+ if (bridge.call)
1294
+ content.push({ ...bridge.call, input: state.input });
1295
+ if (bridge.result && bridge.resultMessage) {
1296
+ const result = {
1297
+ ...bridge.result,
1298
+ result: state.output === bridge.output ? bridge.result.result : bridge.files && typeof state.output === "string" ? rebuildFileContent(bridge.files, state.output) : {
1299
+ type: state.status === "error" ? "error" : "text",
1300
+ value: state.output
1301
+ }
1302
+ };
1303
+ if (bridge.resultMessage === original)
1304
+ content.push(result);
1305
+ else
1306
+ following.push({ ...bridge.resultMessage, content: [result] });
1307
+ }
1308
+ }
1309
+ const guarded = emptyTextGuard ? removeEmptyTextParts(content, rendered) : 0;
1310
+ if (content.length || !original?.content.length && guarded === 0) {
1311
+ const value = {
1312
+ ...original,
1313
+ id,
1314
+ role: message.info.role ?? "user",
1315
+ content
1316
+ };
1317
+ const existing = id ? existingHeads.get(id) : undefined;
1318
+ rendered.push(existing ? Object.assign(existing, { content }) : value);
1319
+ } else if (emptyTextGuard) {
1320
+ omitted += 1;
1321
+ }
1322
+ emptyTextParts += guarded;
1323
+ rendered.push(...following);
1324
+ }
1325
+ if (omitted + emptyTextParts > 0 && !emptyTextOmissionLogged.has(draft.sessionID)) {
1326
+ emptyTextOmissionLogged.add(draft.sessionID);
1327
+ sessionLog2(draft.sessionID, `v2 payload: left out ${omitted} emptied messages and ${emptyTextParts} empty text parts, because Anthropic rejects an empty text block (logged once per session)`);
1328
+ }
1329
+ draft.messages.splice(0, draft.messages.length, ...rendered);
1330
+ }
1331
+ };
1332
+ }
1333
+
1334
+ // src/v2/fold/native-codec.ts
1335
+ class NativeReplayUnavailable extends Error {
1336
+ }
1337
+ function encodeNative(messages) {
1338
+ for (const message of messages)
1339
+ for (const part of message.content) {
1340
+ if (part.type !== "media" || !part.media)
1341
+ continue;
1342
+ const asset = part.media;
1343
+ if (typeof asset.toJSON !== "function" || asset.headers !== undefined)
1344
+ throw new NativeReplayUnavailable("Native media has no lossless replay codec");
1345
+ const encoded = asset.toJSON();
1346
+ const revived = hostMediaFromEncoded(encoded);
1347
+ if (typeof revived === "string" || JSON.stringify(revived) !== JSON.stringify(asset))
1348
+ throw new NativeReplayUnavailable("Native media cannot be decoded losslessly before admission");
1349
+ }
1350
+ const encoded = JSON.parse(JSON.stringify(messages));
1351
+ const freeze = (value) => {
1352
+ if (!value || typeof value !== "object")
1353
+ return;
1354
+ for (const item of Object.values(value))
1355
+ freeze(item);
1356
+ Object.freeze(value);
1357
+ };
1358
+ freeze(encoded);
1359
+ return encoded;
1360
+ }
1361
+ function reviveNative(messages) {
1362
+ const result = structuredClone([...messages]);
1363
+ for (const message of result)
1364
+ for (const part of message.content) {
1365
+ if (part.type !== "media" || !part.media)
1366
+ continue;
1367
+ const asset = hostMediaFromEncoded(part.media);
1368
+ if (typeof asset === "string")
1369
+ throw new NativeReplayUnavailable(asset);
1370
+ part.media = asset;
1371
+ }
1372
+ return result;
1373
+ }
1374
+
1375
+ // src/v2/fold/restore.ts
1376
+ import { fileURLToPath } from "node:url";
1377
+
1378
+ // src/v2/hooks/storage-notice.ts
1379
+ var STORAGE_NOTICE_PREFIX = "[Magic Context storage notice] ";
1380
+ function formatStorageRefusalNotice(reason) {
1381
+ return `${STORAGE_NOTICE_PREFIX}This turn was not sent to the model. ${formatFailClosedBlockingSummary(reason)}`;
1382
+ }
1383
+ function formatStorageRecoveryNotice(hiddenWorkRecovered) {
1384
+ return hiddenWorkRecovered ? `${STORAGE_NOTICE_PREFIX}Magic Context storage is available again and turns are sent to the model. The historian and dreamer are running again. Restart OpenCode to enable Magic Context's tools.` : `${STORAGE_NOTICE_PREFIX}Magic Context storage is available again and turns are sent to the model. Restart OpenCode to enable Magic Context's tools, historian and dreamer.`;
1385
+ }
1386
+ function isStorageNoticeText(text) {
1387
+ return typeof text === "string" && text.startsWith(STORAGE_NOTICE_PREFIX);
1388
+ }
1389
+ function hasStorageNoticeShape(message) {
1390
+ if (message.role !== "user" || typeof message.id !== "string")
1391
+ return false;
1392
+ if (message.content.length !== 1)
1393
+ return false;
1394
+ const part = message.content[0];
1395
+ return part?.type === "text" && isStorageNoticeText(part.text);
1396
+ }
1397
+ async function dropStorageNotices(messages, isAdmittedSynthetic) {
1398
+ const drop = new Set;
1399
+ for (const message of messages) {
1400
+ if (!hasStorageNoticeShape(message))
1401
+ continue;
1402
+ if (await isAdmittedSynthetic(message.id))
1403
+ drop.add(message);
1404
+ }
1405
+ if (drop.size === 0)
1406
+ return 0;
1407
+ const kept = messages.filter((message) => !drop.has(message));
1408
+ messages.splice(0, messages.length, ...kept);
1409
+ return drop.size;
1410
+ }
1411
+
1412
+ // src/v2/fold/restore.ts
1413
+ function unavailableAttachmentNote(name, mediaType) {
1414
+ return `[Attachment ${name ? `"${name}" ` : ""}(${mediaType}) is not available in this restored history]`;
1415
+ }
1416
+ var imageMimes = new Set(["image/png", "image/jpeg", "image/gif", "image/webp"]);
1417
+ function attachmentParts(files, rowID, media) {
1418
+ const seen = new Map;
1419
+ return files.flatMap((file) => {
1420
+ if (imageMimes.has(file.mime) && file.source.type === "inline" && file.mention?.text) {
1421
+ const key = JSON.stringify([
1422
+ file.mime,
1423
+ file.name ?? null,
1424
+ file.description ?? null,
1425
+ file.mention.text
1426
+ ]);
1427
+ const payloads = seen.get(key) ?? new Set;
1428
+ if (payloads.has(file.data))
1429
+ return [];
1430
+ payloads.add(file.data);
1431
+ seen.set(key, payloads);
1432
+ }
1433
+ const uri = file.source.type === "uri" ? file.source.uri : undefined;
1434
+ const location = uri?.startsWith("file:") ? fileURLToPath(uri) : undefined;
1435
+ if (file.mime === "text/plain" || file.mime === "application/x-directory") {
1436
+ const directory = file.mime === "application/x-directory";
1437
+ return [
1438
+ {
1439
+ type: "text",
1440
+ text: `
1441
+
1442
+ ${[
1443
+ directory ? `Attached directory: ${location ?? file.name ?? uri ?? "directory"}` : `Attached file: ${file.name ?? uri ?? "inline attachment"}`,
1444
+ file.description === undefined ? undefined : `Description: ${file.description}`,
1445
+ directory && !file.data.length ? undefined : "",
1446
+ directory && !file.data.length ? undefined : Buffer.from(file.data, "base64").toString("utf8")
1447
+ ].filter((line) => line !== undefined).join(`
1448
+ `)}`,
1449
+ metadata: {
1450
+ attachment: {
1451
+ source: file.source,
1452
+ name: file.name,
1453
+ description: file.description
1454
+ }
1455
+ }
1456
+ }
1457
+ ];
1458
+ }
1459
+ if (!imageMimes.has(file.mime) && file.mime !== "application/pdf")
1460
+ return [];
1461
+ const metadata = file.description === undefined ? undefined : { description: file.description };
1462
+ const located = location ? [{ type: "text", text: `Attached file: ${location}` }] : [];
1463
+ if (!media)
1464
+ return [
1465
+ ...located,
1466
+ {
1467
+ type: "media",
1468
+ mediaType: file.mime,
1469
+ data: file.data,
1470
+ filename: file.name,
1471
+ metadata
1472
+ }
1473
+ ];
1474
+ const asset = media.asset(file.data, file.mime);
1475
+ if (typeof asset === "string") {
1476
+ media.unavailable({ rowID, name: file.name, mediaType: file.mime, reason: asset });
1477
+ return [
1478
+ ...located,
1479
+ { type: "text", text: unavailableAttachmentNote(file.name, file.mime) }
1480
+ ];
1481
+ }
1482
+ return [...located, { type: "media", media: asset, filename: file.name, metadata }];
1483
+ });
1484
+ }
1485
+ function restoreRow(row, model, media) {
1486
+ const data = row.data;
1487
+ const make = (role, content, metadata = data.metadata) => ({
1488
+ id: row.id,
1489
+ role,
1490
+ content,
789
1491
  ...metadata === undefined ? {} : { metadata }
790
1492
  });
791
1493
  if (row.type === "user") {
@@ -866,36 +1568,425 @@ ${data.output?.output ?? ""}`
866
1568
  let input = state.input;
867
1569
  if (state.status === "streaming" && typeof input === "string") {
868
1570
  try {
869
- input = JSON.parse(input);
870
- } catch {}
1571
+ input = JSON.parse(input);
1572
+ } catch {}
1573
+ }
1574
+ content.push({
1575
+ type: "tool-call",
1576
+ id: part.id,
1577
+ name: part.name,
1578
+ input,
1579
+ providerExecuted: part.executed,
1580
+ providerMetadata: toolReuse ? metadata(part.providerState) : undefined
1581
+ });
1582
+ if (!completed)
1583
+ continue;
1584
+ const toolContent = state.content ?? [];
1585
+ const single = toolContent.length === 1 ? toolContent[0] : undefined;
1586
+ const result = {
1587
+ type: "tool-result",
1588
+ id: part.id,
1589
+ name: part.name,
1590
+ providerExecuted: part.executed,
1591
+ providerMetadata: toolReuse ? metadata(part.providerResultState ?? part.providerState) : sameProvider ? metadata(part.providerResultState) : undefined,
1592
+ result: state.status === "error" ? { error: state.error, content: toolContent } : single?.type === "text" ? { type: "text", value: single.text } : { type: "content", value: toolContent },
1593
+ ...state.status === "error" ? { resultType: "error" } : {}
1594
+ };
1595
+ if (part.executed === true)
1596
+ content.push(result);
1597
+ else
1598
+ results.push({ role: "tool", content: [result] });
1599
+ }
1600
+ return [...content.length ? [make("assistant", content)] : [], ...results];
1601
+ }
1602
+
1603
+ // src/v2/fold/native-replay.ts
1604
+ var coordinates = new WeakMap;
1605
+ function nativeRowID(message) {
1606
+ return coordinates.get(message) ?? message.id;
1607
+ }
1608
+ function copyNativeInput(messages) {
1609
+ const copies = reviveNative(encodeNative(messages));
1610
+ copies.forEach((copy, i) => {
1611
+ const original = messages[i];
1612
+ const id = original && nativeRowID(original);
1613
+ if (id !== undefined)
1614
+ coordinates.set(copy, id);
1615
+ });
1616
+ return copies;
1617
+ }
1618
+ function isLocalCheckpoint(row) {
1619
+ return row.type === "compaction" && row.data.status === "completed" && row.data.providerContext === undefined;
1620
+ }
1621
+ var conversational = (row) => RAW_MESSAGE_TYPES.includes(row.type) || row.type === "location-switched";
1622
+
1623
+ class NativeFoldReplay {
1624
+ storage;
1625
+ openReader;
1626
+ changed = new Set;
1627
+ dirty = new Set;
1628
+ unavailable = new Set;
1629
+ metadata = new Map;
1630
+ metadataThrough = new Map;
1631
+ loaded = new Map;
1632
+ sources = new Map;
1633
+ constructor(storage, openReader) {
1634
+ this.storage = storage;
1635
+ this.openReader = openReader;
1636
+ storage.onEvict((sessionID) => this.clear(sessionID));
1637
+ }
1638
+ account(sessionID) {
1639
+ const source = this.sources.get(sessionID);
1640
+ let bytes = 256 + (source?.length ?? 0) * 2;
1641
+ for (const row of this.metadata.get(sessionID) ?? [])
1642
+ bytes += 128 + (row.id.length + row.type.length) * 2;
1643
+ this.storage.accountReplay(sessionID, bytes);
1644
+ }
1645
+ async observeSource(sessionID, reader) {
1646
+ const source = reader.hostIdentity();
1647
+ const prior = this.sources.get(sessionID);
1648
+ if (prior && prior !== source)
1649
+ await this.forget(sessionID);
1650
+ this.sources.set(sessionID, source);
1651
+ this.account(sessionID);
1652
+ }
1653
+ onEvent(event) {
1654
+ const sessionID = event.data?.sessionID;
1655
+ if (sessionID && (event.type?.startsWith("session.revert.") || event.type === "session.message.content.updated"))
1656
+ this.invalidate(sessionID);
1657
+ }
1658
+ invalidate(sessionID, suppressNomination = false) {
1659
+ if (suppressNomination)
1660
+ this.unavailable.add(sessionID);
1661
+ this.dirty.add(sessionID);
1662
+ this.changed.add(sessionID);
1663
+ this.metadata.delete(sessionID);
1664
+ this.metadataThrough.delete(sessionID);
1665
+ this.account(sessionID);
1666
+ }
1667
+ tail(sessionID) {
1668
+ const record = this.storage.tail(sessionID);
1669
+ return record ? JSON.parse(record.data) : undefined;
1670
+ }
1671
+ async baseline(sessionID) {
1672
+ return this.tail(sessionID)?.baseline;
1673
+ }
1674
+ rendered(row, model) {
1675
+ return restoreRow(row, model, hostUsesMediaAssets() ? {
1676
+ asset: hostMediaAsset,
1677
+ unavailable: () => {}
1678
+ } : undefined);
1679
+ }
1680
+ record(row, messages) {
1681
+ const data = JSON.stringify(encodeNative(messages));
1682
+ return { id: row.id, type: row.type, seq: row.seq, data, digest: foldDigest(data) };
1683
+ }
1684
+ records(sessionID, native, reader) {
1685
+ let metadata = this.metadata.get(sessionID);
1686
+ const through = reader.latestSequence(sessionID);
1687
+ const known = new Set(metadata?.map((row) => row.id));
1688
+ if (!metadata || (this.metadataThrough.get(sessionID) ?? -1) < through || native.some((message) => message.id && !known.has(message.id))) {
1689
+ metadata = reader.rowStampsThrough(sessionID, through).filter(conversational);
1690
+ this.metadata.set(sessionID, metadata);
1691
+ this.metadataThrough.set(sessionID, through);
1692
+ }
1693
+ const byID = new Map(metadata.map((row) => [row.id, row]));
1694
+ const grouped = new Map;
1695
+ const anchorIndex = native.findIndex((message) => {
1696
+ const id = nativeRowID(message);
1697
+ return id !== undefined && byID.has(id);
1698
+ });
1699
+ const leading = native.slice(0, anchorIndex < 0 ? native.length : anchorIndex).filter((message) => !nativeRowID(message) && message.role === "system");
1700
+ const anchorMessage = native[anchorIndex];
1701
+ const anchorID = anchorMessage && nativeRowID(anchorMessage);
1702
+ const anchor = anchorID ? byID.get(anchorID) : undefined;
1703
+ const leadingRows = anchor ? metadata.filter((row) => row.type === "system" && row.seq < anchor.seq).slice(-leading.length) : [];
1704
+ const leadingIDs = new Map(leading.map((message, i) => [message, leadingRows[i]?.id]));
1705
+ let cursor = -1;
1706
+ let owner;
1707
+ for (const message of native) {
1708
+ let id = nativeRowID(message);
1709
+ if (!id && message.role === "system") {
1710
+ if (leadingIDs.has(message)) {
1711
+ id = leadingIDs.get(message);
1712
+ if (!id)
1713
+ continue;
1714
+ } else
1715
+ id = metadata.find((row) => row.type === "system" && row.seq > cursor)?.id;
1716
+ }
1717
+ if (!id && message.role === "tool")
1718
+ id = owner;
1719
+ const row = id ? byID.get(id) : undefined;
1720
+ if (!row)
1721
+ throw new NativeReplayUnavailable("Native carrier has no source row coordinate");
1722
+ cursor = row.seq;
1723
+ coordinates.set(message, row.id);
1724
+ if (message.role !== "tool")
1725
+ owner = row.id;
1726
+ const messages = grouped.get(row) ?? [];
1727
+ messages.push(message);
1728
+ grouped.set(row, messages);
1729
+ }
1730
+ return [...grouped].map(([row, messages]) => this.record(row, messages));
1731
+ }
1732
+ async capture(draft, native) {
1733
+ const release = this.storage.hold(draft.sessionID);
1734
+ try {
1735
+ rememberHostMedia(native);
1736
+ const reader = this.openReader(draft.sessionID);
1737
+ try {
1738
+ const rows = this.records(draft.sessionID, native, reader);
1739
+ const baseline = draft.messages.find((message) => message.id === HEAD_IDS[0])?.content.find((part) => part.type === "text")?.text;
1740
+ const through = Math.max(-1, ...rows.map((row) => row.seq));
1741
+ const tail = {
1742
+ model: `${draft.model.providerID}/${draft.model.id}`,
1743
+ sourceSeq: through,
1744
+ baseline: typeof baseline === "string" ? baseline : this.tail(draft.sessionID)?.baseline
1745
+ };
1746
+ await this.storage.saveTail(draft.sessionID, JSON.stringify(tail), rows);
1747
+ this.storage.truncate(draft.sessionID, through);
1748
+ this.loaded.set(draft.sessionID, through);
1749
+ this.unavailable.delete(draft.sessionID);
1750
+ this.changed.delete(draft.sessionID);
1751
+ } finally {
1752
+ reader.close();
1753
+ }
1754
+ } catch {
1755
+ this.unavailable.add(draft.sessionID);
1756
+ this.invalidate(draft.sessionID);
1757
+ } finally {
1758
+ this.account(draft.sessionID);
1759
+ release();
1760
+ }
1761
+ }
1762
+ async canReplay(sessionID, _reader) {
1763
+ return !this.unavailable.has(sessionID) && typeof await this.baseline(sessionID) === "string";
1764
+ }
1765
+ async supply(args) {
1766
+ const release = this.storage.hold(args.draft.sessionID);
1767
+ try {
1768
+ return await this.supplyHeld(args);
1769
+ } finally {
1770
+ this.account(args.draft.sessionID);
1771
+ release();
1772
+ }
1773
+ }
1774
+ async supplyHeld(args) {
1775
+ const { draft, reader, summary } = args;
1776
+ const tail = this.tail(draft.sessionID);
1777
+ const id = reader.latestRunningCompaction(draft.sessionID)?.id;
1778
+ if (!id || !tail || tail.model !== `${draft.model.providerID}/${draft.model.id}`)
1779
+ return false;
1780
+ const through = reader.latestSequence(draft.sessionID);
1781
+ const after = this.dirty.has(draft.sessionID) ? -1 : tail.sourceSeq;
1782
+ const fresh = reader.range(draft.sessionID, after, through).filter(conversational);
1783
+ const records = fresh.map((row) => this.record(row, this.rendered(row, draft.model)));
1784
+ if (this.dirty.has(draft.sessionID))
1785
+ this.storage.replaceRows(draft.sessionID, through, records);
1786
+ await this.storage.saveTail(draft.sessionID, JSON.stringify({
1787
+ ...tail,
1788
+ sourceSeq: Math.max(tail.sourceSeq, ...fresh.map((row) => row.seq))
1789
+ }), records);
1790
+ this.dirty.delete(draft.sessionID);
1791
+ this.metadata.delete(draft.sessionID);
1792
+ this.metadataThrough.delete(draft.sessionID);
1793
+ this.loaded.set(draft.sessionID, through);
1794
+ const snapshot = {
1795
+ source: this.storage.sourceID,
1796
+ sessionID: draft.sessionID,
1797
+ admissionID: id,
1798
+ summary
1799
+ };
1800
+ await this.storage.supply(draft.sessionID, id, JSON.stringify(snapshot));
1801
+ return true;
1802
+ }
1803
+ async restore(sessionID, cut, model, options = {}) {
1804
+ const release = this.storage.hold(sessionID);
1805
+ try {
1806
+ return await this.restoreHeld(sessionID, cut, model, options);
1807
+ } finally {
1808
+ this.account(sessionID);
1809
+ release();
1810
+ }
1811
+ }
1812
+ async restoreHeld(sessionID, cut, model, options) {
1813
+ if (!isLocalCheckpoint(cut))
1814
+ return;
1815
+ const resolvedModel = {
1816
+ providerID: model.slice(0, model.indexOf("/")),
1817
+ id: model.slice(model.indexOf("/") + 1)
1818
+ };
1819
+ const tail = this.tail(sessionID);
1820
+ if (tail && tail.model !== model)
1821
+ this.invalidate(sessionID);
1822
+ let after = options.after ?? -1;
1823
+ if (options.bounded && options.after === undefined && !this.changed.has(sessionID)) {
1824
+ const state = getOrCreateSessionMeta(this.storage.db, sessionID);
1825
+ const max = this.storage.db.prepare("SELECT COALESCE(MAX(id),0) AS id FROM m0_mutation_log WHERE session_id=?").get(sessionID);
1826
+ const boundary = this.storage.db.prepare("SELECT cached_m0_last_baseline_end_message_id AS id FROM session_meta WHERE session_id=?").get(sessionID)?.id;
1827
+ if (max.id <= (state.cachedM0MaxMutationId ?? 0) && boundary)
1828
+ after = this.storage.sequenceForID(sessionID, boundary) ?? -1;
1829
+ }
1830
+ const through = cut.seq - 1;
1831
+ let reader;
1832
+ try {
1833
+ let metadata = this.metadata.get(sessionID);
1834
+ if (!metadata || (this.metadataThrough.get(sessionID) ?? -1) < through) {
1835
+ reader = this.openReader(sessionID);
1836
+ metadata = reader.rowStampsThrough(sessionID, through).filter(conversational);
1837
+ this.metadata.set(sessionID, metadata);
1838
+ this.metadataThrough.set(sessionID, through);
1839
+ }
1840
+ const required = metadata.filter((row) => row.seq > after && row.seq <= through);
1841
+ if (this.dirty.has(sessionID) || !tail || (this.loaded.get(sessionID) ?? -1) < through && !this.storage.admission(sessionID, cut.id) || !this.storage.containsRows(sessionID, required.map((row) => row.id))) {
1842
+ reader ??= this.openReader(sessionID);
1843
+ const fresh = reader.range(sessionID, after, through).filter(conversational);
1844
+ const records = fresh.map((row) => this.record(row, this.rendered(row, resolvedModel)));
1845
+ const restored = new Set(records.map((row) => row.id));
1846
+ if (required.some((row) => !restored.has(row.id)))
1847
+ throw new NativeReplayUnavailable("Host restore omitted a required source row");
1848
+ this.storage.replaceRows(sessionID, through, records, after);
1849
+ await this.storage.saveTail(sessionID, JSON.stringify({
1850
+ model,
1851
+ sourceSeq: through,
1852
+ baseline: tail?.baseline ?? cut.data.summary
1853
+ }), []);
1854
+ this.loaded.set(sessionID, through);
1855
+ this.dirty.delete(sessionID);
1856
+ }
1857
+ } finally {
1858
+ reader?.close();
1859
+ }
1860
+ const messages = [];
1861
+ for (const row of this.storage.rows(sessionID, after, cut.seq - 1)) {
1862
+ const revived = reviveNative(JSON.parse(row.data));
1863
+ for (const message of revived)
1864
+ coordinates.set(message, row.id);
1865
+ messages.push(...revived);
1866
+ }
1867
+ return messages;
1868
+ }
1869
+ async restoreRead(sessionID, cut, model) {
1870
+ const reader = this.openReader(sessionID);
1871
+ try {
1872
+ return reader.range(sessionID, -1, cut.seq - 1).filter(conversational).flatMap((row) => {
1873
+ const messages = this.rendered(row, model);
1874
+ for (const message of messages)
1875
+ coordinates.set(message, row.id);
1876
+ return messages;
1877
+ });
1878
+ } finally {
1879
+ reader.close();
1880
+ }
1881
+ }
1882
+ sourceChanged(sessionID) {
1883
+ return this.changed.has(sessionID);
1884
+ }
1885
+ clear(sessionID) {
1886
+ this.sources.delete(sessionID);
1887
+ this.metadata.delete(sessionID);
1888
+ this.metadataThrough.delete(sessionID);
1889
+ this.loaded.delete(sessionID);
1890
+ this.unavailable.delete(sessionID);
1891
+ this.dirty.delete(sessionID);
1892
+ this.changed.delete(sessionID);
1893
+ }
1894
+ async forget(sessionID) {
1895
+ await this.storage.forget(sessionID);
1896
+ }
1897
+ }
1898
+
1899
+ // src/v2/fold/policy.ts
1900
+ import { randomUUID as randomUUID2 } from "node:crypto";
1901
+ class HostFoldPolicy {
1902
+ deps;
1903
+ active = new Set;
1904
+ owner = randomUUID2();
1905
+ constructor(deps) {
1906
+ this.deps = deps;
1907
+ }
1908
+ owned(sessionID, cut, id) {
1909
+ const row = this.deps.storage.admission(sessionID, id);
1910
+ if (!isLocalCheckpoint(cut) || cut.id !== id || !row?.payload || row.digest !== foldDigest(row.payload))
1911
+ return false;
1912
+ const snapshot = JSON.parse(row.payload);
1913
+ return snapshot.summary === cut.data.summary && snapshot.source === this.deps.storage.sourceID && snapshot.sessionID === sessionID && snapshot.admissionID === id;
1914
+ }
1915
+ async idle(sessionID) {
1916
+ const { storage, session, threshold } = this.deps;
1917
+ if (!Number.isSafeInteger(threshold) || threshold <= 0 || typeof session.compact !== "function" || this.active.has(sessionID))
1918
+ return;
1919
+ this.active.add(sessionID);
1920
+ const now = this.deps.now ?? Date.now;
1921
+ let attempt;
1922
+ let claimed = false;
1923
+ try {
1924
+ const reader = this.deps.openReader();
1925
+ try {
1926
+ const cut = reader.latestCompaction(sessionID);
1927
+ const previous = storage.latestAttempt(sessionID);
1928
+ const old = previous ? JSON.parse(previous.data) : undefined;
1929
+ if (cut && previous?.status === "pending" && old && this.owned(sessionID, cut, old.id)) {
1930
+ if (await storage.claim(sessionID, old.id, previous.data, this.owner, now()) && await storage.finish(sessionID, old.id, this.owner, "completed", now()))
1931
+ this.deps.log(sessionID, `v2 host fold: rows_before=${old.before} rows_after=${reader.storedRowsAfter(sessionID, cut.seq)} duration_ms=${now() - old.started} reason=row_threshold id=${cut.id} status=completed`);
1932
+ return;
1933
+ }
1934
+ const after = cut?.seq ?? -1;
1935
+ const before = reader.storedRowsAfter(sessionID, after);
1936
+ if (before < threshold || !await this.deps.canReplay(sessionID, reader))
1937
+ return;
1938
+ const retry = old?.after === after ? old.attempt + (previous?.status === "failed" || previous?.status === "coalesced" ? 1 : 0) : 0;
1939
+ const id = old?.after === after && previous?.status === "pending" ? old.id : `msg_mc_fold_${foldDigest(`${storage.sourceID}/${sessionID}/${after}/${retry}`).slice(0, 24)}`;
1940
+ attempt = {
1941
+ after,
1942
+ before,
1943
+ watermark: reader.latestSequence(sessionID),
1944
+ attempt: retry,
1945
+ id,
1946
+ started: now()
1947
+ };
1948
+ claimed = await storage.claim(sessionID, id, JSON.stringify(attempt), this.owner, now());
1949
+ if (!claimed)
1950
+ return;
1951
+ } finally {
1952
+ reader.close();
1953
+ }
1954
+ const admitted = await session.compact({
1955
+ sessionID,
1956
+ id: attempt.id,
1957
+ delivery: "queue"
1958
+ });
1959
+ await session.wait({ sessionID });
1960
+ const settled = this.deps.openReader();
1961
+ try {
1962
+ const cut = settled.latestCompaction(sessionID);
1963
+ if (admitted?.id !== attempt.id || !cut || cut.seq <= attempt.after || !this.owned(sessionID, cut, attempt.id)) {
1964
+ if (await storage.finish(sessionID, attempt.id, this.owner, "coalesced", now()))
1965
+ this.deps.log(sessionID, `v2 host fold: rows_before=${attempt.before} rows_after=unknown duration_ms=${now() - attempt.started} reason=row_threshold id=${attempt.id} actual_id=${cut?.id ?? admitted?.id ?? "unknown"} status=coalesced`);
1966
+ return;
1967
+ }
1968
+ const after = settled.storedRowsAfter(sessionID, cut.seq);
1969
+ if (await storage.finish(sessionID, attempt.id, this.owner, "completed", now()))
1970
+ this.deps.log(sessionID, `v2 host fold: rows_before=${attempt.before} rows_after=${after} duration_ms=${now() - attempt.started} reason=row_threshold id=${cut.id} status=completed`);
1971
+ } finally {
1972
+ settled.close();
1973
+ }
1974
+ } catch (error) {
1975
+ if (claimed && attempt) {
1976
+ let finished = false;
1977
+ try {
1978
+ finished = await storage.finish(sessionID, attempt.id, this.owner, "failed", now());
1979
+ } catch {
1980
+ finished = true;
1981
+ }
1982
+ if (finished)
1983
+ this.deps.log(sessionID, `v2 host fold: rows_before=${attempt.before} rows_after=unknown duration_ms=${now() - attempt.started} reason=row_threshold id=${attempt.id} status=failed error=${JSON.stringify(String(error))}`);
1984
+ } else
1985
+ this.deps.log(sessionID, `v2 host fold: rows_before=unknown rows_after=unknown duration_ms=0 reason=row_threshold status=failed error=${JSON.stringify(String(error))} cache_error=${JSON.stringify(String(error))}`);
1986
+ } finally {
1987
+ this.active.delete(sessionID);
871
1988
  }
872
- content.push({
873
- type: "tool-call",
874
- id: part.id,
875
- name: part.name,
876
- input,
877
- providerExecuted: part.executed,
878
- providerMetadata: toolReuse ? metadata(part.providerState) : undefined
879
- });
880
- if (!completed)
881
- continue;
882
- const toolContent = state.content ?? [];
883
- const single = toolContent.length === 1 ? toolContent[0] : undefined;
884
- const result = {
885
- type: "tool-result",
886
- id: part.id,
887
- name: part.name,
888
- providerExecuted: part.executed,
889
- providerMetadata: toolReuse ? metadata(part.providerResultState ?? part.providerState) : sameProvider ? metadata(part.providerResultState) : undefined,
890
- result: state.status === "error" ? { error: state.error, content: toolContent } : single?.type === "text" ? { type: "text", value: single.text } : { type: "content", value: toolContent },
891
- ...state.status === "error" ? { resultType: "error" } : {}
892
- };
893
- if (part.executed === true)
894
- content.push(result);
895
- else
896
- results.push({ role: "tool", content: [result] });
897
1989
  }
898
- return [...content.length ? [make("assistant", content)] : [], ...results];
899
1990
  }
900
1991
 
901
1992
  // src/v2/fork-inheritance.ts
@@ -1459,7 +2550,7 @@ async function createV2HiddenCompletionExecutor(host, options) {
1459
2550
  const runs = new WeakMap;
1460
2551
  const generation = options.generation ?? "opencode2";
1461
2552
  const roleTails = new Map;
1462
- const note = options.log ?? log;
2553
+ const note = options.log ?? log2;
1463
2554
  const removeSession = host.removeSession;
1464
2555
  if (!removeSession)
1465
2556
  throw new Error("Magic Context requires OpenCode 2.0.22 session.remove");
@@ -1694,7 +2785,8 @@ async function createV2HiddenCompletionExecutor(host, options) {
1694
2785
  ...budget ? [budgetStopped] : []
1695
2786
  ]);
1696
2787
  if (!attempt.shaped) {
1697
- throw new HiddenCompletionRefusal("hidden_prompt_unrecognized", "Host did not dispatch the hidden child context hook", true);
2788
+ const task = run.identity.title.replace(/^magic-context-dream-/, "");
2789
+ throw new HiddenCompletionRefusal("hidden_prompt_unrecognized", `Host did not dispatch the hidden child context hook (task=${task}, agent=${run.identity.agent}, child=${run.child.id}, directory=${run.identity.directory}, stage=context/HiddenChildHook.apply). Check that the child's location loads the owning Magic Context instance; changing models cannot repair missing context shaping.`, true);
1698
2790
  }
1699
2791
  const text = assistantText(row);
1700
2792
  const system = typeof request.body.system === "string" ? request.body.system : run.identity.system;
@@ -1829,7 +2921,7 @@ async function deliverPendingChannel2(context, db, sessionID, baseline) {
1829
2921
  async function registerV2Commands(args) {
1830
2922
  const domain = args.command;
1831
2923
  if (!domain || typeof domain.transform !== "function") {
1832
- log("[magic-context] v2 host exposes no command domain; /ctx-* commands are TUI-only");
2924
+ log2("[magic-context] v2 host exposes no command domain; /ctx-* commands are TUI-only");
1833
2925
  return false;
1834
2926
  }
1835
2927
  const descriptions = getMagicContextBuiltinCommands(args.compactionEnabled);
@@ -1845,10 +2937,10 @@ async function registerV2Commands(args) {
1845
2937
  }
1846
2938
  });
1847
2939
  } catch (error) {
1848
- log("[magic-context] v2 command registration failed", error);
2940
+ log2("[magic-context] v2 command registration failed", error);
1849
2941
  return false;
1850
2942
  }
1851
- log(`[magic-context] registered server-side commands: ${commands.map((command) => command.name).join(" ")}`);
2943
+ log2(`[magic-context] registered server-side commands: ${commands.map((command) => command.name).join(" ")}`);
1852
2944
  return true;
1853
2945
  }
1854
2946
  function commandArgument(input, name) {
@@ -1918,6 +3010,10 @@ function buildV2Commands(rpc, directory) {
1918
3010
  const error = typeof reply.error === "string" ? reply.error : "dream request failed";
1919
3011
  throw new Error(`Magic Context could not start the dream run: ${error}`);
1920
3012
  }
3013
+ pushNotification2("toast", {
3014
+ message: "Dream run started; the summary appears when it finishes",
3015
+ variant: "info"
3016
+ }, input.sessionID);
1921
3017
  }
1922
3018
  },
1923
3019
  {
@@ -1925,702 +3021,328 @@ function buildV2Commands(rpc, directory) {
1925
3021
  execute: async (input) => {
1926
3022
  const reply = await rpc.dispatch("flush", { sessionId: input.sessionID });
1927
3023
  reportRpcReply(input.sessionID, "Flush", reply, "Flush started");
3024
+ if (reply.ok === true) {
3025
+ pushNotification2("action", { action: "refresh-sidebar" }, input.sessionID);
3026
+ }
1928
3027
  }
1929
3028
  },
1930
3029
  {
1931
3030
  name: "ctx-embed",
1932
3031
  execute: async (input) => {
1933
3032
  const argument = commandArgument(input, "ctx-embed").toLowerCase();
1934
- if (argument !== "" && argument !== "start" && argument !== "pause") {
1935
- reportUsage(input.sessionID, "Usage: /ctx-embed (status), /ctx-embed start, or /ctx-embed pause");
1936
- throw new Error("Usage: /ctx-embed (status), /ctx-embed start, or /ctx-embed pause");
1937
- }
1938
- const reply = await rpc.dispatch("embed", {
1939
- sessionId: input.sessionID,
1940
- action: argument === "" ? "status" : argument,
1941
- directory
1942
- });
1943
- reportRpcReply(input.sessionID, "Embed", reply, "Embedding started; the summary appears when it finishes");
1944
- }
1945
- },
1946
- {
1947
- name: "ctx-wrapup",
1948
- execute: async (input) => {
1949
- const argument = commandArgument(input, "ctx-wrapup");
1950
- if (argument !== "" && !/^\d+$/.test(argument)) {
1951
- const usage = "Usage: /ctx-wrapup [messages_to_keep] where messages_to_keep is a positive integer";
1952
- reportUsage(input.sessionID, usage);
1953
- throw new Error(usage);
1954
- }
1955
- const messagesToKeep = argument === "" ? 20 : Number.parseInt(argument, 10);
1956
- if (messagesToKeep <= 0) {
1957
- const usage = "messages_to_keep must be a positive integer";
1958
- reportUsage(input.sessionID, usage);
1959
- throw new Error(usage);
1960
- }
1961
- const reply = await rpc.dispatch("wrapup", {
1962
- sessionId: input.sessionID,
1963
- messagesToKeep
1964
- });
1965
- reportRpcReply(input.sessionID, "Wrapup", reply, "Wrapup started; the summary appears when it finishes");
1966
- }
1967
- }
1968
- ];
1969
- }
1970
-
1971
- // src/v2/hooks/deleted-session-tombstones.ts
1972
- class DeletedSessionTombstones {
1973
- limit;
1974
- #ids = new Set;
1975
- constructor(limit = 1000) {
1976
- this.limit = limit;
1977
- if (!Number.isSafeInteger(limit) || limit < 1) {
1978
- throw new Error("Deleted-session tombstone limit must be a positive integer");
1979
- }
1980
- }
1981
- add(sessionID) {
1982
- this.#ids.delete(sessionID);
1983
- this.#ids.add(sessionID);
1984
- while (this.#ids.size > this.limit) {
1985
- const oldest = this.#ids.values().next().value;
1986
- if (oldest === undefined)
1987
- break;
1988
- this.#ids.delete(oldest);
1989
- }
1990
- }
1991
- has(sessionID) {
1992
- return this.#ids.has(sessionID);
1993
- }
1994
- clear() {
1995
- this.#ids.clear();
1996
- }
1997
- get size() {
1998
- return this.#ids.size;
1999
- }
2000
- }
2001
-
2002
- // src/v2/retrospective-raw-provider.ts
2003
- class V2RetrospectiveRawProvider {
2004
- contextDb;
2005
- openReader;
2006
- reader;
2007
- constructor(contextDb, openReader = () => new V2StoreReader(gaDatabasePath(getDataDir(), process.env.OPENCODE_CHANNEL ?? "latest"))) {
2008
- this.contextDb = contextDb;
2009
- this.openReader = openReader;
2010
- }
2011
- store() {
2012
- return this.reader ??= this.openReader();
2013
- }
2014
- listProjectSessions(projectIdentity) {
2015
- const sessions = this.contextDb.prepare(`
2016
- SELECT sp.session_id FROM session_projects sp
2017
- LEFT JOIN session_meta m ON m.session_id = sp.session_id
2018
- WHERE sp.project_path = ? AND sp.harness = 'opencode2'
2019
- AND COALESCE(m.is_subagent, 0) = 0
2020
- ORDER BY sp.session_id`).all(projectIdentity);
2021
- const roots = this.store().rootSessionActivity(sessions.map((row) => row.session_id));
2022
- return sessions.filter((row) => roots.has(row.session_id)).map((row) => ({ sessionId: row.session_id, updatedAt: roots.get(row.session_id) }));
2023
- }
2024
- readOldestMessageTimesSince(sessionIds, sinceMs) {
2025
- return this.store().oldestUserMessageTimesSince(sessionIds, sinceMs);
2026
- }
2027
- read(sessionId, boundaryMs, limit, before = false) {
2028
- return this.store().retrospectiveUserPage(sessionId, {
2029
- boundaryMs,
2030
- before,
2031
- limit,
2032
- maxChars: RETROSPECTIVE_MAX_USER_MESSAGE_CHARS,
2033
- truncationMarker: RETROSPECTIVE_MESSAGE_TRUNCATION_MARKER
2034
- }).map((row) => ({
2035
- sessionId,
2036
- ordinal: row.seq,
2037
- role: "user",
2038
- text: cleanUserText2(row.text),
2039
- ts: row.time_created
2040
- }));
2041
- }
2042
- readUserMessagesSince(sessionId, sinceMs, capPerSession) {
2043
- const cap = Math.max(1, Math.min(9999, Math.floor(capPerSession)));
2044
- const rows = this.read(sessionId, sinceMs, cap + 1);
2045
- return { messages: rows.slice(0, cap), truncated: rows.length > cap };
2046
- }
2047
- readUserMessagesBefore(sessionId, beforeMs, count) {
2048
- return this.read(sessionId, beforeMs, Math.max(1, Math.min(1e4, Math.floor(count))), true).reverse().filter((row) => hasMeaningfulUserText2([{ type: "text", text: row.text }]));
2049
- }
2050
- dispose() {
2051
- this.reader?.close();
2052
- this.reader = undefined;
2053
- }
2054
- }
2055
-
2056
- // src/v2/hooks/dream-manual.ts
2057
- function resolveManualDreamTask(raw) {
2058
- const requested = typeof raw === "string" ? raw.trim() : "";
2059
- if (!requested)
2060
- return {};
2061
- if (!isCanonicalDreamTask(requested)) {
2062
- return {
2063
- error: `Unknown task "${requested}". Valid tasks: ${CANONICAL_DREAM_TASKS.join(", ")}.`
2064
- };
2065
- }
2066
- return { task: requested };
2067
- }
2068
- function selectRunnableDreamTasks(args) {
2069
- const requiresTools = (task) => DREAM_TASK_CAPABILITIES[task].requiresTools;
2070
- if (args.toolsSupported)
2071
- return { runnable: [...args.tasks], unsupported: [] };
2072
- if (args.requestedTask !== undefined) {
2073
- if (requiresTools(args.requestedTask)) {
2074
- return { runnable: [], unsupported: [args.requestedTask] };
2075
- }
2076
- return {
2077
- runnable: args.tasks.filter((config) => config.task === args.requestedTask),
2078
- unsupported: []
2079
- };
2080
- }
2081
- const unsupported = args.tasks.filter((config) => config.schedule.trim() !== "" && requiresTools(config.task)).map((config) => config.task);
2082
- return {
2083
- runnable: args.tasks.filter((config) => !requiresTools(config.task)),
2084
- unsupported
2085
- };
2086
- }
2087
- async function runManualDreamNow(args) {
2088
- const tasks = buildDreamTaskRuntimeConfigs2(args.dreamer, "opencode", args.language, args.mural?.model);
2089
- const executor = createDreamTaskExecutor({
2090
- hiddenCompletionExecutor: args.executor,
2091
- parentSessionId: args.sessionId,
2092
- sessionDirectory: args.directory,
2093
- openOpenCodeDb: () => null,
2094
- retrospectiveRawProvider: (db) => new V2RetrospectiveRawProvider(db),
2095
- language: args.language,
2096
- mural: args.mural
2097
- });
2098
- const selection = selectRunnableDreamTasks({
2099
- tasks,
2100
- toolsSupported: args.executor.capabilities.tools === true,
2101
- ...args.task !== undefined ? { requestedTask: args.task } : {}
2102
- });
2103
- const summary = await runManualDream({
2104
- db: args.db,
2105
- projectIdentity: args.projectIdentity,
2106
- tasks: selection.runnable,
2107
- executor,
2108
- ...args.task !== undefined ? { task: args.task } : {}
2109
- });
2110
- return { summary, unsupportedTasks: selection.unsupported };
2111
- }
2112
-
2113
- // src/v2/hooks/dream-timer.ts
2114
- function findV2DreamParentSession(openReader, directory) {
2115
- let reader;
2116
- try {
2117
- reader = openReader();
2118
- const parent = reader.latestRootSessionInDirectory(directory);
2119
- if (!parent) {
2120
- log(`[dreamer] no OpenCode 2 session in ${directory} to parent a timer-started dream run; tasks that need a child session are skipped until one exists`);
2121
- }
2122
- return parent;
2123
- } catch (error) {
2124
- log(`[dreamer] OpenCode 2 parent session lookup failed for ${directory}:`, error);
2125
- return;
2126
- } finally {
2127
- reader?.close();
2128
- }
2129
- }
2130
- function registerV2DreamScheduleTimer(args) {
2131
- const { config, directory, dreamer, executor } = args;
2132
- const gitCommitIndexing = config.memory.git_commit_indexing;
2133
- let disposed = false;
2134
- const registration = startDreamScheduleTimer({
2135
- directory,
2136
- projectIdentity: args.projectIdentity,
2137
- harness: "opencode",
2138
- hiddenCompletionExecutor: executor,
2139
- findParentSessionId: () => findV2DreamParentSession(args.openReader, directory),
2140
- openOpenCodeDb: () => null,
2141
- retrospectiveRawProvider: (db) => new V2RetrospectiveRawProvider(db),
2142
- dreamerConfig: dreamer,
2143
- sampleDreamRun: () => {
2144
- const current = dreamerRunConfig(config, args.liveConfig());
2145
- return { dreamerConfig: current.dreamer ?? dreamer, mural: current.mural };
3033
+ if (argument !== "" && argument !== "start" && argument !== "pause") {
3034
+ reportUsage(input.sessionID, "Usage: /ctx-embed (status), /ctx-embed start, or /ctx-embed pause");
3035
+ return;
3036
+ }
3037
+ const reply = await rpc.dispatch("embed", {
3038
+ sessionId: input.sessionID,
3039
+ action: argument === "" ? "status" : argument,
3040
+ directory
3041
+ });
3042
+ reportRpcReply(input.sessionID, "Embed", reply, "Embedding started; the summary appears when it finishes");
3043
+ }
2146
3044
  },
2147
- validateTaskModels: (tasks) => selectRunnableDreamTasks({ tasks, toolsSupported: executor.capabilities.tools }).runnable,
2148
- language: config.language,
2149
- mural: config.mural,
2150
- memoryEnabled: config.memory.enabled === true,
2151
- memoryInjectionBudgetTokens: config.memory.injection_budget_tokens,
2152
- retinaHandoff: config.smart_notes.retina_handoff,
2153
- embeddingConfig: config.embedding,
2154
- gitCommitIndexing: gitCommitIndexing?.enabled ? {
2155
- enabled: true,
2156
- since_days: gitCommitIndexing.since_days,
2157
- max_commits: gitCommitIndexing.max_commits
2158
- } : undefined,
2159
- ensureRegistered: ensureProjectRegisteredFromOpenCodeDirectory
2160
- }).catch((error) => {
2161
- log(`[magic-context] v2 dream timer registration failed (continuing without it): ${error}`);
2162
- return;
2163
- });
2164
- return {
2165
- async dispose() {
2166
- if (disposed)
2167
- return;
2168
- disposed = true;
2169
- const stop = await registration;
2170
- stop?.();
2171
- }
2172
- };
2173
- }
2174
-
2175
- // src/v2/hooks/dream-trigger.ts
2176
- async function sessionInThisLocation(context, sessionID) {
2177
- let location;
2178
- try {
2179
- location = (await context.session.get({ sessionID })).location;
2180
- } catch {
2181
- return false;
2182
- }
2183
- return location?.directory === context.location.directory && (location.workspaceID ?? "") === (context.location.workspaceID ?? "");
2184
- }
2185
- function startDreamTrigger(context, args) {
2186
- const controller = new AbortController;
2187
- const done = (async () => {
2188
- try {
2189
- for await (const value of context.event.subscribe({ signal: controller.signal })) {
2190
- if (controller.signal.aborted)
2191
- break;
2192
- const event = value;
2193
- if (event.type !== "session.execution.succeeded" || !event.data?.sessionID)
2194
- continue;
2195
- if (!await sessionInThisLocation(context, event.data.sessionID))
2196
- continue;
2197
- const db = openCurrentDatabase();
2198
- if (!db)
2199
- continue;
2200
- try {
2201
- const reader = args.openReader?.() ?? new V2StoreReader(gaDatabasePath(getDataDir(), process.env.OPENCODE_CHANNEL ?? "latest"));
2202
- try {
2203
- const activity = reader.rootSessionActivity([event.data.sessionID]).get(event.data.sessionID);
2204
- if (activity !== undefined)
2205
- advanceSessionActivity(db, event.data.sessionID, activity);
2206
- } finally {
2207
- reader.close();
2208
- }
2209
- const sampled = args.sample?.();
2210
- if ((sampled?.config ?? args.config).disable === true)
2211
- continue;
2212
- const { runnable } = selectRunnableDreamTasks({
2213
- tasks: buildDreamTaskRuntimeConfigs2(sampled?.config ?? args.config, "opencode", args.language, (sampled?.mural ?? args.mural)?.model),
2214
- toolsSupported: args.executor.capabilities.tools === true
2215
- });
2216
- await runDueTasksForProject({
2217
- db,
2218
- projectIdentity: args.projectIdentity(),
2219
- projectMemoryEnabled: args.projectMemoryEnabled,
2220
- tasks: runnable,
2221
- executor: createDreamTaskExecutor({
2222
- hiddenCompletionExecutor: args.executor,
2223
- parentSessionId: event.data.sessionID,
2224
- sessionDirectory: context.location.directory,
2225
- openOpenCodeDb: () => null,
2226
- retrospectiveRawProvider: (db) => new V2RetrospectiveRawProvider(db),
2227
- language: args.language,
2228
- mural: sampled?.mural ?? args.mural
2229
- })
2230
- });
2231
- } catch (error) {
2232
- log("[magic-context] v2 dream scheduling failed", error);
3045
+ {
3046
+ name: "ctx-wrapup",
3047
+ execute: async (input) => {
3048
+ const argument = commandArgument(input, "ctx-wrapup");
3049
+ if (argument !== "" && !/^\d+$/.test(argument)) {
3050
+ const usage = "Usage: /ctx-wrapup [messages_to_keep] where messages_to_keep is a positive integer";
3051
+ reportUsage(input.sessionID, usage);
3052
+ return;
3053
+ }
3054
+ const messagesToKeep = argument === "" ? 20 : Number.parseInt(argument, 10);
3055
+ if (messagesToKeep <= 0) {
3056
+ const usage = "messages_to_keep must be a positive integer";
3057
+ reportUsage(input.sessionID, usage);
3058
+ return;
2233
3059
  }
3060
+ const reply = await rpc.dispatch("wrapup", {
3061
+ sessionId: input.sessionID,
3062
+ messagesToKeep
3063
+ });
3064
+ reportRpcReply(input.sessionID, "Wrapup", reply, "Wrapup started; the summary appears when it finishes");
2234
3065
  }
2235
- } catch (error) {
2236
- if (!controller.signal.aborted)
2237
- log("[magic-context] v2 dream event subscription failed", error);
2238
- }
2239
- })();
2240
- return {
2241
- async dispose() {
2242
- controller.abort();
2243
- await done;
2244
3066
  }
2245
- };
3067
+ ];
2246
3068
  }
2247
3069
 
2248
- // src/v2/tool-result.ts
2249
- function isToolError(part) {
2250
- const result = part.result;
2251
- return part.resultType === "error" || result?.type === "error" || result !== null && typeof result === "object" && "error" in result;
2252
- }
2253
- function toolErrorText(result) {
2254
- const value = result.value === undefined ? result : result.value;
2255
- return typeof value === "string" ? value : JSON.stringify(value);
2256
- }
2257
- function toolStateContent(state) {
2258
- if (typeof state.output === "string")
2259
- return state.output;
2260
- if (state.status === "error")
2261
- return toolErrorText({ error: state.error, content: state.content ?? [] });
2262
- if (typeof state.content === "string")
2263
- return state.content;
2264
- if (!Array.isArray(state.content))
2265
- return "";
2266
- return state.content.map((part) => {
2267
- if (typeof part === "string")
2268
- return part;
2269
- if (!part || typeof part !== "object")
2270
- return "";
2271
- const value = part;
2272
- if (typeof value.text === "string")
2273
- return value.text;
2274
- if (typeof value.value === "string")
2275
- return value.value;
2276
- return "";
2277
- }).filter(Boolean).join(`
2278
- `);
3070
+ // src/v2/hooks/deleted-session-tombstones.ts
3071
+ class DeletedSessionTombstones {
3072
+ limit;
3073
+ #ids = new Set;
3074
+ constructor(limit = 1000) {
3075
+ this.limit = limit;
3076
+ if (!Number.isSafeInteger(limit) || limit < 1) {
3077
+ throw new Error("Deleted-session tombstone limit must be a positive integer");
3078
+ }
3079
+ }
3080
+ add(sessionID) {
3081
+ this.#ids.delete(sessionID);
3082
+ this.#ids.add(sessionID);
3083
+ while (this.#ids.size > this.limit) {
3084
+ const oldest = this.#ids.values().next().value;
3085
+ if (oldest === undefined)
3086
+ break;
3087
+ this.#ids.delete(oldest);
3088
+ }
3089
+ }
3090
+ has(sessionID) {
3091
+ return this.#ids.has(sessionID);
3092
+ }
3093
+ clear() {
3094
+ this.#ids.clear();
3095
+ }
3096
+ get size() {
3097
+ return this.#ids.size;
3098
+ }
2279
3099
  }
2280
3100
 
2281
- // src/v2/hooks/payload.ts
2282
- var HEAD_IDS = ["__magic_context_v2_m0__", "__magic_context_v2_m1__"];
2283
- var HOST_CONTENT_TYPES = new Set([
2284
- "text",
2285
- "media",
2286
- "tool-call",
2287
- "tool-result",
2288
- "reasoning",
2289
- "compaction",
2290
- "effort"
2291
- ]);
2292
- function rejectContentPart(message, part, reason) {
2293
- const type = typeof part.type === "string" ? part.type : "<missing>";
2294
- const text = `v2 context omitted a content part the host would reject: type=${type} message=${String(message.info.id ?? "<head>")} reason=${reason}`;
2295
- if (typeof message.info.sessionID === "string")
2296
- sessionLog(message.info.sessionID, text);
2297
- else
2298
- log(text);
2299
- }
2300
- function isHostInstance(value) {
2301
- if (!value || typeof value !== "object" || Array.isArray(value))
2302
- return false;
2303
- const prototype = Object.getPrototypeOf(value);
2304
- return prototype !== Object.prototype && prototype !== null;
2305
- }
2306
- function containsHostInstance(value) {
2307
- if (isHostInstance(value))
2308
- return true;
2309
- if (Array.isArray(value))
2310
- return value.some(containsHostInstance);
2311
- if (value && typeof value === "object")
2312
- return Object.values(value).some(containsHostInstance);
2313
- return false;
3101
+ // src/v2/retrospective-raw-provider.ts
3102
+ class V2RetrospectiveRawProvider {
3103
+ contextDb;
3104
+ openReader;
3105
+ reader;
3106
+ constructor(contextDb, openReader = () => new V2StoreReader(gaDatabasePath(getDataDir(), process.env.OPENCODE_CHANNEL ?? "latest"))) {
3107
+ this.contextDb = contextDb;
3108
+ this.openReader = openReader;
3109
+ }
3110
+ store() {
3111
+ return this.reader ??= this.openReader();
3112
+ }
3113
+ listProjectSessions(projectIdentity) {
3114
+ const sessions = this.contextDb.prepare(`
3115
+ SELECT sp.session_id FROM session_projects sp
3116
+ LEFT JOIN session_meta m ON m.session_id = sp.session_id
3117
+ WHERE sp.project_path = ? AND sp.harness = 'opencode2'
3118
+ AND COALESCE(m.is_subagent, 0) = 0
3119
+ ORDER BY sp.session_id`).all(projectIdentity);
3120
+ const roots = this.store().rootSessionActivity(sessions.map((row) => row.session_id));
3121
+ return sessions.filter((row) => roots.has(row.session_id)).map((row) => ({ sessionId: row.session_id, updatedAt: roots.get(row.session_id) }));
3122
+ }
3123
+ readOldestMessageTimesSince(sessionIds, sinceMs) {
3124
+ return this.store().oldestUserMessageTimesSince(sessionIds, sinceMs);
3125
+ }
3126
+ read(sessionId, boundaryMs, limit, before = false) {
3127
+ return this.store().retrospectiveUserPage(sessionId, {
3128
+ boundaryMs,
3129
+ before,
3130
+ limit,
3131
+ maxChars: RETROSPECTIVE_MAX_USER_MESSAGE_CHARS,
3132
+ truncationMarker: RETROSPECTIVE_MESSAGE_TRUNCATION_MARKER
3133
+ }).map((row) => ({
3134
+ sessionId,
3135
+ ordinal: row.seq,
3136
+ role: "user",
3137
+ text: cleanUserText2(row.text),
3138
+ ts: row.time_created
3139
+ }));
3140
+ }
3141
+ readUserMessagesSince(sessionId, sinceMs, capPerSession) {
3142
+ const cap = Math.max(1, Math.min(9999, Math.floor(capPerSession)));
3143
+ const rows = this.read(sessionId, sinceMs, cap + 1);
3144
+ return { messages: rows.slice(0, cap), truncated: rows.length > cap };
3145
+ }
3146
+ readUserMessagesBefore(sessionId, beforeMs, count) {
3147
+ return this.read(sessionId, beforeMs, Math.max(1, Math.min(1e4, Math.floor(count))), true).reverse().filter((row) => hasMeaningfulUserText2([{ type: "text", text: row.text }]));
3148
+ }
3149
+ dispose() {
3150
+ this.reader?.close();
3151
+ this.reader = undefined;
3152
+ }
2314
3153
  }
2315
- function clonePreservingInstances(value) {
2316
- if (isHostInstance(value))
2317
- return value;
2318
- if (Array.isArray(value))
2319
- return value.map(clonePreservingInstances);
2320
- if (value && typeof value === "object") {
2321
- const copy = {};
2322
- for (const [key, entry] of Object.entries(value))
2323
- copy[key] = clonePreservingInstances(entry);
2324
- return copy;
3154
+
3155
+ // src/v2/hooks/dream-manual.ts
3156
+ function resolveManualDreamTask(raw) {
3157
+ const requested = typeof raw === "string" ? raw.trim() : "";
3158
+ if (!requested)
3159
+ return {};
3160
+ if (!isCanonicalDreamTask(requested)) {
3161
+ return {
3162
+ error: `Unknown task "${requested}". Valid tasks: ${CANONICAL_DREAM_TASKS.join(", ")}.`
3163
+ };
2325
3164
  }
2326
- return value;
3165
+ return { task: requested };
2327
3166
  }
2328
- function contentKey(value) {
2329
- const plain = (entry) => {
2330
- if (ArrayBuffer.isView(entry)) {
2331
- return {
2332
- bytes: Buffer.from(entry.buffer, entry.byteOffset, entry.byteLength).toString("base64")
2333
- };
2334
- }
2335
- if (Array.isArray(entry))
2336
- return entry.map(plain);
2337
- if (entry && typeof entry === "object") {
2338
- return Object.fromEntries(Object.entries(entry).map(([key, nested]) => [key, plain(nested)]));
3167
+ function selectRunnableDreamTasks(args) {
3168
+ const requiresTools = (task) => DREAM_TASK_CAPABILITIES[task].requiresTools;
3169
+ if (args.toolsSupported)
3170
+ return { runnable: [...args.tasks], unsupported: [] };
3171
+ if (args.requestedTask !== undefined) {
3172
+ if (requiresTools(args.requestedTask)) {
3173
+ return { runnable: [], unsupported: [args.requestedTask] };
2339
3174
  }
2340
- return entry;
3175
+ return {
3176
+ runnable: args.tasks.filter((config) => config.task === args.requestedTask),
3177
+ unsupported: []
3178
+ };
3179
+ }
3180
+ const unsupported = args.tasks.filter((config) => config.schedule.trim() !== "" && requiresTools(config.task)).map((config) => config.task);
3181
+ return {
3182
+ runnable: args.tasks.filter((config) => !requiresTools(config.task)),
3183
+ unsupported
2341
3184
  };
2342
- return JSON.stringify(plain(value));
2343
- }
2344
- function fileContentValue(result) {
2345
- const value = result?.value;
2346
- if (result?.type !== "content" || !Array.isArray(value))
2347
- return;
2348
- return value.some((item) => item?.type === "file") ? value : undefined;
2349
- }
2350
- function contentValueText(value) {
2351
- return value.filter((item) => item?.type === "text" && typeof item.text === "string").map((item) => item.text).join(`
2352
- `);
2353
3185
  }
2354
- function contentValueAttachments(value) {
2355
- return value.filter((item) => item?.type === "file").map((item) => ({
2356
- type: "file",
2357
- mime: item.mime,
2358
- url: item.uri,
2359
- ...typeof item.name === "string" ? { filename: item.name } : {}
2360
- }));
3186
+ async function runManualDreamNow(args) {
3187
+ const tasks = buildDreamTaskRuntimeConfigs2(args.dreamer, "opencode", args.language, args.smartNotesEnabled);
3188
+ const executor = createDreamTaskExecutor({
3189
+ hiddenCompletionExecutor: args.executor,
3190
+ parentSessionId: args.sessionId,
3191
+ sessionDirectory: args.directory,
3192
+ openOpenCodeDb: () => null,
3193
+ retrospectiveRawProvider: (db) => new V2RetrospectiveRawProvider(db),
3194
+ language: args.language,
3195
+ mural: args.mural,
3196
+ smartNotesEnabled: args.smartNotesEnabled
3197
+ });
3198
+ const selection = selectRunnableDreamTasks({
3199
+ tasks,
3200
+ toolsSupported: args.executor.capabilities.tools === true,
3201
+ ...args.task !== undefined ? { requestedTask: args.task } : {}
3202
+ });
3203
+ const summary = await runManualDream({
3204
+ db: args.db,
3205
+ projectIdentity: args.projectIdentity,
3206
+ tasks: selection.runnable,
3207
+ executor,
3208
+ ...args.task !== undefined ? { task: args.task } : {}
3209
+ });
3210
+ return { summary, unsupportedTasks: selection.unsupported };
2361
3211
  }
2362
- function rebuildFileContent(value, output) {
2363
- if (isDroppedToolOutput(output))
2364
- return { type: "text", value: output };
2365
- const rebuilt = [];
2366
- let placed = false;
2367
- for (const item of value) {
2368
- if (item?.type !== "text") {
2369
- rebuilt.push(item);
2370
- continue;
3212
+
3213
+ // src/v2/hooks/dream-timer.ts
3214
+ function findV2DreamParentSession(openReader, directory) {
3215
+ let reader;
3216
+ try {
3217
+ reader = openReader();
3218
+ const parent = reader.latestRootSessionInDirectory(directory);
3219
+ if (!parent) {
3220
+ log2(`[dreamer] no OpenCode 2 session in ${directory} to parent a timer-started dream run; tasks that need a child session are skipped until one exists`);
2371
3221
  }
2372
- if (placed)
2373
- continue;
2374
- placed = true;
2375
- rebuilt.push({ ...item, text: output });
3222
+ return parent;
3223
+ } catch (error) {
3224
+ log2(`[dreamer] OpenCode 2 parent session lookup failed for ${directory}:`, error);
3225
+ return;
3226
+ } finally {
3227
+ reader?.close();
2376
3228
  }
2377
- if (!placed && output)
2378
- rebuilt.unshift({ type: "text", text: output });
2379
- return { type: "content", value: rebuilt };
2380
3229
  }
2381
- function adaptPayload(draft, admittedIDs = new Set) {
2382
- const existingHeads = new Map(draft.messages.filter((m) => HEAD_IDS.some((id) => m.id === id)).map((m) => [m.id, m]));
2383
- const source = draft.messages.filter((m) => !existingHeads.has(m.id));
2384
- const results = new Map;
2385
- const hostParts = new Map;
2386
- const hostPartTypes = new Set;
2387
- for (const message of source) {
2388
- for (const part of message.content) {
2389
- if (part.type !== "tool-call" && part.type !== "tool-result" && part.type !== "tool" && containsHostInstance(part)) {
2390
- const key = contentKey(part);
2391
- if (!hostParts.has(key))
2392
- hostParts.set(key, part);
2393
- hostPartTypes.add(part.type);
2394
- }
2395
- if (part.type === "tool-result" && typeof part.id === "string") {
2396
- const queue = results.get(part.id) ?? [];
2397
- queue.push({ part, message });
2398
- results.set(part.id, queue);
2399
- }
2400
- }
2401
- }
2402
- const paired = new Set;
2403
- const bridges = new Map;
2404
- const originals = new Map;
2405
- const bridgesByMessageID = new Map;
2406
- const bridgesByCarrier = new Map;
2407
- const originalsByID = new Map;
2408
- const bridgesFor = (message) => typeof message.info.id === "string" ? bridgesByMessageID.get(message.info.id) : bridgesByCarrier.get(message);
2409
- const nativeTool = (call, result) => {
2410
- const hostResult = result?.part.result;
2411
- const failed = result !== undefined && isToolError(result.part);
2412
- const value = hostResult?.value;
2413
- const files = fileContentValue(hostResult);
2414
- const output = failed && hostResult ? toolErrorText(hostResult) : files ? contentValueText(files) : typeof value === "string" ? value : value === undefined ? "" : JSON.stringify(value);
2415
- const part = {
2416
- type: "tool",
2417
- callID: call?.id ?? result?.part.id,
2418
- tool: call?.name ?? result?.part.name,
2419
- state: {
2420
- input: structuredClone(call?.input ?? {}),
2421
- status: failed ? "error" : result ? "completed" : "running",
2422
- ...result ? { output } : {},
2423
- ...result && (call?.name ?? result.part.name) === "question" ? { metadata: { userAnswer: true } } : {},
2424
- ...files ? { attachments: contentValueAttachments(files) } : {}
2425
- }
2426
- };
2427
- bridges.set(part, {
2428
- call,
2429
- result: result?.part,
2430
- resultMessage: result?.message,
2431
- output,
2432
- files
2433
- });
2434
- if (result)
2435
- paired.add(result.part);
2436
- return part;
2437
- };
2438
- const convertedTool = (source) => {
2439
- const sourceState = source.state && typeof source.state === "object" ? source.state : {};
2440
- const output = toolStateContent(sourceState);
2441
- const { content: _content, ...projectedState } = structuredClone(sourceState);
2442
- const part = {
2443
- type: "tool",
2444
- callID: source.callID ?? source.id,
2445
- tool: source.tool ?? source.name,
2446
- state: { ...projectedState, output }
2447
- };
2448
- bridges.set(part, { native: source, output });
2449
- return part;
2450
- };
2451
- const callParts = new Map;
2452
- for (const message of source) {
2453
- for (const part of message.content) {
2454
- if (part.type === "tool-call") {
2455
- callParts.set(part, nativeTool(part, results.get(String(part.id))?.shift()));
2456
- } else if (part.type === "tool") {
2457
- callParts.set(part, convertedTool(part));
2458
- }
2459
- }
2460
- }
2461
- const messages = [];
2462
- for (const message of source) {
2463
- const parts = [];
2464
- for (const content of message.content) {
2465
- if (paired.has(content))
2466
- continue;
2467
- const part = callParts.get(content) ?? (content.type === "tool-result" ? nativeTool(undefined, { part: content, message }) : clonePreservingInstances(content));
2468
- if (message.id && admittedIDs.has(message.id))
2469
- part.synthetic = true;
2470
- parts.push(part);
2471
- }
2472
- if (!parts.length && message.content.length)
2473
- continue;
2474
- const byCallID = new Map;
2475
- for (const part of parts) {
2476
- const bridge = bridges.get(part);
2477
- if (bridge && typeof part.callID === "string")
2478
- byCallID.set(part.callID, bridge);
2479
- }
2480
- if (typeof message.id === "string") {
2481
- bridgesByMessageID.set(message.id, byCallID);
2482
- originalsByID.set(message.id, message);
3230
+ function registerV2DreamScheduleTimer(args) {
3231
+ const { config, directory, dreamer, executor } = args;
3232
+ const gitCommitIndexing = config.memory.git_commit_indexing;
3233
+ let disposed = false;
3234
+ const registration = startDreamScheduleTimer({
3235
+ directory,
3236
+ projectIdentity: args.projectIdentity,
3237
+ harness: "opencode",
3238
+ hiddenCompletionExecutor: executor,
3239
+ findParentSessionId: () => findV2DreamParentSession(args.openReader, directory),
3240
+ openOpenCodeDb: () => null,
3241
+ retrospectiveRawProvider: (db) => new V2RetrospectiveRawProvider(db),
3242
+ dreamerConfig: dreamer,
3243
+ sampleDreamRun: () => {
3244
+ const current = dreamerRunConfig(config, args.liveConfig());
3245
+ return { dreamerConfig: current.dreamer ?? dreamer, mural: current.mural };
3246
+ },
3247
+ validateTaskModels: (tasks) => selectRunnableDreamTasks({ tasks, toolsSupported: executor.capabilities.tools }).runnable,
3248
+ language: config.language,
3249
+ mural: config.mural,
3250
+ memoryEnabled: config.memory.enabled === true,
3251
+ memoryInjectionBudgetTokens: config.memory.injection_budget_tokens,
3252
+ retinaHandoff: config.smart_notes.retina_handoff,
3253
+ smartNotesEnabled: config.smart_notes.enabled,
3254
+ embeddingConfig: config.embedding,
3255
+ gitCommitIndexing: gitCommitIndexing?.enabled ? {
3256
+ enabled: true,
3257
+ since_days: gitCommitIndexing.since_days,
3258
+ max_commits: gitCommitIndexing.max_commits
3259
+ } : undefined,
3260
+ ensureRegistered: ensureProjectRegisteredFromOpenCodeDirectory
3261
+ }).catch((error) => {
3262
+ log2(`[magic-context] v2 dream timer registration failed (continuing without it): ${error}`);
3263
+ return;
3264
+ });
3265
+ return {
3266
+ async dispose() {
3267
+ if (disposed)
3268
+ return;
3269
+ disposed = true;
3270
+ const stop = await registration;
3271
+ stop?.();
2483
3272
  }
2484
- const mapped = {
2485
- info: {
2486
- id: message.id,
2487
- sessionID: draft.sessionID,
2488
- role: message.role,
2489
- ...{
2490
- providerID: draft.model.providerID,
2491
- modelID: draft.model.id,
2492
- agent: draft.agent
2493
- }
2494
- },
2495
- parts
2496
- };
2497
- originals.set(mapped, message);
2498
- if (typeof message.id !== "string")
2499
- bridgesByCarrier.set(mapped, byCallID);
2500
- messages.push(mapped);
3273
+ };
3274
+ }
3275
+
3276
+ // src/v2/hooks/dream-trigger.ts
3277
+ async function sessionInThisLocation(context, sessionID) {
3278
+ let location;
3279
+ try {
3280
+ location = (await context.session.get({ sessionID })).location;
3281
+ } catch {
3282
+ return false;
2501
3283
  }
2502
- return {
2503
- messages,
2504
- commit() {
2505
- let head = 0;
2506
- const rendered = [];
2507
- for (const message of messages) {
2508
- const original = originals.get(message) ?? (typeof message.info.id === "string" ? originalsByID.get(message.info.id) : undefined);
2509
- const id = message.info.syntheticHead ? HEAD_IDS[head++] : original?.id;
2510
- const content = [];
2511
- const following = [];
2512
- for (const candidate of message.parts) {
2513
- const part = candidate;
2514
- const bridge = bridges.get(part) ?? (part.type === "tool" && typeof part.callID === "string" ? bridgesFor(message)?.get(part.callID) : undefined);
2515
- if (!bridge) {
2516
- if (part.type === "tool") {
2517
- const state = part.state;
2518
- if (typeof part.callID !== "string" || typeof part.tool !== "string" || !state || typeof state !== "object") {
2519
- rejectContentPart(message, part, "tool has no call ID, name, or state");
2520
- continue;
2521
- }
2522
- content.push({
2523
- type: "tool-call",
2524
- id: part.callID,
2525
- name: part.tool,
2526
- input: state.input
2527
- });
2528
- if (state.status === "completed" || state.status === "error") {
2529
- following.push({
2530
- role: "tool",
2531
- content: [
2532
- {
2533
- type: "tool-result",
2534
- id: part.callID,
2535
- name: part.tool,
2536
- result: {
2537
- type: state.status === "error" ? "error" : "text",
2538
- value: toolStateContent(state)
2539
- }
2540
- }
2541
- ]
2542
- });
2543
- }
2544
- continue;
2545
- }
2546
- if (part.type === "file") {
2547
- const mime = part.mime;
2548
- const url = part.url;
2549
- const prefix = `data:${mime};base64,`;
2550
- if (typeof mime !== "string" || !/^image\/(png|jpeg|gif|webp)$/.test(mime) || typeof url !== "string" || !url.startsWith(prefix)) {
2551
- rejectContentPart(message, part, "file is not an inline supported image");
2552
- continue;
2553
- }
2554
- const asset = hostMediaAsset(url.slice(prefix.length), mime);
2555
- if (typeof asset === "string") {
2556
- rejectContentPart(message, part, `host media unavailable: ${asset}`);
2557
- continue;
2558
- }
2559
- content.push({ type: "media", media: asset });
2560
- continue;
2561
- }
2562
- if (!HOST_CONTENT_TYPES.has(String(part.type))) {
2563
- rejectContentPart(message, part, "unknown host content type");
2564
- continue;
2565
- }
2566
- const { synthetic: _synthetic, ...clean } = part;
2567
- const original = hostPartTypes.has(clean.type) && !containsHostInstance(clean) ? hostParts.get(contentKey(clean)) : undefined;
2568
- content.push(original ?? clean);
2569
- continue;
3284
+ return location?.directory === context.location.directory && (location.workspaceID ?? "") === (context.location.workspaceID ?? "");
3285
+ }
3286
+ function startDreamTrigger(context, args) {
3287
+ const controller = new AbortController;
3288
+ const done = (async () => {
3289
+ try {
3290
+ for await (const value of context.event.subscribe({ signal: controller.signal })) {
3291
+ if (controller.signal.aborted)
3292
+ break;
3293
+ const event = value;
3294
+ if (event.type !== "session.execution.succeeded" || !event.data?.sessionID)
3295
+ continue;
3296
+ if (!await sessionInThisLocation(context, event.data.sessionID))
3297
+ continue;
3298
+ const db = openCurrentDatabase();
3299
+ if (!db)
3300
+ continue;
3301
+ try {
3302
+ const reader = args.openReader?.() ?? new V2StoreReader(gaDatabasePath(getDataDir(), process.env.OPENCODE_CHANNEL ?? "latest"));
3303
+ try {
3304
+ const activity = reader.rootSessionActivity([event.data.sessionID]).get(event.data.sessionID);
3305
+ if (activity !== undefined)
3306
+ advanceSessionActivity(db, event.data.sessionID, activity);
3307
+ } finally {
3308
+ reader.close();
2570
3309
  }
2571
- const state = part.state;
2572
- if (bridge.native) {
2573
- const native = bridge.native;
2574
- const callID = String(native.id ?? native.callID ?? part.callID);
2575
- const name = String(native.name ?? native.tool ?? part.tool);
2576
- content.push({ type: "tool-call", id: callID, name, input: state.input });
2577
- if (state.status === "completed" || state.status === "error") {
2578
- following.push({
2579
- role: "tool",
2580
- content: [
2581
- {
2582
- type: "tool-result",
2583
- id: callID,
2584
- name,
2585
- result: {
2586
- type: state.status === "error" ? "error" : "text",
2587
- value: state.output
2588
- }
2589
- }
2590
- ]
2591
- });
2592
- }
3310
+ const sampled = args.sample?.();
3311
+ if ((sampled?.config ?? args.config).disable === true)
2593
3312
  continue;
2594
- }
2595
- if (bridge.call)
2596
- content.push({ ...bridge.call, input: state.input });
2597
- if (bridge.result && bridge.resultMessage) {
2598
- const result = {
2599
- ...bridge.result,
2600
- result: state.output === bridge.output ? bridge.result.result : bridge.files && typeof state.output === "string" ? rebuildFileContent(bridge.files, state.output) : {
2601
- type: state.status === "error" ? "error" : "text",
2602
- value: state.output
2603
- }
2604
- };
2605
- if (bridge.resultMessage === original)
2606
- content.push(result);
2607
- else
2608
- following.push({ ...bridge.resultMessage, content: [result] });
2609
- }
2610
- }
2611
- if (content.length || !original?.content.length) {
2612
- const value = {
2613
- ...original,
2614
- id,
2615
- role: message.info.role ?? "user",
2616
- content
2617
- };
2618
- const existing = id ? existingHeads.get(id) : undefined;
2619
- rendered.push(existing ? Object.assign(existing, { content }) : value);
3313
+ const { runnable } = selectRunnableDreamTasks({
3314
+ tasks: buildDreamTaskRuntimeConfigs2(sampled?.config ?? args.config, "opencode", args.language, args.smartNotesEnabled),
3315
+ toolsSupported: args.executor.capabilities.tools === true
3316
+ });
3317
+ await runDueTasksForProject({
3318
+ db,
3319
+ projectIdentity: args.projectIdentity(),
3320
+ projectMemoryEnabled: args.projectMemoryEnabled,
3321
+ tasks: runnable,
3322
+ executor: createDreamTaskExecutor({
3323
+ hiddenCompletionExecutor: args.executor,
3324
+ parentSessionId: event.data.sessionID,
3325
+ sessionDirectory: context.location.directory,
3326
+ openOpenCodeDb: () => null,
3327
+ retrospectiveRawProvider: (db) => new V2RetrospectiveRawProvider(db),
3328
+ language: args.language,
3329
+ mural: sampled?.mural ?? args.mural,
3330
+ smartNotesEnabled: args.smartNotesEnabled
3331
+ })
3332
+ });
3333
+ } catch (error) {
3334
+ log2("[magic-context] v2 dream scheduling failed", error);
2620
3335
  }
2621
- rendered.push(...following);
2622
3336
  }
2623
- draft.messages.splice(0, draft.messages.length, ...rendered);
3337
+ } catch (error) {
3338
+ if (!controller.signal.aborted)
3339
+ log2("[magic-context] v2 dream event subscription failed", error);
3340
+ }
3341
+ })();
3342
+ return {
3343
+ async dispose() {
3344
+ controller.abort();
3345
+ await done;
2624
3346
  }
2625
3347
  };
2626
3348
  }
@@ -2738,7 +3460,7 @@ async function warmModelLimitCacheFromCatalog(context, options = {}) {
2738
3460
  retryDelayMs: options.retryDelayMs ?? 1000
2739
3461
  });
2740
3462
  } catch (error) {
2741
- sessionLog("global", `v2 model-limit cache warm failed: ${getErrorMessage(error)}`);
3463
+ sessionLog2("global", `v2 model-limit cache warm failed: ${getErrorMessage(error)}`);
2742
3464
  } finally {
2743
3465
  if (!modelLimitCacheWarm())
2744
3466
  warmStarted = false;
@@ -2899,7 +3621,7 @@ function runV2SessionProjectBackfill(db, openStoreReader, allowHomeProject = fal
2899
3621
  } finally {
2900
3622
  reader.close();
2901
3623
  }
2902
- }, { leaseKey: `${getHarness()}:session-projects-creation-v2`, allowHomeProject });
3624
+ }, { leaseKey: `${getHarness2()}:session-projects-creation-v2`, allowHomeProject });
2903
3625
  }
2904
3626
 
2905
3627
  // src/v2/hooks/storage-gate.ts
@@ -3223,6 +3945,7 @@ async function registerTools(context, db, config, rustToolBackends, isInternalCh
3223
3945
  ...createCtxNoteTools({
3224
3946
  ...project,
3225
3947
  dreamerEnabled: isDreamerRunnable(config),
3948
+ smartNotesEnabled: config.smart_notes.enabled,
3226
3949
  ...rustToolBackends ? { rustToolBackends } : {}
3227
3950
  }),
3228
3951
  ...createCtxSearchTools(project),
@@ -3250,7 +3973,7 @@ async function registerTools(context, db, config, rustToolBackends, isInternalCh
3250
3973
  if (refusal)
3251
3974
  return { content: refusal };
3252
3975
  if (name === "ctx_memory" || name === "ctx_note" || name === "ctx_reduce")
3253
- await withAsyncPrivilegedWriter(db, () => {
3976
+ await withAsyncPrivilegedWriter2(db, () => {
3254
3977
  return;
3255
3978
  });
3256
3979
  const parsedInput = tool.schema.object(definition.args).passthrough().safeParse(input);
@@ -3316,7 +4039,7 @@ function persistV2UsageReading(args) {
3316
4039
  const { db, sessionID, draftModel, reading } = args;
3317
4040
  const currentMeta = getOrCreateSessionMeta(db, sessionID);
3318
4041
  if (reading.completed !== undefined && currentMeta.lastResponseTime > 0 && reading.completed <= currentMeta.lastResponseTime) {
3319
- sessionLog(sessionID, `v2 usage: skipped stale reading completed=${reading.completed} <= lastResponseTime=${currentMeta.lastResponseTime}`);
4042
+ sessionLog2(sessionID, `v2 usage: skipped stale reading completed=${reading.completed} <= lastResponseTime=${currentMeta.lastResponseTime}`);
3320
4043
  return;
3321
4044
  }
3322
4045
  const draftModelKey = `${draftModel.providerID}/${draftModel.id}`;
@@ -3343,7 +4066,7 @@ function persistV2UsageReading(args) {
3343
4066
  if (responseTime)
3344
4067
  updates.lastResponseTime = responseTime;
3345
4068
  updateSessionMeta(db, sessionID, updates);
3346
- sessionLog(sessionID, `v2 usage: inputTokens=${reading.inputTokens} contextLimit=${reading.limit} percentage=${percentage} responseModel=${reading.modelKey ?? "legacy"} draftContextLimit=${reading.admissionLimit} pressure=${readingMatchesDraft ? "current" : "stale-model-ignored"}`);
4069
+ sessionLog2(sessionID, `v2 usage: inputTokens=${reading.inputTokens} contextLimit=${reading.limit} percentage=${percentage} responseModel=${reading.modelKey ?? "legacy"} draftContextLimit=${reading.admissionLimit} pressure=${readingMatchesDraft ? "current" : "stale-model-ignored"}`);
3347
4070
  if (readingMatchesDraft) {
3348
4071
  args.contextUsageMap.set(sessionID, {
3349
4072
  usage: { inputTokens: reading.inputTokens, percentage },
@@ -3356,6 +4079,8 @@ function persistV2UsageReading(args) {
3356
4079
  }
3357
4080
 
3358
4081
  // src/v2/hooks/context.ts
4082
+ class V2LkgAdmissionReplay extends Error {
4083
+ }
3359
4084
  var HIDDEN_SESSION_ERROR_GRACE_MS = 50;
3360
4085
  function isBlockingV2TransformError(error) {
3361
4086
  return error instanceof EmergencyFailClosedError || error instanceof UnresolvedHistoryBoundaryError || error instanceof UnmanagedOverWindowError || error instanceof DegradedPassRefusalError || isFailClosedBlockingError(error);
@@ -3369,7 +4094,7 @@ function checkHistoryBoundary(db, reader, sessionID) {
3369
4094
  isInHostStore: (messageId) => storeHasSession ? reader.sequenceForId(sessionID, messageId) !== undefined : null
3370
4095
  });
3371
4096
  } catch (error) {
3372
- sessionLog(sessionID, "history boundary check failed; continuing without repair", error);
4097
+ sessionLog2(sessionID, "history boundary check failed; continuing without repair", error);
3373
4098
  return;
3374
4099
  }
3375
4100
  }
@@ -3382,18 +4107,19 @@ async function cacheV2SessionDirectory(session, sessionID, directories) {
3382
4107
  directories.set(sessionID, directory);
3383
4108
  }
3384
4109
  } catch (error) {
3385
- sessionLog(sessionID, "v2 session directory lookup failed; using the launch directory:", error);
4110
+ sessionLog2(sessionID, "v2 session directory lookup failed; using the launch directory:", error);
3386
4111
  }
3387
4112
  }
3388
4113
  function refuseBeforeProvider(session, sessionID, arm, cause) {
3389
4114
  const detail = cause instanceof Error ? `${cause.name}: ${cause.message}` : cause === undefined ? "" : String(cause);
3390
- sessionLog(sessionID, `v2 refusal: interrupting the turn before the provider request arm=${arm}${detail ? ` cause=${JSON.stringify(detail.slice(0, 500))}` : ""}`);
4115
+ sessionLog2(sessionID, `v2 refusal: interrupting the turn before the provider request arm=${arm}${detail ? ` cause=${JSON.stringify(detail.slice(0, 500))}` : ""}`);
3391
4116
  return interruptBeforeProvider(session, sessionID);
3392
4117
  }
3393
4118
  function createHostSeams(context, readAllForConversion, reconciliationSource, liveModels) {
3394
4119
  return {
3395
4120
  hostRawMessages: readAllForConversion,
3396
4121
  hostMessageReconciliationSource: reconciliationSource,
4122
+ hostPrepareRawOrdinals: async () => true,
3397
4123
  hostProtectedTailBoundary: (args) => resolveOpenCodeProtectedTailBoundary({
3398
4124
  ...args,
3399
4125
  cacheNamespace: `opencode2:${args.sessionId}`
@@ -3449,7 +4175,7 @@ function toolResultText2(result) {
3449
4175
  `);
3450
4176
  }
3451
4177
  function reportPreProviderRefusal(sessionID, error) {
3452
- sessionLog(sessionID, `v2 refusing this turn before the model call: the context could not be read: ${getErrorMessage(error)}`);
4178
+ sessionLog2(sessionID, `v2 refusing this turn before the model call: the context could not be read: ${getErrorMessage(error)}`);
3453
4179
  }
3454
4180
  function catalogModels(listed, draftModel) {
3455
4181
  const rows = Array.isArray(listed) ? listed : listed && typeof listed === "object" && Array.isArray(listed.data) ? listed.data : [];
@@ -3487,7 +4213,7 @@ function removeDreamerOnlyTools(draft) {
3487
4213
  if (draft.tools)
3488
4214
  delete draft.tools.ctx_memory_list;
3489
4215
  }
3490
- function applyV2PromptSurfaceTools(draft, runtime, config) {
4216
+ function applyV2PromptSurfaceTools(draft, runtime, config, smartNotesEnabled = true) {
3491
4217
  if (!draft.tools)
3492
4218
  return;
3493
4219
  const modelKey = `${draft.model.providerID}/${draft.model.id}`;
@@ -3496,8 +4222,8 @@ function applyV2PromptSurfaceTools(draft, runtime, config) {
3496
4222
  const tool = draft.tools[id];
3497
4223
  if (!tool)
3498
4224
  continue;
3499
- tool.description = registration.descriptionFor(id, tool.description);
3500
- applyJsonSchemaParameterDescriptions(id, tool.input, registration.preset);
4225
+ tool.description = id === "ctx_note" && !smartNotesEnabled ? withoutSmartNoteText(registration.preset === "light" ? CTX_NOTE_LIGHT_DESCRIPTION : CTX_NOTE_DESCRIPTION) : registration.descriptionFor(id, tool.description);
4226
+ applyJsonSchemaParameterDescriptions(id, tool.input, registration.preset, smartNotesEnabled);
3501
4227
  }
3502
4228
  }
3503
4229
  function recordV2ToolDefinitions(draft) {
@@ -3539,13 +4265,13 @@ async function registerContext(context) {
3539
4265
  if (!hasRequiredSessionAPI(context.session) || !nativeRemove) {
3540
4266
  const message = OPENCODE2_SESSION_API_NOTICE;
3541
4267
  console.warn(`[magic-context] v2 host API unavailable: ${message}`);
3542
- log(`[magic-context] ${message}`);
4268
+ log2(`[magic-context] ${message}`);
3543
4269
  let noticed = false;
3544
4270
  const refuseUnsupportedHost = async (draft) => {
3545
4271
  if (!noticed) {
3546
4272
  noticed = true;
3547
4273
  pushNotification2("toast", { message, variant: "error" }, draft.sessionID);
3548
- context.session.wait({ sessionID: draft.sessionID }).then(() => deliverSynthetic(context, draft.sessionID, message)).catch((error) => sessionLog(draft.sessionID, "host API notice could not be delivered:", error));
4274
+ context.session.wait({ sessionID: draft.sessionID }).then(() => deliverSynthetic(context, draft.sessionID, message)).catch((error) => sessionLog2(draft.sessionID, "host API notice could not be delivered:", error));
3549
4275
  }
3550
4276
  await refuseBeforeProvider(context.session, draft.sessionID, "unsupported-session-api");
3551
4277
  };
@@ -3557,7 +4283,6 @@ async function registerContext(context) {
3557
4283
  return;
3558
4284
  }
3559
4285
  const liveConfigReader = pluginConfigReader(directory, config);
3560
- const checkoutClaim = createSubcCheckoutClaimGate("opencode", () => config.subc?.connection_file ?? getDefaultSubcConnectionFile());
3561
4286
  const compactionOff = !isCompactionEnabled(config);
3562
4287
  const conflicts = detectConflicts(directory, {
3563
4288
  compactionEnabled: !compactionOff,
@@ -3568,6 +4293,8 @@ async function registerContext(context) {
3568
4293
  return;
3569
4294
  }
3570
4295
  const folds = new FoldOwner(context.storage);
4296
+ const nativeFoldMemory = !compactionOff && process.env.MC_OC2_INVISIBLE_FOLD === "1" ? nativeFoldCache(() => storage.require()) : undefined;
4297
+ const nativeFoldReplay = nativeFoldMemory ? new NativeFoldReplay(nativeFoldMemory, () => openStoreReader()) : undefined;
3571
4298
  setOutputReserveConfig(config.output_reserve);
3572
4299
  const queriedModels = new Set;
3573
4300
  const rawLimits = new Map;
@@ -3576,13 +4303,13 @@ async function registerContext(context) {
3576
4303
  const promptSurfaceRuntime = createPromptSurfaceRuntime({
3577
4304
  harness: "opencode2",
3578
4305
  directory,
3579
- warn: (message) => log(`[magic-context] config warning: ${message}`)
4306
+ warn: (message) => log2(`[magic-context] config warning: ${message}`)
3580
4307
  });
3581
4308
  const storage = createV2StorageGate({
3582
4309
  onUnavailable: (reason) => {
3583
4310
  const message = formatFailClosedBlockingMessage(reason);
3584
4311
  console.warn(`[magic-context] v2 storage unavailable: ${message}`);
3585
- log(`[magic-context] v2 storage unavailable: ${message}`);
4312
+ log2(`[magic-context] v2 storage unavailable: ${message}`);
3586
4313
  }
3587
4314
  });
3588
4315
  let db = await probeV2StorageAtBoot(storage);
@@ -3592,14 +4319,14 @@ async function registerContext(context) {
3592
4319
  if (legacyCleanupStarted)
3593
4320
  return;
3594
4321
  legacyCleanupStarted = true;
3595
- await cleanupLegacyHiddenChildren(database, nativeRemove, log);
4322
+ await cleanupLegacyHiddenChildren(database, nativeRemove, log2);
3596
4323
  };
3597
4324
  if (db && isDatabasePersisted(db))
3598
4325
  await cleanupLegacyOnce(db);
3599
4326
  let storageRecoveryAnnounced = false;
3600
4327
  const storageNoticeBySession = new Map;
3601
4328
  const storeStorageNotice = (sessionID, text, what) => {
3602
- withoutSqliteTransformPass(() => context.session.wait({ sessionID }).then(() => deliverSynthetic(context, sessionID, text)).catch((error) => sessionLog(sessionID, `v2 storage ${what} notice could not be delivered:`, error)));
4329
+ withoutSqliteTransformPass2(() => Promise.resolve().then(() => context.session.wait({ sessionID })).then(() => deliverSynthetic(context, sessionID, text)).catch((error) => sessionLog2(sessionID, `v2 storage ${what} notice could not be delivered:`, error)));
3603
4330
  };
3604
4331
  const noticeStorageRefusal = (sessionID, reason) => {
3605
4332
  const message = formatStorageRefusalNotice(reason);
@@ -3651,7 +4378,7 @@ async function registerContext(context) {
3651
4378
  const refusal = hiddenToolCallRefusal(draft, hiddenChildHook);
3652
4379
  if (refusal === undefined)
3653
4380
  return;
3654
- sessionLog(draft.sessionID, "hidden child tool call refused", {
4381
+ sessionLog2(draft.sessionID, "hidden child tool call refused", {
3655
4382
  tool: draft.tool,
3656
4383
  agent: draft.agent ?? null
3657
4384
  });
@@ -3704,6 +4431,7 @@ async function registerContext(context) {
3704
4431
  const cappedExecutor = withLiveDreamerOutputCap(executor, config, () => liveConfigReader.poll().effective);
3705
4432
  const trigger = startDreamTrigger(context, {
3706
4433
  config: dreamerAtBoot,
4434
+ smartNotesEnabled: config.smart_notes.enabled,
3707
4435
  sample: () => {
3708
4436
  const current = dreamerRunConfig(config, liveConfigReader.poll().effective);
3709
4437
  return { config: current.dreamer ?? dreamerAtBoot, mural: current.mural };
@@ -3739,7 +4467,7 @@ async function registerContext(context) {
3739
4467
  dreamTrigger ??= startDreamer(hiddenCompletionExecutor);
3740
4468
  return true;
3741
4469
  } catch (error) {
3742
- log("[magic-context] v2 historian and dreamer could not start after recovery:", error);
4470
+ log2("[magic-context] v2 historian and dreamer could not start after recovery:", error);
3743
4471
  return false;
3744
4472
  }
3745
4473
  })();
@@ -3798,7 +4526,7 @@ async function registerContext(context) {
3798
4526
  const baseline = channel1.get(draft.sessionID);
3799
4527
  await deliverPendingChannel2(context, db, draft.sessionID, baseline);
3800
4528
  } catch (error) {
3801
- log("[magic-context] v2 Channel 2 delivery deferred", error);
4529
+ log2("[magic-context] v2 Channel 2 delivery deferred", error);
3802
4530
  }
3803
4531
  });
3804
4532
  const pagedRead = createV2RawMessageReader(openStoreReader);
@@ -3816,7 +4544,7 @@ async function registerContext(context) {
3816
4544
  } finally {
3817
4545
  reader.close();
3818
4546
  }
3819
- })).catch((error) => log("[session-project-backfill] OpenCode 2 backfill failed:", error));
4547
+ })).catch((error) => log2("[session-project-backfill] OpenCode 2 backfill failed:", error));
3820
4548
  });
3821
4549
  }
3822
4550
  const readAllForConversion = (sessionID) => readAllV2RawMessagesForConversion(openStoreReader, sessionID);
@@ -3861,17 +4589,17 @@ async function registerContext(context) {
3861
4589
  forkSeedSettled.add(sessionID);
3862
4590
  if (outcome.kind === "seeded") {
3863
4591
  const { result } = outcome;
3864
- sessionLog(sessionID, `v2 fork inheritance: seeded from ${outcome.parentSessionID} through the fork boundary; paired rows=${outcome.pairedRows} compartments=${result.compartmentsCopied} tags=${result.tagsCopied} pending_ops=${result.pendingOpsCopied} facts=${result.factsCopied} notes=${result.notesCopied}`);
4592
+ sessionLog2(sessionID, `v2 fork inheritance: seeded from ${outcome.parentSessionID} through the fork boundary; paired rows=${outcome.pairedRows} compartments=${result.compartmentsCopied} tags=${result.tagsCopied} pending_ops=${result.pendingOpsCopied} facts=${result.factsCopied} notes=${result.notesCopied}`);
3865
4593
  } else if (outcome.kind === "parent-missing") {
3866
- sessionLog(sessionID, `v2 fork inheritance: fork of ${outcome.parentSessionID} starts without inherited state (${outcome.reason})`);
4594
+ sessionLog2(sessionID, `v2 fork inheritance: fork of ${outcome.parentSessionID} starts without inherited state (${outcome.reason})`);
3867
4595
  } else if (outcome.kind === "destination-not-empty") {
3868
- sessionLog(sessionID, `v2 fork inheritance: fork of ${outcome.parentSessionID} already has state; not copied again`);
4596
+ sessionLog2(sessionID, `v2 fork inheritance: fork of ${outcome.parentSessionID} already has state; not copied again`);
3869
4597
  }
3870
4598
  } catch (error) {
3871
- if (isTransientSqliteError(error))
4599
+ if (isTransientSqliteError2(error))
3872
4600
  throw error;
3873
4601
  forkSeedSettled.add(sessionID);
3874
- sessionLog(sessionID, "v2 fork inheritance failed; continuing without it:", error);
4602
+ sessionLog2(sessionID, "v2 fork inheritance failed; continuing without it:", error);
3875
4603
  } finally {
3876
4604
  reader?.close();
3877
4605
  }
@@ -3957,6 +4685,14 @@ async function registerContext(context) {
3957
4685
  }
3958
4686
  return unsafe;
3959
4687
  };
4688
+ const hostFolds = nativeFoldReplay && nativeFoldMemory ? new HostFoldPolicy({
4689
+ session: context.session,
4690
+ storage: nativeFoldMemory,
4691
+ openReader: openStoreReader,
4692
+ canReplay: (sessionID, reader) => nativeFoldReplay.canReplay(sessionID, reader),
4693
+ threshold: Number(process.env.MC_OC2_HOST_FOLD_ROWS ?? 1000),
4694
+ log: sessionLog2
4695
+ }) : undefined;
3960
4696
  const usageController = new AbortController;
3961
4697
  const usageDone = (async () => {
3962
4698
  try {
@@ -3967,10 +4703,28 @@ async function registerContext(context) {
3967
4703
  if (!event.data?.sessionID)
3968
4704
  continue;
3969
4705
  const sessionID = event.data.sessionID;
4706
+ if (event.type?.startsWith("session.revert.") || event.type === "session.message.content.updated") {
4707
+ nativeFoldReplay?.onEvent(event);
4708
+ restoredRows.forget(sessionID);
4709
+ }
3970
4710
  if (event.type === "session.error" || event.type === "session.execution.failed") {
3971
4711
  const error = hiddenTerminalError(event);
3972
4712
  if (error !== undefined)
3973
4713
  hiddenSessionErrors.set(sessionID, error);
4714
+ if (error !== undefined && db && !compactionOff) {
4715
+ const model = liveModels.get(sessionID);
4716
+ try {
4717
+ armLatestThinkingRecoveryFromError({
4718
+ db,
4719
+ sessionId: sessionID,
4720
+ error,
4721
+ providerID: model?.providerID,
4722
+ modelID: model?.modelID
4723
+ });
4724
+ } catch (armError) {
4725
+ log2("[magic-context] v2 latest-thinking recovery arm failed", armError);
4726
+ }
4727
+ }
3974
4728
  continue;
3975
4729
  }
3976
4730
  if (event.type === "session.deleted") {
@@ -3992,6 +4746,7 @@ async function registerContext(context) {
3992
4746
  pendingMaterializationSessions.delete(sessionID);
3993
4747
  lastHeuristicsTurnId.delete(sessionID);
3994
4748
  restoredRows.forget(sessionID);
4749
+ await nativeFoldReplay?.forget(sessionID);
3995
4750
  generateReplay.forget(sessionID);
3996
4751
  systemPromptRefreshSessions.delete(sessionID);
3997
4752
  systemPrompt?.clearSession(sessionID);
@@ -4001,15 +4756,18 @@ async function registerContext(context) {
4001
4756
  if (event.type !== "session.execution.succeeded")
4002
4757
  continue;
4003
4758
  const model = liveModels.get(sessionID);
4004
- if (model)
4759
+ if (model) {
4005
4760
  await recordUsage({
4006
4761
  sessionID,
4007
4762
  model: { providerID: model.providerID, id: model.modelID }
4008
4763
  });
4764
+ if (!compactionOff && typeof await nativeFoldReplay?.baseline(sessionID) === "string")
4765
+ hostFolds?.idle(sessionID);
4766
+ }
4009
4767
  }
4010
4768
  } catch (error) {
4011
4769
  if (!usageController.signal.aborted)
4012
- log("[magic-context] v2 usage subscription failed", error);
4770
+ log2("[magic-context] v2 usage subscription failed", error);
4013
4771
  }
4014
4772
  })();
4015
4773
  const materialize = (draft) => {
@@ -4040,19 +4798,41 @@ async function registerContext(context) {
4040
4798
  }
4041
4799
  if (compactionOff)
4042
4800
  return;
4801
+ if (nativeFoldReplay)
4802
+ rememberHostMedia(draft.messages);
4043
4803
  const reader = openStoreReader();
4044
4804
  try {
4045
4805
  const watermark = reader.latestSequenceForIds(draft.sessionID, draft.messages.flatMap((message) => message.id ? [message.id] : []));
4046
4806
  const running = reader.latestRunningCompaction(draft.sessionID);
4047
4807
  const moduleBaseline = rustModeModuleClient ? servedModuleM0Text(draft.sessionID) : undefined;
4048
4808
  const source = !rustModeModuleClient ? "typescript" : moduleBaseline === null ? "typescript_fallback" : "module";
4809
+ if (nativeFoldReplay) {
4810
+ try {
4811
+ if (await nativeFoldReplay.canReplay(draft.sessionID, reader)) {
4812
+ const state = getOrCreateSessionMeta(storage.require(), draft.sessionID);
4813
+ const summary = moduleBaseline ?? await nativeFoldReplay.baseline(draft.sessionID) ?? state.cachedM0Bytes?.toString("utf8") ?? "<session-history></session-history>";
4814
+ if (await nativeFoldReplay.supply({
4815
+ draft,
4816
+ reader,
4817
+ previousCut: reader.latestCompaction(draft.sessionID),
4818
+ summary
4819
+ })) {
4820
+ draft.result = { summary };
4821
+ return;
4822
+ }
4823
+ }
4824
+ } catch (error) {
4825
+ nativeFoldReplay.invalidate(draft.sessionID, true);
4826
+ sessionLog2(draft.sessionID, `v2 host fold: legacy compaction reason=${JSON.stringify(String(error))}`);
4827
+ }
4828
+ }
4049
4829
  const fold = await folds.supply({
4050
4830
  sessionID: draft.sessionID,
4051
4831
  watermark,
4052
4832
  runningCut: running?.seq,
4053
4833
  materialize: () => moduleBaseline ?? materialize(draft)
4054
4834
  });
4055
- sessionLog(draft.sessionID, `v2 compaction hook: fired answered=true source=${source}`);
4835
+ sessionLog2(draft.sessionID, `v2 compaction hook: fired answered=true source=${source}`);
4056
4836
  draft.result = { summary: fold.submitted };
4057
4837
  } catch (cause) {
4058
4838
  await refuseBeforeProvider(context.session, draft.sessionID, "compaction-fold", cause);
@@ -4072,17 +4852,11 @@ async function registerContext(context) {
4072
4852
  removeDreamerOnlyTools(draft);
4073
4853
  if (deletedSessions.has(draft.sessionID))
4074
4854
  return;
4075
- const claimRefusal = await checkoutClaim.refusal(draft.sessionID, directory);
4076
- if (claimRefusal) {
4077
- pushNotification2("toast", { message: claimRefusal.message, variant: "error" }, draft.sessionID);
4078
- await refuseBeforeProvider(context.session, draft.sessionID, "checkout-claim-held-elsewhere", claimRefusal);
4079
- throw new V2ContextRefusal(claimRefusal.message, { cause: claimRefusal });
4080
- }
4081
4855
  const systemAtEntry = structuredClone(draft.system);
4082
4856
  const slotAtEntry = getSlot(draft.sessionID);
4083
4857
  const restoreLkgSystem = () => {
4084
4858
  if (!lkgSystems.restore(draft.sessionID, getSlot(draft.sessionID), systemAtEntry, draft.system)) {
4085
- sessionLog(draft.sessionID, "lkg_system_state_mismatch");
4859
+ sessionLog2(draft.sessionID, "lkg_system_state_mismatch");
4086
4860
  throw new Error("LKG system identity is unavailable or changed");
4087
4861
  }
4088
4862
  };
@@ -4099,15 +4873,68 @@ async function registerContext(context) {
4099
4873
  });
4100
4874
  variants.set(draft.sessionID, draft.model.variant);
4101
4875
  if (!modelLimitCacheWarm())
4102
- withoutSqliteTransformPass(() => warmModelLimitCacheFromCatalog(context));
4876
+ withoutSqliteTransformPass2(() => warmModelLimitCacheFromCatalog(context));
4103
4877
  agents.set(draft.sessionID, draft.agent);
4104
- applyV2PromptSurfaceTools(draft, promptSurfaceRuntime, config.prompt_surface);
4878
+ applyV2PromptSurfaceTools(draft, promptSurfaceRuntime, config.prompt_surface, config.smart_notes.enabled);
4879
+ const admissionDb = db ?? storage.current();
4880
+ const replayFits = (messages) => {
4881
+ const system = structuredClone(draft.system);
4882
+ if (!admissionDb || !draft.tools || !lkgSystems.restore(draft.sessionID, getSlot(draft.sessionID), draft.system, system))
4883
+ return false;
4884
+ const limit = lkgReplayLimit({
4885
+ db: admissionDb,
4886
+ sessionId: draft.sessionID,
4887
+ model: {
4888
+ providerID: draft.model.providerID,
4889
+ modelID: draft.model.id
4890
+ },
4891
+ modelKey: `${draft.model.providerID}/${draft.model.id}`
4892
+ });
4893
+ if (limit === undefined)
4894
+ return false;
4895
+ let toolDefinitionTokens = 0;
4896
+ for (const tool of Object.values(draft.tools)) {
4897
+ if (!tool || typeof tool.description !== "string" || !tool.input)
4898
+ return false;
4899
+ const schema = JSON.stringify(tool.input);
4900
+ if (!schema)
4901
+ return false;
4902
+ toolDefinitionTokens += estimateTokens(tool.description) + estimateTokens(schema);
4903
+ }
4904
+ return measureLkgReplay({
4905
+ messages,
4906
+ limit,
4907
+ estimate: () => estimateFinalWireInputTokens({
4908
+ messages,
4909
+ toolDefinitionTokens,
4910
+ systemPromptTokens: estimateTokens(JSON.stringify(system)),
4911
+ providerID: draft.model.providerID,
4912
+ modelID: draft.model.id,
4913
+ agentName: draft.agent
4914
+ })
4915
+ }).fit === "under";
4916
+ };
4105
4917
  let postFold = false;
4106
4918
  try {
4107
- const admissionDb = db ?? storage.current();
4108
4919
  if (!compactionOff && admissionDb)
4109
- await withAsyncPrivilegedWriter(admissionDb, () => {
4920
+ await withAsyncPrivilegedWriter2(admissionDb, () => {
4110
4921
  return;
4922
+ }, {
4923
+ beforeRetry: (error) => {
4924
+ const mapped = adaptPayload(draft);
4925
+ if (tryMessagesTransformLkgReplay({
4926
+ output: mapped,
4927
+ sessionId: draft.sessionID,
4928
+ error,
4929
+ agent: draft.agent,
4930
+ rust: transform?.getRustReplayParticipant() ?? undefined,
4931
+ replayFits,
4932
+ onLkgReplay: restoreLkgSystem
4933
+ })) {
4934
+ mapped.commit();
4935
+ throw new V2LkgAdmissionReplay;
4936
+ }
4937
+ }
4111
4938
  });
4112
4939
  if (admissionDb)
4113
4940
  hideSubagentTools(draft, admissionDb);
@@ -4128,7 +4955,7 @@ async function registerContext(context) {
4128
4955
  storageRecoveryAnnounced = true;
4129
4956
  const recovered = await recoverHiddenWork(db);
4130
4957
  const message = formatStorageRecoveryNotice(recovered);
4131
- log(`[magic-context] v2 storage recovered: ${message}`);
4958
+ log2(`[magic-context] v2 storage recovered: ${message}`);
4132
4959
  pushNotification2("toast", { message, variant: "info" }, draft.sessionID);
4133
4960
  storeStorageNotice(draft.sessionID, message, "recovery");
4134
4961
  }
@@ -4143,11 +4970,12 @@ async function registerContext(context) {
4143
4970
  readMessagePages: (sessionID) => readV2RawMessagePagesForConversion(openStoreReader, sessionID)
4144
4971
  });
4145
4972
  } catch (error) {
4146
- sessionLog(draft.sessionID, "store projection rebase failed before system prompt (retrying in transform):", error);
4973
+ sessionLog2(draft.sessionID, "store projection rebase failed before system prompt (retrying in transform):", error);
4147
4974
  }
4148
4975
  systemPrompt ??= createSystemPromptHashHandler({
4149
4976
  db,
4150
4977
  dreamerEnabled: config.dreamer !== undefined && !config.dreamer.disable,
4978
+ smartNotesEnabled: config.smart_notes.enabled,
4151
4979
  memoryEnabled: config.memory.enabled && !!resolveProjectIdentityForSession(directory, config.allow_home_project),
4152
4980
  language: config.language,
4153
4981
  promptSurface: config.prompt_surface,
@@ -4210,7 +5038,7 @@ async function registerContext(context) {
4210
5038
  pendingMaterializationSessions,
4211
5039
  lastHeuristicsTurnId,
4212
5040
  variantBySession: variants,
4213
- clearReasoningAge: config.clear_reasoning_age,
5041
+ keepReasoningTokens: config.keep_reasoning_tokens,
4214
5042
  directory,
4215
5043
  sessionDirectoryBySession: sessionDirectories,
4216
5044
  projectPath: directory,
@@ -4262,6 +5090,8 @@ async function registerContext(context) {
4262
5090
  admitted.add(message.id);
4263
5091
  }
4264
5092
  const cut = reader.latestCompaction(draft.sessionID);
5093
+ if (nativeFoldReplay)
5094
+ await nativeFoldReplay.observeSource(draft.sessionID, reader);
4265
5095
  const boundaryRepair = !rustModeModuleClient && db && !compactionOff ? checkHistoryBoundary(db, reader, draft.sessionID) : undefined;
4266
5096
  if (boundaryRepair?.kind === "repaired" || boundaryRepair?.kind === "baseline-reset") {
4267
5097
  historyRefreshSessions.add(draft.sessionID);
@@ -4271,14 +5101,35 @@ async function registerContext(context) {
4271
5101
  postFold = cut !== undefined;
4272
5102
  if (cut && !incoming)
4273
5103
  throw new Error("The host checkpoint disappeared from the context draft");
4274
- if (cut && incoming) {
5104
+ let nativeRestored;
5105
+ if (cut && nativeFoldReplay && isLocalCheckpoint(cut)) {
5106
+ try {
5107
+ nativeRestored = await nativeFoldReplay.restore(draft.sessionID, cut, `${draft.model.providerID}/${draft.model.id}`, { bounded: !rustModeModuleClient });
5108
+ } catch (error) {
5109
+ nativeFoldReplay.invalidate(draft.sessionID, true);
5110
+ sessionLog2(draft.sessionID, "v2 host fold: cache unavailable; restoring host rows", error);
5111
+ nativeRestored = await nativeFoldReplay.restoreRead(draft.sessionID, cut, draft.model);
5112
+ }
5113
+ }
5114
+ if (nativeRestored && nativeFoldReplay?.sourceChanged(draft.sessionID)) {
5115
+ historyRefreshSessions.add(draft.sessionID);
5116
+ pendingMaterializationSessions.add(draft.sessionID);
5117
+ }
5118
+ if (cut && incoming && nativeRestored) {
5119
+ const present = new Set(draft.messages.flatMap((message) => message.id ? [message.id] : []));
5120
+ const hidden = nativeRestored.filter((message) => {
5121
+ const id = nativeRowID(message);
5122
+ return !id || !present.has(id);
5123
+ });
5124
+ draft.messages.splice(0, draft.messages.length, ...hidden, ...draft.messages.filter((message) => message !== incoming));
5125
+ } else if (cut && incoming) {
4275
5126
  const identity = await folds.observe({
4276
5127
  sessionID: draft.sessionID,
4277
5128
  cutSeq: cut.seq,
4278
5129
  summary: cut.data.summary ?? "",
4279
5130
  rendered: incoming,
4280
5131
  onHard: (reason) => {
4281
- sessionLog(draft.sessionID, `HARD reason=${reason}`);
5132
+ sessionLog2(draft.sessionID, `HARD reason=${reason}`);
4282
5133
  materialize(draft);
4283
5134
  pendingMaterializationSessions.add(draft.sessionID);
4284
5135
  }
@@ -4291,11 +5142,11 @@ async function registerContext(context) {
4291
5142
  const servedBoundary = boundaryID ? servedBoundaryRow(reader, draft.sessionID, boundaryID) : null;
4292
5143
  const boundary = (moduleBoundarySeq !== undefined ? moduleBoundarySeq - 1 : undefined) ?? servedBoundary?.seq ?? reader.sequenceForId(draft.sessionID, boundaryID) ?? (reader.earliestSequence(draft.sessionID) ?? 0) - 1;
4293
5144
  if (moduleBoundarySeq !== undefined)
4294
- sessionLog(draft.sessionID, `v2 restore: from the module boundary ${moduleBoundaryID} to the host checkpoint`);
5145
+ sessionLog2(draft.sessionID, `v2 restore: from the module boundary ${moduleBoundaryID} to the host checkpoint`);
4295
5146
  const present = new Set(draft.messages.map((message) => message.id));
4296
5147
  const restored = restoredRows.rows(reader, draft.sessionID, boundary, cut.seq).filter((row) => !present.has(row.id)).flatMap((row) => restoreRow(row, draft.model, hostUsesMediaAssets() ? {
4297
5148
  asset: hostMediaAsset,
4298
- unavailable: (detail) => sessionLog(draft.sessionID, `v2 restore: attachment replaced by a note row=${detail.rowID} name=${JSON.stringify(detail.name ?? null)} mediaType=${detail.mediaType} reason=${JSON.stringify(detail.reason)}`)
5149
+ unavailable: (detail) => sessionLog2(draft.sessionID, `v2 restore: attachment replaced by a note row=${detail.rowID} name=${JSON.stringify(detail.name ?? null)} mediaType=${detail.mediaType} reason=${JSON.stringify(detail.reason)}`)
4299
5150
  } : undefined));
4300
5151
  draft.messages.splice(0, draft.messages.length, ...restored, ...draft.messages.filter((message) => message !== incoming));
4301
5152
  }
@@ -4305,13 +5156,22 @@ async function registerContext(context) {
4305
5156
  if (rustModeModuleClient && db) {
4306
5157
  const dropped = trimToRecordedBoundary(db, draft.sessionID, draft.messages);
4307
5158
  if (dropped > 0)
4308
- sessionLog(draft.sessionID, `v2 boundary trim: dropped ${dropped} messages before the module boundary`);
5159
+ sessionLog2(draft.sessionID, `v2 boundary trim: dropped ${dropped} messages before the module boundary`);
5160
+ }
5161
+ let nativeMessages;
5162
+ if (nativeFoldReplay) {
5163
+ try {
5164
+ nativeMessages = copyNativeInput(draft.messages);
5165
+ } catch {
5166
+ nativeFoldReplay.invalidate(draft.sessionID, true);
5167
+ }
4309
5168
  }
4310
5169
  const mapped = adaptPayload(draft, admitted);
4311
5170
  beginV2LkgRequest(draft.sessionID, `${draft.model.providerID}/${draft.model.id}`, latestLkgResponseIds.get(draft.sessionID));
4312
5171
  await createMessagesTransformHandler({
4313
5172
  magicContext: { "experimental.chat.messages.transform": transform },
4314
5173
  compactionOff,
5174
+ replayFits,
4315
5175
  onLkgReplay: restoreLkgSystem,
4316
5176
  rustReplayParticipant: () => transform?.getRustReplayParticipant() ?? null
4317
5177
  })({}, mapped);
@@ -4337,18 +5197,29 @@ ${baseline}
4337
5197
  draft.messages.splice(0, draft.messages.length, checkpoint, ...draft.messages.filter((message) => message !== head));
4338
5198
  }
4339
5199
  }
5200
+ if (nativeMessages && !checkpoint) {
5201
+ try {
5202
+ await nativeFoldReplay?.capture(draft, nativeMessages);
5203
+ } catch (error) {
5204
+ nativeFoldReplay?.invalidate(draft.sessionID, true);
5205
+ sessionLog2(draft.sessionID, "v2 host fold: optional capture unavailable", error);
5206
+ }
5207
+ }
4340
5208
  const capturedSlot = getSlot(draft.sessionID);
4341
5209
  if (capturedSlot && (!slotAtEntry || capturedSlot.capturedAt !== slotAtEntry.capturedAt || capturedSlot.captureSequence !== slotAtEntry.captureSequence || capturedSlot.jsonPrefix !== slotAtEntry.jsonPrefix)) {
4342
5210
  lkgSystems.capture(draft.sessionID, capturedSlot, systemAtEntry, draft.system);
4343
5211
  }
4344
5212
  } catch (error) {
5213
+ if (error instanceof V2LkgAdmissionReplay)
5214
+ return;
4345
5215
  if (error instanceof V2ContextRefusal)
4346
5216
  throw error;
4347
- if (!compactionOff && (isTransientSqliteError(error) || error instanceof StorageBusyRefusalError)) {
4348
- if (isTransientSqliteError(error)) {
5217
+ if (!compactionOff && (isTransientSqliteError2(error) || error instanceof StorageBusyRefusalError)) {
5218
+ if (isTransientSqliteError2(error)) {
4349
5219
  const mapped = adaptPayload(draft);
4350
5220
  try {
4351
5221
  await createMessagesTransformHandler({
5222
+ replayFits,
4352
5223
  onLkgReplay: restoreLkgSystem,
4353
5224
  rustReplayParticipant: () => transform?.getRustReplayParticipant() ?? null,
4354
5225
  magicContext: {
@@ -4381,16 +5252,16 @@ ${baseline}
4381
5252
  cause: managedError
4382
5253
  });
4383
5254
  }
4384
- log("[magic-context] compaction-off: fail-closed inert, passing through", error);
5255
+ log2("[magic-context] compaction-off: fail-closed inert, passing through", error);
4385
5256
  } else if (postFold) {
4386
5257
  await refuseBeforeProvider(context.session, draft.sessionID, "post-fold-restore", error);
4387
5258
  throw new V2ContextRefusal("Magic Context could not restore the unarchived host history.", { cause: error });
4388
5259
  } else {
4389
- log("[magic-context] v2 context unavailable", error);
5260
+ log2("[magic-context] v2 context unavailable", error);
4390
5261
  }
4391
5262
  }
4392
5263
  };
4393
- await context.session.hook("context", (draft) => withSqliteTransformPass(async () => {
5264
+ await context.session.hook("context", (draft) => withSqliteTransformPass2(async () => {
4394
5265
  const anchor = draft.messages.at(-1)?.id;
4395
5266
  await runManagedContext(draft);
4396
5267
  if (!compactionOff && draft.messages.some((message) => message.id === HEAD_IDS[0] || message.content.some((part) => typeof part.text === "string" && part.text.includes("<session-history>"))))
@@ -4400,7 +5271,7 @@ ${baseline}
4400
5271
  if (!compactionOff && !deletedSessions.has(draft.sessionID))
4401
5272
  generateReplay.apply(draft);
4402
5273
  });
4403
- withoutSqliteTransformPass(() => warmModelLimitCacheFromCatalog(context));
5274
+ withoutSqliteTransformPass2(() => warmModelLimitCacheFromCatalog(context));
4404
5275
  const rpcLiveSessionState = createV2RpcLiveSessionState({
4405
5276
  liveModelBySession: liveModels,
4406
5277
  variantBySession: variants,
@@ -4461,6 +5332,7 @@ ${baseline}
4461
5332
  runManualDreamNow({
4462
5333
  db: runDb,
4463
5334
  dreamer: manualDreamer,
5335
+ smartNotesEnabled: config.smart_notes.enabled,
4464
5336
  projectIdentity: resolveProjectIdentityForSession(directory, config.allow_home_project) ?? "",
4465
5337
  directory,
4466
5338
  language: config.language,
@@ -4499,7 +5371,7 @@ ${baseline}
4499
5371
  setTimeout(() => {
4500
5372
  if (rpcStopped)
4501
5373
  return;
4502
- rpcServer.start().catch((error) => log("[magic-context] v2 RPC server failed to start", error));
5374
+ rpcServer.start().catch((error) => log2("[magic-context] v2 RPC server failed to start", error));
4503
5375
  }, 0);
4504
5376
  return {
4505
5377
  async dispose() {