@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,30 +1,28 @@
1
- import {
2
- getHarness2
3
- } from "./index-pavzsdc6.js";
4
- import {
5
- sanitizeDiagnosticText,
6
- log2
7
- } from "./index-mvvephtj.js";
8
- import {
9
- isUserHomeDirectory,
10
- setBootQuietPeriodForTests
11
- } from "./index-0jz47061.js";
12
1
  import {
13
2
  inRootAsyncContext2,
3
+ getSqliteDatabasePath2,
14
4
  withSqliteBackgroundWriter2,
15
5
  withoutSqliteTransformPass2,
16
6
  isTransientSqliteError2
17
7
  } from "./index-wafzvyhg.js";
18
8
  import {
19
9
  estimateTokens
20
- } from "./index-gjvjh960.js";
10
+ } from "./index-hqkczed7.js";
11
+ import {
12
+ getHarness2
13
+ } from "./index-pavzsdc6.js";
14
+ import {
15
+ sanitizeDiagnosticText,
16
+ log2
17
+ } from "./index-j75v2476.js";
21
18
  import {
22
19
  SYNAPSE_DEFAULT_MODEL,
23
20
  isSynapseEmbeddingTruncated,
24
21
  getSynapseBatchRequestKey,
25
22
  SynapseEmbeddingProvider
26
- } from "./index-kvw6xew3.js";
23
+ } from "./index-fkx2qnvw.js";
27
24
  import {
25
+ DEFAULT_COMPARTMENT_CHUNK_MAX_INPUT_TOKENS,
28
26
  CHUNK_WINDOW_SAFETY_RATIO,
29
27
  normalizeCompartmentChunkMaxInputTokens,
30
28
  buildCanonicalChunkTextFromFts,
@@ -40,20 +38,31 @@ import {
40
38
  countSessionCompartmentEmbedCoverage,
41
39
  countSessionCompartmentEmbedCoveragePolite,
42
40
  countUnembeddedSessionCompartmentsPolite
43
- } from "./index-9159kk15.js";
41
+ } from "./index-3kx0kg0f.js";
44
42
  import {
45
43
  DEFAULT_LOCAL_EMBEDDING_MODEL
46
- } from "./index-w28y7d0z.js";
44
+ } from "./index-1sarmj9z.js";
47
45
  import {
48
46
  embeddingModelsMatch,
49
47
  resolveEmbeddingTextPrefixes,
50
48
  getEmbeddingProviderIdentity,
51
49
  dominantEmbeddingFailure,
52
50
  LocalEmbeddingProvider
53
- } from "./index-bmwfzz28.js";
51
+ } from "./index-e20m7284.js";
52
+ import {
53
+ setBootQuietPeriodForTests
54
+ } from "./index-a8bvhwqs.js";
54
55
  import {
55
56
  isEmbeddingHostBusy2
56
57
  } from "./index-qt1qqasc.js";
58
+ import {
59
+ findMisScopedCompartmentChunkEmbeddingIdsForProject,
60
+ recordSessionProjectIdentity,
61
+ repairMisScopedCompartmentChunkEmbeddingsForProject,
62
+ acquireGitSweepLease,
63
+ renewGitSweepLease,
64
+ releaseGitSweepLease
65
+ } from "./index-saews2s3.js";
57
66
  import {
58
67
  saveEmbeddingIfHashMatches,
59
68
  getMemoryEmbedCoverage,
@@ -61,88 +70,44 @@ import {
61
70
  } from "./index-4dhv7mqz.js";
62
71
  import {
63
72
  logSlowWriteTransaction
64
- } from "./index-150zz6fh.js";
73
+ } from "./index-k29z4aqh.js";
65
74
 
66
- // src/features/magic-context/session-project-storage.ts
67
- var SESSION_CHUNK_REPAIR_BATCH_SIZE = 100;
68
- var upsertSessionProjectStatements = new WeakMap;
69
- var repairSessionChunkProjectStatements = new WeakMap;
70
- var misScopedProjectChunkStatements = new WeakMap;
71
- var MIS_SCOPED_PROJECT_CHUNK_IDS_SQL = `
72
- SELECT e.id FROM compartment_chunk_embeddings e
73
- JOIN session_projects sp ON sp.session_id = e.session_id AND sp.harness = e.harness
74
- WHERE e.project_path = ? AND sp.project_path <> e.project_path
75
- UNION ALL
76
- SELECT e.id FROM session_projects sp
77
- JOIN compartment_chunk_embeddings e ON e.session_id = sp.session_id
78
- WHERE sp.project_path = ? AND e.harness = sp.harness AND e.project_path <> sp.project_path`;
79
- function getUpsertSessionProjectStatement(db) {
80
- let stmt = upsertSessionProjectStatements.get(db);
81
- if (!stmt) {
82
- stmt = db.prepare(`INSERT INTO session_projects (session_id, harness, project_path, updated_at)
83
- VALUES (?, ?, ?, ?)
84
- ON CONFLICT(session_id, harness) DO UPDATE SET
85
- project_path = excluded.project_path,
86
- updated_at = excluded.updated_at
87
- WHERE session_projects.project_path <> excluded.project_path`);
88
- upsertSessionProjectStatements.set(db, stmt);
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
+ }
89
99
  }
90
- return stmt;
100
+ return { status: "idle" };
91
101
  }
92
- function getRepairSessionChunkProjectStatement(db) {
93
- let stmt = repairSessionChunkProjectStatements.get(db);
94
- if (!stmt) {
95
- stmt = db.prepare(`UPDATE compartment_chunk_embeddings
96
- SET project_path = ?
97
- WHERE id IN (
98
- SELECT id
99
- FROM compartment_chunk_embeddings
100
- WHERE session_id = ?
101
- AND harness = ?
102
- AND project_path <> ?
103
- LIMIT ?
104
- )`);
105
- repairSessionChunkProjectStatements.set(db, stmt);
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);
106
109
  }
107
- return stmt;
108
- }
109
- function findMisScopedCompartmentChunkEmbeddingIdsForProject(db, projectPath) {
110
- return db.prepare(`SELECT id FROM (${MIS_SCOPED_PROJECT_CHUNK_IDS_SQL}) LIMIT 25`).all(projectPath, projectPath).map(({ id }) => id);
111
- }
112
- function recordSessionProjectIdentity(db, sessionId, projectPath) {
113
- if (!sessionId || !projectPath)
114
- return;
115
- if (!projectPath.startsWith("git:") && !projectPath.startsWith("dir:") && isUserHomeDirectory(projectPath))
116
- return;
117
- const harness = getHarness2();
118
- const now = Date.now();
119
- let previousProjectPath;
120
- db.transaction(() => {
121
- const existing = db.prepare("SELECT project_path FROM session_projects WHERE session_id = ? AND harness = ?").get(sessionId, harness);
122
- previousProjectPath = existing?.project_path;
123
- getUpsertSessionProjectStatement(db).run(sessionId, harness, projectPath, now);
124
- getRepairSessionChunkProjectStatement(db).run(projectPath, sessionId, harness, projectPath, SESSION_CHUNK_REPAIR_BATCH_SIZE);
125
- }).immediate();
126
- return previousProjectPath === projectPath ? undefined : { previousProjectPath, projectPath };
127
- }
128
- function hasRecordedSessionProjectIdentity(db, sessionId) {
129
- const row = db.prepare("SELECT 1 AS found FROM session_projects WHERE session_id = ? AND harness = ?").get(sessionId, getHarness2());
130
- return row?.found === 1;
131
- }
132
- function repairMisScopedCompartmentChunkEmbeddingsForProject(db, projectPath, ids = findMisScopedCompartmentChunkEmbeddingIdsForProject(db, projectPath)) {
133
- if (!projectPath || ids.length === 0)
134
- return 0;
135
- return db.prepare(`UPDATE compartment_chunk_embeddings
136
- SET project_path = (SELECT sp.project_path FROM session_projects sp
137
- WHERE sp.session_id = compartment_chunk_embeddings.session_id
138
- AND sp.harness = compartment_chunk_embeddings.harness)
139
- WHERE id IN (${ids.map(() => "?").join(",")}) AND EXISTS (
140
- SELECT 1 FROM session_projects sp
141
- WHERE sp.session_id = compartment_chunk_embeddings.session_id
142
- AND sp.harness = compartment_chunk_embeddings.harness
143
- AND sp.project_path <> compartment_chunk_embeddings.project_path
144
- AND (sp.project_path = ? OR compartment_chunk_embeddings.project_path = ?)
145
- )`).run(...ids, projectPath, projectPath).changes;
110
+ invalidateAutoEmbedSession(sessionId);
146
111
  }
147
112
 
148
113
  // src/shared/background-batch-drain.ts
@@ -223,6 +188,9 @@ function pruneSynapseBatchLedgerForProject(db, projectIdentity, ttlMs = SYNAPSE_
223
188
  return db.prepare(`DELETE FROM synapse_batch_ledger WHERE ${predicate}`).run(projectIdentity, shadow, cutoff).changes;
224
189
  }
225
190
 
191
+ // src/features/magic-context/memory/embedding-openai.ts
192
+ import { createHash as createHash2 } from "node:crypto";
193
+
226
194
  // src/features/magic-context/memory/embedding-ssrf.ts
227
195
  var METADATA_HOSTNAMES = new Set(["metadata.google.internal", "metadata.goog"]);
228
196
  var IPV6_METADATA_HOSTS = new Set(["fd00:ec2::254"]);
@@ -322,6 +290,55 @@ var FAILURE_THRESHOLD = 3;
322
290
  var FAILURE_WINDOW_MS = 60000;
323
291
  var OPEN_DURATION_MS = 5 * 60000;
324
292
  var FETCH_TIMEOUT_MS = 30000;
293
+ var RETRY_AFTER_CAP_MS = 60000;
294
+ var RATE_LIMIT_BACKOFF_BASE_MS = 1000;
295
+ var RATE_LIMIT_BACKOFF_CAP_MS = 30000;
296
+ var RATE_LIMIT_BACKOFF_JITTER = 0.25;
297
+ var rateLimitStates = new Map;
298
+ function rateLimitStateKey(endpoint, apiKey) {
299
+ const keyHash = apiKey ? createHash2("sha256").update(apiKey).digest("hex").slice(0, 16) : "";
300
+ return `${endpoint}\x00${keyHash}`;
301
+ }
302
+ function parseRetryAfterMs(value, nowMs) {
303
+ const trimmed = value?.trim() ?? "";
304
+ if (!trimmed)
305
+ return null;
306
+ let delayMs;
307
+ if (/^\d+(?:\.\d+)?$/.test(trimmed)) {
308
+ delayMs = Number(trimmed) * 1000;
309
+ } else {
310
+ const at = Date.parse(trimmed);
311
+ if (!Number.isFinite(at))
312
+ return null;
313
+ delayMs = at - nowMs;
314
+ }
315
+ if (!(delayMs > 0))
316
+ return null;
317
+ return Math.min(Math.ceil(delayMs), RETRY_AFTER_CAP_MS);
318
+ }
319
+ function rateLimitBackoffMs(consecutive, random = Math.random) {
320
+ const exponent = Math.min(Math.max(0, Math.floor(consecutive)), 30);
321
+ const nominal = Math.min(RATE_LIMIT_BACKOFF_CAP_MS, RATE_LIMIT_BACKOFF_BASE_MS * 2 ** exponent);
322
+ const jitter = Math.min(1, Math.max(0, random())) * RATE_LIMIT_BACKOFF_JITTER;
323
+ return Math.min(RATE_LIMIT_BACKOFF_CAP_MS, Math.round(nominal * (1 + jitter)));
324
+ }
325
+ function sleepUnlessAborted(ms, signal) {
326
+ if (signal?.aborted)
327
+ return Promise.resolve(false);
328
+ return new Promise((resolve) => {
329
+ const onAbort = () => {
330
+ clearTimeout(timer);
331
+ resolve(false);
332
+ };
333
+ const timer = setTimeout(() => {
334
+ signal?.removeEventListener("abort", onAbort);
335
+ resolve(true);
336
+ }, ms);
337
+ signal?.addEventListener("abort", onAbort, { once: true });
338
+ });
339
+ }
340
+ var RATE_LIMITED = Symbol("rate-limited");
341
+ var maxInputTokensWarnings = new Set;
325
342
 
326
343
  class OpenAICompatibleEmbeddingProvider {
327
344
  modelId;
@@ -342,6 +359,7 @@ class OpenAICompatibleEmbeddingProvider {
342
359
  lastFailureReason = null;
343
360
  halfOpenProbeInFlight = false;
344
361
  queryTruncationLogged = false;
362
+ rateLimitKey;
345
363
  constructor(options) {
346
364
  this.endpoint = normalizeEndpoint(options.endpoint);
347
365
  this.model = options.model?.trim() ?? "";
@@ -352,7 +370,16 @@ class OpenAICompatibleEmbeddingProvider {
352
370
  this.queryPrefix = prefixes.queryPrefix;
353
371
  this.documentPrefix = prefixes.documentPrefix;
354
372
  this.truncate = options.truncate?.trim() ?? "";
355
- this.maxInputTokens = typeof options.maxInputTokens === "number" && Number.isFinite(options.maxInputTokens) ? Math.max(1, Math.floor(options.maxInputTokens)) : 512;
373
+ this.rateLimitKey = rateLimitStateKey(this.endpoint, this.apiKey);
374
+ const maxInputTokensSet = typeof options.maxInputTokens === "number" && Number.isFinite(options.maxInputTokens);
375
+ this.maxInputTokens = maxInputTokensSet ? Math.max(1, Math.floor(options.maxInputTokens)) : DEFAULT_COMPARTMENT_CHUNK_MAX_INPUT_TOKENS;
376
+ if (!maxInputTokensSet && this.endpoint && this.model) {
377
+ const warningKey = `${this.endpoint}\x00${this.model}`;
378
+ if (!maxInputTokensWarnings.has(warningKey)) {
379
+ maxInputTokensWarnings.add(warningKey);
380
+ 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).`);
381
+ }
382
+ }
356
383
  this.modelId = getEmbeddingProviderIdentity({
357
384
  provider: "openai-compatible",
358
385
  endpoint: this.endpoint,
@@ -410,6 +437,23 @@ class OpenAICompatibleEmbeddingProvider {
410
437
  if (signal?.aborted) {
411
438
  return Array.from({ length: texts.length }, () => null);
412
439
  }
440
+ const isQuery = purpose === "query";
441
+ for (;; ) {
442
+ if (Date.now() < this.rateLimit.until) {
443
+ if (isQuery)
444
+ return Array.from({ length: texts.length }, () => null);
445
+ if (!await this.waitForRateLimitCooldown(signal)) {
446
+ return Array.from({ length: texts.length }, () => null);
447
+ }
448
+ }
449
+ const outcome = await this.requestOnce(texts, requestTexts, signal, purpose);
450
+ if (outcome !== RATE_LIMITED)
451
+ return outcome;
452
+ if (isQuery)
453
+ return Array.from({ length: texts.length }, () => null);
454
+ }
455
+ }
456
+ async requestOnce(texts, requestTexts, signal, purpose) {
413
457
  let isProbe = false;
414
458
  let internalController;
415
459
  let timeoutHandle;
@@ -442,9 +486,14 @@ class OpenAICompatibleEmbeddingProvider {
442
486
  redirect: "error",
443
487
  signal: internalController.signal
444
488
  });
489
+ if (response.status === 429) {
490
+ await response.text().catch(() => "");
491
+ this.noteRateLimit(response.headers.get("retry-after"));
492
+ return RATE_LIMITED;
493
+ }
445
494
  if (!response.ok) {
446
495
  const excerpt = await response.text().catch(() => "");
447
- const failure = this.failure("http_error", `HTTP ${response.status} from endpoint${this.bodyExcerpt(excerpt)}`, response.status >= 500 || response.status === 408 || response.status === 429);
496
+ const failure = this.failure("http_error", `HTTP ${response.status} from endpoint${this.bodyExcerpt(excerpt)}`, response.status >= 500 || response.status === 408);
448
497
  log2(`[magic-context] openai-compatible embedding request failed: ${failure.reason}`);
449
498
  this.recordFailure(isProbe, failure);
450
499
  return Array.from({ length: texts.length }, () => null);
@@ -543,6 +592,36 @@ class OpenAICompatibleEmbeddingProvider {
543
592
  isLoaded() {
544
593
  return this.initialized;
545
594
  }
595
+ get rateLimit() {
596
+ let state = rateLimitStates.get(this.rateLimitKey);
597
+ if (!state) {
598
+ state = { until: 0, consecutive: 0 };
599
+ rateLimitStates.set(this.rateLimitKey, state);
600
+ }
601
+ return state;
602
+ }
603
+ async waitForRateLimitCooldown(signal) {
604
+ for (;; ) {
605
+ const remaining = this.rateLimit.until - Date.now();
606
+ if (remaining <= 0)
607
+ return true;
608
+ if (!await sleepUnlessAborted(remaining, signal))
609
+ return false;
610
+ }
611
+ }
612
+ noteRateLimit(retryAfter) {
613
+ const state = this.rateLimit;
614
+ const now = Date.now();
615
+ const headerDelayMs = parseRetryAfterMs(retryAfter, now);
616
+ const delayMs = headerDelayMs ?? rateLimitBackoffMs(state.consecutive);
617
+ state.consecutive += 1;
618
+ const alreadyCoolingDown = now < state.until;
619
+ state.until = Math.max(state.until, now + delayMs);
620
+ const seconds = Math.ceil(delayMs / 1000);
621
+ if (!alreadyCoolingDown) {
622
+ 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`);
623
+ }
624
+ }
546
625
  claimProbeOrShortCircuit() {
547
626
  if (this.circuitOpenUntil === 0) {
548
627
  return "allow";
@@ -597,6 +676,7 @@ class OpenAICompatibleEmbeddingProvider {
597
676
  this.circuitOpenUntil = 0;
598
677
  this.openLogged = false;
599
678
  this.lastFailureReason = null;
679
+ this.rateLimit.consecutive = 0;
600
680
  }
601
681
  getLastFailureReason() {
602
682
  return this.lastFailureReason;
@@ -612,6 +692,9 @@ class OpenAICompatibleEmbeddingProvider {
612
692
  _getFailureCount() {
613
693
  return this.failureTimes.length;
614
694
  }
695
+ _getRateLimitedUntil() {
696
+ return this.rateLimit.until;
697
+ }
615
698
  _resetCircuit() {
616
699
  this.failureTimes = [];
617
700
  this.circuitOpenUntil = 0;
@@ -622,7 +705,85 @@ class OpenAICompatibleEmbeddingProvider {
622
705
  }
623
706
 
624
707
  // src/features/magic-context/project-embedding-registry.ts
625
- import { createHash as createHash2, randomUUID } from "node:crypto";
708
+ import { createHash as createHash3, randomUUID } from "node:crypto";
709
+
710
+ // src/features/magic-context/chunk-embedding-writer.ts
711
+ import { Worker } from "node:worker_threads";
712
+ function createChunkEmbeddingWriter(db) {
713
+ const path = getSqliteDatabasePath2(db);
714
+ if (!path)
715
+ return null;
716
+ if (path.startsWith("file:"))
717
+ throw new Error("chunk embedding writer requires a filesystem path");
718
+ const entry = new URL(import.meta.url.endsWith(".ts") ? "./chunk-embedding-write-worker.ts" : "./chunk-embedding-write-worker.js", import.meta.url);
719
+ const timeout = db.prepare("PRAGMA busy_timeout").get().timeout;
720
+ const worker = inRootAsyncContext2(() => new Worker(entry, { workerData: { path, harness: getHarness2(), timeout } }));
721
+ let pending;
722
+ let failure;
723
+ let deadline;
724
+ worker.on("message", (reply) => {
725
+ clearTimeout(deadline);
726
+ const request = pending;
727
+ pending = undefined;
728
+ if (reply.error)
729
+ request?.reject(new Error(reply.error));
730
+ else
731
+ request?.resolve(reply.value);
732
+ });
733
+ const fail = (error) => {
734
+ clearTimeout(deadline);
735
+ failure = error;
736
+ pending?.reject(error);
737
+ pending = undefined;
738
+ };
739
+ worker.on("error", fail);
740
+ worker.on("exit", (code) => fail(new Error(`chunk embedding writer exited (${code})`)));
741
+ worker.unref();
742
+ let queue = Promise.resolve();
743
+ const request = (message) => {
744
+ const result = queue.then(() => {
745
+ if (failure)
746
+ throw failure;
747
+ return new Promise((resolve, reject) => {
748
+ pending = { resolve, reject };
749
+ deadline = inRootAsyncContext2(() => setTimeout(() => {
750
+ fail(new Error("chunk embedding database operation timed out; coverage will be rechecked"));
751
+ worker.terminate();
752
+ }, 30000));
753
+ deadline.unref();
754
+ worker.postMessage(message);
755
+ });
756
+ });
757
+ queue = result.catch(() => {});
758
+ return result;
759
+ };
760
+ return {
761
+ async replace(rows, sourceKey) {
762
+ if (rows.some((row) => isSynapseEmbeddingTruncated(row.vector)))
763
+ return;
764
+ await request({ kind: "replace", rows, sourceKey });
765
+ },
766
+ project: (project, session) => request({ kind: "project", project, session }),
767
+ count: (project, session, model, tokens) => request({ kind: "count", project, session, model, tokens }),
768
+ candidates: (project, session, model, limit, excluded, tokens) => request({
769
+ kind: "candidates",
770
+ project,
771
+ session,
772
+ model,
773
+ limit,
774
+ excluded,
775
+ tokens
776
+ }),
777
+ backoff: (candidate, project, model) => request({ kind: "backoff", candidate, project, model }),
778
+ acquire: (project, holder) => request({ kind: "acquire", project, holder }),
779
+ renew: (project, holder) => request({ kind: "renew", project, holder }),
780
+ release: (project, holder) => request({ kind: "release", project, holder }),
781
+ async close() {
782
+ clearTimeout(deadline);
783
+ await worker.terminate();
784
+ }
785
+ };
786
+ }
626
787
 
627
788
  // src/features/magic-context/git-commits/storage-git-commit-embeddings.ts
628
789
  var saveStatements = new WeakMap;
@@ -806,142 +967,6 @@ function enforceProjectCap(db, projectPath, maxCommits) {
806
967
  return evicted;
807
968
  }
808
969
 
809
- // src/features/magic-context/git-commits/sweep-coordinator.ts
810
- var GIT_SWEEP_COOLDOWN_MS = 10 * 60 * 1000;
811
- var GIT_SWEEP_LEASE_TTL_MS = 5 * 60 * 1000;
812
- var GIT_SWEEP_NON_INDEXABLE_REPROBE_MS = 24 * 60 * 60 * 1000;
813
- var GIT_SWEEP_LEASE_RENEWAL_MS = 60 * 1000;
814
- function runImmediate(db, body) {
815
- db.exec("BEGIN IMMEDIATE");
816
- const transactionStartedAt = performance.now();
817
- let committed = false;
818
- try {
819
- const result = body();
820
- db.exec("COMMIT");
821
- committed = true;
822
- logSlowWriteTransaction("git_sweep_lease", transactionStartedAt);
823
- return result;
824
- } finally {
825
- if (!committed) {
826
- try {
827
- db.exec("ROLLBACK");
828
- } catch {}
829
- }
830
- }
831
- }
832
- function rowToState(row) {
833
- return {
834
- projectPath: row.project_path,
835
- leaseHolder: row.lease_holder,
836
- leaseExpiresAt: row.lease_expires_at,
837
- lastSweptAt: row.last_swept_at
838
- };
839
- }
840
- function getGitSweepCoordinatorState(db, projectPath) {
841
- const row = db.prepare(`SELECT project_path, lease_holder, lease_expires_at, last_swept_at
842
- FROM git_sweep_coordinator
843
- WHERE project_path = ?`).get(projectPath);
844
- return row ? rowToState(row) : null;
845
- }
846
- function acquireGitSweepLease(db, projectPath, holderId, options = {}) {
847
- const cooldownMs = options.cooldownMs ?? GIT_SWEEP_COOLDOWN_MS;
848
- const leaseTtlMs = options.leaseTtlMs ?? GIT_SWEEP_LEASE_TTL_MS;
849
- return runImmediate(db, () => {
850
- const now = Date.now();
851
- const row = getGitSweepCoordinatorState(db, projectPath);
852
- if (row?.leaseHolder && row.leaseExpiresAt !== null && row.leaseExpiresAt > now) {
853
- return {
854
- acquired: false,
855
- projectPath,
856
- reason: "lease_active",
857
- leaseHolder: row.leaseHolder,
858
- leaseExpiresAt: row.leaseExpiresAt,
859
- lastSweptAt: row.lastSweptAt,
860
- nextAllowedAt: null
861
- };
862
- }
863
- if (!options.ignoreCooldown && row?.lastSweptAt !== null && row?.lastSweptAt !== undefined) {
864
- const nextAllowedAt = row.lastSweptAt + cooldownMs;
865
- if (nextAllowedAt > now) {
866
- return {
867
- acquired: false,
868
- projectPath,
869
- reason: "cooldown_active",
870
- leaseHolder: row.leaseHolder,
871
- leaseExpiresAt: row.leaseExpiresAt,
872
- lastSweptAt: row.lastSweptAt,
873
- nextAllowedAt
874
- };
875
- }
876
- }
877
- const leaseExpiresAt = now + leaseTtlMs;
878
- db.prepare(`INSERT INTO git_sweep_coordinator (
879
- project_path,
880
- lease_holder,
881
- lease_expires_at,
882
- last_swept_at
883
- ) VALUES (?, ?, ?, NULL)
884
- ON CONFLICT(project_path) DO UPDATE SET
885
- lease_holder = excluded.lease_holder,
886
- lease_expires_at = excluded.lease_expires_at`).run(projectPath, holderId, leaseExpiresAt);
887
- return {
888
- acquired: true,
889
- projectPath,
890
- holderId,
891
- acquiredAt: now,
892
- leaseExpiresAt
893
- };
894
- });
895
- }
896
- function renewGitSweepLease(db, projectPath, holderId, leaseTtlMs = GIT_SWEEP_LEASE_TTL_MS) {
897
- return runImmediate(db, () => {
898
- const now = Date.now();
899
- const leaseExpiresAt = now + leaseTtlMs;
900
- const result = db.prepare(`UPDATE git_sweep_coordinator
901
- SET lease_expires_at = ?
902
- WHERE project_path = ?
903
- AND lease_holder = ?
904
- AND lease_expires_at > ?`).run(leaseExpiresAt, projectPath, holderId, now);
905
- return result.changes === 1;
906
- });
907
- }
908
- function markGitSweepSuccessAndRelease(db, projectPath, holderId) {
909
- return runImmediate(db, () => {
910
- const now = Date.now();
911
- const result = db.prepare(`UPDATE git_sweep_coordinator
912
- SET lease_holder = NULL,
913
- lease_expires_at = NULL,
914
- last_swept_at = ?
915
- WHERE project_path = ?
916
- AND lease_holder = ?
917
- AND lease_expires_at > ?`).run(now, projectPath, holderId, now);
918
- return result.changes === 1;
919
- });
920
- }
921
- function parkGitSweepNonIndexable(db, projectPath, holderId, reprobeMs = GIT_SWEEP_NON_INDEXABLE_REPROBE_MS) {
922
- return runImmediate(db, () => {
923
- const now = Date.now();
924
- const sweptAt = now + reprobeMs - GIT_SWEEP_COOLDOWN_MS;
925
- const result = db.prepare(`UPDATE git_sweep_coordinator
926
- SET lease_holder = NULL,
927
- lease_expires_at = NULL,
928
- last_swept_at = ?
929
- WHERE project_path = ?
930
- AND lease_holder = ?
931
- AND lease_expires_at > ?`).run(sweptAt, projectPath, holderId, now);
932
- return result.changes === 1;
933
- });
934
- }
935
- function releaseGitSweepLease(db, projectPath, holderId) {
936
- runImmediate(db, () => {
937
- db.prepare(`UPDATE git_sweep_coordinator
938
- SET lease_holder = NULL,
939
- lease_expires_at = NULL
940
- WHERE project_path = ?
941
- AND lease_holder = ?`).run(projectPath, holderId);
942
- });
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 { recordSessionProjectIdentity, hasRecordedSessionProjectIdentity, drainBackgroundBatches, recordEmbeddingMeasurement, OpenAICompatibleEmbeddingProvider, saveCommitEmbedding, loadProjectCommitEmbeddings, loadUnembeddedCommits, countEmbeddedCommits, upsertCommits, getLatestIndexedCommitSha, enforceProjectCap, GIT_SWEEP_LEASE_RENEWAL_MS, acquireGitSweepLease, renewGitSweepLease, markGitSweepSuccessAndRelease, parkGitSweepNonIndexable, releaseGitSweepLease, 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, OpenAICompatibleEmbeddingProvider, saveCommitEmbedding, loadProjectCommitEmbeddings, loadUnembeddedCommits, countEmbeddedCommits, upsertCommits, getLatestIndexedCommitSha, enforceProjectCap, 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 };