@cortexkit/opencode-magic-context 0.49.11 → 0.49.13

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 (253) hide show
  1. package/README.md +1 -1
  2. package/dist/agents/smart-notes-dreamer-gate.fixture.d.ts +28 -0
  3. package/dist/agents/smart-notes-dreamer-gate.fixture.d.ts.map +1 -0
  4. package/dist/{announcement-hdbkt8v5.js → announcement-g789dmt6.js} +2 -2
  5. package/dist/auto-search-worker.js +4 -4
  6. package/dist/chunk-embedding-write-worker.js +89 -0
  7. package/dist/{compaction-marker-candidates-xxz35vwp.js → compaction-marker-candidates-v5c6997n.js} +3 -3
  8. package/dist/compaction-marker-candidates-worker.js +1 -1
  9. package/dist/config/agent-disable.d.ts +14 -0
  10. package/dist/config/agent-disable.d.ts.map +1 -1
  11. package/dist/config/dependency-notes.d.ts +34 -0
  12. package/dist/config/dependency-notes.d.ts.map +1 -0
  13. package/dist/config/schema/agent-overrides.d.ts +12 -12
  14. package/dist/config/schema/magic-context.d.ts +88 -88
  15. package/dist/config/schema/magic-context.d.ts.map +1 -1
  16. package/dist/{conflict-warning-hook-xwkfncav.js → conflict-warning-hook-mgq17yr3.js} +8 -8
  17. package/dist/{context-twz3s0cg.js → context-azqk0vfd.js} +121 -145
  18. package/dist/{derive-budgets-3nbxsyss.js → derive-budgets-zn7yzd2d.js} +3 -3
  19. package/dist/embedding-backfill-5e1t5wha.js +22 -0
  20. package/dist/embedding-worker-process.js +2 -2
  21. package/dist/embedding-worker.js +6 -6
  22. package/dist/features/magic-context/chunk-embedding-write-worker.d.ts +2 -0
  23. package/dist/features/magic-context/chunk-embedding-write-worker.d.ts.map +1 -0
  24. package/dist/features/magic-context/chunk-embedding-writer.d.ts +48 -0
  25. package/dist/features/magic-context/chunk-embedding-writer.d.ts.map +1 -0
  26. package/dist/features/magic-context/compartment-chunk-embedding.d.ts +1 -1
  27. package/dist/features/magic-context/compartment-chunk-embedding.d.ts.map +1 -1
  28. package/dist/features/magic-context/dreamer/hidden-single-shot.d.ts +3 -2
  29. package/dist/features/magic-context/dreamer/hidden-single-shot.d.ts.map +1 -1
  30. package/dist/features/magic-context/dreamer/map-memories.d.ts +8 -1
  31. package/dist/features/magic-context/dreamer/map-memories.d.ts.map +1 -1
  32. package/dist/features/magic-context/dreamer/retrospective-raw-provider.d.ts +2 -0
  33. package/dist/features/magic-context/dreamer/retrospective-raw-provider.d.ts.map +1 -1
  34. package/dist/features/magic-context/dreamer/storage-dream-runs.d.ts +5 -0
  35. package/dist/features/magic-context/dreamer/storage-dream-runs.d.ts.map +1 -1
  36. package/dist/features/magic-context/dreamer/task-config.d.ts +22 -4
  37. package/dist/features/magic-context/dreamer/task-config.d.ts.map +1 -1
  38. package/dist/features/magic-context/dreamer/task-executor.d.ts.map +1 -1
  39. package/dist/features/magic-context/dreamer/task-registry.d.ts +22 -0
  40. package/dist/features/magic-context/dreamer/task-registry.d.ts.map +1 -1
  41. package/dist/features/magic-context/dreamer/task-scheduler.d.ts +4 -1
  42. package/dist/features/magic-context/dreamer/task-scheduler.d.ts.map +1 -1
  43. package/dist/features/magic-context/dreamer/verify-prompt.d.ts +6 -1
  44. package/dist/features/magic-context/dreamer/verify-prompt.d.ts.map +1 -1
  45. package/dist/features/magic-context/dreamer/verify.d.ts +25 -11
  46. package/dist/features/magic-context/dreamer/verify.d.ts.map +1 -1
  47. package/dist/features/magic-context/memory/embedding-openai.d.ts +32 -0
  48. package/dist/features/magic-context/memory/embedding-openai.d.ts.map +1 -1
  49. package/dist/features/magic-context/memory/project-identity.d.ts +1 -0
  50. package/dist/features/magic-context/memory/project-identity.d.ts.map +1 -1
  51. package/dist/features/magic-context/memory/unborn-head.d.ts +34 -0
  52. package/dist/features/magic-context/memory/unborn-head.d.ts.map +1 -0
  53. package/dist/features/magic-context/mural/compress-cues.d.ts +3 -0
  54. package/dist/features/magic-context/mural/compress-cues.d.ts.map +1 -1
  55. package/dist/features/magic-context/project-embedding-registry.d.ts +5 -0
  56. package/dist/features/magic-context/project-embedding-registry.d.ts.map +1 -1
  57. package/dist/features/magic-context/storage-tags.d.ts +2 -0
  58. package/dist/features/magic-context/storage-tags.d.ts.map +1 -1
  59. package/dist/{history-owner-ty29fz0f.js → history-owner-xp3pngv7.js} +3 -3
  60. package/dist/hooks/magic-context/apply-operations.d.ts.map +1 -1
  61. package/dist/hooks/magic-context/auto-embed-session.d.ts +10 -0
  62. package/dist/hooks/magic-context/auto-embed-session.d.ts.map +1 -0
  63. package/dist/hooks/magic-context/compartment-prompt.d.ts +6 -0
  64. package/dist/hooks/magic-context/compartment-prompt.d.ts.map +1 -1
  65. package/dist/hooks/magic-context/compartment-runner-incremental.d.ts.map +1 -1
  66. package/dist/hooks/magic-context/compartment-runner-types.d.ts +3 -0
  67. package/dist/hooks/magic-context/compartment-runner-types.d.ts.map +1 -1
  68. package/dist/hooks/magic-context/compartment-trigger-error.d.ts +12 -0
  69. package/dist/hooks/magic-context/compartment-trigger-error.d.ts.map +1 -0
  70. package/dist/hooks/magic-context/embed-session-state.d.ts +8 -1
  71. package/dist/hooks/magic-context/embed-session-state.d.ts.map +1 -1
  72. package/dist/hooks/magic-context/historian-prompt-fit.d.ts +2 -0
  73. package/dist/hooks/magic-context/historian-prompt-fit.d.ts.map +1 -1
  74. package/dist/hooks/magic-context/hook.d.ts +3 -1
  75. package/dist/hooks/magic-context/hook.d.ts.map +1 -1
  76. package/dist/hooks/magic-context/pending-materialization.d.ts +2 -0
  77. package/dist/hooks/magic-context/pending-materialization.d.ts.map +1 -1
  78. package/dist/hooks/magic-context/protected-tail-boundary.d.ts +12 -0
  79. package/dist/hooks/magic-context/protected-tail-boundary.d.ts.map +1 -1
  80. package/dist/hooks/magic-context/raw-exact-ordinal-read.d.ts +58 -0
  81. package/dist/hooks/magic-context/raw-exact-ordinal-read.d.ts.map +1 -0
  82. package/dist/hooks/magic-context/raw-ordinal-warmup.d.ts +7 -0
  83. package/dist/hooks/magic-context/raw-ordinal-warmup.d.ts.map +1 -1
  84. package/dist/hooks/magic-context/read-session-raw.d.ts +19 -0
  85. package/dist/hooks/magic-context/read-session-raw.d.ts.map +1 -1
  86. package/dist/hooks/magic-context/recomp-orchestrator.d.ts +2 -0
  87. package/dist/hooks/magic-context/recomp-orchestrator.d.ts.map +1 -1
  88. package/dist/hooks/magic-context/transform-compartment-phase.d.ts +2 -0
  89. package/dist/hooks/magic-context/transform-compartment-phase.d.ts.map +1 -1
  90. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts.map +1 -1
  91. package/dist/hooks/magic-context/transform.d.ts +4 -0
  92. package/dist/hooks/magic-context/transform.d.ts.map +1 -1
  93. package/dist/hooks/magic-context/wrapup-orchestrator.d.ts.map +1 -1
  94. package/dist/{index-bzp9s8z2.js → index-1d289pq2.js} +2 -2
  95. package/dist/{index-w28y7d0z.js → index-1sarmj9z.js} +15 -15
  96. package/dist/{index-z7avx6rw.js → index-2jr1smmh.js} +280 -160
  97. package/dist/{index-4ccdr7yw.js → index-3kdm78zp.js} +5 -5
  98. package/dist/{index-9159kk15.js → index-3kx0kg0f.js} +64 -7
  99. package/dist/{index-0jz47061.js → index-a8bvhwqs.js} +190 -30
  100. package/dist/{index-84j7jq8a.js → index-aw1bh90w.js} +10 -10
  101. package/dist/{index-qr1mkc2y.js → index-b16gpywn.js} +9 -9
  102. package/dist/{index-g7jkrz0x.js → index-bp5083x2.js} +1 -1
  103. package/dist/{index-yhrrx7qa.js → index-bxdg2nbt.js} +3 -3
  104. package/dist/{index-0abg88h2.js → index-dgs16axy.js} +4 -4
  105. package/dist/{index-mp2kghkv.js → index-dyvbsvga.js} +1 -1
  106. package/dist/{index-bmwfzz28.js → index-e20m7284.js} +4 -4
  107. package/dist/{index-4jkhhpn1.js → index-e4dsjj1p.js} +3 -3
  108. package/dist/{index-s178h9z8.js → index-f71thw8j.js} +1 -1
  109. package/dist/{index-kvw6xew3.js → index-fkx2qnvw.js} +2 -2
  110. package/dist/{index-f8cn4xqa.js → index-fwefky9w.js} +18 -5
  111. package/dist/{index-0sahzkwr.js → index-g2q4htwp.js} +46 -2
  112. package/dist/{index-mw7c950g.js → index-gp3kcpc4.js} +1 -1
  113. package/dist/{index-g40wgxxt.js → index-hnm8raee.js} +4 -4
  114. package/dist/{index-gjvjh960.js → index-hqkczed7.js} +1 -1
  115. package/dist/{index-mvvephtj.js → index-j75v2476.js} +1 -1
  116. package/dist/{index-150zz6fh.js → index-k29z4aqh.js} +1 -1
  117. package/dist/{index-b64n4d0h.js → index-kee4kn5j.js} +1 -1
  118. package/dist/index-ksdyrrav.js +52 -0
  119. package/dist/{index-angx1s0k.js → index-mmfa86mt.js} +16 -6
  120. package/dist/{index-9jvab89d.js → index-n6m03s3n.js} +2 -2
  121. package/dist/{index-q28hsbpg.js → index-nj7yykkx.js} +1 -1
  122. package/dist/{index-ghc9f0n7.js → index-p5y3k4g7.js} +29 -1
  123. package/dist/{index-xztdf9t7.js → index-qkd9zz0p.js} +17 -17
  124. package/dist/index-saews2s3.js +229 -0
  125. package/dist/{index-kkvxnbt8.js → index-sj89f3b0.js} +62 -33
  126. package/dist/{index-jw4gbfkv.js → index-v10f1rjv.js} +5 -5
  127. package/dist/{index-0j6crjgh.js → index-v13skev1.js} +13 -13
  128. package/dist/{index-hqnggmxn.js → index-wj6ht7nm.js} +547 -179
  129. package/dist/{index-a865mj02.js → index-wk0n1cgt.js} +4 -4
  130. package/dist/{index-q3qck7j2.js → index-wz6mzzb1.js} +6 -5
  131. package/dist/{index-se1w3v2m.js → index-y1qysm3q.js} +332 -256
  132. package/dist/{index-a4b0gbyg.js → index-y9f76s3f.js} +1 -1
  133. package/dist/index.d.ts.map +1 -1
  134. package/dist/index.js +119 -129
  135. package/dist/{logger-wn328tfg.js → logger-jm3sqqzr.js} +2 -2
  136. package/dist/{message-index-bounded-0rbbg9rd.js → message-index-bounded-vm64mqpq.js} +16 -16
  137. package/dist/{message-index-ct5x2kwa.js → message-index-seaqpb7c.js} +16 -16
  138. package/dist/{message-time-backfill-nb5hhnrt.js → message-time-backfill-qjge9044.js} +3 -3
  139. package/dist/migration-worker.js +11 -11
  140. package/dist/plugin/dream-timer.d.ts.map +1 -1
  141. package/dist/plugin/hooks/create-session-hooks.d.ts.map +1 -1
  142. package/dist/plugin/tool-registry.d.ts.map +1 -1
  143. package/dist/{project-embedding-registry-ft9gh2e2.js → project-embedding-registry-x45bv3qr.js} +12 -11
  144. package/dist/raw-ordinal-warmup-worker.js +12 -7
  145. package/dist/{read-session-chunk-y3hhsbzw.js → read-session-chunk-ax05f7gr.js} +11 -11
  146. package/dist/{read-session-raw-gm6xj30v.js → read-session-raw-m56hc7v2.js} +7 -3
  147. package/dist/recomp-orchestrator-dmbeadwt.js +61 -0
  148. package/dist/{safe-notification-target-jdynm677.js → safe-notification-target-1szv1k5k.js} +3 -3
  149. package/dist/{search-jd8xh721.js → search-5yd5ytzs.js} +25 -24
  150. package/dist/{send-session-notification-vzhj8bsg.js → send-session-notification-24r4esbh.js} +6 -6
  151. package/dist/shared/data-path.d.ts +4 -0
  152. package/dist/shared/data-path.d.ts.map +1 -1
  153. package/dist/shared/model-suggestion-retry.d.ts +2 -0
  154. package/dist/shared/model-suggestion-retry.d.ts.map +1 -1
  155. package/dist/shared/prompt-async-transport.d.ts.map +1 -1
  156. package/dist/{storage-tags-35m4gms2.js → storage-tags-yygfb9c8.js} +7 -5
  157. package/dist/{task-config-cgpg0nvh.js → task-config-x3qmayd2.js} +6 -2
  158. package/dist/tools/ctx-note/tools.d.ts.map +1 -1
  159. package/dist/{transform-postprocess-phase-pmqxfq4q.js → transform-postprocess-phase-72v86syx.js} +32 -31
  160. package/dist/v2/auto-search-worker.js +4 -4
  161. package/dist/v2/chunk-embedding-write-worker.js +88 -0
  162. package/dist/v2/{compaction-marker-candidates-a15w3mqh.js → compaction-marker-candidates-1vqwr3s5.js} +2 -2
  163. package/dist/v2/compaction-marker-candidates-worker.js +1 -1
  164. package/dist/v2/{context-p1zfcw41.js → context-w055w17c.js} +628 -255
  165. package/dist/v2/{derive-budgets-0rmpmxjw.js → derive-budgets-2zh4gm2c.js} +3 -3
  166. package/dist/v2/embedding-backfill-jmaf8zrr.js +21 -0
  167. package/dist/v2/embedding-worker-process.js +1 -1
  168. package/dist/v2/embedding-worker.js +5 -5
  169. package/dist/v2/{history-owner-2cr9py37.js → history-owner-42e16w0n.js} +2 -2
  170. package/dist/v2/hooks/context.d.ts.map +1 -1
  171. package/dist/v2/hooks/dream-manual.d.ts.map +1 -1
  172. package/dist/v2/hooks/dream-trigger.d.ts +1 -1
  173. package/dist/v2/hooks/dream-trigger.d.ts.map +1 -1
  174. package/dist/v2/hooks/hidden-child.d.ts.map +1 -1
  175. package/dist/v2/hooks/transform-features.d.ts +3 -2
  176. package/dist/v2/hooks/transform-features.d.ts.map +1 -1
  177. package/dist/v2/{logger-te6e1j72.js → logger-7qt02bnb.js} +1 -1
  178. package/dist/v2/{message-index-bounded-7wcbp975.js → message-index-bounded-wepg5723.js} +15 -15
  179. package/dist/v2/{message-index-cjhv92m2.js → message-index-gcmd0ng0.js} +15 -15
  180. package/dist/v2/{message-time-backfill-rz1pnpaj.js → message-time-backfill-bsteyc4d.js} +2 -2
  181. package/dist/v2/migration-worker.js +10 -10
  182. package/dist/v2/{project-embedding-registry-g34gcf74.js → project-embedding-registry-0msp56p8.js} +11 -10
  183. package/dist/v2/raw-ordinal-warmup-worker.js +12 -7
  184. package/dist/v2/{read-session-chunk-8d3v87vr.js → read-session-chunk-hr3w5bjk.js} +10 -10
  185. package/dist/v2/{read-session-raw-h4azh85b.js → read-session-raw-b3tf6ra1.js} +6 -2
  186. package/dist/v2/recomp-orchestrator-ca7qt75a.js +60 -0
  187. package/dist/v2/retrospective-raw-provider.d.ts.map +1 -1
  188. package/dist/v2/{safe-notification-target-936374xx.js → safe-notification-target-qg7n2s77.js} +2 -2
  189. package/dist/v2/{search-a1acjwf8.js → search-c86dcv14.js} +24 -23
  190. package/dist/v2/{send-session-notification-z5mcjdea.js → send-session-notification-8ghn9tnv.js} +5 -5
  191. package/dist/v2/{server-npm52h2q.js → server-05xjtq6c.js} +1 -1
  192. package/dist/v2/{server-s6jqh8bj.js → server-0ppsweh6.js} +1 -1
  193. package/dist/v2/server-0s95v3en.js +49 -0
  194. package/dist/v2/{server-hn9fb3v0.js → server-34kwfsr4.js} +2 -2
  195. package/dist/v2/server-4gn3z5an.js +229 -0
  196. package/dist/v2/{server-kn7skz9r.js → server-6cdy4rc0.js} +3 -3
  197. package/dist/v2/{server-7dv9wt9r.js → server-6pmqg9m4.js} +1 -1
  198. package/dist/v2/{server-7fvmt15t.js → server-b81w6sw3.js} +273 -107
  199. package/dist/v2/{server-kmapq3v0.js → server-bxpwy6fy.js} +18 -5
  200. package/dist/v2/{server-d6t16r89.js → server-d8tj10db.js} +1 -1
  201. package/dist/v2/{server-cxsr0ng6.js → server-da07v4xp.js} +1 -1
  202. package/dist/v2/{server-rxcq4t50.js → server-ef89gdsx.js} +5 -5
  203. package/dist/v2/{server-9e5r8y60.js → server-f2xf5gcb.js} +46 -2
  204. package/dist/v2/{server-83d71zab.js → server-g10mdym6.js} +3 -3
  205. package/dist/v2/{server-njnx39q2.js → server-gvkm8xaj.js} +189 -29
  206. package/dist/v2/{server-ckrb5rm8.js → server-h0410h0v.js} +1 -1
  207. package/dist/v2/{server-sg68np13.js → server-hek6z3w6.js} +330 -254
  208. package/dist/v2/{server-f27he3j1.js → server-k2bzedxk.js} +4 -4
  209. package/dist/v2/{server-wkhfyzpg.js → server-m97brnat.js} +9 -9
  210. package/dist/v2/{server-erfp0xb6.js → server-n8ch9683.js} +16 -16
  211. package/dist/v2/{server-bx59ezg6.js → server-prg55b7k.js} +16 -6
  212. package/dist/v2/{server-89fcbe37.js → server-pwv4ezb0.js} +1 -1
  213. package/dist/v2/{server-r5p3b1wy.js → server-qd11g795.js} +29 -1
  214. package/dist/v2/{server-ewqshbs8.js → server-qhfvvfxj.js} +64 -7
  215. package/dist/v2/{server-988cqjme.js → server-rrqpvwqd.js} +2 -2
  216. package/dist/v2/{server-d3f4g62c.js → server-t4prcjc1.js} +13 -13
  217. package/dist/v2/{server-nveratm5.js → server-tbe1femw.js} +4 -4
  218. package/dist/v2/{server-jc8v585p.js → server-th4y11y7.js} +15 -15
  219. package/dist/v2/{server-h3wc20sv.js → server-vbe4se57.js} +4 -4
  220. package/dist/v2/{server-pbpp8r8h.js → server-xh7jar6k.js} +9 -9
  221. package/dist/v2/{server-63ha7f0f.js → server-yrvqaswb.js} +1 -1
  222. package/dist/v2/{server-5x7kmyz8.js → server-zc3e54vy.js} +10 -51
  223. package/dist/v2/{server-xqf2d2mg.js → server-zs8d0s3b.js} +2 -2
  224. package/dist/v2/server.d.ts.map +1 -1
  225. package/dist/v2/server.js +18 -10
  226. package/dist/v2/{storage-tags-c4zfcxv4.js → storage-tags-a2gq6dw7.js} +6 -4
  227. package/dist/v2/store-reader.d.ts +1 -0
  228. package/dist/v2/store-reader.d.ts.map +1 -1
  229. package/dist/v2/{task-config-x0hq3qfd.js → task-config-nvz8mapa.js} +6 -2
  230. package/dist/v2/{wrapup-orchestrator-87q9d5e2.js → wrapup-orchestrator-e1a2w6jh.js} +31 -29
  231. package/dist/wrapup-orchestrator-2051r6qm.js +48 -0
  232. package/package.json +6 -5
  233. package/src/agents/smart-notes-dreamer-gate.fixture.ts +171 -0
  234. package/src/agents/smart-notes-dreamer-gate.golden.json +245 -0
  235. package/src/agents/smart-notes-dreamer-gate.test.ts +161 -0
  236. package/src/config/agent-disable.ts +13 -0
  237. package/src/config/dependency-notes.test.ts +114 -0
  238. package/src/config/dependency-notes.ts +80 -0
  239. package/src/config/schema/magic-context.ts +23 -14
  240. package/src/features/magic-context/dreamer/task-registry.ts +40 -0
  241. package/src/shared/data-path.test.ts +35 -1
  242. package/src/shared/data-path.ts +57 -1
  243. package/src/shared/model-suggestion-retry.test.ts +34 -0
  244. package/src/shared/model-suggestion-retry.ts +23 -3
  245. package/src/shared/prompt-async-transport.test.ts +1 -1
  246. package/src/shared/prompt-async-transport.ts +16 -3
  247. package/dist/embedding-backfill-fjbfh1dt.js +0 -21
  248. package/dist/recomp-orchestrator-67k45s0b.js +0 -60
  249. package/dist/v2/embedding-backfill-xcw3t6hp.js +0 -20
  250. package/dist/v2/recomp-orchestrator-n0pq36f0.js +0 -59
  251. package/dist/wrapup-orchestrator-jqapepw0.js +0 -47
  252. /package/dist/{index-e6xnpach.js → index-b7p25tm0.js} +0 -0
  253. /package/dist/v2/{index-e6xnpach.js → index-b7p25tm0.js} +0 -0
@@ -1,16 +1,16 @@
1
1
  import {
2
2
  inRootAsyncContext2,
3
+ getSqliteDatabasePath2,
3
4
  withSqliteBackgroundWriter2,
4
5
  withoutSqliteTransformPass2,
5
6
  isTransientSqliteError2
6
7
  } from "./server-wafzvyhg.js";
7
8
  import {
8
9
  DEFAULT_LOCAL_EMBEDDING_MODEL
9
- } from "./server-jc8v585p.js";
10
+ } from "./server-th4y11y7.js";
10
11
  import {
11
- isUserHomeDirectory,
12
12
  setBootQuietPeriodForTests
13
- } from "./server-njnx39q2.js";
13
+ } from "./server-gvkm8xaj.js";
14
14
  import {
15
15
  isEmbeddingHostBusy2
16
16
  } from "./server-qt1qqasc.js";
@@ -20,17 +20,18 @@ import {
20
20
  import {
21
21
  sanitizeDiagnosticText,
22
22
  log2
23
- } from "./server-9e5r8y60.js";
24
- import {
25
- estimateTokens
26
- } from "./server-s6jqh8bj.js";
23
+ } from "./server-f2xf5gcb.js";
27
24
  import {
28
25
  SYNAPSE_DEFAULT_MODEL,
29
26
  isSynapseEmbeddingTruncated,
30
27
  getSynapseBatchRequestKey,
31
28
  SynapseEmbeddingProvider
32
- } from "./server-988cqjme.js";
29
+ } from "./server-rrqpvwqd.js";
33
30
  import {
31
+ estimateTokens
32
+ } from "./server-0ppsweh6.js";
33
+ import {
34
+ DEFAULT_COMPARTMENT_CHUNK_MAX_INPUT_TOKENS,
34
35
  CHUNK_WINDOW_SAFETY_RATIO,
35
36
  normalizeCompartmentChunkMaxInputTokens,
36
37
  buildCanonicalChunkTextFromFts,
@@ -46,7 +47,15 @@ import {
46
47
  countSessionCompartmentEmbedCoverage,
47
48
  countSessionCompartmentEmbedCoveragePolite,
48
49
  countUnembeddedSessionCompartmentsPolite
49
- } from "./server-ewqshbs8.js";
50
+ } from "./server-qhfvvfxj.js";
51
+ import {
52
+ acquireGitSweepLease,
53
+ renewGitSweepLease,
54
+ releaseGitSweepLease,
55
+ findMisScopedCompartmentChunkEmbeddingIdsForProject,
56
+ recordSessionProjectIdentity,
57
+ repairMisScopedCompartmentChunkEmbeddingsForProject
58
+ } from "./server-4gn3z5an.js";
50
59
  import {
51
60
  saveEmbeddingIfHashMatches,
52
61
  getMemoryEmbedCoverage,
@@ -58,10 +67,48 @@ import {
58
67
  resolveEmbeddingTextPrefixes,
59
68
  getEmbeddingProviderIdentity,
60
69
  LocalEmbeddingProvider
61
- } from "./server-83d71zab.js";
70
+ } from "./server-g10mdym6.js";
62
71
  import {
63
72
  logSlowWriteTransaction
64
- } from "./server-7dv9wt9r.js";
73
+ } from "./server-6pmqg9m4.js";
74
+
75
+ // src/hooks/magic-context/embed-session-state.ts
76
+ var embedPauseBySession = new Set;
77
+ var embedRunStateBySession = new Map;
78
+ var activeEmbeddingSessions = new Map;
79
+ var autoEmbedAttemptedBySession = new Set;
80
+ var autoEmbedIdentityBySession = new Map;
81
+ var autoEmbedRetryAfterBySession = new Map;
82
+ function invalidateAutoEmbedSession(sessionId) {
83
+ autoEmbedAttemptedBySession.delete(sessionId);
84
+ autoEmbedIdentityBySession.delete(sessionId);
85
+ autoEmbedRetryAfterBySession.delete(sessionId);
86
+ }
87
+ function getEmbedDrainUiStatus(sessionId, progress) {
88
+ if (embedPauseBySession.has(sessionId)) {
89
+ return { status: "paused" };
90
+ }
91
+ const activeRun = embedRunStateBySession.get(sessionId);
92
+ if (activeRun && !activeRun.signal.aborted || progress?.kind === "embed" && progress.phase === "recomp") {
93
+ return { status: "running" };
94
+ }
95
+ if (progress?.kind === "embed" && (progress.phase === "failed" || progress.phase === "skipped") && progress.message) {
96
+ if (/provider/i.test(progress.message)) {
97
+ return { status: "stopped", detail: progress.message };
98
+ }
99
+ }
100
+ return { status: "idle" };
101
+ }
102
+ function clearEmbedSessionState(sessionId) {
103
+ activeEmbeddingSessions.delete(sessionId);
104
+ embedPauseBySession.delete(sessionId);
105
+ const ctrl = embedRunStateBySession.get(sessionId);
106
+ if (ctrl) {
107
+ ctrl.abort();
108
+ embedRunStateBySession.delete(sessionId);
109
+ }
110
+ invalidateAutoEmbedSession(sessionId);
111
+ }
65
112
 
66
113
  // src/shared/background-batch-drain.ts
67
114
  async function drainBackgroundBatches(step, options = {}) {
@@ -142,7 +189,85 @@ function pruneSynapseBatchLedgerForProject(db, projectIdentity, ttlMs = SYNAPSE_
142
189
  }
143
190
 
144
191
  // src/features/magic-context/project-embedding-registry.ts
145
- import { createHash as createHash2, randomUUID } from "node:crypto";
192
+ import { createHash as createHash3, randomUUID } from "node:crypto";
193
+
194
+ // src/features/magic-context/chunk-embedding-writer.ts
195
+ import { Worker } from "node:worker_threads";
196
+ function createChunkEmbeddingWriter(db) {
197
+ const path = getSqliteDatabasePath2(db);
198
+ if (!path)
199
+ return null;
200
+ if (path.startsWith("file:"))
201
+ throw new Error("chunk embedding writer requires a filesystem path");
202
+ const entry = new URL(import.meta.url.endsWith(".ts") ? "./chunk-embedding-write-worker.ts" : "./chunk-embedding-write-worker.js", import.meta.url);
203
+ const timeout = db.prepare("PRAGMA busy_timeout").get().timeout;
204
+ const worker = inRootAsyncContext2(() => new Worker(entry, { workerData: { path, harness: getHarness2(), timeout } }));
205
+ let pending;
206
+ let failure;
207
+ let deadline;
208
+ worker.on("message", (reply) => {
209
+ clearTimeout(deadline);
210
+ const request = pending;
211
+ pending = undefined;
212
+ if (reply.error)
213
+ request?.reject(new Error(reply.error));
214
+ else
215
+ request?.resolve(reply.value);
216
+ });
217
+ const fail = (error) => {
218
+ clearTimeout(deadline);
219
+ failure = error;
220
+ pending?.reject(error);
221
+ pending = undefined;
222
+ };
223
+ worker.on("error", fail);
224
+ worker.on("exit", (code) => fail(new Error(`chunk embedding writer exited (${code})`)));
225
+ worker.unref();
226
+ let queue = Promise.resolve();
227
+ const request = (message) => {
228
+ const result = queue.then(() => {
229
+ if (failure)
230
+ throw failure;
231
+ return new Promise((resolve, reject) => {
232
+ pending = { resolve, reject };
233
+ deadline = inRootAsyncContext2(() => setTimeout(() => {
234
+ fail(new Error("chunk embedding database operation timed out; coverage will be rechecked"));
235
+ worker.terminate();
236
+ }, 30000));
237
+ deadline.unref();
238
+ worker.postMessage(message);
239
+ });
240
+ });
241
+ queue = result.catch(() => {});
242
+ return result;
243
+ };
244
+ return {
245
+ async replace(rows, sourceKey) {
246
+ if (rows.some((row) => isSynapseEmbeddingTruncated(row.vector)))
247
+ return;
248
+ await request({ kind: "replace", rows, sourceKey });
249
+ },
250
+ project: (project, session) => request({ kind: "project", project, session }),
251
+ count: (project, session, model, tokens) => request({ kind: "count", project, session, model, tokens }),
252
+ candidates: (project, session, model, limit, excluded, tokens) => request({
253
+ kind: "candidates",
254
+ project,
255
+ session,
256
+ model,
257
+ limit,
258
+ excluded,
259
+ tokens
260
+ }),
261
+ backoff: (candidate, project, model) => request({ kind: "backoff", candidate, project, model }),
262
+ acquire: (project, holder) => request({ kind: "acquire", project, holder }),
263
+ renew: (project, holder) => request({ kind: "renew", project, holder }),
264
+ release: (project, holder) => request({ kind: "release", project, holder }),
265
+ async close() {
266
+ clearTimeout(deadline);
267
+ await worker.terminate();
268
+ }
269
+ };
270
+ }
146
271
 
147
272
  // src/features/magic-context/git-commits/storage-git-commit-embeddings.ts
148
273
  var saveStatements = new WeakMap;
@@ -326,141 +451,8 @@ function enforceProjectCap(db, projectPath, maxCommits) {
326
451
  return evicted;
327
452
  }
328
453
 
329
- // src/features/magic-context/git-commits/sweep-coordinator.ts
330
- var GIT_SWEEP_COOLDOWN_MS = 10 * 60 * 1000;
331
- var GIT_SWEEP_LEASE_TTL_MS = 5 * 60 * 1000;
332
- var GIT_SWEEP_NON_INDEXABLE_REPROBE_MS = 24 * 60 * 60 * 1000;
333
- var GIT_SWEEP_LEASE_RENEWAL_MS = 60 * 1000;
334
- function runImmediate(db, body) {
335
- db.exec("BEGIN IMMEDIATE");
336
- const transactionStartedAt = performance.now();
337
- let committed = false;
338
- try {
339
- const result = body();
340
- db.exec("COMMIT");
341
- committed = true;
342
- logSlowWriteTransaction("git_sweep_lease", transactionStartedAt);
343
- return result;
344
- } finally {
345
- if (!committed) {
346
- try {
347
- db.exec("ROLLBACK");
348
- } catch {}
349
- }
350
- }
351
- }
352
- function rowToState(row) {
353
- return {
354
- projectPath: row.project_path,
355
- leaseHolder: row.lease_holder,
356
- leaseExpiresAt: row.lease_expires_at,
357
- lastSweptAt: row.last_swept_at
358
- };
359
- }
360
- function getGitSweepCoordinatorState(db, projectPath) {
361
- const row = db.prepare(`SELECT project_path, lease_holder, lease_expires_at, last_swept_at
362
- FROM git_sweep_coordinator
363
- WHERE project_path = ?`).get(projectPath);
364
- return row ? rowToState(row) : null;
365
- }
366
- function acquireGitSweepLease(db, projectPath, holderId, options = {}) {
367
- const cooldownMs = options.cooldownMs ?? GIT_SWEEP_COOLDOWN_MS;
368
- const leaseTtlMs = options.leaseTtlMs ?? GIT_SWEEP_LEASE_TTL_MS;
369
- return runImmediate(db, () => {
370
- const now = Date.now();
371
- const row = getGitSweepCoordinatorState(db, projectPath);
372
- if (row?.leaseHolder && row.leaseExpiresAt !== null && row.leaseExpiresAt > now) {
373
- return {
374
- acquired: false,
375
- projectPath,
376
- reason: "lease_active",
377
- leaseHolder: row.leaseHolder,
378
- leaseExpiresAt: row.leaseExpiresAt,
379
- lastSweptAt: row.lastSweptAt,
380
- nextAllowedAt: null
381
- };
382
- }
383
- if (!options.ignoreCooldown && row?.lastSweptAt !== null && row?.lastSweptAt !== undefined) {
384
- const nextAllowedAt = row.lastSweptAt + cooldownMs;
385
- if (nextAllowedAt > now) {
386
- return {
387
- acquired: false,
388
- projectPath,
389
- reason: "cooldown_active",
390
- leaseHolder: row.leaseHolder,
391
- leaseExpiresAt: row.leaseExpiresAt,
392
- lastSweptAt: row.lastSweptAt,
393
- nextAllowedAt
394
- };
395
- }
396
- }
397
- const leaseExpiresAt = now + leaseTtlMs;
398
- db.prepare(`INSERT INTO git_sweep_coordinator (
399
- project_path,
400
- lease_holder,
401
- lease_expires_at,
402
- last_swept_at
403
- ) VALUES (?, ?, ?, NULL)
404
- ON CONFLICT(project_path) DO UPDATE SET
405
- lease_holder = excluded.lease_holder,
406
- lease_expires_at = excluded.lease_expires_at`).run(projectPath, holderId, leaseExpiresAt);
407
- return {
408
- acquired: true,
409
- projectPath,
410
- holderId,
411
- acquiredAt: now,
412
- leaseExpiresAt
413
- };
414
- });
415
- }
416
- function renewGitSweepLease(db, projectPath, holderId, leaseTtlMs = GIT_SWEEP_LEASE_TTL_MS) {
417
- return runImmediate(db, () => {
418
- const now = Date.now();
419
- const leaseExpiresAt = now + leaseTtlMs;
420
- const result = db.prepare(`UPDATE git_sweep_coordinator
421
- SET lease_expires_at = ?
422
- WHERE project_path = ?
423
- AND lease_holder = ?
424
- AND lease_expires_at > ?`).run(leaseExpiresAt, projectPath, holderId, now);
425
- return result.changes === 1;
426
- });
427
- }
428
- function markGitSweepSuccessAndRelease(db, projectPath, holderId) {
429
- return runImmediate(db, () => {
430
- const now = Date.now();
431
- const result = db.prepare(`UPDATE git_sweep_coordinator
432
- SET lease_holder = NULL,
433
- lease_expires_at = NULL,
434
- last_swept_at = ?
435
- WHERE project_path = ?
436
- AND lease_holder = ?
437
- AND lease_expires_at > ?`).run(now, projectPath, holderId, now);
438
- return result.changes === 1;
439
- });
440
- }
441
- function parkGitSweepNonIndexable(db, projectPath, holderId, reprobeMs = GIT_SWEEP_NON_INDEXABLE_REPROBE_MS) {
442
- return runImmediate(db, () => {
443
- const now = Date.now();
444
- const sweptAt = now + reprobeMs - GIT_SWEEP_COOLDOWN_MS;
445
- const result = db.prepare(`UPDATE git_sweep_coordinator
446
- SET lease_holder = NULL,
447
- lease_expires_at = NULL,
448
- last_swept_at = ?
449
- WHERE project_path = ?
450
- AND lease_holder = ?
451
- AND lease_expires_at > ?`).run(sweptAt, projectPath, holderId, now);
452
- return result.changes === 1;
453
- });
454
- }
455
- function releaseGitSweepLease(db, projectPath, holderId) {
456
- runImmediate(db, () => {
457
- db.prepare(`UPDATE git_sweep_coordinator
458
- SET lease_holder = NULL,
459
- lease_expires_at = NULL
460
- WHERE project_path = ?
461
- AND lease_holder = ?`).run(projectPath, holderId);
462
- });
463
- }
454
+ // src/features/magic-context/memory/embedding-openai.ts
455
+ import { createHash as createHash2 } from "node:crypto";
464
456
 
465
457
  // src/features/magic-context/memory/embedding-ssrf.ts
466
458
  var METADATA_HOSTNAMES = new Set(["metadata.google.internal", "metadata.goog"]);
@@ -561,6 +553,55 @@ var FAILURE_THRESHOLD = 3;
561
553
  var FAILURE_WINDOW_MS = 60000;
562
554
  var OPEN_DURATION_MS = 5 * 60000;
563
555
  var FETCH_TIMEOUT_MS = 30000;
556
+ var RETRY_AFTER_CAP_MS = 60000;
557
+ var RATE_LIMIT_BACKOFF_BASE_MS = 1000;
558
+ var RATE_LIMIT_BACKOFF_CAP_MS = 30000;
559
+ var RATE_LIMIT_BACKOFF_JITTER = 0.25;
560
+ var rateLimitStates = new Map;
561
+ function rateLimitStateKey(endpoint, apiKey) {
562
+ const keyHash = apiKey ? createHash2("sha256").update(apiKey).digest("hex").slice(0, 16) : "";
563
+ return `${endpoint}\x00${keyHash}`;
564
+ }
565
+ function parseRetryAfterMs(value, nowMs) {
566
+ const trimmed = value?.trim() ?? "";
567
+ if (!trimmed)
568
+ return null;
569
+ let delayMs;
570
+ if (/^\d+(?:\.\d+)?$/.test(trimmed)) {
571
+ delayMs = Number(trimmed) * 1000;
572
+ } else {
573
+ const at = Date.parse(trimmed);
574
+ if (!Number.isFinite(at))
575
+ return null;
576
+ delayMs = at - nowMs;
577
+ }
578
+ if (!(delayMs > 0))
579
+ return null;
580
+ return Math.min(Math.ceil(delayMs), RETRY_AFTER_CAP_MS);
581
+ }
582
+ function rateLimitBackoffMs(consecutive, random = Math.random) {
583
+ const exponent = Math.min(Math.max(0, Math.floor(consecutive)), 30);
584
+ const nominal = Math.min(RATE_LIMIT_BACKOFF_CAP_MS, RATE_LIMIT_BACKOFF_BASE_MS * 2 ** exponent);
585
+ const jitter = Math.min(1, Math.max(0, random())) * RATE_LIMIT_BACKOFF_JITTER;
586
+ return Math.min(RATE_LIMIT_BACKOFF_CAP_MS, Math.round(nominal * (1 + jitter)));
587
+ }
588
+ function sleepUnlessAborted(ms, signal) {
589
+ if (signal?.aborted)
590
+ return Promise.resolve(false);
591
+ return new Promise((resolve) => {
592
+ const onAbort = () => {
593
+ clearTimeout(timer);
594
+ resolve(false);
595
+ };
596
+ const timer = setTimeout(() => {
597
+ signal?.removeEventListener("abort", onAbort);
598
+ resolve(true);
599
+ }, ms);
600
+ signal?.addEventListener("abort", onAbort, { once: true });
601
+ });
602
+ }
603
+ var RATE_LIMITED = Symbol("rate-limited");
604
+ var maxInputTokensWarnings = new Set;
564
605
 
565
606
  class OpenAICompatibleEmbeddingProvider {
566
607
  modelId;
@@ -581,6 +622,7 @@ class OpenAICompatibleEmbeddingProvider {
581
622
  lastFailureReason = null;
582
623
  halfOpenProbeInFlight = false;
583
624
  queryTruncationLogged = false;
625
+ rateLimitKey;
584
626
  constructor(options) {
585
627
  this.endpoint = normalizeEndpoint(options.endpoint);
586
628
  this.model = options.model?.trim() ?? "";
@@ -591,7 +633,16 @@ class OpenAICompatibleEmbeddingProvider {
591
633
  this.queryPrefix = prefixes.queryPrefix;
592
634
  this.documentPrefix = prefixes.documentPrefix;
593
635
  this.truncate = options.truncate?.trim() ?? "";
594
- this.maxInputTokens = typeof options.maxInputTokens === "number" && Number.isFinite(options.maxInputTokens) ? Math.max(1, Math.floor(options.maxInputTokens)) : 512;
636
+ this.rateLimitKey = rateLimitStateKey(this.endpoint, this.apiKey);
637
+ const maxInputTokensSet = typeof options.maxInputTokens === "number" && Number.isFinite(options.maxInputTokens);
638
+ this.maxInputTokens = maxInputTokensSet ? Math.max(1, Math.floor(options.maxInputTokens)) : DEFAULT_COMPARTMENT_CHUNK_MAX_INPUT_TOKENS;
639
+ if (!maxInputTokensSet && this.endpoint && this.model) {
640
+ const warningKey = `${this.endpoint}\x00${this.model}`;
641
+ if (!maxInputTokensWarnings.has(warningKey)) {
642
+ maxInputTokensWarnings.add(warningKey);
643
+ log2(`[magic-context] embedding.max_input_tokens is not set for openai-compatible model "${sanitizeDiagnosticText(this.model)}"; chunk embeddings use the ${DEFAULT_COMPARTMENT_CHUNK_MAX_INPUT_TOKENS}-token default, which is sized for the bundled local model and splits history into small pieces. Set embedding.max_input_tokens to the model's input limit (changing it re-embeds stored chunks once).`);
644
+ }
645
+ }
595
646
  this.modelId = getEmbeddingProviderIdentity({
596
647
  provider: "openai-compatible",
597
648
  endpoint: this.endpoint,
@@ -649,6 +700,23 @@ class OpenAICompatibleEmbeddingProvider {
649
700
  if (signal?.aborted) {
650
701
  return Array.from({ length: texts.length }, () => null);
651
702
  }
703
+ const isQuery = purpose === "query";
704
+ for (;; ) {
705
+ if (Date.now() < this.rateLimit.until) {
706
+ if (isQuery)
707
+ return Array.from({ length: texts.length }, () => null);
708
+ if (!await this.waitForRateLimitCooldown(signal)) {
709
+ return Array.from({ length: texts.length }, () => null);
710
+ }
711
+ }
712
+ const outcome = await this.requestOnce(texts, requestTexts, signal, purpose);
713
+ if (outcome !== RATE_LIMITED)
714
+ return outcome;
715
+ if (isQuery)
716
+ return Array.from({ length: texts.length }, () => null);
717
+ }
718
+ }
719
+ async requestOnce(texts, requestTexts, signal, purpose) {
652
720
  let isProbe = false;
653
721
  let internalController;
654
722
  let timeoutHandle;
@@ -681,9 +749,14 @@ class OpenAICompatibleEmbeddingProvider {
681
749
  redirect: "error",
682
750
  signal: internalController.signal
683
751
  });
752
+ if (response.status === 429) {
753
+ await response.text().catch(() => "");
754
+ this.noteRateLimit(response.headers.get("retry-after"));
755
+ return RATE_LIMITED;
756
+ }
684
757
  if (!response.ok) {
685
758
  const excerpt = await response.text().catch(() => "");
686
- const failure = this.failure("http_error", `HTTP ${response.status} from endpoint${this.bodyExcerpt(excerpt)}`, response.status >= 500 || response.status === 408 || response.status === 429);
759
+ const failure = this.failure("http_error", `HTTP ${response.status} from endpoint${this.bodyExcerpt(excerpt)}`, response.status >= 500 || response.status === 408);
687
760
  log2(`[magic-context] openai-compatible embedding request failed: ${failure.reason}`);
688
761
  this.recordFailure(isProbe, failure);
689
762
  return Array.from({ length: texts.length }, () => null);
@@ -782,6 +855,36 @@ class OpenAICompatibleEmbeddingProvider {
782
855
  isLoaded() {
783
856
  return this.initialized;
784
857
  }
858
+ get rateLimit() {
859
+ let state = rateLimitStates.get(this.rateLimitKey);
860
+ if (!state) {
861
+ state = { until: 0, consecutive: 0 };
862
+ rateLimitStates.set(this.rateLimitKey, state);
863
+ }
864
+ return state;
865
+ }
866
+ async waitForRateLimitCooldown(signal) {
867
+ for (;; ) {
868
+ const remaining = this.rateLimit.until - Date.now();
869
+ if (remaining <= 0)
870
+ return true;
871
+ if (!await sleepUnlessAborted(remaining, signal))
872
+ return false;
873
+ }
874
+ }
875
+ noteRateLimit(retryAfter) {
876
+ const state = this.rateLimit;
877
+ const now = Date.now();
878
+ const headerDelayMs = parseRetryAfterMs(retryAfter, now);
879
+ const delayMs = headerDelayMs ?? rateLimitBackoffMs(state.consecutive);
880
+ state.consecutive += 1;
881
+ const alreadyCoolingDown = now < state.until;
882
+ state.until = Math.max(state.until, now + delayMs);
883
+ const seconds = Math.ceil(delayMs / 1000);
884
+ if (!alreadyCoolingDown) {
885
+ log2(`[magic-context] openai-compatible embedding rate limited (HTTP 429): pausing requests for ${seconds}s (${headerDelayMs !== null ? "Retry-After" : "backoff"}); background embedding resumes after the pause and searches run lexical-only until then`);
886
+ }
887
+ }
785
888
  claimProbeOrShortCircuit() {
786
889
  if (this.circuitOpenUntil === 0) {
787
890
  return "allow";
@@ -836,6 +939,7 @@ class OpenAICompatibleEmbeddingProvider {
836
939
  this.circuitOpenUntil = 0;
837
940
  this.openLogged = false;
838
941
  this.lastFailureReason = null;
942
+ this.rateLimit.consecutive = 0;
839
943
  }
840
944
  getLastFailureReason() {
841
945
  return this.lastFailureReason;
@@ -851,6 +955,9 @@ class OpenAICompatibleEmbeddingProvider {
851
955
  _getFailureCount() {
852
956
  return this.failureTimes.length;
853
957
  }
958
+ _getRateLimitedUntil() {
959
+ return this.rateLimit.until;
960
+ }
854
961
  _resetCircuit() {
855
962
  this.failureTimes = [];
856
963
  this.circuitOpenUntil = 0;
@@ -860,88 +967,6 @@ class OpenAICompatibleEmbeddingProvider {
860
967
  }
861
968
  }
862
969
 
863
- // src/features/magic-context/session-project-storage.ts
864
- var SESSION_CHUNK_REPAIR_BATCH_SIZE = 100;
865
- var upsertSessionProjectStatements = new WeakMap;
866
- var repairSessionChunkProjectStatements = new WeakMap;
867
- var misScopedProjectChunkStatements = new WeakMap;
868
- var MIS_SCOPED_PROJECT_CHUNK_IDS_SQL = `
869
- SELECT e.id FROM compartment_chunk_embeddings e
870
- JOIN session_projects sp ON sp.session_id = e.session_id AND sp.harness = e.harness
871
- WHERE e.project_path = ? AND sp.project_path <> e.project_path
872
- UNION ALL
873
- SELECT e.id FROM session_projects sp
874
- JOIN compartment_chunk_embeddings e ON e.session_id = sp.session_id
875
- WHERE sp.project_path = ? AND e.harness = sp.harness AND e.project_path <> sp.project_path`;
876
- function getUpsertSessionProjectStatement(db) {
877
- let stmt = upsertSessionProjectStatements.get(db);
878
- if (!stmt) {
879
- stmt = db.prepare(`INSERT INTO session_projects (session_id, harness, project_path, updated_at)
880
- VALUES (?, ?, ?, ?)
881
- ON CONFLICT(session_id, harness) DO UPDATE SET
882
- project_path = excluded.project_path,
883
- updated_at = excluded.updated_at
884
- WHERE session_projects.project_path <> excluded.project_path`);
885
- upsertSessionProjectStatements.set(db, stmt);
886
- }
887
- return stmt;
888
- }
889
- function getRepairSessionChunkProjectStatement(db) {
890
- let stmt = repairSessionChunkProjectStatements.get(db);
891
- if (!stmt) {
892
- stmt = db.prepare(`UPDATE compartment_chunk_embeddings
893
- SET project_path = ?
894
- WHERE id IN (
895
- SELECT id
896
- FROM compartment_chunk_embeddings
897
- WHERE session_id = ?
898
- AND harness = ?
899
- AND project_path <> ?
900
- LIMIT ?
901
- )`);
902
- repairSessionChunkProjectStatements.set(db, stmt);
903
- }
904
- return stmt;
905
- }
906
- function findMisScopedCompartmentChunkEmbeddingIdsForProject(db, projectPath) {
907
- return db.prepare(`SELECT id FROM (${MIS_SCOPED_PROJECT_CHUNK_IDS_SQL}) LIMIT 25`).all(projectPath, projectPath).map(({ id }) => id);
908
- }
909
- function recordSessionProjectIdentity(db, sessionId, projectPath) {
910
- if (!sessionId || !projectPath)
911
- return;
912
- if (!projectPath.startsWith("git:") && !projectPath.startsWith("dir:") && isUserHomeDirectory(projectPath))
913
- return;
914
- const harness = getHarness2();
915
- const now = Date.now();
916
- let previousProjectPath;
917
- db.transaction(() => {
918
- const existing = db.prepare("SELECT project_path FROM session_projects WHERE session_id = ? AND harness = ?").get(sessionId, harness);
919
- previousProjectPath = existing?.project_path;
920
- getUpsertSessionProjectStatement(db).run(sessionId, harness, projectPath, now);
921
- getRepairSessionChunkProjectStatement(db).run(projectPath, sessionId, harness, projectPath, SESSION_CHUNK_REPAIR_BATCH_SIZE);
922
- }).immediate();
923
- return previousProjectPath === projectPath ? undefined : { previousProjectPath, projectPath };
924
- }
925
- function hasRecordedSessionProjectIdentity(db, sessionId) {
926
- const row = db.prepare("SELECT 1 AS found FROM session_projects WHERE session_id = ? AND harness = ?").get(sessionId, getHarness2());
927
- return row?.found === 1;
928
- }
929
- function repairMisScopedCompartmentChunkEmbeddingsForProject(db, projectPath, ids = findMisScopedCompartmentChunkEmbeddingIdsForProject(db, projectPath)) {
930
- if (!projectPath || ids.length === 0)
931
- return 0;
932
- return db.prepare(`UPDATE compartment_chunk_embeddings
933
- SET project_path = (SELECT sp.project_path FROM session_projects sp
934
- WHERE sp.session_id = compartment_chunk_embeddings.session_id
935
- AND sp.harness = compartment_chunk_embeddings.harness)
936
- WHERE id IN (${ids.map(() => "?").join(",")}) AND EXISTS (
937
- SELECT 1 FROM session_projects sp
938
- WHERE sp.session_id = compartment_chunk_embeddings.session_id
939
- AND sp.harness = compartment_chunk_embeddings.harness
940
- AND sp.project_path <> compartment_chunk_embeddings.project_path
941
- AND (sp.project_path = ? OR compartment_chunk_embeddings.project_path = ?)
942
- )`).run(...ids, projectPath, projectPath).changes;
943
- }
944
-
945
970
  // src/features/magic-context/shadow-backfill-state.ts
946
971
  var SHADOW_BACKFILL_PROVENANCE_KEY = "_magicContextShadowBackfill";
947
972
  function parseJsonRecord(value) {
@@ -1305,10 +1330,10 @@ function stableStringify(value) {
1305
1330
  return JSON.stringify(value);
1306
1331
  }
1307
1332
  function sha256Prefix(value, length = 16) {
1308
- return createHash2("sha256").update(value).digest("hex").slice(0, length);
1333
+ return createHash3("sha256").update(value).digest("hex").slice(0, length);
1309
1334
  }
1310
1335
  function contentSha2562(value) {
1311
- return createHash2("sha256").update(value).digest("hex");
1336
+ return createHash3("sha256").update(value).digest("hex");
1312
1337
  }
1313
1338
  function getRuntimeFingerprint(config) {
1314
1339
  if (config.provider === "off") {
@@ -2632,22 +2657,31 @@ async function drainCommitBacklogForProject2(db, projectIdentity, deadline) {
2632
2657
  }
2633
2658
  return total;
2634
2659
  }
2635
- async function embedCompartmentChunkBatch(db, projectIdentity, batchSize) {
2660
+ async function embedCompartmentChunkBatch(db, projectIdentity, batchSize, signal) {
2636
2661
  const snapshot = getProjectEmbeddingSnapshot2(projectIdentity);
2637
2662
  if (!snapshot?.historyEnabled || snapshot.chunkModelId === "off")
2638
2663
  return 0;
2639
2664
  repairMisScopedCompartmentChunkEmbeddingsForProject(db, projectIdentity);
2640
- const candidates = await loadUnembeddedCompartmentChunkCandidatesPolite(db, projectIdentity, snapshot.chunkModelId, batchSize, getProjectEmbeddingMaxInputTokens2(projectIdentity), true);
2665
+ const priorModels = db.prepare(`SELECT COUNT(*) AS total,
2666
+ COALESCE(MAX(model_id = ?), 0) AS current
2667
+ FROM compartment_chunk_embeddings WHERE compartment_id = ?`);
2668
+ const candidates = await loadUnembeddedCompartmentChunkCandidatesPolite(db, projectIdentity, snapshot.chunkModelId, batchSize, getProjectEmbeddingMaxInputTokens2(projectIdentity), true, (candidate) => {
2669
+ const activity = activeEmbeddingSessions.get(candidate.sessionId);
2670
+ if (activity?.project === projectIdentity && activity.model === snapshot.chunkModelId && !embedPauseBySession.has(candidate.sessionId))
2671
+ return true;
2672
+ const prior = priorModels.get(snapshot.chunkModelId, candidate.id);
2673
+ return prior.total === 0 || prior.current !== 0;
2674
+ });
2641
2675
  if (candidates.length === 0)
2642
2676
  return 0;
2643
- const { embedded } = await embedCandidateChunkBatch(db, projectIdentity, snapshot.chunkModelId, candidates);
2677
+ const { embedded } = await embedCandidateChunkBatch(db, projectIdentity, snapshot.chunkModelId, candidates, signal);
2644
2678
  return embedded;
2645
2679
  }
2646
2680
  function getLastEmbeddingFailureForProject(projectIdentity) {
2647
2681
  const registration = projectRegistrations.get(projectIdentity);
2648
2682
  return registration?.provider?.getLastFailureReason?.() ?? null;
2649
2683
  }
2650
- async function embedCandidateChunkBatch(db, projectIdentity, modelId, candidates, signal) {
2684
+ async function embedCandidateChunkBatch(db, projectIdentity, modelId, candidates, signal, writer) {
2651
2685
  const noWork = [];
2652
2686
  const failed = [];
2653
2687
  const failureReasons = [];
@@ -2662,7 +2696,10 @@ async function embedCandidateChunkBatch(db, projectIdentity, modelId, candidates
2662
2696
  continue;
2663
2697
  const canonicalText = mappedText || buildCompartmentSummaryFallbackText(db, candidate.id);
2664
2698
  if (canonicalText.length === 0) {
2665
- recordChunkEmbedBackoff(db, candidate, projectIdentity, modelId);
2699
+ if (writer)
2700
+ await writer.backoff(candidate, projectIdentity, modelId);
2701
+ else
2702
+ recordChunkEmbedBackoff(db, candidate, projectIdentity, modelId);
2666
2703
  noWork.push(candidate.id);
2667
2704
  continue;
2668
2705
  }
@@ -2719,6 +2756,8 @@ async function embedCandidateChunkBatch(db, projectIdentity, modelId, candidates
2719
2756
  if (result) {
2720
2757
  let writeSliceStarted = performance.now();
2721
2758
  for (const item of slice) {
2759
+ if (signal?.aborted || getProjectChunkEmbeddingModelId2(projectIdentity) !== modelId)
2760
+ break;
2722
2761
  if (persistedIds.has(item.candidate.id))
2723
2762
  continue;
2724
2763
  const vectors = item.windows.map((window) => result.vectors.get(`chunk:${item.candidate.id}:${window.windowIndex}`));
@@ -2733,7 +2772,10 @@ async function embedCandidateChunkBatch(db, projectIdentity, modelId, candidates
2733
2772
  modelId,
2734
2773
  vector: vectors[index]
2735
2774
  }));
2736
- replaceCompartmentChunkEmbeddings(db, rows, item.windowSourceKey);
2775
+ if (writer)
2776
+ await writer.replace(rows, item.windowSourceKey);
2777
+ else
2778
+ replaceCompartmentChunkEmbeddings(db, rows, item.windowSourceKey);
2737
2779
  persistedIds.add(item.candidate.id);
2738
2780
  enqueueShadowEmbeddingItems2(projectIdentity, "chunk", [
2739
2781
  String(item.candidate.id)
@@ -2758,7 +2800,10 @@ async function embedCandidateChunkBatch(db, projectIdentity, modelId, candidates
2758
2800
  if (!signal?.aborted) {
2759
2801
  for (const item of slice) {
2760
2802
  if (!persistedIds.has(item.candidate.id)) {
2761
- recordChunkEmbedBackoff(db, item.candidate, projectIdentity, modelId);
2803
+ if (writer)
2804
+ await writer.backoff(item.candidate, projectIdentity, modelId);
2805
+ else
2806
+ recordChunkEmbedBackoff(db, item.candidate, projectIdentity, modelId);
2762
2807
  failed.push(item.candidate.id);
2763
2808
  }
2764
2809
  }
@@ -2777,6 +2822,9 @@ async function drainCompartmentChunkBacklogForProject(db, projectIdentity, deadl
2777
2822
  }
2778
2823
  let total = 0;
2779
2824
  let leaseLost = false;
2825
+ const drainAbort = new AbortController;
2826
+ const deadlineTimer = setTimeout(() => drainAbort.abort(), Math.max(0, deadline - Date.now()));
2827
+ deadlineTimer.unref?.();
2780
2828
  const renewal = inRootAsyncContext2(() => setInterval(() => {
2781
2829
  try {
2782
2830
  if (!renewGitSweepLease(db, projectIdentity, holderId))
@@ -2785,8 +2833,8 @@ async function drainCompartmentChunkBacklogForProject(db, projectIdentity, deadl
2785
2833
  }, SESSION_EMBED_LEASE_RENEWAL_MS));
2786
2834
  renewal.unref?.();
2787
2835
  try {
2788
- while (!leaseLost && !isEmbeddingHostBusy2() && Date.now() < deadline && total < CHUNK_DRAIN_MAX_PER_SWEEP) {
2789
- const embedded = await embedCompartmentChunkBatch(db, projectIdentity, CHUNK_DRAIN_BATCH_SIZE);
2836
+ while (!leaseLost && !drainAbort.signal.aborted && !isEmbeddingHostBusy2() && Date.now() < deadline && total < CHUNK_DRAIN_MAX_PER_SWEEP) {
2837
+ const embedded = await embedCompartmentChunkBatch(db, projectIdentity, CHUNK_DRAIN_BATCH_SIZE, drainAbort.signal);
2790
2838
  if (!renewGitSweepLease(db, projectIdentity, holderId))
2791
2839
  leaseLost = true;
2792
2840
  if (leaseLost || embedded === 0)
@@ -2796,6 +2844,7 @@ async function drainCompartmentChunkBacklogForProject(db, projectIdentity, deadl
2796
2844
  break;
2797
2845
  }
2798
2846
  } finally {
2847
+ clearTimeout(deadlineTimer);
2799
2848
  clearInterval(renewal);
2800
2849
  releaseGitSweepLease(db, projectIdentity, holderId);
2801
2850
  }
@@ -2809,11 +2858,28 @@ async function embedSessionCompartmentChunks2(db, projectIdentity, sessionId, op
2809
2858
  if (!snapshot?.historyEnabled || snapshot.chunkModelId === "off") {
2810
2859
  return { status: "disabled", embedded: 0, total: 0 };
2811
2860
  }
2812
- recordSessionProjectIdentity(db, sessionId, projectIdentity);
2861
+ if (options?.automatic && !options.databaseWorker) {
2862
+ const worker = createChunkEmbeddingWriter(db);
2863
+ if (worker) {
2864
+ try {
2865
+ return await embedSessionCompartmentChunks2(db, projectIdentity, sessionId, {
2866
+ ...options,
2867
+ databaseWorker: worker
2868
+ });
2869
+ } finally {
2870
+ await worker.close();
2871
+ }
2872
+ }
2873
+ }
2874
+ const writer = options?.databaseWorker ?? null;
2875
+ if (writer)
2876
+ await writer.project(projectIdentity, sessionId);
2877
+ else
2878
+ recordSessionProjectIdentity(db, sessionId, projectIdentity);
2813
2879
  const maxInputTokens = getProjectEmbeddingMaxInputTokens2(projectIdentity);
2814
- const total = await countUnembeddedSessionCompartmentsPolite(db, projectIdentity, sessionId, snapshot.chunkModelId, maxInputTokens);
2880
+ const total = writer ? await writer.count(projectIdentity, sessionId, snapshot.chunkModelId, maxInputTokens) : await countUnembeddedSessionCompartmentsPolite(db, projectIdentity, sessionId, snapshot.chunkModelId, maxInputTokens);
2815
2881
  const holderId = `session-embed-${randomUUID()}`;
2816
- const lease = acquireGitSweepLease(db, projectIdentity, holderId, { ignoreCooldown: true });
2882
+ const lease = writer ? await writer.acquire(projectIdentity, holderId) : acquireGitSweepLease(db, projectIdentity, holderId, { ignoreCooldown: true });
2817
2883
  if (!lease.acquired)
2818
2884
  return { status: "busy", embedded: 0, total };
2819
2885
  let leaseLost = false;
@@ -2823,9 +2889,9 @@ async function embedSessionCompartmentChunks2(db, projectIdentity, sessionId, op
2823
2889
  drainAbort.abort();
2824
2890
  else
2825
2891
  options?.signal?.addEventListener("abort", forwardCallerAbort, { once: true });
2826
- const renewal = inRootAsyncContext2(() => setInterval(() => {
2892
+ const renewal = inRootAsyncContext2(() => setInterval(async () => {
2827
2893
  try {
2828
- if (!renewGitSweepLease(db, projectIdentity, holderId)) {
2894
+ if (!(writer ? await writer.renew(projectIdentity, holderId) : renewGitSweepLease(db, projectIdentity, holderId))) {
2829
2895
  leaseLost = true;
2830
2896
  drainAbort.abort();
2831
2897
  }
@@ -2843,11 +2909,18 @@ async function embedSessionCompartmentChunks2(db, projectIdentity, sessionId, op
2843
2909
  try {
2844
2910
  options?.onProgress?.({ embedded, total });
2845
2911
  for (;; ) {
2846
- if (leaseLost || drainAbort.signal.aborted || isEmbeddingHostBusy2()) {
2912
+ if (leaseLost || drainAbort.signal.aborted || !options?.automatic && isEmbeddingHostBusy2() || getProjectEmbeddingSnapshot2(projectIdentity)?.generation !== snapshot.generation) {
2847
2913
  aborted = true;
2848
2914
  break;
2849
2915
  }
2850
- const candidates = await loadUnembeddedSessionChunkCandidatesPolite(db, projectIdentity, sessionId, snapshot.chunkModelId, batchSize, [...skipIds, ...failedIds], maxInputTokens, true);
2916
+ if (options?.automatic && isEmbeddingHostBusy2()) {
2917
+ await new Promise((resolve) => setTimeout(resolve, 100));
2918
+ if (drainAbort.signal.aborted) {
2919
+ aborted = true;
2920
+ break;
2921
+ }
2922
+ }
2923
+ const candidates = writer ? await writer.candidates(projectIdentity, sessionId, snapshot.chunkModelId, batchSize, [...skipIds, ...failedIds], maxInputTokens) : await loadUnembeddedSessionChunkCandidatesPolite(db, projectIdentity, sessionId, snapshot.chunkModelId, batchSize, [...skipIds, ...failedIds], maxInputTokens, true);
2851
2924
  if (candidates.length === 0)
2852
2925
  break;
2853
2926
  const {
@@ -2855,8 +2928,8 @@ async function embedSessionCompartmentChunks2(db, projectIdentity, sessionId, op
2855
2928
  noWork,
2856
2929
  failed,
2857
2930
  failureReasons: batchFailureReasons
2858
- } = await embedCandidateChunkBatch(db, projectIdentity, snapshot.chunkModelId, candidates, drainAbort.signal);
2859
- if (leaseLost || !renewGitSweepLease(db, projectIdentity, holderId)) {
2931
+ } = await embedCandidateChunkBatch(db, projectIdentity, snapshot.chunkModelId, candidates, drainAbort.signal, writer);
2932
+ if (leaseLost || !(writer ? await writer.renew(projectIdentity, holderId) : renewGitSweepLease(db, projectIdentity, holderId))) {
2860
2933
  leaseLost = true;
2861
2934
  drainAbort.abort();
2862
2935
  aborted = true;
@@ -2884,7 +2957,10 @@ async function embedSessionCompartmentChunks2(db, projectIdentity, sessionId, op
2884
2957
  clearInterval(renewal);
2885
2958
  options?.signal?.removeEventListener("abort", forwardCallerAbort);
2886
2959
  try {
2887
- releaseGitSweepLease(db, projectIdentity, holderId);
2960
+ if (writer)
2961
+ await writer.release(projectIdentity, holderId);
2962
+ else
2963
+ releaseGitSweepLease(db, projectIdentity, holderId);
2888
2964
  } catch (error) {
2889
2965
  log2("[magic-context] embed drain: lease release failed (will TTL-expire):", error);
2890
2966
  }
@@ -2894,7 +2970,7 @@ async function embedSessionCompartmentChunks2(db, projectIdentity, sessionId, op
2894
2970
  if (aborted)
2895
2971
  return { status: "aborted", embedded, total, failed: failedIds.length };
2896
2972
  if (providerDown || failedIds.length > 0) {
2897
- const remaining = Math.max(failedIds.length, await countUnembeddedSessionCompartmentsPolite(db, projectIdentity, sessionId, snapshot.chunkModelId, maxInputTokens) - skipIds.length);
2973
+ const remaining = Math.max(failedIds.length, (writer ? await writer.count(projectIdentity, sessionId, snapshot.chunkModelId, maxInputTokens) : await countUnembeddedSessionCompartmentsPolite(db, projectIdentity, sessionId, snapshot.chunkModelId, maxInputTokens)) - skipIds.length);
2898
2974
  if (remaining > 0) {
2899
2975
  return {
2900
2976
  status: "stalled",
@@ -3029,4 +3105,4 @@ function _resetProjectEmbeddingRegistryForTests2() {
3029
3105
  setBootQuietPeriodForTests(null);
3030
3106
  }
3031
3107
 
3032
- export { drainBackgroundBatches, recordEmbeddingMeasurement, saveCommitEmbedding, loadProjectCommitEmbeddings, loadUnembeddedCommits, countEmbeddedCommits, upsertCommits, getLatestIndexedCommitSha, enforceProjectCap, GIT_SWEEP_LEASE_RENEWAL_MS, acquireGitSweepLease, renewGitSweepLease, markGitSweepSuccessAndRelease, parkGitSweepNonIndexable, releaseGitSweepLease, OpenAICompatibleEmbeddingProvider, recordSessionProjectIdentity, hasRecordedSessionProjectIdentity, describeShadowBackfillWriteRefusal2, listShadowBackfillStalls2, getShadowBackfillStopReason2, markProjectLoadUntrusted2, contentSha2562, drainProjectEmbeddingIdentityMaintenance2, drainStaleEmbeddingIdentitiesForProject2, registerProjectEmbedding2, registerProjectShadowEmbedding2, getShadowEmbeddingMeasurementCohort2, getPrimaryEmbeddingMeasurementCohort2, embedShadowTextForProject2, enqueueShadowEmbeddingItems2, getShadowBackfillRemaining2, flushShadowEmbeddingBacklog2, registerProjectInObservationMode2, unregisterProjectShadowEmbedding2, unregisterProjectEmbedding2, getProjectEmbeddingSnapshot2, installProjectEmbeddingSearchBridge2, getProjectChunkEmbeddingModelId2, getProjectEmbeddingMaxInputTokens2, embedTextForProject2, embedBatchForProject2, embedItemsForProject2, embedUnembeddedMemoriesForProject2, embedUnembeddedMemoriesForProjectOutcome2, drainCommitBacklogForProject2, embedUnembeddedCompartmentChunksForProject2, embedSessionCompartmentChunks2, getEmbeddingCoverageStatus2, getAutoEmbeddingSessionCoverage2, sweepAllRegisteredProjects2, _setTestProviderFactoryForProject2, _resetProjectEmbeddingRegistryForTests2 };
3108
+ export { embedPauseBySession, embedRunStateBySession, activeEmbeddingSessions, autoEmbedAttemptedBySession, autoEmbedIdentityBySession, autoEmbedRetryAfterBySession, invalidateAutoEmbedSession, getEmbedDrainUiStatus, clearEmbedSessionState, drainBackgroundBatches, recordEmbeddingMeasurement, saveCommitEmbedding, loadProjectCommitEmbeddings, loadUnembeddedCommits, countEmbeddedCommits, upsertCommits, getLatestIndexedCommitSha, enforceProjectCap, OpenAICompatibleEmbeddingProvider, describeShadowBackfillWriteRefusal2, listShadowBackfillStalls2, getShadowBackfillStopReason2, markProjectLoadUntrusted2, contentSha2562, drainProjectEmbeddingIdentityMaintenance2, drainStaleEmbeddingIdentitiesForProject2, registerProjectEmbedding2, registerProjectShadowEmbedding2, getShadowEmbeddingMeasurementCohort2, getPrimaryEmbeddingMeasurementCohort2, embedShadowTextForProject2, enqueueShadowEmbeddingItems2, getShadowBackfillRemaining2, flushShadowEmbeddingBacklog2, registerProjectInObservationMode2, unregisterProjectShadowEmbedding2, unregisterProjectEmbedding2, getProjectEmbeddingSnapshot2, installProjectEmbeddingSearchBridge2, getProjectChunkEmbeddingModelId2, getProjectEmbeddingMaxInputTokens2, embedTextForProject2, embedBatchForProject2, embedItemsForProject2, embedUnembeddedMemoriesForProject2, embedUnembeddedMemoriesForProjectOutcome2, drainCommitBacklogForProject2, embedUnembeddedCompartmentChunksForProject2, embedSessionCompartmentChunks2, getEmbeddingCoverageStatus2, getAutoEmbeddingSessionCoverage2, sweepAllRegisteredProjects2, _setTestProviderFactoryForProject2, _resetProjectEmbeddingRegistryForTests2 };