@cortexkit/opencode-magic-context 0.45.0 → 0.46.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (396) hide show
  1. package/README.md +26 -0
  2. package/dist/{announcement-f75t58v9.js → announcement-y35wzg2r.js} +1 -1
  3. package/dist/config/index.d.ts.map +1 -1
  4. package/dist/config/live-run-config.d.ts.map +1 -1
  5. package/dist/config/migrate-config-location.d.ts.map +1 -1
  6. package/dist/config/schema/magic-context.d.ts +13 -7
  7. package/dist/config/schema/magic-context.d.ts.map +1 -1
  8. package/dist/{conflict-warning-hook-5yrz2r24.js → conflict-warning-hook-7fj2b9jw.js} +6 -5
  9. package/dist/context-sh2m2vde.js +4525 -0
  10. package/dist/{derive-budgets-a63zsm5c.js → derive-budgets-7nj7r1rv.js} +2 -2
  11. package/dist/embedding-worker.js +4 -4
  12. package/dist/features/magic-context/checkout-claim-fake-subc.test-support.d.ts +45 -0
  13. package/dist/features/magic-context/checkout-claim-fake-subc.test-support.d.ts.map +1 -0
  14. package/dist/features/magic-context/checkout-claim.d.ts +155 -0
  15. package/dist/features/magic-context/checkout-claim.d.ts.map +1 -0
  16. package/dist/features/magic-context/compaction-marker.d.ts +20 -3
  17. package/dist/features/magic-context/compaction-marker.d.ts.map +1 -1
  18. package/dist/features/magic-context/compartment-storage.d.ts +23 -2
  19. package/dist/features/magic-context/compartment-storage.d.ts.map +1 -1
  20. package/dist/features/magic-context/dreamer/classify.d.ts.map +1 -1
  21. package/dist/features/magic-context/dreamer/evaluate-smart-notes.d.ts.map +1 -1
  22. package/dist/features/magic-context/dreamer/provider-output-failure.d.ts +6 -2
  23. package/dist/features/magic-context/dreamer/provider-output-failure.d.ts.map +1 -1
  24. package/dist/features/magic-context/dreamer/provider-output-failure.test-support.d.ts +30 -0
  25. package/dist/features/magic-context/dreamer/provider-output-failure.test-support.d.ts.map +1 -0
  26. package/dist/features/magic-context/dreamer/storage-dream-runs.d.ts.map +1 -1
  27. package/dist/features/magic-context/dreamer/task-executor.d.ts +9 -0
  28. package/dist/features/magic-context/dreamer/task-executor.d.ts.map +1 -1
  29. package/dist/features/magic-context/dreamer/task-gates.d.ts.map +1 -1
  30. package/dist/features/magic-context/dreamer/task-scheduler.d.ts.map +1 -1
  31. package/dist/features/magic-context/dreamer/verify-diff.d.ts.map +1 -1
  32. package/dist/features/magic-context/dreamer/verify-gate.d.ts.map +1 -1
  33. package/dist/features/magic-context/dreamer/verify.d.ts.map +1 -1
  34. package/dist/features/magic-context/git-commits/search-git-commits.d.ts.map +1 -1
  35. package/dist/features/magic-context/memory/embedding-local.d.ts.map +1 -1
  36. package/dist/features/magic-context/memory/project-identity-cache.d.ts.map +1 -1
  37. package/dist/features/magic-context/memory/storage-memory-verifications.d.ts.map +1 -1
  38. package/dist/features/magic-context/memory/storage-memory.d.ts +3 -0
  39. package/dist/features/magic-context/memory/storage-memory.d.ts.map +1 -1
  40. package/dist/features/magic-context/memory/verification-paths.d.ts +2 -2
  41. package/dist/features/magic-context/memory/verification-paths.d.ts.map +1 -1
  42. package/dist/features/magic-context/merged-reasoning-decisions.d.ts.map +1 -1
  43. package/dist/features/magic-context/message-index-async.d.ts +3 -3
  44. package/dist/features/magic-context/message-index-async.d.ts.map +1 -1
  45. package/dist/features/magic-context/message-index.d.ts +2 -0
  46. package/dist/features/magic-context/message-index.d.ts.map +1 -1
  47. package/dist/features/magic-context/migration-v95-perf-indexes.d.ts +12 -0
  48. package/dist/features/magic-context/migration-v95-perf-indexes.d.ts.map +1 -0
  49. package/dist/features/magic-context/migration-worker-client.d.ts +4 -4
  50. package/dist/features/magic-context/migration-worker-client.d.ts.map +1 -1
  51. package/dist/features/magic-context/migrations.d.ts +1 -0
  52. package/dist/features/magic-context/migrations.d.ts.map +1 -1
  53. package/dist/features/magic-context/mural/render-trigger.d.ts.map +1 -1
  54. package/dist/features/magic-context/mural/resolve-mural.d.ts +15 -4
  55. package/dist/features/magic-context/mural/resolve-mural.d.ts.map +1 -1
  56. package/dist/features/magic-context/mural/source-revision.d.ts +7 -0
  57. package/dist/features/magic-context/mural/source-revision.d.ts.map +1 -0
  58. package/dist/features/magic-context/mural/storage-mural-cues.d.ts.map +1 -1
  59. package/dist/features/magic-context/reclaim-protection.d.ts +15 -10
  60. package/dist/features/magic-context/reclaim-protection.d.ts.map +1 -1
  61. package/dist/features/magic-context/session-cache-ttl.d.ts +4 -2
  62. package/dist/features/magic-context/session-cache-ttl.d.ts.map +1 -1
  63. package/dist/features/magic-context/smart-notes/capabilities.d.ts +3 -0
  64. package/dist/features/magic-context/smart-notes/capabilities.d.ts.map +1 -1
  65. package/dist/features/magic-context/smart-notes/compiler.d.ts.map +1 -1
  66. package/dist/features/magic-context/smart-notes/github-token.d.ts +5 -0
  67. package/dist/features/magic-context/smart-notes/github-token.d.ts.map +1 -0
  68. package/dist/features/magic-context/smart-notes/runner.d.ts +1 -0
  69. package/dist/features/magic-context/smart-notes/runner.d.ts.map +1 -1
  70. package/dist/features/magic-context/smart-notes/sandbox-runner.d.ts +12 -0
  71. package/dist/features/magic-context/smart-notes/sandbox-runner.d.ts.map +1 -1
  72. package/dist/features/magic-context/smart-notes/ssrf-guard.d.ts +6 -0
  73. package/dist/features/magic-context/smart-notes/ssrf-guard.d.ts.map +1 -1
  74. package/dist/features/magic-context/smart-notes/storage.d.ts.map +1 -1
  75. package/dist/features/magic-context/smart-notes/types.d.ts +2 -0
  76. package/dist/features/magic-context/smart-notes/types.d.ts.map +1 -1
  77. package/dist/features/magic-context/storage-clone.d.ts.map +1 -1
  78. package/dist/features/magic-context/storage-db.d.ts +6 -9
  79. package/dist/features/magic-context/storage-db.d.ts.map +1 -1
  80. package/dist/features/magic-context/storage-meta-shared.d.ts +1 -1
  81. package/dist/features/magic-context/storage-meta-shared.d.ts.map +1 -1
  82. package/dist/features/magic-context/storage-ops.d.ts +8 -1
  83. package/dist/features/magic-context/storage-ops.d.ts.map +1 -1
  84. package/dist/features/magic-context/storage-replay-document.d.ts +7 -0
  85. package/dist/features/magic-context/storage-replay-document.d.ts.map +1 -1
  86. package/dist/features/magic-context/storage-schema-helpers.d.ts +2 -0
  87. package/dist/features/magic-context/storage-schema-helpers.d.ts.map +1 -1
  88. package/dist/features/magic-context/storage-session-tables.d.ts.map +1 -1
  89. package/dist/features/magic-context/storage-source.d.ts.map +1 -1
  90. package/dist/features/magic-context/storage-tags.d.ts +11 -3
  91. package/dist/features/magic-context/storage-tags.d.ts.map +1 -1
  92. package/dist/features/magic-context/storage.d.ts +2 -2
  93. package/dist/features/magic-context/storage.d.ts.map +1 -1
  94. package/dist/features/magic-context/temporal-decisions.d.ts +10 -0
  95. package/dist/features/magic-context/temporal-decisions.d.ts.map +1 -0
  96. package/dist/features/magic-context/tool-definition-tokens.d.ts +2 -0
  97. package/dist/features/magic-context/tool-definition-tokens.d.ts.map +1 -1
  98. package/dist/features/magic-context/transform-decision-log.d.ts.map +1 -1
  99. package/dist/features/magic-context/types.d.ts +7 -6
  100. package/dist/features/magic-context/types.d.ts.map +1 -1
  101. package/dist/features/magic-context/window-report-ledger.d.ts.map +1 -1
  102. package/dist/hooks/auto-update-checker/index.d.ts.map +1 -1
  103. package/dist/hooks/magic-context/apply-operations.d.ts +8 -0
  104. package/dist/hooks/magic-context/apply-operations.d.ts.map +1 -1
  105. package/dist/hooks/magic-context/cache-busting-signals.d.ts +6 -3
  106. package/dist/hooks/magic-context/cache-busting-signals.d.ts.map +1 -1
  107. package/dist/hooks/magic-context/channel2-cycle.d.ts +2 -0
  108. package/dist/hooks/magic-context/channel2-cycle.d.ts.map +1 -1
  109. package/dist/hooks/magic-context/compaction-marker-manager.d.ts +7 -0
  110. package/dist/hooks/magic-context/compaction-marker-manager.d.ts.map +1 -1
  111. package/dist/hooks/magic-context/compartment-prompt.d.ts +2 -2
  112. package/dist/hooks/magic-context/compartment-prompt.d.ts.map +1 -1
  113. package/dist/hooks/magic-context/compartment-render-epoch.d.ts +8 -0
  114. package/dist/hooks/magic-context/compartment-render-epoch.d.ts.map +1 -1
  115. package/dist/hooks/magic-context/compartment-runner-drop-queue.d.ts +18 -4
  116. package/dist/hooks/magic-context/compartment-runner-drop-queue.d.ts.map +1 -1
  117. package/dist/hooks/magic-context/compartment-runner-incremental.d.ts.map +1 -1
  118. package/dist/hooks/magic-context/compartment-runner-partial-recomp.d.ts.map +1 -1
  119. package/dist/hooks/magic-context/compartment-runner-recomp.d.ts.map +1 -1
  120. package/dist/hooks/magic-context/ctx-reduce-availability.d.ts +12 -0
  121. package/dist/hooks/magic-context/ctx-reduce-availability.d.ts.map +1 -1
  122. package/dist/hooks/magic-context/decision-calibration.d.ts +3 -0
  123. package/dist/hooks/magic-context/decision-calibration.d.ts.map +1 -1
  124. package/dist/hooks/magic-context/default-protection-pressure.test-support.d.ts +37 -0
  125. package/dist/hooks/magic-context/default-protection-pressure.test-support.d.ts.map +1 -0
  126. package/dist/hooks/magic-context/drop-stale-reduce-calls.d.ts +4 -0
  127. package/dist/hooks/magic-context/drop-stale-reduce-calls.d.ts.map +1 -1
  128. package/dist/hooks/magic-context/edit-marker.d.ts.map +1 -1
  129. package/dist/hooks/magic-context/emergency-drop.d.ts +2 -0
  130. package/dist/hooks/magic-context/emergency-drop.d.ts.map +1 -1
  131. package/dist/hooks/magic-context/emergency-fail-closed.d.ts +21 -1
  132. package/dist/hooks/magic-context/emergency-fail-closed.d.ts.map +1 -1
  133. package/dist/hooks/magic-context/event-handler.d.ts +5 -0
  134. package/dist/hooks/magic-context/event-handler.d.ts.map +1 -1
  135. package/dist/hooks/magic-context/final-wire-token-estimate.d.ts +30 -1
  136. package/dist/hooks/magic-context/final-wire-token-estimate.d.ts.map +1 -1
  137. package/dist/hooks/magic-context/heuristic-cleanup.d.ts +2 -0
  138. package/dist/hooks/magic-context/heuristic-cleanup.d.ts.map +1 -1
  139. package/dist/hooks/magic-context/historian-prompt-fit.d.ts +4 -2
  140. package/dist/hooks/magic-context/historian-prompt-fit.d.ts.map +1 -1
  141. package/dist/hooks/magic-context/hook.d.ts +2 -1
  142. package/dist/hooks/magic-context/hook.d.ts.map +1 -1
  143. package/dist/hooks/magic-context/inject-compartments.d.ts +9 -10
  144. package/dist/hooks/magic-context/inject-compartments.d.ts.map +1 -1
  145. package/dist/hooks/magic-context/lkg-measured-request.d.ts +69 -0
  146. package/dist/hooks/magic-context/lkg-measured-request.d.ts.map +1 -0
  147. package/dist/hooks/magic-context/lkg-persist.d.ts +2 -0
  148. package/dist/hooks/magic-context/lkg-persist.d.ts.map +1 -1
  149. package/dist/hooks/magic-context/lkg-replay-fit.d.ts +14 -0
  150. package/dist/hooks/magic-context/lkg-replay-fit.d.ts.map +1 -1
  151. package/dist/hooks/magic-context/lkg-replay.d.ts +10 -1
  152. package/dist/hooks/magic-context/lkg-replay.d.ts.map +1 -1
  153. package/dist/hooks/magic-context/lkg-slot.d.ts +4 -0
  154. package/dist/hooks/magic-context/lkg-slot.d.ts.map +1 -1
  155. package/dist/hooks/magic-context/module-state-sync.d.ts +2 -0
  156. package/dist/hooks/magic-context/module-state-sync.d.ts.map +1 -1
  157. package/dist/hooks/magic-context/module-transport.d.ts.map +1 -1
  158. package/dist/hooks/magic-context/module-wire.d.ts.map +1 -1
  159. package/dist/hooks/magic-context/note-nudger.d.ts +17 -5
  160. package/dist/hooks/magic-context/note-nudger.d.ts.map +1 -1
  161. package/dist/hooks/magic-context/read-session-chunk.d.ts +1 -1
  162. package/dist/hooks/magic-context/read-session-chunk.d.ts.map +1 -1
  163. package/dist/hooks/magic-context/read-session-db.d.ts +1 -0
  164. package/dist/hooks/magic-context/read-session-db.d.ts.map +1 -1
  165. package/dist/hooks/magic-context/read-session-formatting.d.ts +7 -0
  166. package/dist/hooks/magic-context/read-session-formatting.d.ts.map +1 -1
  167. package/dist/hooks/magic-context/read-session-raw.d.ts +4 -0
  168. package/dist/hooks/magic-context/read-session-raw.d.ts.map +1 -1
  169. package/dist/hooks/magic-context/read-session-true-raw-tokens.d.ts.map +1 -1
  170. package/dist/hooks/magic-context/recomp-orchestrator.d.ts +2 -0
  171. package/dist/hooks/magic-context/recomp-orchestrator.d.ts.map +1 -1
  172. package/dist/hooks/magic-context/reference-retrieval.d.ts +27 -17
  173. package/dist/hooks/magic-context/reference-retrieval.d.ts.map +1 -1
  174. package/dist/hooks/magic-context/request-hook-order.d.ts +56 -0
  175. package/dist/hooks/magic-context/request-hook-order.d.ts.map +1 -0
  176. package/dist/hooks/magic-context/rust-mode-transform.d.ts +22 -3
  177. package/dist/hooks/magic-context/rust-mode-transform.d.ts.map +1 -1
  178. package/dist/hooks/magic-context/strip-content.d.ts +4 -2
  179. package/dist/hooks/magic-context/strip-content.d.ts.map +1 -1
  180. package/dist/hooks/magic-context/supersession-reclaim.d.ts +4 -0
  181. package/dist/hooks/magic-context/supersession-reclaim.d.ts.map +1 -1
  182. package/dist/hooks/magic-context/system-prompt-hash.d.ts +7 -0
  183. package/dist/hooks/magic-context/system-prompt-hash.d.ts.map +1 -1
  184. package/dist/hooks/magic-context/tail-hygiene-walk.d.ts +12 -3
  185. package/dist/hooks/magic-context/tail-hygiene-walk.d.ts.map +1 -1
  186. package/dist/hooks/magic-context/temporal-awareness.d.ts +6 -3
  187. package/dist/hooks/magic-context/temporal-awareness.d.ts.map +1 -1
  188. package/dist/hooks/magic-context/temporal-served-projection.d.ts +4 -0
  189. package/dist/hooks/magic-context/temporal-served-projection.d.ts.map +1 -0
  190. package/dist/hooks/magic-context/tool-drop-target.d.ts.map +1 -1
  191. package/dist/hooks/magic-context/tool-reclaim.d.ts +2 -0
  192. package/dist/hooks/magic-context/tool-reclaim.d.ts.map +1 -1
  193. package/dist/hooks/magic-context/transform-message-helpers.d.ts +5 -0
  194. package/dist/hooks/magic-context/transform-message-helpers.d.ts.map +1 -1
  195. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts +41 -17
  196. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts.map +1 -1
  197. package/dist/hooks/magic-context/transform.d.ts +12 -0
  198. package/dist/hooks/magic-context/transform.d.ts.map +1 -1
  199. package/dist/hooks/magic-context/wrapup-orchestrator.d.ts.map +1 -1
  200. package/dist/{index-vvtfyw1z.js → index-0d3g3461.js} +5 -13
  201. package/dist/index-1bc61ans.js +154 -0
  202. package/dist/{index-n96ag4rk.js → index-1zx87sdm.js} +5 -1
  203. package/dist/{index-4krbw8z9.js → index-3h0ybwah.js} +608 -102
  204. package/dist/{index-gd5qx1j9.js → index-5eqk6z3s.js} +62 -1
  205. package/dist/index-5gq3b2ya.js +494 -0
  206. package/dist/{index-8fgkmxmy.js → index-5p8jdswx.js} +4 -3
  207. package/dist/{index-75zjgwga.js → index-7qw742ev.js} +1 -1
  208. package/dist/{index-f85teqck.js → index-8da2zjhz.js} +3 -256
  209. package/dist/{index-q7yesyk9.js → index-8x2v7gg9.js} +25 -24
  210. package/dist/{index-w9jwmntv.js → index-b35pxds2.js} +9 -1
  211. package/dist/{v2/server-a4m2b1yv.js → index-fg34g6a5.js} +55 -1
  212. package/dist/index-hpecdzec.js +28506 -0
  213. package/dist/{index-2ntg5sd4.js → index-k5bdx1bx.js} +9 -5
  214. package/dist/{index-bmzf7zxv.js → index-majxda46.js} +23 -5
  215. package/dist/{index-2aq21j41.js → index-pkbcrdqs.js} +418 -127
  216. package/dist/{index-remp7e2g.js → index-q4yp4b52.js} +16 -1
  217. package/dist/{index-fr2z4qy8.js → index-r5hmbx3t.js} +132 -169
  218. package/dist/index-sfnj6h8h.js +259 -0
  219. package/dist/{index-xgt9k6c6.js → index-sgthv3f7.js} +2 -1
  220. package/dist/index-sj29b3z2.js +30 -0
  221. package/dist/{index-16ny736w.js → index-sjthx78w.js} +20526 -19817
  222. package/dist/index.d.ts.map +1 -1
  223. package/dist/index.js +1983 -33118
  224. package/dist/{message-time-backfill-an311pmk.js → message-time-backfill-68gj6t3e.js} +2 -2
  225. package/dist/migration-worker.js +12 -7
  226. package/dist/plugin/dream-timer.d.ts +25 -1
  227. package/dist/plugin/dream-timer.d.ts.map +1 -1
  228. package/dist/plugin/hooks/create-session-hooks.d.ts +2 -1
  229. package/dist/plugin/hooks/create-session-hooks.d.ts.map +1 -1
  230. package/dist/plugin/messages-transform.d.ts +13 -0
  231. package/dist/plugin/messages-transform.d.ts.map +1 -1
  232. package/dist/plugin/rpc-handlers.d.ts +4 -0
  233. package/dist/plugin/rpc-handlers.d.ts.map +1 -1
  234. package/dist/plugin/subagent-tool-policy.d.ts +14 -0
  235. package/dist/plugin/subagent-tool-policy.d.ts.map +1 -0
  236. package/dist/plugin/tool-registry.d.ts +1 -0
  237. package/dist/plugin/tool-registry.d.ts.map +1 -1
  238. package/dist/{read-session-chunk-8rxs0tc9.js → read-session-chunk-egz7r68d.js} +8 -8
  239. package/dist/{recomp-orchestrator-nzamtw29.js → recomp-orchestrator-y15j0rb9.js} +15 -15
  240. package/dist/{send-session-notification-nqpv7cne.js → send-session-notification-dyw42dtr.js} +4 -4
  241. package/dist/shared/announcement.d.ts.map +1 -1
  242. package/dist/shared/cache-ttl-display.d.ts +6 -4
  243. package/dist/shared/cache-ttl-display.d.ts.map +1 -1
  244. package/dist/shared/model-cache-ttl.d.ts +1 -1
  245. package/dist/shared/model-cache-ttl.d.ts.map +1 -1
  246. package/dist/shared/model-suggestion-retry.d.ts +2 -0
  247. package/dist/shared/model-suggestion-retry.d.ts.map +1 -1
  248. package/dist/shared/models-dev-cache.d.ts.map +1 -1
  249. package/dist/shared/protected-tools-policy.d.ts +6 -0
  250. package/dist/shared/protected-tools-policy.d.ts.map +1 -0
  251. package/dist/shared/quota-diagnostic.d.ts +4 -0
  252. package/dist/shared/quota-diagnostic.d.ts.map +1 -0
  253. package/dist/shared/rpc-server.d.ts.map +1 -1
  254. package/dist/shared/sqlite-context-pragmas.d.ts +12 -0
  255. package/dist/shared/sqlite-context-pragmas.d.ts.map +1 -0
  256. package/dist/shared/sqlite-helpers.d.ts +9 -0
  257. package/dist/shared/sqlite-helpers.d.ts.map +1 -1
  258. package/dist/shared/sqlite.d.ts +10 -0
  259. package/dist/shared/sqlite.d.ts.map +1 -1
  260. package/dist/shared/status-summary.d.ts +1 -0
  261. package/dist/shared/status-summary.d.ts.map +1 -1
  262. package/dist/shared/status-view-check.d.ts.map +1 -1
  263. package/dist/shared/status-view.d.ts +4 -0
  264. package/dist/shared/status-view.d.ts.map +1 -1
  265. package/dist/shared/storage-permissions.d.ts +24 -0
  266. package/dist/shared/storage-permissions.d.ts.map +1 -1
  267. package/dist/shared/temporal-upgrade-fixture.d.ts +19 -0
  268. package/dist/shared/temporal-upgrade-fixture.d.ts.map +1 -0
  269. package/dist/shared/user-facing-codes.d.ts +5 -0
  270. package/dist/shared/user-facing-codes.d.ts.map +1 -1
  271. package/dist/shared/write-transaction-timing.d.ts +8 -1
  272. package/dist/shared/write-transaction-timing.d.ts.map +1 -1
  273. package/dist/tools/ctx-expand/render.d.ts.map +1 -1
  274. package/dist/tools/ctx-memory/tools.d.ts.map +1 -1
  275. package/dist/tools/ctx-reduce/constants.d.ts +2 -0
  276. package/dist/tools/ctx-reduce/constants.d.ts.map +1 -1
  277. package/dist/tools/ctx-reduce/tools.d.ts +4 -4
  278. package/dist/tools/ctx-reduce/tools.d.ts.map +1 -1
  279. package/dist/{transform-postprocess-phase-414phndq.js → transform-postprocess-phase-bqhz6vdr.js} +15 -15
  280. package/dist/v2/context-zecmzk5s.js +52209 -0
  281. package/dist/v2/{derive-budgets-v0krf3t7.js → derive-budgets-kdgp4s3r.js} +4 -3
  282. package/dist/v2/embedding-worker.js +6 -5
  283. package/dist/v2/fold/boundary.d.ts +2 -0
  284. package/dist/v2/fold/boundary.d.ts.map +1 -1
  285. package/dist/v2/fold/owner.d.ts.map +1 -1
  286. package/dist/v2/hidden-child-native.d.ts +7 -0
  287. package/dist/v2/hidden-child-native.d.ts.map +1 -1
  288. package/dist/v2/hidden-child-record.d.ts +8 -0
  289. package/dist/v2/hidden-child-record.d.ts.map +1 -1
  290. package/dist/v2/hidden-completion.d.ts.map +1 -1
  291. package/dist/v2/hooks/channel2.d.ts +2 -0
  292. package/dist/v2/hooks/channel2.d.ts.map +1 -1
  293. package/dist/v2/hooks/context.d.ts +2 -2
  294. package/dist/v2/hooks/context.d.ts.map +1 -1
  295. package/dist/v2/hooks/dream-timer.d.ts +39 -0
  296. package/dist/v2/hooks/dream-timer.d.ts.map +1 -0
  297. package/dist/v2/hooks/dream-trigger.d.ts +15 -1
  298. package/dist/v2/hooks/dream-trigger.d.ts.map +1 -1
  299. package/dist/v2/hooks/hidden-child.d.ts +54 -3
  300. package/dist/v2/hooks/hidden-child.d.ts.map +1 -1
  301. package/dist/v2/hooks/payload.d.ts.map +1 -1
  302. package/dist/v2/hooks/store.d.ts.map +1 -1
  303. package/dist/v2/hooks/tools.d.ts +1 -1
  304. package/dist/v2/hooks/tools.d.ts.map +1 -1
  305. package/dist/v2/hooks/types.d.ts +12 -1
  306. package/dist/v2/hooks/types.d.ts.map +1 -1
  307. package/dist/v2/hooks/update-check.d.ts.map +1 -1
  308. package/dist/v2/{message-time-backfill-0n93vrd7.js → message-time-backfill-r6qkem1x.js} +3 -3
  309. package/dist/v2/migration-worker.js +13 -8
  310. package/dist/v2/{read-session-chunk-hjza38hr.js → read-session-chunk-8vjp6581.js} +9 -9
  311. package/dist/v2/recomp-orchestrator-8ejxvrzz.js +39 -0
  312. package/dist/v2/{safe-notification-target-wtj0bbc2.js → safe-notification-target-eb1n1vfb.js} +2 -2
  313. package/dist/v2/{send-session-notification-mq9frrtm.js → send-session-notification-qs0j78v6.js} +6 -6
  314. package/dist/v2/server-14vq4kpm.js +30 -0
  315. package/dist/v2/server-1bc61ans.js +154 -0
  316. package/dist/v2/{server-n96ag4rk.js → server-1zx87sdm.js} +5 -1
  317. package/dist/v2/server-3n4q9xme.js +79 -0
  318. package/dist/v2/{server-rhdgxp1t.js → server-51dv1pr5.js} +63 -2
  319. package/dist/v2/{server-5317ykaf.js → server-6r257mf5.js} +1 -1
  320. package/dist/v2/server-84w6rvvf.js +14 -0
  321. package/dist/v2/{server-qpg6wf72.js → server-ajzeteqw.js} +9 -1
  322. package/dist/v2/server-c5gz8wph.js +3892 -0
  323. package/dist/v2/{server-v5xgft5v.js → server-e29d7p7c.js} +188 -3533
  324. package/dist/{index-a4m2b1yv.js → v2/server-fg34g6a5.js} +55 -1
  325. package/dist/v2/{server-e36nf2p1.js → server-frbm99q5.js} +1595 -1599
  326. package/dist/v2/{server-remp7e2g.js → server-g0fjrkta.js} +16 -1
  327. package/dist/v2/{server-c4g2y1z8.js → server-jc7y02q0.js} +2816 -5392
  328. package/dist/v2/{server-z19x7eqz.js → server-mcfawjgc.js} +4 -4
  329. package/dist/v2/{server-hfjfbg59.js → server-qp5hx1ad.js} +608 -105
  330. package/dist/v2/server-vs5gpnd4.js +493 -0
  331. package/dist/v2/{server-w99cyt6a.js → server-wvjvfhck.js} +14 -6
  332. package/dist/v2/server-xa4xe3rv.js +3351 -0
  333. package/dist/v2/{server-0jqw05sa.js → server-y8maxeft.js} +6 -84
  334. package/dist/v2/server.d.ts.map +1 -1
  335. package/dist/v2/server.js +104 -49288
  336. package/dist/v2/store-reader.d.ts +39 -1
  337. package/dist/v2/store-reader.d.ts.map +1 -1
  338. package/dist/v2/tool-result.d.ts +8 -0
  339. package/dist/v2/tool-result.d.ts.map +1 -0
  340. package/dist/v2/tui/index.d.ts.map +1 -1
  341. package/dist/v2/{wrapup-orchestrator-tbyx78dz.js → wrapup-orchestrator-0snhvwcv.js} +20 -16
  342. package/dist/wrapup-orchestrator-39amhv9s.js +26 -0
  343. package/package.json +26 -10
  344. package/src/config/index.ts +21 -4
  345. package/src/config/latch-permanence-guard.test.ts +6 -1
  346. package/src/config/live-run-config.ts +1 -0
  347. package/src/config/migrate-config-location.test.ts +31 -1
  348. package/src/config/migrate-config-location.ts +8 -41
  349. package/src/config/protected-tools.test.ts +70 -0
  350. package/src/config/raw-loader.test.ts +15 -0
  351. package/src/config/raw-loader.ts +1 -1
  352. package/src/config/removed-agent-source-fence.test.ts +10 -1
  353. package/src/config/schema/magic-context.test.ts +20 -1
  354. package/src/config/schema/magic-context.ts +26 -7
  355. package/src/shared/announcement.ts +6 -5
  356. package/src/shared/cache-ttl-display.test.ts +1 -1
  357. package/src/shared/cache-ttl-display.ts +17 -16
  358. package/src/shared/fold-render-lock-fence.test.ts +84 -0
  359. package/src/shared/fold-render-lock-fixtures.test.ts +276 -0
  360. package/src/shared/model-cache-ttl.test.ts +2 -2
  361. package/src/shared/model-cache-ttl.ts +8 -4
  362. package/src/shared/model-suggestion-retry.test.ts +104 -1
  363. package/src/shared/model-suggestion-retry.ts +63 -6
  364. package/src/shared/models-dev-cache.ts +3 -11
  365. package/src/shared/protected-tools-policy.ts +23 -0
  366. package/src/shared/quota-diagnostic.ts +9 -0
  367. package/src/shared/rpc-server.ts +6 -54
  368. package/src/shared/sqlite-context-pragmas.test.ts +105 -0
  369. package/src/shared/sqlite-context-pragmas.ts +24 -0
  370. package/src/shared/sqlite-helpers.ts +17 -0
  371. package/src/shared/sqlite.ts +75 -0
  372. package/src/shared/status-detail-text.test.ts +18 -1
  373. package/src/shared/status-summary.ts +11 -0
  374. package/src/shared/status-view-check.ts +5 -0
  375. package/src/shared/status-view.test.ts +11 -2
  376. package/src/shared/status-view.ts +12 -1
  377. package/src/shared/storage-permissions.test.ts +204 -0
  378. package/src/shared/storage-permissions.ts +192 -0
  379. package/src/shared/temporal-upgrade-fixture.ts +50 -0
  380. package/src/shared/user-facing-codes.ts +6 -0
  381. package/src/shared/write-transaction-timing.test.ts +39 -0
  382. package/src/shared/write-transaction-timing.ts +25 -1
  383. package/src/tui/dialogs/status-dialog-render.test.ts +1 -1
  384. package/src/tui/index.tsx +3 -1
  385. package/src/tui/startup-order.test.ts +16 -0
  386. package/src/tui-compiled/index.tsx +3 -1
  387. package/src/v2/tui/index.ts +9 -2
  388. package/dist/index-anq4nn6f.js +0 -131
  389. package/dist/index-e44zzy84.js +0 -10
  390. package/dist/index-x23gah8c.js +0 -16
  391. package/dist/v2/recomp-orchestrator-1aq7h44c.js +0 -36
  392. package/dist/v2/server-e44zzy84.js +0 -10
  393. package/dist/v2/server-fgmxwrgy.js +0 -16
  394. package/dist/v2/server-r7cmye3k.js +0 -131
  395. package/dist/wrapup-orchestrator-h28bqsy6.js +0 -26
  396. package/dist/v2/{server-ckpc8pxy.js → server-1qbnzc80.js} +8 -8
@@ -1,28 +1,164 @@
1
1
  import {
2
- toolTemplateError
3
- } from "./server-remp7e2g.js";
4
- import {
5
- getHarness,
6
- getMagicContextStorageDir,
7
- importPluginModule,
8
- log
9
- } from "./server-ckpc8pxy.js";
10
- import {
11
- estimateTokens
12
- } from "./server-rhdgxp1t.js";
13
- import {
14
- shouldEnforcePrivateStoragePermissions
15
- } from "./server-e44zzy84.js";
2
+ toolTemplateError,
3
+ DEFAULT_PROTECTED_TOOLS,
4
+ mergeProtectedTools
5
+ } from "./server-g0fjrkta.js";
16
6
  import {
17
7
  modelRefLookupOrder
18
8
  } from "./server-avwt563y.js";
19
9
 
20
- // src/features/magic-context/memory/embedding-local.ts
21
- import { chmodSync, mkdirSync, readdirSync, statSync } from "node:fs";
22
- import { open, stat, unlink, writeFile } from "node:fs/promises";
23
- import { dirname, join } from "node:path";
24
- import { pathToFileURL } from "node:url";
25
- import { workerData } from "node:worker_threads";
10
+ // src/agents/language-directive.ts
11
+ var ENGLISH_LANGUAGE_NAMES = new Intl.DisplayNames(["en"], {
12
+ type: "language",
13
+ fallback: "none"
14
+ });
15
+ function resolveLanguageName(language) {
16
+ const code = typeof language === "string" ? language.trim().toLowerCase() : "";
17
+ if (!/^[a-z]{2}$/.test(code))
18
+ return "";
19
+ let english;
20
+ try {
21
+ english = ENGLISH_LANGUAGE_NAMES.of(code) ?? undefined;
22
+ } catch {
23
+ return "";
24
+ }
25
+ if (!english)
26
+ return "";
27
+ let endonym;
28
+ try {
29
+ endonym = new Intl.DisplayNames([code], { type: "language", fallback: "none" }).of(code) ?? undefined;
30
+ } catch {
31
+ endonym = undefined;
32
+ }
33
+ return endonym && endonym !== english ? `${english} (${endonym})` : english;
34
+ }
35
+ function isValidLanguageCode(language) {
36
+ return resolveLanguageName(language) !== "";
37
+ }
38
+ function buildContentLanguageDirective(language, options = {}) {
39
+ const target = resolveLanguageName(language);
40
+ if (!target)
41
+ return "";
42
+ const lines = [
43
+ "## Output language",
44
+ "",
45
+ `Write human-readable prose you author in: ${target}.`,
46
+ "",
47
+ "Do not translate or rename structural tokens. Copy required output schemas exactly:",
48
+ "- XML tag names, XML attribute names, JSON keys, tool names, tool-call argument keys, enum values, booleans/null, and required sentinel strings stay in English exactly as shown.",
49
+ "- Keep code identifiers, file paths, commands, config keys, CLI flags, URLs, commit hashes, model/provider IDs, stack traces, diagnostics, and transcript role markers such as U:, A:, and TC: verbatim.",
50
+ "- Localize only free-text prose values/content: summaries, memory text, explanations, titles, observations, and answers — unless the prompt says to preserve original wording.",
51
+ "",
52
+ "These literal values must remain English when used:",
53
+ "PROJECT_RULES, ARCHITECTURE, CONSTRAINTS, CONFIG_VALUES, NAMING;",
54
+ "causal_incident, trajectory_correction;",
55
+ "feature, design, docs, release, investigation, bug, refactor, infra;",
56
+ "memory, observation; true, false; No relevant memories found.",
57
+ "",
58
+ "Preserve the required output shape. Do not add commentary outside the requested XML/JSON/tool output."
59
+ ];
60
+ if (options.preserveUserQuotes) {
61
+ lines.push("", `Preserve U: lines and directly quoted user text in their original source language; write the surrounding summary prose in ${target}.`);
62
+ }
63
+ if (options.retrospective) {
64
+ lines.push("", `Write the lesson text in ${target}; paraphrase source text and never quote the user.`);
65
+ }
66
+ return lines.join(`
67
+ `);
68
+ }
69
+ function withContentLanguageDirective(systemPrompt, language, options = {}) {
70
+ const directive = buildContentLanguageDirective(language, options);
71
+ return directive ? `${systemPrompt}
72
+
73
+ ${directive}` : systemPrompt;
74
+ }
75
+ function buildPrimaryLanguageDirective(language) {
76
+ const target = resolveLanguageName(language);
77
+ if (!target)
78
+ return "";
79
+ return `Use ${target} for your natural-language replies to the user unless the user explicitly asks for another language. Keep code, identifiers, file paths, commands, logs, and quoted text verbatim.`;
80
+ }
81
+
82
+ // src/shared/prompt-surface.ts
83
+ function promptSurfaceConfigIdentity(config) {
84
+ return JSON.stringify({
85
+ default: config?.default ?? "full",
86
+ models: Object.entries(config?.models ?? {}).sort(([left], [right]) => left < right ? -1 : left > right ? 1 : 0),
87
+ guidanceOverridePath: config?.guidance_override_path ?? null,
88
+ toolDescriptions: Object.entries(config?.tool_descriptions ?? {}).sort(([left], [right]) => left < right ? -1 : left > right ? 1 : 0)
89
+ });
90
+ }
91
+ function isValidPromptSurfaceModelKey(key) {
92
+ if (key.length === 0 || key.trim() !== key)
93
+ return false;
94
+ const slash = key.indexOf("/");
95
+ if (slash < 0)
96
+ return !key.includes("*");
97
+ if (slash === 0 || slash === key.length - 1)
98
+ return false;
99
+ const provider = key.slice(0, slash);
100
+ const modelID = key.slice(slash + 1);
101
+ if (provider.trim() !== provider || modelID.trim() !== modelID || provider.includes("*") || modelID.includes("*") && modelID !== "*") {
102
+ return false;
103
+ }
104
+ if (modelID === "*")
105
+ return true;
106
+ return modelID.length > 0 && !modelID.startsWith("/") && !modelID.endsWith("/") && !modelID.includes("//");
107
+ }
108
+ function modelKeyLookupOrder(modelKey) {
109
+ if (!modelKey)
110
+ return [];
111
+ const slash = modelKey.indexOf("/");
112
+ if (slash <= 0 || slash === modelKey.length - 1)
113
+ return [];
114
+ const provider = modelKey.slice(0, slash);
115
+ let modelID = modelKey.slice(slash + 1);
116
+ const providerRefs = modelRefLookupOrder(`${provider}/${modelID}`);
117
+ const candidates = [];
118
+ while (modelID.length > 0) {
119
+ for (const providerRef of providerRefs) {
120
+ const providerSlash = providerRef.indexOf("/");
121
+ const providerPrefix = providerRef.slice(0, providerSlash);
122
+ candidates.push({ key: `${providerPrefix}/${modelID}`, source: "exact" });
123
+ }
124
+ candidates.push({ key: modelID, source: "bare" });
125
+ const lastDash = modelID.lastIndexOf("-");
126
+ if (lastDash <= 0)
127
+ break;
128
+ modelID = modelID.slice(0, lastDash);
129
+ }
130
+ for (const providerRef of providerRefs) {
131
+ const providerSlash = providerRef.indexOf("/");
132
+ const providerPrefix = providerRef.slice(0, providerSlash);
133
+ candidates.push({ key: `${providerPrefix}/*`, source: "wildcard" });
134
+ }
135
+ const seen = new Set;
136
+ return candidates.filter((candidate) => {
137
+ if (seen.has(candidate.key))
138
+ return false;
139
+ seen.add(candidate.key);
140
+ return true;
141
+ });
142
+ }
143
+ function resolveModelConfigValue(values, modelKey) {
144
+ if (!values)
145
+ return;
146
+ for (const candidate of modelKeyLookupOrder(modelKey)) {
147
+ const value = values[candidate.key];
148
+ if (value !== undefined) {
149
+ return { value, source: candidate.source };
150
+ }
151
+ }
152
+ return;
153
+ }
154
+ function resolvePromptSurface(config, modelKey) {
155
+ const fallback = config?.default ?? "full";
156
+ const match = resolveModelConfigValue(config?.models, modelKey);
157
+ if (match) {
158
+ return { preset: match.value, source: match.source };
159
+ }
160
+ return { preset: fallback, source: "default" };
161
+ }
26
162
 
27
163
  // src/config/schema/magic-context.ts
28
164
  import { homedir } from "node:os";
@@ -3293,7 +3429,7 @@ function initializeContext(params) {
3293
3429
  external: params?.external ?? undefined
3294
3430
  };
3295
3431
  }
3296
- function process2(schema, ctx, _params = { path: [], schemaPath: [] }) {
3432
+ function process(schema, ctx, _params = { path: [], schemaPath: [] }) {
3297
3433
  var _a;
3298
3434
  const def = schema._zod.def;
3299
3435
  const seen = ctx.seen.get(schema);
@@ -3330,7 +3466,7 @@ function process2(schema, ctx, _params = { path: [], schemaPath: [] }) {
3330
3466
  if (parent) {
3331
3467
  if (!result.ref)
3332
3468
  result.ref = parent;
3333
- process2(parent, ctx, params);
3469
+ process(parent, ctx, params);
3334
3470
  ctx.seen.get(parent).isParent = true;
3335
3471
  }
3336
3472
  }
@@ -3613,14 +3749,14 @@ function isTransforming(_schema, _ctx) {
3613
3749
  }
3614
3750
  var createToJSONSchemaMethod = (schema, processors = {}) => (params) => {
3615
3751
  const ctx = initializeContext({ ...params, processors });
3616
- process2(schema, ctx);
3752
+ process(schema, ctx);
3617
3753
  extractDefs(ctx, schema);
3618
3754
  return finalize(ctx, schema);
3619
3755
  };
3620
3756
  var createStandardJSONSchemaMethod = (schema, io, processors = {}) => (params) => {
3621
3757
  const { libraryOptions, target } = params ?? {};
3622
3758
  const ctx = initializeContext({ ...libraryOptions ?? {}, target, io, processors });
3623
- process2(schema, ctx);
3759
+ process(schema, ctx);
3624
3760
  extractDefs(ctx, schema);
3625
3761
  return finalize(ctx, schema);
3626
3762
  };
@@ -3770,7 +3906,7 @@ var arrayProcessor = (schema, ctx, _json, params) => {
3770
3906
  if (typeof maximum === "number")
3771
3907
  json.maxItems = maximum;
3772
3908
  json.type = "array";
3773
- json.items = process2(def.element, ctx, {
3909
+ json.items = process(def.element, ctx, {
3774
3910
  ...params,
3775
3911
  path: [...params.path, "items"]
3776
3912
  });
@@ -3782,7 +3918,7 @@ var objectProcessor = (schema, ctx, _json, params) => {
3782
3918
  json.properties = {};
3783
3919
  const shape = def.shape;
3784
3920
  for (const key in shape) {
3785
- json.properties[key] = process2(shape[key], ctx, {
3921
+ json.properties[key] = process(shape[key], ctx, {
3786
3922
  ...params,
3787
3923
  path: [...params.path, "properties", key]
3788
3924
  });
@@ -3805,7 +3941,7 @@ var objectProcessor = (schema, ctx, _json, params) => {
3805
3941
  if (ctx.io === "output")
3806
3942
  json.additionalProperties = false;
3807
3943
  } else if (def.catchall) {
3808
- json.additionalProperties = process2(def.catchall, ctx, {
3944
+ json.additionalProperties = process(def.catchall, ctx, {
3809
3945
  ...params,
3810
3946
  path: [...params.path, "additionalProperties"]
3811
3947
  });
@@ -3814,7 +3950,7 @@ var objectProcessor = (schema, ctx, _json, params) => {
3814
3950
  var unionProcessor = (schema, ctx, json, params) => {
3815
3951
  const def = schema._zod.def;
3816
3952
  const isExclusive = def.inclusive === false;
3817
- const options = def.options.map((x, i) => process2(x, ctx, {
3953
+ const options = def.options.map((x, i) => process(x, ctx, {
3818
3954
  ...params,
3819
3955
  path: [...params.path, isExclusive ? "oneOf" : "anyOf", i]
3820
3956
  }));
@@ -3826,11 +3962,11 @@ var unionProcessor = (schema, ctx, json, params) => {
3826
3962
  };
3827
3963
  var intersectionProcessor = (schema, ctx, json, params) => {
3828
3964
  const def = schema._zod.def;
3829
- const a = process2(def.left, ctx, {
3965
+ const a = process(def.left, ctx, {
3830
3966
  ...params,
3831
3967
  path: [...params.path, "allOf", 0]
3832
3968
  });
3833
- const b = process2(def.right, ctx, {
3969
+ const b = process(def.right, ctx, {
3834
3970
  ...params,
3835
3971
  path: [...params.path, "allOf", 1]
3836
3972
  });
@@ -3847,11 +3983,11 @@ var tupleProcessor = (schema, ctx, _json, params) => {
3847
3983
  json.type = "array";
3848
3984
  const prefixPath = ctx.target === "draft-2020-12" ? "prefixItems" : "items";
3849
3985
  const restPath = ctx.target === "draft-2020-12" ? "items" : ctx.target === "openapi-3.0" ? "items" : "additionalItems";
3850
- const prefixItems = def.items.map((x, i) => process2(x, ctx, {
3986
+ const prefixItems = def.items.map((x, i) => process(x, ctx, {
3851
3987
  ...params,
3852
3988
  path: [...params.path, prefixPath, i]
3853
3989
  }));
3854
- const rest = def.rest ? process2(def.rest, ctx, {
3990
+ const rest = def.rest ? process(def.rest, ctx, {
3855
3991
  ...params,
3856
3992
  path: [...params.path, restPath, ...ctx.target === "openapi-3.0" ? [def.items.length] : []]
3857
3993
  }) : null;
@@ -3891,7 +4027,7 @@ var recordProcessor = (schema, ctx, _json, params) => {
3891
4027
  const keyBag = keyType._zod.bag;
3892
4028
  const patterns = keyBag?.patterns;
3893
4029
  if (def.mode === "loose" && patterns && patterns.size > 0) {
3894
- const valueSchema = process2(def.valueType, ctx, {
4030
+ const valueSchema = process(def.valueType, ctx, {
3895
4031
  ...params,
3896
4032
  path: [...params.path, "patternProperties", "*"]
3897
4033
  });
@@ -3901,12 +4037,12 @@ var recordProcessor = (schema, ctx, _json, params) => {
3901
4037
  }
3902
4038
  } else {
3903
4039
  if (ctx.target === "draft-07" || ctx.target === "draft-2020-12") {
3904
- json.propertyNames = process2(def.keyType, ctx, {
4040
+ json.propertyNames = process(def.keyType, ctx, {
3905
4041
  ...params,
3906
4042
  path: [...params.path, "propertyNames"]
3907
4043
  });
3908
4044
  }
3909
- json.additionalProperties = process2(def.valueType, ctx, {
4045
+ json.additionalProperties = process(def.valueType, ctx, {
3910
4046
  ...params,
3911
4047
  path: [...params.path, "additionalProperties"]
3912
4048
  });
@@ -3921,7 +4057,7 @@ var recordProcessor = (schema, ctx, _json, params) => {
3921
4057
  };
3922
4058
  var nullableProcessor = (schema, ctx, json, params) => {
3923
4059
  const def = schema._zod.def;
3924
- const inner = process2(def.innerType, ctx, params);
4060
+ const inner = process(def.innerType, ctx, params);
3925
4061
  const seen = ctx.seen.get(schema);
3926
4062
  if (ctx.target === "openapi-3.0") {
3927
4063
  seen.ref = def.innerType;
@@ -3932,20 +4068,20 @@ var nullableProcessor = (schema, ctx, json, params) => {
3932
4068
  };
3933
4069
  var nonoptionalProcessor = (schema, ctx, _json, params) => {
3934
4070
  const def = schema._zod.def;
3935
- process2(def.innerType, ctx, params);
4071
+ process(def.innerType, ctx, params);
3936
4072
  const seen = ctx.seen.get(schema);
3937
4073
  seen.ref = def.innerType;
3938
4074
  };
3939
4075
  var defaultProcessor = (schema, ctx, json, params) => {
3940
4076
  const def = schema._zod.def;
3941
- process2(def.innerType, ctx, params);
4077
+ process(def.innerType, ctx, params);
3942
4078
  const seen = ctx.seen.get(schema);
3943
4079
  seen.ref = def.innerType;
3944
4080
  json.default = JSON.parse(JSON.stringify(def.defaultValue));
3945
4081
  };
3946
4082
  var prefaultProcessor = (schema, ctx, json, params) => {
3947
4083
  const def = schema._zod.def;
3948
- process2(def.innerType, ctx, params);
4084
+ process(def.innerType, ctx, params);
3949
4085
  const seen = ctx.seen.get(schema);
3950
4086
  seen.ref = def.innerType;
3951
4087
  if (ctx.io === "input")
@@ -3953,7 +4089,7 @@ var prefaultProcessor = (schema, ctx, json, params) => {
3953
4089
  };
3954
4090
  var catchProcessor = (schema, ctx, json, params) => {
3955
4091
  const def = schema._zod.def;
3956
- process2(def.innerType, ctx, params);
4092
+ process(def.innerType, ctx, params);
3957
4093
  const seen = ctx.seen.get(schema);
3958
4094
  seen.ref = def.innerType;
3959
4095
  let catchValue;
@@ -3968,20 +4104,20 @@ var pipeProcessor = (schema, ctx, _json, params) => {
3968
4104
  const def = schema._zod.def;
3969
4105
  const inIsTransform = def.in._zod.traits.has("$ZodTransform");
3970
4106
  const innerType = ctx.io === "input" ? inIsTransform ? def.out : def.in : def.out;
3971
- process2(innerType, ctx, params);
4107
+ process(innerType, ctx, params);
3972
4108
  const seen = ctx.seen.get(schema);
3973
4109
  seen.ref = innerType;
3974
4110
  };
3975
4111
  var readonlyProcessor = (schema, ctx, json, params) => {
3976
4112
  const def = schema._zod.def;
3977
- process2(def.innerType, ctx, params);
4113
+ process(def.innerType, ctx, params);
3978
4114
  const seen = ctx.seen.get(schema);
3979
4115
  seen.ref = def.innerType;
3980
4116
  json.readOnly = true;
3981
4117
  };
3982
4118
  var optionalProcessor = (schema, ctx, _json, params) => {
3983
4119
  const def = schema._zod.def;
3984
- process2(def.innerType, ctx, params);
4120
+ process(def.innerType, ctx, params);
3985
4121
  const seen = ctx.seen.get(schema);
3986
4122
  seen.ref = def.innerType;
3987
4123
  };
@@ -4883,78 +5019,6 @@ function superRefine(fn, params) {
4883
5019
  }
4884
5020
  // ../../node_modules/.bun/zod@4.4.3/node_modules/zod/v4/classic/external.js
4885
5021
  config(en_default());
4886
- // src/agents/language-directive.ts
4887
- var ENGLISH_LANGUAGE_NAMES = new Intl.DisplayNames(["en"], {
4888
- type: "language",
4889
- fallback: "none"
4890
- });
4891
- function resolveLanguageName(language) {
4892
- const code = typeof language === "string" ? language.trim().toLowerCase() : "";
4893
- if (!/^[a-z]{2}$/.test(code))
4894
- return "";
4895
- let english;
4896
- try {
4897
- english = ENGLISH_LANGUAGE_NAMES.of(code) ?? undefined;
4898
- } catch {
4899
- return "";
4900
- }
4901
- if (!english)
4902
- return "";
4903
- let endonym;
4904
- try {
4905
- endonym = new Intl.DisplayNames([code], { type: "language", fallback: "none" }).of(code) ?? undefined;
4906
- } catch {
4907
- endonym = undefined;
4908
- }
4909
- return endonym && endonym !== english ? `${english} (${endonym})` : english;
4910
- }
4911
- function isValidLanguageCode(language) {
4912
- return resolveLanguageName(language) !== "";
4913
- }
4914
- function buildContentLanguageDirective(language, options = {}) {
4915
- const target = resolveLanguageName(language);
4916
- if (!target)
4917
- return "";
4918
- const lines = [
4919
- "## Output language",
4920
- "",
4921
- `Write human-readable prose you author in: ${target}.`,
4922
- "",
4923
- "Do not translate or rename structural tokens. Copy required output schemas exactly:",
4924
- "- XML tag names, XML attribute names, JSON keys, tool names, tool-call argument keys, enum values, booleans/null, and required sentinel strings stay in English exactly as shown.",
4925
- "- Keep code identifiers, file paths, commands, config keys, CLI flags, URLs, commit hashes, model/provider IDs, stack traces, diagnostics, and transcript role markers such as U:, A:, and TC: verbatim.",
4926
- "- Localize only free-text prose values/content: summaries, memory text, explanations, titles, observations, and answers — unless the prompt says to preserve original wording.",
4927
- "",
4928
- "These literal values must remain English when used:",
4929
- "PROJECT_RULES, ARCHITECTURE, CONSTRAINTS, CONFIG_VALUES, NAMING;",
4930
- "causal_incident, trajectory_correction;",
4931
- "feature, design, docs, release, investigation, bug, refactor, infra;",
4932
- "memory, observation; true, false; No relevant memories found.",
4933
- "",
4934
- "Preserve the required output shape. Do not add commentary outside the requested XML/JSON/tool output."
4935
- ];
4936
- if (options.preserveUserQuotes) {
4937
- lines.push("", `Preserve U: lines and directly quoted user text in their original source language; write the surrounding summary prose in ${target}.`);
4938
- }
4939
- if (options.retrospective) {
4940
- lines.push("", `Write the lesson text in ${target}; paraphrase source text and never quote the user.`);
4941
- }
4942
- return lines.join(`
4943
- `);
4944
- }
4945
- function withContentLanguageDirective(systemPrompt, language, options = {}) {
4946
- const directive = buildContentLanguageDirective(language, options);
4947
- return directive ? `${systemPrompt}
4948
-
4949
- ${directive}` : systemPrompt;
4950
- }
4951
- function buildPrimaryLanguageDirective(language) {
4952
- const target = resolveLanguageName(language);
4953
- if (!target)
4954
- return "";
4955
- return `Use ${target} for your natural-language replies to the user unless the user explicitly asks for another language. Keep code, identifiers, file paths, commands, logs, and quoted text verbatim.`;
4956
- }
4957
-
4958
5022
  // src/features/magic-context/dreamer/cron.ts
4959
5023
  var FIELDS = [
4960
5024
  { name: "minute", min: 0, max: 59 },
@@ -5105,87 +5169,6 @@ function nextDueAtMs(expression, afterMs, consumedScheduledAtMs, maxSearchMs = M
5105
5169
  return next ? next.getTime() : null;
5106
5170
  }
5107
5171
 
5108
- // src/shared/prompt-surface.ts
5109
- function promptSurfaceConfigIdentity(config) {
5110
- return JSON.stringify({
5111
- default: config?.default ?? "full",
5112
- models: Object.entries(config?.models ?? {}).sort(([left], [right]) => left < right ? -1 : left > right ? 1 : 0),
5113
- guidanceOverridePath: config?.guidance_override_path ?? null,
5114
- toolDescriptions: Object.entries(config?.tool_descriptions ?? {}).sort(([left], [right]) => left < right ? -1 : left > right ? 1 : 0)
5115
- });
5116
- }
5117
- function isValidPromptSurfaceModelKey(key) {
5118
- if (key.length === 0 || key.trim() !== key)
5119
- return false;
5120
- const slash = key.indexOf("/");
5121
- if (slash < 0)
5122
- return !key.includes("*");
5123
- if (slash === 0 || slash === key.length - 1)
5124
- return false;
5125
- const provider = key.slice(0, slash);
5126
- const modelID = key.slice(slash + 1);
5127
- if (provider.trim() !== provider || modelID.trim() !== modelID || provider.includes("*") || modelID.includes("*") && modelID !== "*") {
5128
- return false;
5129
- }
5130
- if (modelID === "*")
5131
- return true;
5132
- return modelID.length > 0 && !modelID.startsWith("/") && !modelID.endsWith("/") && !modelID.includes("//");
5133
- }
5134
- function modelKeyLookupOrder(modelKey) {
5135
- if (!modelKey)
5136
- return [];
5137
- const slash = modelKey.indexOf("/");
5138
- if (slash <= 0 || slash === modelKey.length - 1)
5139
- return [];
5140
- const provider = modelKey.slice(0, slash);
5141
- let modelID = modelKey.slice(slash + 1);
5142
- const providerRefs = modelRefLookupOrder(`${provider}/${modelID}`);
5143
- const candidates = [];
5144
- while (modelID.length > 0) {
5145
- for (const providerRef of providerRefs) {
5146
- const providerSlash = providerRef.indexOf("/");
5147
- const providerPrefix = providerRef.slice(0, providerSlash);
5148
- candidates.push({ key: `${providerPrefix}/${modelID}`, source: "exact" });
5149
- }
5150
- candidates.push({ key: modelID, source: "bare" });
5151
- const lastDash = modelID.lastIndexOf("-");
5152
- if (lastDash <= 0)
5153
- break;
5154
- modelID = modelID.slice(0, lastDash);
5155
- }
5156
- for (const providerRef of providerRefs) {
5157
- const providerSlash = providerRef.indexOf("/");
5158
- const providerPrefix = providerRef.slice(0, providerSlash);
5159
- candidates.push({ key: `${providerPrefix}/*`, source: "wildcard" });
5160
- }
5161
- const seen = new Set;
5162
- return candidates.filter((candidate) => {
5163
- if (seen.has(candidate.key))
5164
- return false;
5165
- seen.add(candidate.key);
5166
- return true;
5167
- });
5168
- }
5169
- function resolveModelConfigValue(values, modelKey) {
5170
- if (!values)
5171
- return;
5172
- for (const candidate of modelKeyLookupOrder(modelKey)) {
5173
- const value = values[candidate.key];
5174
- if (value !== undefined) {
5175
- return { value, source: candidate.source };
5176
- }
5177
- }
5178
- return;
5179
- }
5180
- function resolvePromptSurface(config, modelKey) {
5181
- const fallback = config?.default ?? "full";
5182
- const match = resolveModelConfigValue(config?.models, modelKey);
5183
- if (match) {
5184
- return { preset: match.value, source: match.source };
5185
- }
5186
- return { preset: fallback, source: "default" };
5187
- }
5188
-
5189
5172
  // src/config/schema/agent-overrides.ts
5190
5173
  var PermissionValueSchema = _enum(["ask", "allow", "deny"]);
5191
5174
  var PermissionSchema = object({
@@ -5465,6 +5448,7 @@ var AgentMetadataSchema = AgentOverrideConfigSchema.pick({
5465
5448
  maxTokens: true
5466
5449
  });
5467
5450
  var DreamerConfigSchema = AgentMetadataSchema.extend({
5451
+ disable: boolean2().optional().describe("Disable this agent"),
5468
5452
  runner: _enum(["broca", "host"]).optional().describe(`Which side runs the dreamer completions the Rust module routes (classify-memories) in Rust transform mode: "host" runs them on this process's carrier, "broca" routes them to the Broca module. When unset, historian.runner applies, and when that is unset too the harness decides the same way it does for the historian. User-level config only.`),
5469
5453
  opencode: DreamerOpenCodeHarnessBlockSchema.optional(),
5470
5454
  pi: DreamerPiHarnessBlockSchema.optional(),
@@ -5613,7 +5597,7 @@ var MagicContextConfigSchema = object({
5613
5597
  smart_notes: object({
5614
5598
  retina_handoff: boolean2().default(false).describe("When true, dreamer skips smart notes whose surface conditions compiled to retina provider configs at authoring time. Default false keeps both paths active until the retina consumer is deployed.")
5615
5599
  }).default({ retina_handoff: false }).describe("Smart-note ownership transition controls."),
5616
- cache_ttl: union([string(), object({ default: string() }).catchall(string())]).default("5m").describe(`How long Magic Context assumes the provider's cached prefix stays valid. This is MC's own deferral gate — it does not change the provider's actual cache lifetime. String (e.g. "5m", "1h", "30s") or per-model object ({ default: "5m", "provider/model": "1h", "provider/*": "never" }); keys resolve most-specific first (exact provider/model, bare model ID, shorter dash-prefixes, then the provider/* wildcard). Explicit per-model entries win; otherwise GPT-5.6 and later (including gpt-6*, through any provider prefix) use a built-in 30m lifetime before the object default or 5m fallback. An unset or global "5m" opts into built-in defaults; any other global string is an explicit policy and wins. Policy is frozen per session, including across restarts; a model switch resolves against that frozen policy. /ctx-status shows the effective value and source. OpenAI documents at least 30 minutes since the latest write or reuse: https://developers.openai.com/api/docs/guides/prompt-caching (Cache lifetime and Summary of model differences). Set to "never" to mean MC never assumes expiry (for lanes kept warm externally by a cache-keep tool) — disables the idle-TTL heuristic so MC never initiates a rebuild based on elapsed time. Provider-side extended TTL is a separate request-level concern (cache_control: { ttl } in the request body).`),
5600
+ cache_ttl: union([string(), object({ default: string() }).catchall(string())]).default("5m").describe(`How long Magic Context assumes the provider's cached prefix stays valid. This is MC's own deferral gate — it does not change the provider's actual cache lifetime. String (e.g. "5m", "1h", "30s") or per-model object ({ default: "5m", "provider/model": "1h", "provider/*": "never" }); keys resolve most-specific first (exact provider/model, bare model ID, shorter dash-prefixes, then the provider/* wildcard, then default). User and project settings, including an explicit "5m" or object default, apply on the next pass. Only built-in defaults are frozen per session, including across restarts: when unset, GPT-5.6 and later (including gpt-6*, through any provider prefix) use 30m, other models use 5m. /ctx-status shows the effective TTL and whether it comes from your config or a frozen built-in default. Editing the TTL does not itself rewrite prompt bytes; a lowered TTL rebuilds only after normal idle expiry. OpenAI documents at least 30 minutes since the latest write or reuse: https://developers.openai.com/api/docs/guides/prompt-caching (Cache lifetime and Summary of model differences). Set to "never" to mean MC never assumes expiry (for lanes kept warm externally by a cache-keep tool) — disables the idle-TTL heuristic so MC never initiates a rebuild based on elapsed time. Provider-side extended TTL is a separate request-level concern (cache_control: { ttl } in the request body).`),
5617
5601
  prompt_surface: PromptSurfaceConfigSchema.default({ default: "full" }).describe("Prompt-surface presets: default is full; models use bare model IDs, provider/model, or provider/* routing keys. Guidance and tool-description overrides are user-level only. OpenCode 1.x, Pi, and OMP register tool descriptions once per process (they follow the default preset). OpenCode 2 rewrites the five ctx_* descriptions per request from the draft model."),
5618
5602
  output_reserve: union([
5619
5603
  number2().min(0),
@@ -5651,8 +5635,8 @@ var MagicContextConfigSchema = object({
5651
5635
  mmap_size_mb: number2().min(0).max(8192).default(0).describe("Memory-mapped I/O size in MiB (PRAGMA mmap_size). 0 disables mmap (SQLite default). Raising it can cut read overhead on large DBs at the cost of address space. (min 0, max 8192, default 0)")
5652
5636
  }).default({ cache_size_mb: 64, mmap_size_mb: 0 }).describe("SQLite connection tuning for Magic Context's own context.db. These are per-connection PRAGMAs applied at open; they do not change the schema or what is stored."),
5653
5637
  storage: object({
5654
- enforce_private_permissions: boolean2().default(true).describe("When true (default), Magic Context creates and re-tightens its storage directories to owner-only 0700 and storage files to owner-only 0600. Set false only for a deliberate trusted-group deployment whose operator manages directory, database, WAL/SHM, cache, and RPC file permissions externally; Magic Context then never chmods or supplies restrictive creation modes. USER-LEVEL ONLY — ignored in project config for security. On Windows, POSIX chmod modes are already meaningless, so this setting is a no-op.")
5655
- }).default({ enforce_private_permissions: true }).describe("Storage permission policy. The default keeps session content and memories owner-private. Disabling enforcement is for trusted shared-group storage managed externally; every group member able to read the storage can read all stored session content and memories."),
5638
+ enforce_private_permissions: boolean2().default(true).describe("When true (default), Magic Context creates and re-tightens its TypeScript-mode storage directories to owner-only 0700 and storage files to owner-only 0600. Set false only for a deliberate trusted-group deployment whose operator manages those files externally; in TypeScript mode Magic Context then skips its own creation modes and recursive tightening. In Rust transform mode, ck-mc's store library always keeps the shared data directory owner-only 0700, regardless of this setting. USER-LEVEL ONLY — ignored in project config for security. On Windows, POSIX chmod modes are already meaningless, so this setting is a no-op.")
5639
+ }).default({ enforce_private_permissions: true }).describe("Storage permission policy. The default keeps session content and memories owner-private. Disabling enforcement is for trusted shared-group storage managed externally; TypeScript mode follows that policy, but Rust transform mode always keeps its shared data directory owner-only because ck-mc's store library enforces it."),
5656
5640
  embedding: EmbeddingConfigSchema.default({
5657
5641
  provider: "local",
5658
5642
  model: DEFAULT_LOCAL_EMBEDDING_MODEL,
@@ -5676,7 +5660,8 @@ var MagicContextConfigSchema = object({
5676
5660
  overlay: boolean2().default(true).describe("Pi only: show the persistent todo overlay above the editor while tasks are active.")
5677
5661
  }).default({ enabled: false, overlay: true }).describe("Pi-only todowrite tool and overlay controls. Pi registers tools and widgets at extension boot, so changing this after /cd requires /reload or restart."),
5678
5662
  pi: PiConfigSchema.describe("Pi-only child-process extension controls. This setting is user-level only; project configuration cannot choose which extensions a user's subagent children load."),
5679
- smart_drops: boolean2().default(false).describe("Content-aware reclaim of provably-superseded tool output, layered on the existing execute-pass auto-drop. When on: superseded todowrite (keep newest 1), spent ctx_reduce (keep newest 3), and zero-value meta (bash_status, bash_kill, ctx_note read/dismiss) outputs are dropped; older edits to a file are compressed to a filePath-preserving marker while the newest edit per file stays full. Only acts on passes already busting the cache, so it never originates a cache bust. Honors the protected-tag reserve. Experimental: opt-in, default off until cache stability is proven; when off the wire is byte-identical to the positional-only reclaim. Requires a restart."),
5663
+ smart_drops: unknown().optional().describe("Deprecated: ignored. Content-aware supersession reclaim is always on, only on passes already rebuilding the cache. Remove this key; it no longer does anything.").meta({ deprecated: true }),
5664
+ protected_tools: record(string(), number2().int().nonnegative()).default({ ...DEFAULT_PROTECTED_TOOLS }).transform((map) => mergeProtectedTools(map)).describe("Keep each tool's newest N still-active results in every automatic drop lane (issue 621). User and project maps merge over defaults {todowrite: 1, ctx_reduce: 3}; 0 turns protection off. Names are case-insensitive and ignore leading mcp_. Holds even at 95% pressure, with no byte cap: large protected outputs can reach refusal sooner. Queued drops, from the agent or historian publication, are held until newer calls displace the result and a later cache-rebuilding pass applies them. The historian's summary is unaffected; the raw result leaves at the next fold. Frozen strips are unaffected. Changes and rotation never originate a bust; dropped results are never restored."),
5680
5665
  caveman_text_compression: object({
5681
5666
  enabled: boolean2().default(false).describe("Apply deterministic caveman-style text compression to old conversation text. Active for primary sessions when enabled; never for subagents. Compresses user/assistant text in oldest-first tiers: ultra (oldest 20%), full, lite, untouched (newest 40%)."),
5682
5667
  min_chars: number2().min(100).max(1e4).default(500).describe("Text parts shorter than this (characters) stay untouched. Min 100, max 10000. Default: 500.")
@@ -5711,6 +5696,7 @@ var MagicContextConfigSchema = object({
5711
5696
  };
5712
5697
  });
5713
5698
  var LIVE_RELOAD_CONFIG_PATHS = [
5699
+ "cache_ttl",
5714
5700
  "mural.model",
5715
5701
  "toast_duration_ms",
5716
5702
  "historian.opencode.model",
@@ -5729,6 +5715,7 @@ var LIVE_RELOAD_CONFIG_PATHS = [
5729
5715
  "commit_cluster_trigger.enabled",
5730
5716
  "commit_cluster_trigger.min_clusters",
5731
5717
  "memory.auto_promote",
5718
+ "dreamer.disable",
5732
5719
  "dreamer.maxTokens",
5733
5720
  "dreamer.opencode.model",
5734
5721
  "dreamer.opencode.fallback_models",
@@ -5781,3336 +5768,4 @@ function deriveDefaultProtectedTokens(usableSoft) {
5781
5768
  return Math.min(64000, Math.max(lowerBound, target));
5782
5769
  }
5783
5770
 
5784
- // src/features/magic-context/memory/embedding-failure.ts
5785
- function errorMessage(error) {
5786
- return error instanceof Error ? error.message : String(error ?? "unknown error");
5787
- }
5788
- function nestedMessages(error) {
5789
- const messages = [errorMessage(error)];
5790
- if (error && typeof error === "object" && "cause" in error) {
5791
- const cause = error.cause;
5792
- if (cause !== undefined)
5793
- messages.push(...nestedMessages(cause));
5794
- }
5795
- return messages;
5796
- }
5797
- function safeErrorDetail(message) {
5798
- return message.replace(/https?:\/\/[^\s"']+/gi, "<remote URL>").replace(/\/(?:Users|home)\/[^/\s]+/g, "~").replace(/\s+/g, " ").trim().slice(0, 240);
5799
- }
5800
- function hasAny(messages, patterns) {
5801
- return messages.some((message) => {
5802
- const lower = message.toLowerCase();
5803
- return patterns.some((pattern) => lower.includes(pattern));
5804
- });
5805
- }
5806
- function classifyLocalEmbeddingFailure(error, context = {}) {
5807
- const primaryMessages = nestedMessages(error);
5808
- const nativeMessages = context.nativeError === undefined ? [] : nestedMessages(context.nativeError);
5809
- if (hasAny(primaryMessages, [
5810
- "mc_embedding_fs_unavailable",
5811
- "file system cache is not available"
5812
- ]) || context.usesWasm && hasAny(primaryMessages, ["unable to get model file path or buffer"])) {
5813
- return {
5814
- class: "local_fs_unavailable",
5815
- reason: "the WASM model cache cannot access the Node filesystem",
5816
- retryable: false
5817
- };
5818
- }
5819
- if (hasAny(primaryMessages, [
5820
- "failed to fetch",
5821
- "fetch failed",
5822
- "network error",
5823
- "enotfound",
5824
- "econnreset",
5825
- "econnrefused",
5826
- "certificate",
5827
- "unable to load file",
5828
- "unauthorized access to file",
5829
- "forbidden access to file",
5830
- "not found at"
5831
- ]) || primaryMessages.some((message) => /\bHTTP\s+[45]\d\d\b/i.test(message))) {
5832
- return {
5833
- class: "local_download_failure",
5834
- reason: `the embedding model download failed: ${safeErrorDetail(primaryMessages[0])}`,
5835
- retryable: true
5836
- };
5837
- }
5838
- const bindingMessages = [...primaryMessages, ...nativeMessages];
5839
- if (hasAny(bindingMessages, [
5840
- "onnxruntime_binding.node",
5841
- "cannot find package 'onnxruntime-node'",
5842
- 'cannot find package "onnxruntime-node"',
5843
- "cannot find module 'onnxruntime-node'",
5844
- 'cannot find module "onnxruntime-node"',
5845
- "could not resolve: onnxruntime-node"
5846
- ])) {
5847
- const platform = context.platform ?? process.platform;
5848
- const arch = context.arch ?? process.arch;
5849
- return {
5850
- class: "local_binding_missing",
5851
- reason: platform === "darwin" && arch === "x64" ? "onnxruntime-node has no darwin/x64 native binding and the WASM fallback could not complete" : `onnxruntime-node has no usable native binding for ${platform}/${arch} and the WASM fallback could not complete`,
5852
- retryable: false
5853
- };
5854
- }
5855
- return {
5856
- class: "local_runtime_error",
5857
- reason: `the local embedding runtime failed: ${safeErrorDetail(primaryMessages[0])}`,
5858
- retryable: false
5859
- };
5860
- }
5861
- function dominantEmbeddingFailure(failures) {
5862
- const counts = new Map;
5863
- for (const failure of failures) {
5864
- const key = `${failure.class}\x00${failure.reason}`;
5865
- const current = counts.get(key);
5866
- if (current)
5867
- current.count += 1;
5868
- else
5869
- counts.set(key, { failure, count: 1 });
5870
- }
5871
- let dominant;
5872
- for (const candidate of counts.values()) {
5873
- if (!dominant || candidate.count > dominant.count)
5874
- dominant = candidate;
5875
- }
5876
- return dominant?.failure;
5877
- }
5878
-
5879
- // src/features/magic-context/memory/embedding-model-match.ts
5880
- function parseEmbeddingModel(model) {
5881
- const lastColon = model.lastIndexOf(":");
5882
- if (lastColon > model.lastIndexOf("/")) {
5883
- return { base: model.slice(0, lastColon), tag: model.slice(lastColon + 1) };
5884
- }
5885
- return { base: model };
5886
- }
5887
- function normalizeEmbeddingModelId(model) {
5888
- return parseEmbeddingModel(model.trim().toLowerCase()).base;
5889
- }
5890
- function matchNormalizedEmbeddingModels(a, b) {
5891
- if (a.length === 0 || b.length === 0)
5892
- return true;
5893
- if (a === b)
5894
- return true;
5895
- const longer = a.length >= b.length ? a : b;
5896
- const shorter = a.length >= b.length ? b : a;
5897
- const isBoundary = (ch) => ch === "-" || ch === "/";
5898
- if (longer.startsWith(shorter) && isBoundary(longer.charAt(shorter.length)))
5899
- return true;
5900
- if (longer.endsWith(shorter) && isBoundary(longer.charAt(longer.length - shorter.length - 1)))
5901
- return true;
5902
- return false;
5903
- }
5904
- function embeddingModelsMatch(served, requested) {
5905
- const servedNormalized = served.trim().toLowerCase();
5906
- const requestedNormalized = requested.trim().toLowerCase();
5907
- const servedModel = parseEmbeddingModel(servedNormalized);
5908
- const requestedModel = parseEmbeddingModel(requestedNormalized);
5909
- if (servedModel.tag !== undefined && requestedModel.tag !== undefined && servedModel.tag !== requestedModel.tag) {
5910
- return false;
5911
- }
5912
- return matchNormalizedEmbeddingModels(servedModel.base, requestedModel.base);
5913
- }
5914
- var QWEN3_QUERY_INSTRUCTION = `Instruct: Given a web search query, retrieve relevant passages that answer the query
5915
- Query: `;
5916
- var INSTRUCT_WEB_SEARCH_QUERY_PREFIX = QWEN3_QUERY_INSTRUCTION;
5917
- var EMBEDDING_MODEL_PREFIX_FAMILIES = [
5918
- {
5919
- family: "qwen3-embedding",
5920
- basenamePattern: /^qwen3-embedding(?:-|$)/,
5921
- prefixes: { queryPrefix: QWEN3_QUERY_INSTRUCTION, documentPrefix: "" }
5922
- },
5923
- {
5924
- family: "gte-qwen-instruct",
5925
- basenamePattern: /^gte-qwen.*-instruct(?:-|$)/,
5926
- prefixes: { queryPrefix: INSTRUCT_WEB_SEARCH_QUERY_PREFIX, documentPrefix: "" }
5927
- },
5928
- {
5929
- family: "e5-instruct",
5930
- basenamePattern: /^(?:multilingual-)?e5-.*-instruct(?:-|$)/,
5931
- prefixes: { queryPrefix: INSTRUCT_WEB_SEARCH_QUERY_PREFIX, documentPrefix: "" }
5932
- },
5933
- {
5934
- family: "nomic-embed-text",
5935
- basenamePattern: /^nomic-embed-text(?:-|$)/,
5936
- prefixes: { queryPrefix: "search_query: ", documentPrefix: "search_document: " }
5937
- }
5938
- ];
5939
- function modelBasename(model) {
5940
- const normalized = normalizeEmbeddingModelId(model);
5941
- return normalized.slice(normalized.lastIndexOf("/") + 1);
5942
- }
5943
- function resolveEmbeddingTextPrefixes(model, queryInstruction, documentPrefix) {
5944
- const family = EMBEDDING_MODEL_PREFIX_FAMILIES.find(({ basenamePattern }) => basenamePattern.test(modelBasename(model)));
5945
- return {
5946
- queryPrefix: queryInstruction === false ? "" : queryInstruction !== undefined ? queryInstruction : family?.prefixes.queryPrefix ?? "",
5947
- documentPrefix: documentPrefix ?? family?.prefixes.documentPrefix ?? ""
5948
- };
5949
- }
5950
-
5951
- // src/features/magic-context/memory/embedding-synapse.ts
5952
- import { createHash } from "node:crypto";
5953
-
5954
- // ../../node_modules/.bun/@cortexkit+subc-client@0.11.1/node_modules/@cortexkit/subc-client/dist/client.js
5955
- import { promises as fs2 } from "node:fs";
5956
- import { debuglog } from "node:util";
5957
-
5958
- // ../../node_modules/.bun/@cortexkit+subc-client@0.11.1/node_modules/@cortexkit/subc-client/dist/auth.js
5959
- import { createHmac, randomBytes, timingSafeEqual } from "node:crypto";
5960
-
5961
- // ../../node_modules/.bun/@cortexkit+subc-client@0.11.1/node_modules/@cortexkit/subc-client/dist/socket.js
5962
- import net from "node:net";
5963
-
5964
- // ../../node_modules/.bun/@cortexkit+subc-client@0.11.1/node_modules/@cortexkit/subc-client/dist/envelope.js
5965
- var PROTOCOL_VERSION = 2;
5966
- var HEADER_LEN = 21;
5967
- var FROZEN_PREFIX_LEN = 5;
5968
- var MAX_FRAME_BODY_LEN = 64 * 1024 * 1024;
5969
- var FrameType;
5970
- (function(FrameType) {
5971
- FrameType[FrameType["Request"] = 0] = "Request";
5972
- FrameType[FrameType["Response"] = 1] = "Response";
5973
- FrameType[FrameType["Push"] = 2] = "Push";
5974
- FrameType[FrameType["StreamData"] = 3] = "StreamData";
5975
- FrameType[FrameType["StreamEnd"] = 4] = "StreamEnd";
5976
- FrameType[FrameType["Error"] = 5] = "Error";
5977
- FrameType[FrameType["Cancel"] = 6] = "Cancel";
5978
- FrameType[FrameType["Ping"] = 7] = "Ping";
5979
- FrameType[FrameType["Pong"] = 8] = "Pong";
5980
- FrameType[FrameType["Hello"] = 9] = "Hello";
5981
- FrameType[FrameType["HelloAck"] = 10] = "HelloAck";
5982
- FrameType[FrameType["Goodbye"] = 11] = "Goodbye";
5983
- })(FrameType || (FrameType = {}));
5984
- var FRAME_TYPE_MAX = FrameType.Goodbye;
5985
- function isPureHeader(ty) {
5986
- return ty === FrameType.Cancel || ty === FrameType.Ping || ty === FrameType.Pong || ty === FrameType.Goodbye;
5987
- }
5988
- var Priority;
5989
- (function(Priority) {
5990
- Priority[Priority["Passive"] = 0] = "Passive";
5991
- Priority[Priority["Interactive"] = 1] = "Interactive";
5992
- Priority[Priority["Background"] = 2] = "Background";
5993
- })(Priority || (Priority = {}));
5994
- var AdmissionClass;
5995
- (function(AdmissionClass) {
5996
- AdmissionClass[AdmissionClass["Normal"] = 0] = "Normal";
5997
- AdmissionClass[AdmissionClass["Expedite"] = 1] = "Expedite";
5998
- AdmissionClass[AdmissionClass["Sheddable"] = 2] = "Sheddable";
5999
- })(AdmissionClass || (AdmissionClass = {}));
6000
- var FLAG_BINARY = 1;
6001
- var FLAG_PRIORITY_MASK = 6;
6002
- var FLAG_PRIORITY_SHIFT = 1;
6003
- var FLAG_LAST = 8;
6004
- var FLAG_ADMISSION_MASK = 48;
6005
- var FLAG_ADMISSION_SHIFT = 4;
6006
- var FLAG_RESERVED_MASK = 128;
6007
- function buildFlags(binary, priority, last, admissionClass = AdmissionClass.Normal) {
6008
- let flags = 0;
6009
- if (binary)
6010
- flags |= FLAG_BINARY;
6011
- flags |= priority << FLAG_PRIORITY_SHIFT;
6012
- if (last)
6013
- flags |= FLAG_LAST;
6014
- flags |= admissionClass << FLAG_ADMISSION_SHIFT;
6015
- return flags;
6016
- }
6017
- function hasBinary(flags) {
6018
- return (flags & FLAG_BINARY) !== 0;
6019
- }
6020
- function encodeHeader(header) {
6021
- const buffer = new Uint8Array(HEADER_LEN);
6022
- const view = new DataView(buffer.buffer);
6023
- view.setUint32(0, header.len, true);
6024
- buffer[4] = header.ver;
6025
- buffer[5] = header.ty;
6026
- buffer[6] = header.flags;
6027
- view.setUint16(7, header.channel, true);
6028
- view.setUint32(9, header.epoch, true);
6029
- view.setBigUint64(13, header.corr, true);
6030
- return buffer;
6031
- }
6032
-
6033
- class DecodeError extends Error {
6034
- code;
6035
- constructor(message, code) {
6036
- super(message);
6037
- this.code = code;
6038
- this.name = "DecodeError";
6039
- }
6040
- }
6041
- function validateHeaderFields(header) {
6042
- const len = header.len >>> 0;
6043
- const ver = header.ver >>> 0 & 255;
6044
- const typeByte = header.ty >>> 0 & 255;
6045
- const flags = header.flags >>> 0 & 255;
6046
- const channel = header.channel >>> 0 & 65535;
6047
- const epoch = header.epoch >>> 0;
6048
- BigInt.asUintN(64, header.corr);
6049
- if (ver !== PROTOCOL_VERSION)
6050
- throw new DecodeError(`unsupported envelope version ${ver}`, "unsupported_version");
6051
- if (typeByte > FRAME_TYPE_MAX)
6052
- throw new DecodeError(`unknown frame type byte ${typeByte}`, "unknown_frame_type");
6053
- const ty = typeByte;
6054
- if ((flags & FLAG_RESERVED_MASK) !== 0) {
6055
- throw new DecodeError(`reserved flag bits set in flags 0b${flags.toString(2).padStart(8, "0")}`, "reserved_flag_bits");
6056
- }
6057
- if ((flags & FLAG_PRIORITY_MASK) >> FLAG_PRIORITY_SHIFT === 3) {
6058
- throw new DecodeError(`reserved priority bits set in flags 0b${flags.toString(2).padStart(8, "0")}`, "reserved_priority_bits");
6059
- }
6060
- const admission = (flags & FLAG_ADMISSION_MASK) >> FLAG_ADMISSION_SHIFT;
6061
- if (admission === 3) {
6062
- throw new DecodeError(`reserved admission class set in flags 0b${flags.toString(2).padStart(8, "0")}`, "reserved_admission_class");
6063
- }
6064
- if (admission === AdmissionClass.Sheddable && ty !== FrameType.Push && ty !== FrameType.StreamData) {
6065
- throw new DecodeError(`SHEDDABLE admission class is illegal on ${FrameType[ty]} in flags 0b${flags.toString(2).padStart(8, "0")}`, "sheddable_illegal_frame_type");
6066
- }
6067
- if (channel === 0 && epoch !== 0) {
6068
- throw new DecodeError(`control channel carried nonzero epoch ${epoch}`, "nonzero_epoch_on_control_channel");
6069
- }
6070
- if (isPureHeader(ty) && len !== 0) {
6071
- throw new DecodeError(`pure-header frame ${FrameType[ty]} declared non-zero body length ${len}`, "pure_header_frame_with_body");
6072
- }
6073
- }
6074
- function decodeHeader(bytes) {
6075
- if (bytes.length < FROZEN_PREFIX_LEN) {
6076
- throw new DecodeError(`header shorter than frozen prefix: have ${bytes.length} bytes`, "too_short_for_prefix");
6077
- }
6078
- const ver = bytes[4];
6079
- if (ver !== PROTOCOL_VERSION)
6080
- throw new DecodeError(`unsupported envelope version ${ver}`, "unsupported_version");
6081
- if (bytes.length < HEADER_LEN) {
6082
- throw new DecodeError(`header too short for version: have ${bytes.length} bytes, need ${HEADER_LEN}`, "too_short_for_header");
6083
- }
6084
- const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
6085
- const len = view.getUint32(0, true);
6086
- const typeByte = bytes[5];
6087
- if (typeByte > FRAME_TYPE_MAX)
6088
- throw new DecodeError(`unknown frame type byte ${typeByte}`, "unknown_frame_type");
6089
- const ty = typeByte;
6090
- const flags = bytes[6];
6091
- if ((flags & FLAG_RESERVED_MASK) !== 0) {
6092
- throw new DecodeError(`reserved flag bits set in flags 0b${flags.toString(2).padStart(8, "0")}`, "reserved_flag_bits");
6093
- }
6094
- if ((flags & FLAG_PRIORITY_MASK) >> FLAG_PRIORITY_SHIFT === 3) {
6095
- throw new DecodeError(`reserved priority bits set in flags 0b${flags.toString(2).padStart(8, "0")}`, "reserved_priority_bits");
6096
- }
6097
- const admission = (flags & FLAG_ADMISSION_MASK) >> FLAG_ADMISSION_SHIFT;
6098
- if (admission === 3) {
6099
- throw new DecodeError(`reserved admission class set in flags 0b${flags.toString(2).padStart(8, "0")}`, "reserved_admission_class");
6100
- }
6101
- if (admission === AdmissionClass.Sheddable && ty !== FrameType.Push && ty !== FrameType.StreamData) {
6102
- throw new DecodeError(`SHEDDABLE admission class is illegal on ${FrameType[ty]} in flags 0b${flags.toString(2).padStart(8, "0")}`, "sheddable_illegal_frame_type");
6103
- }
6104
- const channel = view.getUint16(7, true);
6105
- const epoch = view.getUint32(9, true);
6106
- if (channel === 0 && epoch !== 0) {
6107
- throw new DecodeError(`control channel carried nonzero epoch ${epoch}`, "nonzero_epoch_on_control_channel");
6108
- }
6109
- if (isPureHeader(ty) && len !== 0) {
6110
- throw new DecodeError(`pure-header frame ${FrameType[ty]} declared non-zero body length ${len}`, "pure_header_frame_with_body");
6111
- }
6112
- return { len, ver, ty, flags, channel, epoch, corr: view.getBigUint64(13, true) };
6113
- }
6114
- function buildFrame(ty, flags, channel, epoch, corr, body) {
6115
- return buildFrameWithVersion(PROTOCOL_VERSION, ty, flags, channel, epoch, corr, body);
6116
- }
6117
- function buildFrameWithVersion(ver, ty, flags, channel, epoch, corr, body) {
6118
- if (body.length > MAX_FRAME_BODY_LEN) {
6119
- throw new DecodeError(`frame body ${body.length} exceeds max ${MAX_FRAME_BODY_LEN}`, "frame_body_too_large");
6120
- }
6121
- const header = { len: body.length, ver, ty, flags, channel, epoch, corr };
6122
- validateHeaderFields(header);
6123
- return { header, body };
6124
- }
6125
- function encodeFrame(frame) {
6126
- if (frame.header.len !== frame.body.length) {
6127
- throw new DecodeError(`frame header length ${frame.header.len} does not match body length ${frame.body.length}`, "frame_length_mismatch");
6128
- }
6129
- const header = encodeHeader(frame.header);
6130
- const output = new Uint8Array(header.length + frame.body.length);
6131
- output.set(header, 0);
6132
- output.set(frame.body, header.length);
6133
- return output;
6134
- }
6135
-
6136
- // ../../node_modules/.bun/@cortexkit+subc-client@0.11.1/node_modules/@cortexkit/subc-client/dist/socket.js
6137
- class SocketClosedError extends Error {
6138
- }
6139
-
6140
- class SocketTimeoutError extends Error {
6141
- }
6142
-
6143
- class SocketWriteNotQueuedError extends Error {
6144
- cause;
6145
- constructor(message, cause) {
6146
- super(message);
6147
- this.cause = cause;
6148
- }
6149
- }
6150
-
6151
- class SocketWriteQueuedError extends Error {
6152
- cause;
6153
- constructor(message, cause) {
6154
- super(message);
6155
- this.cause = cause;
6156
- }
6157
- }
6158
- function toWriteBuffer(bytes) {
6159
- return Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength);
6160
- }
6161
- var WRITE_BORROWED = Symbol("subc.socket.writeBorrowed");
6162
- var WRITE_TRACKED_BORROWED = Symbol("subc.socket.writeTrackedBorrowed");
6163
- function writeBorrowed(socket, bytes, deadlineMs) {
6164
- const borrowed = socket[WRITE_BORROWED];
6165
- return borrowed ? borrowed.call(socket, bytes, deadlineMs) : socket.write(bytes, deadlineMs);
6166
- }
6167
- function writeTrackedBorrowed(socket, bytes, deadlineMs) {
6168
- const borrowed = socket[WRITE_TRACKED_BORROWED];
6169
- return borrowed ? borrowed.call(socket, bytes, deadlineMs) : socket.writeTracked(bytes, deadlineMs);
6170
- }
6171
-
6172
- class SubcSocket {
6173
- sock;
6174
- chunks = [];
6175
- buffered = 0;
6176
- waiter = null;
6177
- closedErr = null;
6178
- bufferedBytes() {
6179
- return this.buffered;
6180
- }
6181
- constructor(sock) {
6182
- this.sock = sock;
6183
- sock.on("data", (chunk) => {
6184
- this.chunks.push(chunk);
6185
- this.buffered += chunk.length;
6186
- this.tryServe();
6187
- });
6188
- const fail = (err) => {
6189
- if (!this.closedErr)
6190
- this.closedErr = err;
6191
- this.tryServe();
6192
- };
6193
- sock.on("error", (err) => fail(err instanceof Error ? err : new Error(String(err))));
6194
- sock.on("end", () => fail(new SocketClosedError("subc closed the connection")));
6195
- sock.on("close", () => fail(new SocketClosedError("subc connection closed")));
6196
- }
6197
- localPort() {
6198
- return this.sock.localPort ?? null;
6199
- }
6200
- static connect(host, port, deadlineMs) {
6201
- return new Promise((resolve, reject) => {
6202
- const sock = net.connect({ host, port });
6203
- sock.setNoDelay(true);
6204
- const timer = setTimeout(() => {
6205
- sock.destroy();
6206
- reject(new SocketTimeoutError(`timed out connecting to ${host}:${port}`));
6207
- }, Math.max(0, deadlineMs - Date.now()));
6208
- sock.once("connect", () => {
6209
- clearTimeout(timer);
6210
- resolve(new SubcSocket(sock));
6211
- });
6212
- sock.once("error", (err) => {
6213
- clearTimeout(timer);
6214
- reject(err);
6215
- });
6216
- });
6217
- }
6218
- async readFrame(headerDeadlineMs, bodyDeadline, onHeader) {
6219
- const prefix = await this.readExact(FROZEN_PREFIX_LEN, headerDeadlineMs);
6220
- const version = prefix[4];
6221
- if (version !== PROTOCOL_VERSION)
6222
- throw new DecodeError(`unsupported envelope version ${version}`, "unsupported_version");
6223
- const remainder = await this.readExact(HEADER_LEN - FROZEN_PREFIX_LEN, headerDeadlineMs);
6224
- const headerBytes = new Uint8Array(HEADER_LEN);
6225
- headerBytes.set(prefix);
6226
- headerBytes.set(remainder, FROZEN_PREFIX_LEN);
6227
- const header = decodeHeader(headerBytes);
6228
- if (header.len > MAX_FRAME_BODY_LEN) {
6229
- throw new DecodeError(`frame body ${header.len} exceeds max ${MAX_FRAME_BODY_LEN}`, "frame_body_too_large");
6230
- }
6231
- onHeader?.();
6232
- const bodyDeadlineMs = typeof bodyDeadline === "number" ? bodyDeadline : Date.now() + bodyDeadline.afterHeaderMs;
6233
- const body = header.len === 0 ? new Uint8Array(0) : await this.readExact(header.len, bodyDeadlineMs);
6234
- return { header, body };
6235
- }
6236
- readExact(n, deadlineMs) {
6237
- if (this.waiter) {
6238
- return Promise.reject(new Error("concurrent readExact is not supported"));
6239
- }
6240
- if (n === 0)
6241
- return Promise.resolve(new Uint8Array(0));
6242
- return new Promise((resolve, reject) => {
6243
- let timer = null;
6244
- if (Number.isFinite(deadlineMs)) {
6245
- const remaining = deadlineMs - Date.now();
6246
- if (remaining <= 0) {
6247
- reject(new SocketTimeoutError(`timed out waiting for ${n} bytes`));
6248
- return;
6249
- }
6250
- timer = setTimeout(() => {
6251
- this.waiter = null;
6252
- reject(new SocketTimeoutError(`timed out waiting for ${n} bytes`));
6253
- }, remaining);
6254
- }
6255
- this.waiter = { need: n, resolve, reject, timer };
6256
- this.tryServe();
6257
- });
6258
- }
6259
- async write(bytes, deadlineMs) {
6260
- await this.writeBuffer(Buffer.from(bytes), deadlineMs);
6261
- }
6262
- writeTracked(bytes, deadlineMs) {
6263
- return this.writeTrackedBuffer(Buffer.from(bytes), deadlineMs);
6264
- }
6265
- async[WRITE_BORROWED](bytes, deadlineMs) {
6266
- await this.writeBuffer(toWriteBuffer(bytes), deadlineMs);
6267
- }
6268
- [WRITE_TRACKED_BORROWED](bytes, deadlineMs) {
6269
- return this.writeTrackedBuffer(toWriteBuffer(bytes), deadlineMs);
6270
- }
6271
- async writeBuffer(buffer, deadlineMs) {
6272
- try {
6273
- await this.writeTrackedBuffer(buffer, deadlineMs).completed;
6274
- } catch (err) {
6275
- if (err instanceof SocketWriteNotQueuedError || err instanceof SocketWriteQueuedError) {
6276
- throw err.cause ?? err;
6277
- }
6278
- throw err;
6279
- }
6280
- }
6281
- writeTrackedBuffer(buffer, deadlineMs) {
6282
- if (this.closedErr) {
6283
- return {
6284
- queued: false,
6285
- completed: Promise.reject(new SocketWriteNotQueuedError("subc socket was closed before bytes could be queued", this.closedErr))
6286
- };
6287
- }
6288
- let queued = false;
6289
- let settled = false;
6290
- let timer = null;
6291
- const completed = new Promise((resolve, reject) => {
6292
- const settle = (run) => {
6293
- if (settled)
6294
- return;
6295
- settled = true;
6296
- if (timer)
6297
- clearTimeout(timer);
6298
- run();
6299
- };
6300
- const remaining = deadlineMs - Date.now();
6301
- if (remaining <= 0) {
6302
- settle(() => reject(new SocketWriteNotQueuedError("timed out before bytes could be queued to subc", new SocketTimeoutError("timed out writing to subc"))));
6303
- return;
6304
- }
6305
- timer = setTimeout(() => {
6306
- const timeout = new SocketTimeoutError("timed out writing to subc");
6307
- settle(() => reject(queued ? new SocketWriteQueuedError("timed out after bytes were handed to the subc socket", timeout) : new SocketWriteNotQueuedError("timed out before bytes could be queued to subc", timeout)));
6308
- }, remaining);
6309
- try {
6310
- this.sock.write(buffer, (err) => {
6311
- settle(() => {
6312
- if (err) {
6313
- reject(new SocketWriteQueuedError("subc socket reported a write error after bytes were handed to the socket", err instanceof Error ? err : new Error(String(err))));
6314
- } else {
6315
- resolve();
6316
- }
6317
- });
6318
- });
6319
- queued = true;
6320
- } catch (err) {
6321
- settle(() => reject(new SocketWriteNotQueuedError("subc socket write threw before bytes could be queued", err instanceof Error ? err : new Error(String(err)))));
6322
- }
6323
- });
6324
- return { queued, completed };
6325
- }
6326
- close() {
6327
- this.sock.destroy();
6328
- }
6329
- tryServe() {
6330
- const w = this.waiter;
6331
- if (!w)
6332
- return;
6333
- if (this.buffered >= w.need) {
6334
- const out = this.take(w.need);
6335
- this.waiter = null;
6336
- if (w.timer)
6337
- clearTimeout(w.timer);
6338
- w.resolve(out);
6339
- return;
6340
- }
6341
- if (this.closedErr) {
6342
- this.waiter = null;
6343
- if (w.timer)
6344
- clearTimeout(w.timer);
6345
- w.reject(this.closedErr);
6346
- }
6347
- }
6348
- take(n) {
6349
- const out = Buffer.allocUnsafe(n);
6350
- let off = 0;
6351
- while (off < n) {
6352
- const head = this.chunks[0];
6353
- const want = n - off;
6354
- if (head.length <= want) {
6355
- head.copy(out, off);
6356
- off += head.length;
6357
- this.chunks.shift();
6358
- } else {
6359
- head.copy(out, off, 0, want);
6360
- this.chunks[0] = head.subarray(want);
6361
- off += want;
6362
- }
6363
- }
6364
- this.buffered -= n;
6365
- return out;
6366
- }
6367
- }
6368
-
6369
- // ../../node_modules/.bun/@cortexkit+subc-client@0.11.1/node_modules/@cortexkit/subc-client/dist/auth.js
6370
- var NONCE_LEN = 32;
6371
- var MAX_AUTH_MESSAGE_LEN = 4096;
6372
- var SERVER_PROOF_DOMAIN = "subc-server-v1";
6373
- var CLIENT_AUTH_DOMAIN = "subc-client-v1";
6374
- var DEFAULT_CLIENT_ROLE = "client";
6375
-
6376
- class AuthError extends Error {
6377
- }
6378
- function computeProof(key, domain, clientNonce, serverNonce, daemonId) {
6379
- const mac = createHmac("sha256", Buffer.from(key));
6380
- mac.update(Buffer.from(domain, "utf8"));
6381
- mac.update(Buffer.from(clientNonce));
6382
- mac.update(Buffer.from(serverNonce));
6383
- mac.update(Buffer.from(daemonId));
6384
- return new Uint8Array(mac.digest());
6385
- }
6386
- function constantTimeEq(a, b) {
6387
- if (a.length !== b.length)
6388
- return false;
6389
- return timingSafeEqual(Buffer.from(a), Buffer.from(b));
6390
- }
6391
- async function writeMessage(sock, value, deadlineMs) {
6392
- const json = Buffer.from(JSON.stringify(value), "utf8");
6393
- if (json.length > MAX_AUTH_MESSAGE_LEN) {
6394
- throw new AuthError(`auth message too large: ${json.length} > ${MAX_AUTH_MESSAGE_LEN}`);
6395
- }
6396
- const lenPrefix = new Uint8Array(4);
6397
- new DataView(lenPrefix.buffer).setUint32(0, json.length, true);
6398
- await writeBorrowed(sock, lenPrefix, deadlineMs);
6399
- await writeBorrowed(sock, json, deadlineMs);
6400
- }
6401
- async function readMessage(sock, deadlineMs) {
6402
- const lenBytes = await sock.readExact(4, deadlineMs);
6403
- const len = new DataView(lenBytes.buffer, lenBytes.byteOffset, 4).getUint32(0, true);
6404
- if (len > MAX_AUTH_MESSAGE_LEN) {
6405
- throw new AuthError(`auth message too large: ${len} > ${MAX_AUTH_MESSAGE_LEN}`);
6406
- }
6407
- const body = len === 0 ? new Uint8Array(0) : await sock.readExact(len, deadlineMs);
6408
- try {
6409
- return JSON.parse(Buffer.from(body).toString("utf8"));
6410
- } catch (err) {
6411
- throw new AuthError(`auth message JSON decode failed: ${String(err)}`);
6412
- }
6413
- }
6414
- function authBytes(value, field) {
6415
- if (!Array.isArray(value)) {
6416
- throw new AuthError(`auth field '${field}' must be a byte array`);
6417
- }
6418
- for (const byte of value) {
6419
- if (typeof byte !== "number" || !Number.isInteger(byte) || byte < 0 || byte > 255) {
6420
- throw new AuthError(`auth field '${field}' has invalid byte ${String(byte)}`);
6421
- }
6422
- }
6423
- return Uint8Array.from(value);
6424
- }
6425
- async function authenticateClient(sock, conn, deadlineMs) {
6426
- const clientNonce = new Uint8Array(randomBytes(NONCE_LEN));
6427
- await writeMessage(sock, { client_nonce: Array.from(clientNonce), role: DEFAULT_CLIENT_ROLE }, deadlineMs);
6428
- const proof = await readMessage(sock, deadlineMs);
6429
- const serverNonce = authBytes(proof.server_nonce, "server_nonce");
6430
- const daemonId = authBytes(proof.daemon_id, "daemon_id");
6431
- const serverProof = authBytes(proof.server_proof, "server_proof");
6432
- const expected = computeProof(conn.key, SERVER_PROOF_DOMAIN, clientNonce, serverNonce, daemonId);
6433
- if (!constantTimeEq(expected, serverProof)) {
6434
- throw new AuthError("server proof mismatch — wrong key or impostor daemon");
6435
- }
6436
- if (!constantTimeEq(daemonId, conn.daemonId)) {
6437
- throw new AuthError("daemon id mismatch — connection file points at a different daemon");
6438
- }
6439
- const clientAuth = computeProof(conn.key, CLIENT_AUTH_DOMAIN, clientNonce, serverNonce, daemonId);
6440
- await writeMessage(sock, { client_auth: Array.from(clientAuth) }, deadlineMs);
6441
- }
6442
-
6443
- // ../../node_modules/.bun/@cortexkit+subc-client@0.11.1/node_modules/@cortexkit/subc-client/dist/connection-file.js
6444
- import { promises as fs } from "node:fs";
6445
- var SCHEMA_VERSION = 1;
6446
- var MIN_KEY_LEN = 32;
6447
- var DAEMON_ID_LEN = 16;
6448
-
6449
- class ConnectionFileError extends Error {
6450
- }
6451
- function toBytes(value, field) {
6452
- if (!Array.isArray(value)) {
6453
- throw new ConnectionFileError(`connection file field '${field}' must be a JSON array of bytes`);
6454
- }
6455
- for (const byte of value) {
6456
- if (typeof byte !== "number" || !Number.isInteger(byte) || byte < 0 || byte > 255) {
6457
- throw new ConnectionFileError(`connection file field '${field}' has invalid byte ${String(byte)}`);
6458
- }
6459
- }
6460
- return Uint8Array.from(value);
6461
- }
6462
- function validate(info) {
6463
- if (info.schema !== SCHEMA_VERSION) {
6464
- throw new ConnectionFileError(`unsupported connection file schema ${info.schema}; expected ${SCHEMA_VERSION}`);
6465
- }
6466
- if (info.endpoints.length === 0) {
6467
- throw new ConnectionFileError("connection file must include at least one endpoint");
6468
- }
6469
- if (info.key.length < MIN_KEY_LEN) {
6470
- throw new ConnectionFileError(`connection file key is too short: ${info.key.length} bytes, need at least ${MIN_KEY_LEN}`);
6471
- }
6472
- if (info.daemonId.length !== DAEMON_ID_LEN) {
6473
- throw new ConnectionFileError(`connection file daemon_id must be ${DAEMON_ID_LEN} bytes, got ${info.daemonId.length}`);
6474
- }
6475
- }
6476
- async function verifyOwnerOnly(path) {
6477
- if (process.platform === "win32")
6478
- return;
6479
- const stat = await fs.stat(path);
6480
- const mode = stat.mode & 511;
6481
- if ((mode & 63) !== 0) {
6482
- throw new ConnectionFileError(`connection file ${path} has insecure permissions 0o${mode.toString(8)}; expected owner-only 0600`);
6483
- }
6484
- }
6485
- async function readConnectionFile(path) {
6486
- await verifyOwnerOnly(path);
6487
- const raw = await fs.readFile(path, "utf8");
6488
- let parsed;
6489
- try {
6490
- parsed = JSON.parse(raw);
6491
- } catch (err) {
6492
- throw new ConnectionFileError(`connection file JSON read failed for ${path}: ${String(err)}`);
6493
- }
6494
- const wireVersion = parsed.wire_version;
6495
- if (wireVersion !== undefined && wireVersion !== PROTOCOL_VERSION) {
6496
- throw new ConnectionFileError(`connection file wire_version ${String(wireVersion)} but this client speaks ${PROTOCOL_VERSION}; the client library must be upgraded`);
6497
- }
6498
- const endpointsRaw = parsed.endpoints;
6499
- if (!Array.isArray(endpointsRaw)) {
6500
- throw new ConnectionFileError("connection file 'endpoints' must be an array");
6501
- }
6502
- const endpoints = endpointsRaw.map((e) => {
6503
- const ep = e;
6504
- if (typeof ep.host !== "string" || typeof ep.port !== "number") {
6505
- throw new ConnectionFileError("connection file endpoint must be { host: string, port: number }");
6506
- }
6507
- return { host: ep.host, port: ep.port };
6508
- });
6509
- const info = {
6510
- schema: parsed.schema,
6511
- endpoints,
6512
- key: toBytes(parsed.key, "key"),
6513
- daemonId: toBytes(parsed.daemon_id, "daemon_id"),
6514
- pid: parsed.pid,
6515
- daemonVer: parsed.daemon_ver ?? ""
6516
- };
6517
- validate(info);
6518
- return info;
6519
- }
6520
-
6521
- // ../../node_modules/.bun/@cortexkit+subc-client@0.11.1/node_modules/@cortexkit/subc-client/dist/route-handle.js
6522
- var connectionToken = new WeakMap;
6523
-
6524
- class RouteHandle {
6525
- channel;
6526
- epoch;
6527
- constructor(channel, epoch, token) {
6528
- if (!Number.isInteger(channel) || channel <= 0 || channel > 65535) {
6529
- throw new RangeError(`route channel must be an integer in 1..65535, got ${channel}`);
6530
- }
6531
- if (!Number.isInteger(epoch) || epoch <= 0 || epoch > 4294967295) {
6532
- throw new RangeError(`route epoch must be an integer in 1..4294967295, got ${epoch}`);
6533
- }
6534
- this.channel = channel;
6535
- this.epoch = epoch;
6536
- connectionToken.set(this, token);
6537
- Object.freeze(this);
6538
- }
6539
- static create(channel, epoch, token) {
6540
- return new RouteHandle(channel, epoch, token);
6541
- }
6542
- }
6543
- function createRouteHandle(channel, epoch, token) {
6544
- const factory = RouteHandle;
6545
- return factory.create(channel, epoch, token);
6546
- }
6547
-
6548
- class StaleRouteHandleError extends Error {
6549
- handle;
6550
- code = "stale_route_handle";
6551
- constructor(handle) {
6552
- super(`route handle (${handle.channel}, ${handle.epoch}) is not live on the current connection`);
6553
- this.handle = handle;
6554
- this.name = "StaleRouteHandleError";
6555
- }
6556
- }
6557
- function newConnectionToken() {
6558
- return Object.freeze({});
6559
- }
6560
- function belongsToConnection(handle, token) {
6561
- return connectionToken.get(handle) === token;
6562
- }
6563
- function sameRouteHandle(left, right) {
6564
- return left === right;
6565
- }
6566
-
6567
- // ../../node_modules/.bun/@cortexkit+subc-client@0.11.1/node_modules/@cortexkit/subc-client/dist/client.js
6568
- var debug = debuglog("subc-client");
6569
- var DEFAULT_HANDSHAKE_TIMEOUT_MS = 1e4;
6570
- var DEFAULT_REQUEST_TIMEOUT_MS = 30000;
6571
- var TIMEOUT_ARBITRATION_GRACE_MS = 50;
6572
- var LIVENESS_PROBE_WINDOW_MS = 2000;
6573
- var REQUEST_DEADLINE_MARKER = "request_deadline";
6574
- var DEADLINE_NO_DROP_CODE = "deadline_exceeded_no_drop_observed";
6575
- var ROUTE_OPEN_RETRY_DEADLINE_MS = 30000;
6576
- var BODY_READ_TIMEOUT_MS = 30000;
6577
- var EMPTY_BODY = new Uint8Array(0);
6578
- var DEFAULT_MANAGED_TARGET_KIND = "management_surface";
6579
- var SUBC_MODULE_ID_ENV = "SUBC_MODULE_ID";
6580
- var SUBC_LAUNCH_NONCE_ENV = "SUBC_LAUNCH_NONCE";
6581
- var DEFAULT_RECONNECT_BACKOFF = {
6582
- baseMs: 100,
6583
- capMs: 2000,
6584
- maxAttempts: 6
6585
- };
6586
-
6587
- class SubcCallError extends Error {
6588
- kind;
6589
- code;
6590
- cause;
6591
- constructor(kind, message, code, cause) {
6592
- super(message);
6593
- this.kind = kind;
6594
- this.code = code;
6595
- this.cause = cause;
6596
- this.name = "SubcCallError";
6597
- }
6598
- get detail() {
6599
- return this.cause instanceof SubcError ? this.cause.detail : undefined;
6600
- }
6601
- }
6602
-
6603
- class SubcError extends Error {
6604
- code;
6605
- detail;
6606
- constructor(message, code, detail) {
6607
- super(message);
6608
- this.code = code;
6609
- this.detail = detail;
6610
- }
6611
- }
6612
- function requireBinaryBody(body) {
6613
- if (body instanceof Uint8Array)
6614
- return body;
6615
- const type = body === null ? "null" : Array.isArray(body) ? "array" : typeof body;
6616
- throw new SubcError(`binary request body must be a Uint8Array; got ${type}`, "binary_body_required");
6617
- }
6618
- class SubcClient {
6619
- sock;
6620
- currentConn;
6621
- opts;
6622
- nextCorr = 1n;
6623
- pending = new Map;
6624
- lateResponses = new Map;
6625
- routes = new Map;
6626
- liveRoutes = new Map;
6627
- connectionToken = newConnectionToken();
6628
- ingressEpochDropCount = 0;
6629
- closedErr = null;
6630
- closeStarted = false;
6631
- reconnecting = null;
6632
- generation = 1;
6633
- readerActive = false;
6634
- constructor(sock, currentConn, opts) {
6635
- this.sock = sock;
6636
- this.currentConn = currentConn;
6637
- this.opts = opts;
6638
- this.readLoop(sock, this.generation);
6639
- }
6640
- get conn() {
6641
- return this.currentConn;
6642
- }
6643
- static async connect(opts) {
6644
- const normalized = normalizeConnectOptions(opts);
6645
- const opened = await SubcClient.openConnection(normalized);
6646
- return new SubcClient(opened.sock, opened.conn, normalized);
6647
- }
6648
- async catalogList(moduleId) {
6649
- const body = this.encode(moduleId === undefined ? { op: "catalog.list" } : { op: "catalog.list", module_id: moduleId });
6650
- const reply = await this.controlRpc(body);
6651
- const parsed = this.parseJson(reply);
6652
- return parsed.modules ?? [];
6653
- }
6654
- async resolveProvider(capability) {
6655
- const claimants = await this.resolveProviders(capability);
6656
- if (claimants.length === 0) {
6657
- throw new SubcError(`no catalog claimant for capability ${capability}`, "capability_unprovided");
6658
- }
6659
- if (claimants.length > 1) {
6660
- throw new SubcError(`multiple catalog claimants for capability ${capability}: ${claimants.join(", ")}`, "capability_ambiguous");
6661
- }
6662
- return claimants[0];
6663
- }
6664
- async resolveProviders(capability) {
6665
- if (!isValidCapabilityIdentifier(capability)) {
6666
- throw new SubcError(`malformed capability identifier ${JSON.stringify(capability)}`, "invalid_capability_identifier");
6667
- }
6668
- const modules = await this.catalogList();
6669
- return modules.filter((module) => module.capabilities?.provides.includes(capability) ?? false).map((module) => module.module_id).sort();
6670
- }
6671
- async routeOpen(target, identity, opts = {}) {
6672
- const consumerIdentity = routeOpenConsumerIdentity(opts);
6673
- const consumerCapabilities = opts.consumerCapabilities;
6674
- const body = this.encode({
6675
- op: "route.open",
6676
- target,
6677
- identity,
6678
- ...consumerIdentity ? { consumer_identity: consumerIdentity } : {},
6679
- ...consumerCapabilities !== undefined ? { consumer_capabilities: consumerCapabilities } : {}
6680
- });
6681
- let installed = null;
6682
- const install = (frame) => {
6683
- if (frame.header.ty !== FrameType.Response)
6684
- return true;
6685
- const parsed = this.parseJson(frame);
6686
- if (typeof parsed.route_channel !== "number" || typeof parsed.route_epoch !== "number") {
6687
- throw new SubcError(`route.open returned no route handle: ${JSON.stringify(parsed)}`);
6688
- }
6689
- installed = this.installRoute(parsed.route_channel, parsed.route_epoch);
6690
- return true;
6691
- };
6692
- const closeLateRoute = (frame) => {
6693
- if (frame.header.ty !== FrameType.Response)
6694
- return;
6695
- try {
6696
- const parsed = this.parseJson(frame);
6697
- if (typeof parsed.route_channel !== "number" || typeof parsed.route_epoch !== "number")
6698
- return;
6699
- const lateHandle = this.installRoute(parsed.route_channel, parsed.route_epoch);
6700
- this.failHandle(lateHandle, new SubcError("late route.open was closed", "route_closed"));
6701
- this.liveRoutes.delete(lateHandle.channel);
6702
- this.sendRouteGoodbye(lateHandle, true);
6703
- } catch {
6704
- this.closeConnectionAfterCleanupFailure();
6705
- }
6706
- };
6707
- await this.controlRpc(body, install, closeLateRoute);
6708
- if (!installed)
6709
- throw new SubcError("route.open response was not installed");
6710
- return installed;
6711
- }
6712
- async request(handle, body, opts = {}) {
6713
- this.assertLiveHandle(handle);
6714
- const binary = opts.binary ?? false;
6715
- const bytes = binary ? requireBinaryBody(body) : body instanceof Uint8Array ? body : this.encode(body);
6716
- const priority = opts.priority ?? Priority.Interactive;
6717
- const admission = opts.admissionClass ?? AdmissionClass.Normal;
6718
- const reply = await this.send(handle, bytes, priority, admission, opts.timeoutMs, opts.onProgress, undefined, undefined, binary);
6719
- return this.decodeReply(reply);
6720
- }
6721
- async call(moduleId, method, params, opts = {}) {
6722
- if (opts.binary) {
6723
- throw new SubcError("call() builds a JSON body and cannot send a binary request; use callBinary(moduleId, body, opts) with a Uint8Array", "binary_call_requires_call_binary");
6724
- }
6725
- const body = params === undefined ? { method } : { method, params };
6726
- return await this.managedCall(moduleId, body, opts);
6727
- }
6728
- async callBinary(moduleId, body, opts = {}) {
6729
- const bytes = requireBinaryBody(body);
6730
- return this.managedCall(moduleId, bytes, { ...opts, binary: true });
6731
- }
6732
- async managedCall(moduleId, body, opts) {
6733
- let retriedUnknownChannel = false;
6734
- for (;; ) {
6735
- const routeHandle = await this.cachedRouteHandle(moduleId, opts);
6736
- try {
6737
- return await this.managedRequest(routeHandle, body, opts);
6738
- } catch (err) {
6739
- if (!(err instanceof SubcCallError))
6740
- throw this.terminalCallError("managed call failed", err);
6741
- const deadBindCode = err.code === "unknown_channel" || err.code === "stale_route_epoch";
6742
- if (deadBindCode && !retriedUnknownChannel && !this.closeStarted) {
6743
- retriedUnknownChannel = true;
6744
- this.evictRouteHandle(routeHandle);
6745
- continue;
6746
- }
6747
- if (deadBindCode && retriedUnknownChannel) {
6748
- this.evictRouteHandle(routeHandle);
6749
- }
6750
- if (err.kind === "not_sent") {
6751
- try {
6752
- await this.reconnectAfterDrop(err);
6753
- } catch (reconnectErr) {
6754
- throw this.notSentRecoveryError("managed call was not sent", reconnectErr);
6755
- }
6756
- continue;
6757
- }
6758
- if (err.kind === "outcome_unknown" && err.code !== DEADLINE_NO_DROP_CODE) {
6759
- this.scheduleReconnectAfterDrop(err);
6760
- } else if (err.kind === "outcome_unknown" && err.code === DEADLINE_NO_DROP_CODE) {
6761
- this.probeLivenessAfterDeadline();
6762
- }
6763
- throw err;
6764
- }
6765
- }
6766
- }
6767
- subscribe(handle, body, onEvent, opts = {}) {
6768
- this.assertLiveHandle(handle);
6769
- const bytes = body instanceof Uint8Array ? body : this.encode(body);
6770
- const priority = opts.priority ?? Priority.Interactive;
6771
- const admission = opts.admissionClass ?? AdmissionClass.Normal;
6772
- const corr = this.allocateCorr();
6773
- const key = pendingKey(handle, corr);
6774
- let subscriptionPending = null;
6775
- let resolveClosed = null;
6776
- const closed = new Promise((resolve, reject) => {
6777
- if (this.closedErr) {
6778
- reject(this.closedErr);
6779
- return;
6780
- }
6781
- resolveClosed = resolve;
6782
- subscriptionPending = {
6783
- handle,
6784
- resolve: () => resolve(),
6785
- reject,
6786
- onProgress: onEvent,
6787
- timer: null,
6788
- subscription: true
6789
- };
6790
- this.pending.set(key, subscriptionPending);
6791
- const frame = buildFrame(FrameType.Request, buildFlags(false, priority, false, admission), handle.channel, handle.epoch, corr, bytes);
6792
- writeBorrowed(this.sock, encodeFrame(frame), Date.now() + DEFAULT_REQUEST_TIMEOUT_MS).catch((err) => {
6793
- const pending = this.pending.get(key);
6794
- if (pending)
6795
- this.rejectPending(key, pending, err instanceof Error ? err : new SubcError(String(err)));
6796
- });
6797
- });
6798
- let cancelled = false;
6799
- const unsubscribe = () => {
6800
- if (cancelled)
6801
- return;
6802
- cancelled = true;
6803
- if (subscriptionPending && resolveClosed)
6804
- this.settle(key, subscriptionPending, resolveClosed);
6805
- if (this.isLiveHandle(handle))
6806
- this.cancel(handle, corr, priority);
6807
- };
6808
- return { unsubscribe, closed };
6809
- }
6810
- cancel(handle, corr, priority = Priority.Interactive) {
6811
- this.assertLiveHandle(handle);
6812
- const cancel = buildFrame(FrameType.Cancel, buildFlags(false, priority, false), handle.channel, handle.epoch, corr, EMPTY_BODY);
6813
- writeBorrowed(this.sock, encodeFrame(cancel), Date.now() + DEFAULT_REQUEST_TIMEOUT_MS).catch(() => {
6814
- return;
6815
- });
6816
- }
6817
- async routePoll(handle, kind) {
6818
- this.assertLiveHandle(handle);
6819
- const body = this.encode({
6820
- op: "route.poll",
6821
- route_channel: handle.channel,
6822
- route_epoch: handle.epoch,
6823
- kind
6824
- });
6825
- const reply = await this.controlRpc(body, (frame) => {
6826
- if (frame.header.ty !== FrameType.Response)
6827
- return true;
6828
- const parsed = this.parseJson(frame);
6829
- return parsed.route_channel === handle.channel && parsed.route_epoch === handle.epoch;
6830
- });
6831
- return this.parseJson(reply);
6832
- }
6833
- async closeRoute(handle, opts = {}) {
6834
- this.assertLiveHandle(handle);
6835
- for (const [key, cached] of this.routes) {
6836
- if (cached.handle && sameRouteHandle(cached.handle, handle)) {
6837
- cached.closed = true;
6838
- cached.handle = null;
6839
- this.routes.delete(key);
6840
- }
6841
- }
6842
- if (opts.drain)
6843
- await this.drainUnaryOnHandle(handle);
6844
- this.failHandle(handle, new SubcError("route closed by closeRoute", "route_closed"));
6845
- if (this.liveRoutes.get(handle.channel) === handle)
6846
- this.liveRoutes.delete(handle.channel);
6847
- this.sendRouteGoodbye(handle);
6848
- }
6849
- async closeManagedRoute(target, identity, opts = {}) {
6850
- const key = routeCacheKey(target, identity, routeOpenConsumerIdentity(opts));
6851
- const cached = this.routes.get(key);
6852
- if (!cached)
6853
- return;
6854
- cached.closed = true;
6855
- this.routes.delete(key);
6856
- const handle = cached.handle;
6857
- cached.handle = null;
6858
- if (handle)
6859
- await this.closeRoute(handle, opts);
6860
- }
6861
- async closeRouteChannel(handle, opts = {}) {
6862
- await this.closeRoute(handle, opts);
6863
- }
6864
- close() {
6865
- this.closeStarted = true;
6866
- this.fail(new SubcError("client closed"));
6867
- this.sock.close();
6868
- }
6869
- drainUnaryOnHandle(handle) {
6870
- const waiters = [];
6871
- for (const pending of this.pending.values()) {
6872
- if (pending.handle === handle && !pending.subscription) {
6873
- waiters.push(new Promise((resolve) => {
6874
- const previous = pending.onSettle;
6875
- pending.onSettle = () => {
6876
- previous?.();
6877
- resolve();
6878
- };
6879
- }));
6880
- }
6881
- }
6882
- return Promise.all(waiters).then(() => {
6883
- return;
6884
- });
6885
- }
6886
- sendRouteGoodbye(handle, closeOnQueueFailure = false) {
6887
- this.assertLiveConnection(handle);
6888
- if (this.closedErr) {
6889
- if (closeOnQueueFailure)
6890
- this.closeConnectionAfterCleanupFailure();
6891
- return;
6892
- }
6893
- const goodbye = buildFrame(FrameType.Goodbye, buildFlags(false, Priority.Interactive, false), handle.channel, handle.epoch, 0n, EMPTY_BODY);
6894
- const write = writeTrackedBorrowed(this.sock, encodeFrame(goodbye), Date.now() + DEFAULT_REQUEST_TIMEOUT_MS);
6895
- if (!write.queued && closeOnQueueFailure)
6896
- this.closeConnectionAfterCleanupFailure();
6897
- write.completed.catch(() => {
6898
- if (closeOnQueueFailure && !write.queued)
6899
- this.closeConnectionAfterCleanupFailure();
6900
- });
6901
- }
6902
- static async openConnection(opts) {
6903
- const conn = await readConnectionFile(opts.connectionFile);
6904
- const deadline = Date.now() + (opts.handshakeTimeoutMs ?? DEFAULT_HANDSHAKE_TIMEOUT_MS);
6905
- const endpoint = conn.endpoints[0];
6906
- const sock = await SubcSocket.connect(endpoint.host, endpoint.port, deadline);
6907
- try {
6908
- await authenticateClient(sock, conn, deadline);
6909
- } catch (err) {
6910
- sock.close();
6911
- throw err;
6912
- }
6913
- return { sock, conn };
6914
- }
6915
- async controlRpc(body, acceptFrame, onLateResponse) {
6916
- return this.send(null, body, Priority.Interactive, AdmissionClass.Normal, undefined, undefined, acceptFrame, onLateResponse);
6917
- }
6918
- send(handle, body, priority, admission, timeoutMs, onProgress, acceptFrame, onLateResponse, binary = false) {
6919
- if (handle)
6920
- this.assertLiveHandle(handle);
6921
- if (this.closedErr)
6922
- return Promise.reject(this.closedErr);
6923
- let corr;
6924
- try {
6925
- corr = this.allocateCorr();
6926
- } catch (error) {
6927
- return Promise.reject(error);
6928
- }
6929
- const key = pendingKey(handle, corr);
6930
- const channel = handle?.channel ?? 0;
6931
- const epoch = handle?.epoch ?? 0;
6932
- const frame = buildFrame(FrameType.Request, buildFlags(binary, priority, false, admission), channel, epoch, corr, body);
6933
- return new Promise((resolve, reject) => {
6934
- const ms = timeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
6935
- const pending = {
6936
- handle,
6937
- resolve,
6938
- reject,
6939
- onProgress,
6940
- timer: null,
6941
- acceptFrame,
6942
- onLateResponse
6943
- };
6944
- pending.timer = setTimeout(() => this.arbitrateTimeout(key, pending, channel, corr, ms), ms);
6945
- this.pending.set(key, pending);
6946
- writeBorrowed(this.sock, encodeFrame(frame), Date.now() + ms).catch((error) => {
6947
- const current = this.pending.get(key);
6948
- if (current)
6949
- this.rejectPending(key, current, error instanceof Error ? error : new SubcError(String(error)));
6950
- });
6951
- });
6952
- }
6953
- arbitrateTimeout(key, pending, channel, corr, ms) {
6954
- const settleAsTimeout = () => {
6955
- if (pending.onLateResponse)
6956
- this.lateResponses.set(key, pending.onLateResponse);
6957
- this.rejectPending(key, pending, new SubcError(this.timeoutMessage(channel, corr, ms), REQUEST_DEADLINE_MARKER));
6958
- };
6959
- const graceDeadline = Date.now() + this.opts.timeoutArbitrationGraceMs;
6960
- const arbitrate = () => {
6961
- if (this.pending.get(key) !== pending)
6962
- return;
6963
- const readerDraining = this.readerActive || this.sock.bufferedBytes() > 0;
6964
- if (readerDraining && Date.now() < graceDeadline) {
6965
- setImmediate(arbitrate);
6966
- return;
6967
- }
6968
- settleAsTimeout();
6969
- };
6970
- setImmediate(arbitrate);
6971
- }
6972
- async managedRequest(handle, body, opts) {
6973
- const binary = opts.binary ?? false;
6974
- const bytes = binary ? requireBinaryBody(body) : body instanceof Uint8Array ? body : this.encode(body);
6975
- const priority = opts.priority ?? Priority.Interactive;
6976
- const admission = opts.admissionClass ?? AdmissionClass.Normal;
6977
- try {
6978
- const reply = await this.sendManaged(handle, bytes, priority, admission, opts.timeoutMs, opts.onProgress, binary);
6979
- return this.decodeReply(reply);
6980
- } catch (error) {
6981
- if (error instanceof SubcCallError)
6982
- throw error;
6983
- throw this.terminalCallError("managed call failed", error);
6984
- }
6985
- }
6986
- sendManaged(handle, body, priority, admission, timeoutMs, onProgress, binary = false) {
6987
- try {
6988
- this.assertLiveHandle(handle);
6989
- } catch (error) {
6990
- return Promise.reject(this.notSentCallError("request used a stale route handle", error));
6991
- }
6992
- if (this.closedErr) {
6993
- return Promise.reject(this.notSentCallError("request was not sent because the subc connection was already closed", this.closedErr));
6994
- }
6995
- let corr;
6996
- try {
6997
- corr = this.allocateCorr();
6998
- } catch (error) {
6999
- return Promise.reject(this.notSentCallError("request correlation allocator was exhausted", error));
7000
- }
7001
- const key = pendingKey(handle, corr);
7002
- const frame = buildFrame(FrameType.Request, buildFlags(binary, priority, false, admission), handle.channel, handle.epoch, corr, body);
7003
- let handedToSocket = false;
7004
- const classifyFailure = (error) => {
7005
- if (!handedToSocket)
7006
- return this.notSentCallError("request bytes were not queued to the subc socket", error);
7007
- if (error instanceof SubcError && error.code === REQUEST_DEADLINE_MARKER) {
7008
- return new SubcCallError("outcome_unknown", `managed call deadline exceeded after request bytes were queued to the local socket; no terminal response was observed; outcome unknown${causeMessage(error)}`, DEADLINE_NO_DROP_CODE, error);
7009
- }
7010
- return this.outcomeUnknownCallError("connection dropped before the managed call returned a response", error);
7011
- };
7012
- return new Promise((resolve, reject) => {
7013
- const ms = timeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
7014
- const pending = {
7015
- handle,
7016
- resolve,
7017
- reject,
7018
- onProgress,
7019
- timer: null,
7020
- classifyFailure
7021
- };
7022
- pending.timer = setTimeout(() => this.arbitrateTimeout(key, pending, handle.channel, corr, ms), ms);
7023
- this.pending.set(key, pending);
7024
- const write = writeTrackedBorrowed(this.sock, encodeFrame(frame), Date.now() + ms);
7025
- handedToSocket = write.queued;
7026
- write.completed.catch((error) => {
7027
- const current = this.pending.get(key);
7028
- if (current)
7029
- this.rejectPending(key, current, error instanceof Error ? error : new SubcError(String(error)));
7030
- });
7031
- });
7032
- }
7033
- async cachedRouteHandle(moduleId, opts) {
7034
- const identity = opts.identity ?? this.opts.identity;
7035
- if (!identity) {
7036
- throw new SubcCallError("terminal", "managed call requires a BindIdentity in SubcClient.connect({ identity }) or call(..., { identity })", "missing_identity");
7037
- }
7038
- const target = { kind: opts.targetKind ?? this.opts.targetKind, module_id: moduleId };
7039
- const consumerIdentity = routeOpenConsumerIdentity(opts);
7040
- const key = routeCacheKey(target, identity, consumerIdentity);
7041
- let cached = this.routes.get(key);
7042
- if (!cached) {
7043
- cached = {
7044
- key,
7045
- moduleId,
7046
- target,
7047
- identity,
7048
- consumerIdentity,
7049
- handle: null,
7050
- opening: null
7051
- };
7052
- this.routes.set(key, cached);
7053
- }
7054
- if (cached.handle && this.isLiveHandle(cached.handle))
7055
- return cached.handle;
7056
- if (!cached.opening) {
7057
- cached.opening = this.openCachedRoute(cached).finally(() => {
7058
- cached.opening = null;
7059
- });
7060
- }
7061
- return cached.opening;
7062
- }
7063
- async openCachedRoute(cached) {
7064
- const routeRetryDeadline = Date.now() + this.opts.routeOpenRetryDeadlineMs;
7065
- let routeRetryDelay = this.opts.reconnectBackoff.baseMs;
7066
- let routeRetryAttempt = 0;
7067
- for (;; ) {
7068
- if (cached.closed)
7069
- throw this.routeClosedDuringOpen();
7070
- try {
7071
- await this.ensureConnectedForManaged();
7072
- } catch (error) {
7073
- throw this.notSentRecoveryError("route.open could not run because reconnect failed", error);
7074
- }
7075
- if (cached.handle && this.isLiveHandle(cached.handle))
7076
- return cached.handle;
7077
- try {
7078
- const handle = await this.routeOpen(cached.target, cached.identity, {
7079
- consumerIdentity: cached.consumerIdentity ?? null
7080
- });
7081
- if (cached.closed) {
7082
- this.liveRoutes.delete(handle.channel);
7083
- this.sendRouteGoodbye(handle);
7084
- throw this.routeClosedDuringOpen();
7085
- }
7086
- cached.handle = handle;
7087
- return handle;
7088
- } catch (error) {
7089
- if (error instanceof SubcCallError && error.code === "route_closed")
7090
- throw error;
7091
- if (!this.closeStarted && isConsumerReconnectTransient(error)) {
7092
- try {
7093
- await this.reconnectAfterDrop(error);
7094
- } catch (reconnectError) {
7095
- throw this.notSentRecoveryError("route.open was not sent and reconnect failed", reconnectError);
7096
- }
7097
- continue;
7098
- }
7099
- if (!this.closeStarted && error instanceof SubcError && isRetryableRouteOpenCode(error.code)) {
7100
- routeRetryAttempt += 1;
7101
- if (Date.now() < routeRetryDeadline) {
7102
- await this.opts.sleep(routeRetryDelay);
7103
- routeRetryDelay = Math.min(routeRetryDelay * 2, this.opts.reconnectBackoff.capMs);
7104
- continue;
7105
- }
7106
- throw this.notSentCallError(`route.open failed for module ${cached.moduleId}: ${error.code} (retry deadline exhausted after ${routeRetryAttempt} attempts)`, error);
7107
- }
7108
- throw this.terminalCallError(`route.open failed for module ${cached.moduleId}`, error);
7109
- }
7110
- }
7111
- }
7112
- lastInboundAtMs = 0;
7113
- livenessProbe = null;
7114
- hasControlPending() {
7115
- for (const pending of this.pending.values()) {
7116
- if (pending.handle === null)
7117
- return true;
7118
- }
7119
- return false;
7120
- }
7121
- probeLivenessAfterDeadline() {
7122
- if (this.livenessProbe || this.closeStarted || this.closedErr)
7123
- return;
7124
- if (this.hasControlPending())
7125
- return;
7126
- const sock = this.sock;
7127
- const generation = this.generation;
7128
- let corr;
7129
- try {
7130
- corr = this.allocateCorr();
7131
- } catch {
7132
- return;
7133
- }
7134
- const t0 = Date.now();
7135
- const ping = buildFrame(FrameType.Ping, buildFlags(false, Priority.Interactive, false, AdmissionClass.Normal), 0, 0, corr, new Uint8Array);
7136
- const probe = (async () => {
7137
- await writeBorrowed(sock, encodeFrame(ping), t0 + this.opts.livenessProbeWindowMs).catch(() => {});
7138
- await this.opts.sleep(this.opts.livenessProbeWindowMs);
7139
- if (this.sock !== sock || this.generation !== generation || this.closeStarted)
7140
- return;
7141
- if (this.lastInboundAtMs >= t0)
7142
- return;
7143
- if (this.hasControlPending())
7144
- return;
7145
- this.fail(new SocketClosedError(`liveness probe convicted a half-open socket: no inbound frame for ${this.opts.livenessProbeWindowMs}ms after a channel-0 Ping (deadline-no-drop settles preceded this); closing so the next call reconnects`));
7146
- sock.close();
7147
- })().finally(() => {
7148
- this.livenessProbe = null;
7149
- });
7150
- this.livenessProbe = probe;
7151
- }
7152
- async ensureConnectedForManaged() {
7153
- if (this.closeStarted)
7154
- throw new SubcError("client closed");
7155
- if (this.reconnecting)
7156
- await this.reconnecting;
7157
- if (this.closedErr)
7158
- await this.reconnectAfterDrop(this.closedErr);
7159
- }
7160
- scheduleReconnectAfterDrop(err) {
7161
- if (this.closeStarted || this.reconnecting)
7162
- return;
7163
- this.reconnectAfterDrop(err).catch(() => {});
7164
- }
7165
- reconnectAfterDrop(trigger) {
7166
- if (this.closeStarted)
7167
- return Promise.reject(new SubcError("client closed"));
7168
- if (this.reconnecting)
7169
- return this.reconnecting;
7170
- const promise = this.reconnectWithRetry(trigger).finally(() => {
7171
- if (this.reconnecting === promise)
7172
- this.reconnecting = null;
7173
- });
7174
- this.reconnecting = promise;
7175
- return promise;
7176
- }
7177
- async reconnectWithRetry(_trigger) {
7178
- let attempt = 0;
7179
- let delay = this.opts.reconnectBackoff.baseMs;
7180
- for (;; ) {
7181
- if (this.closeStarted)
7182
- throw new SubcError("client closed");
7183
- attempt += 1;
7184
- try {
7185
- const opened = await SubcClient.openConnection(this.opts);
7186
- if (this.closeStarted) {
7187
- opened.sock.close();
7188
- throw new SubcError("client closed");
7189
- }
7190
- this.replaceConnection(opened);
7191
- await this.reopenCachedRoutes();
7192
- return;
7193
- } catch (err) {
7194
- if (!isConsumerReconnectTransient(err) || attempt >= this.opts.reconnectBackoff.maxAttempts) {
7195
- if (err instanceof AuthError && attempt > 1) {
7196
- throw new AuthError(`reconnect gave up after ${attempt} attempts: ${err.message} — the connection file and the daemon's key disagree persistently ` + `(daemon restarting in a loop, split connection-file paths, or a genuinely foreign daemon on this port); ` + `check the daemon, then restart this host app`);
7197
- }
7198
- throw err;
7199
- }
7200
- await this.opts.sleep(delay);
7201
- delay = Math.min(delay * 2, this.opts.reconnectBackoff.capMs);
7202
- }
7203
- }
7204
- }
7205
- replaceConnection(opened) {
7206
- this.sock.close();
7207
- this.sock = opened.sock;
7208
- this.currentConn = opened.conn;
7209
- this.closedErr = null;
7210
- this.generation += 1;
7211
- this.connectionToken = newConnectionToken();
7212
- this.liveRoutes.clear();
7213
- this.lateResponses.clear();
7214
- this.nextCorr = 1n;
7215
- this.readLoop(opened.sock, this.generation);
7216
- }
7217
- async reopenCachedRoutes() {
7218
- const routeKeys = [...this.routes.keys()];
7219
- for (const key of routeKeys) {
7220
- const cached = this.routes.get(key);
7221
- if (cached)
7222
- cached.handle = null;
7223
- }
7224
- for (const key of routeKeys) {
7225
- const cached = this.routes.get(key);
7226
- if (!cached || cached.closed)
7227
- continue;
7228
- try {
7229
- const handle = await this.routeOpen(cached.target, cached.identity, {
7230
- consumerIdentity: cached.consumerIdentity ?? null
7231
- });
7232
- if (cached.closed) {
7233
- this.liveRoutes.delete(handle.channel);
7234
- this.sendRouteGoodbye(handle);
7235
- continue;
7236
- }
7237
- cached.handle = handle;
7238
- } catch (error) {
7239
- if (isRouteOpenRefusal(error)) {
7240
- this.routes.delete(key);
7241
- continue;
7242
- }
7243
- throw error;
7244
- }
7245
- }
7246
- }
7247
- timeoutMessage(channel, corr, ms) {
7248
- const port = this.sock.localPort();
7249
- const where = port === null ? "channel" : `local_port=${port} channel`;
7250
- return `request on ${where} ${channel} corr ${corr} timed out after ${ms}ms`;
7251
- }
7252
- routeClosedDuringOpen() {
7253
- return new SubcCallError("not_sent", "route was closed before route.open completed", "route_closed");
7254
- }
7255
- async readLoop(sock, generation) {
7256
- try {
7257
- for (;; ) {
7258
- this.readerActive = false;
7259
- const frame = await sock.readFrame(Number.POSITIVE_INFINITY, { afterHeaderMs: BODY_READ_TIMEOUT_MS }, () => {
7260
- this.readerActive = true;
7261
- });
7262
- try {
7263
- if (this.sock === sock && this.generation === generation)
7264
- this.dispatch(frame);
7265
- } finally {
7266
- this.readerActive = false;
7267
- }
7268
- }
7269
- } catch (error) {
7270
- if (this.sock === sock && this.generation === generation) {
7271
- this.fail(error instanceof Error ? error : new SubcError(String(error)));
7272
- }
7273
- }
7274
- }
7275
- dispatch(frame) {
7276
- this.lastInboundAtMs = Date.now();
7277
- if (frame.header.channel === 0 && frame.header.ty === FrameType.Push) {
7278
- const observer = this.opts.onControlPush;
7279
- if (observer) {
7280
- let parsed = null;
7281
- try {
7282
- const body = this.parseJson(frame);
7283
- if (body && typeof body.op === "string")
7284
- parsed = { op: body.op, body };
7285
- } catch {}
7286
- if (parsed) {
7287
- try {
7288
- observer(parsed);
7289
- } catch {}
7290
- }
7291
- }
7292
- return;
7293
- }
7294
- let handle = null;
7295
- if (frame.header.channel !== 0) {
7296
- handle = this.liveRoutes.get(frame.header.channel) ?? null;
7297
- if (!handle || handle.epoch !== frame.header.epoch) {
7298
- this.ingressEpochDropCount += 1;
7299
- return;
7300
- }
7301
- }
7302
- const key = pendingKey(handle, frame.header.corr);
7303
- const pending = this.pending.get(key);
7304
- if (pending) {
7305
- if (pending.acceptFrame && !pending.acceptFrame(frame))
7306
- return;
7307
- switch (frame.header.ty) {
7308
- case FrameType.Push:
7309
- case FrameType.StreamData:
7310
- try {
7311
- pending.onProgress?.(frame.body);
7312
- } catch {}
7313
- return;
7314
- case FrameType.Response:
7315
- case FrameType.StreamEnd:
7316
- this.settle(key, pending, () => pending.resolve(frame));
7317
- return;
7318
- case FrameType.Error:
7319
- this.settle(key, pending, () => pending.reject(this.errorFromFrame(frame)));
7320
- return;
7321
- default:
7322
- return;
7323
- }
7324
- }
7325
- const late = this.lateResponses.get(key);
7326
- if (late && (frame.header.ty === FrameType.Response || frame.header.ty === FrameType.Error)) {
7327
- this.lateResponses.delete(key);
7328
- late(frame);
7329
- return;
7330
- }
7331
- if (frame.header.ty === FrameType.Goodbye && handle) {
7332
- this.failHandle(handle, new SubcError("route closed by subc (GOODBYE)", "route_closed"));
7333
- if (this.liveRoutes.get(handle.channel) === handle)
7334
- this.liveRoutes.delete(handle.channel);
7335
- this.evictRouteHandle(handle);
7336
- return;
7337
- }
7338
- if (frame.header.ty === FrameType.Response || frame.header.ty === FrameType.Error || frame.header.ty === FrameType.StreamEnd) {
7339
- debug("dropped terminal frame with no waiter: type=%d channel=%d epoch=%d corr=%s port=%s", frame.header.ty, frame.header.channel, frame.header.epoch, frame.header.corr, this.sock.localPort() ?? "?");
7340
- }
7341
- }
7342
- settle(key, pending, run) {
7343
- if (this.pending.get(key) !== pending)
7344
- return false;
7345
- this.pending.delete(key);
7346
- if (pending.timer)
7347
- clearTimeout(pending.timer);
7348
- run();
7349
- pending.onSettle?.();
7350
- return true;
7351
- }
7352
- rejectPending(key, pending, err) {
7353
- this.settle(key, pending, () => pending.reject(pending.classifyFailure?.(err) ?? err));
7354
- }
7355
- errorFromFrame(frame) {
7356
- try {
7357
- const parsed = JSON.parse(Buffer.from(frame.body).toString("utf8"));
7358
- return new SubcError(parsed.message ?? "subc error", parsed.code, parsed.detail);
7359
- } catch {
7360
- return new SubcError(Buffer.from(frame.body).toString("utf8") || "subc error");
7361
- }
7362
- }
7363
- evictRouteHandle(handle) {
7364
- for (const cached of this.routes.values()) {
7365
- if (cached.handle && sameRouteHandle(cached.handle, handle))
7366
- cached.handle = null;
7367
- }
7368
- }
7369
- failHandle(handle, error) {
7370
- for (const [key, pending] of this.pending) {
7371
- if (pending.handle && sameRouteHandle(pending.handle, handle))
7372
- this.rejectPending(key, pending, error);
7373
- }
7374
- }
7375
- fail(err) {
7376
- if (!this.closedErr)
7377
- this.closedErr = err;
7378
- for (const [key, pending] of this.pending) {
7379
- this.rejectPending(key, pending, err);
7380
- }
7381
- }
7382
- notSentCallError(message, cause) {
7383
- return new SubcCallError("not_sent", `${message}${causeMessage(cause)}`, errorCode(cause), cause);
7384
- }
7385
- outcomeUnknownCallError(message, cause) {
7386
- return new SubcCallError("outcome_unknown", `${message}${causeMessage(cause)}`, errorCode(cause), cause);
7387
- }
7388
- terminalCallError(message, cause) {
7389
- if (cause instanceof SubcCallError)
7390
- return cause;
7391
- return new SubcCallError("terminal", `${message}${causeMessage(cause)}`, errorCode(cause), cause);
7392
- }
7393
- notSentRecoveryError(message, cause) {
7394
- if (cause instanceof SubcCallError)
7395
- return cause;
7396
- if (isConsumerReconnectTransient(cause))
7397
- return this.notSentCallError(message, cause);
7398
- return this.terminalCallError(message, cause);
7399
- }
7400
- get droppedIngressFrames() {
7401
- return this.ingressEpochDropCount;
7402
- }
7403
- installRoute(channel, epoch) {
7404
- const handle = createRouteHandle(channel, epoch, this.connectionToken);
7405
- this.liveRoutes.set(channel, handle);
7406
- return handle;
7407
- }
7408
- isLiveHandle(handle) {
7409
- return belongsToConnection(handle, this.connectionToken) && this.liveRoutes.get(handle.channel) === handle;
7410
- }
7411
- assertLiveConnection(handle) {
7412
- if (!belongsToConnection(handle, this.connectionToken))
7413
- throw new StaleRouteHandleError(handle);
7414
- }
7415
- assertLiveHandle(handle) {
7416
- if (!this.isLiveHandle(handle))
7417
- throw new StaleRouteHandleError(handle);
7418
- }
7419
- allocateCorr() {
7420
- const maximum = 0xffffffffffffffffn;
7421
- if (this.nextCorr > maximum) {
7422
- const error = new SubcError("channel-0 correlation id allocator exhausted", "corr_exhausted");
7423
- this.fail(error);
7424
- this.sock.close();
7425
- this.scheduleReconnectAfterDrop(error);
7426
- throw error;
7427
- }
7428
- const corr = this.nextCorr;
7429
- this.nextCorr += 1n;
7430
- return corr;
7431
- }
7432
- closeConnectionAfterCleanupFailure() {
7433
- const error = new SubcError("late route cleanup could not be queued", "late_route_cleanup_failed");
7434
- this.fail(error);
7435
- this.sock.close();
7436
- this.scheduleReconnectAfterDrop(error);
7437
- }
7438
- encode(value) {
7439
- return Buffer.from(JSON.stringify(value), "utf8");
7440
- }
7441
- decodeReply(frame) {
7442
- return hasBinary(frame.header.flags) ? frame.body : this.parseJson(frame);
7443
- }
7444
- parseJson(frame) {
7445
- const b = frame.body;
7446
- return JSON.parse(Buffer.from(b.buffer, b.byteOffset, b.byteLength).toString("utf8"));
7447
- }
7448
- }
7449
- function isConsumerReconnectTransient(err) {
7450
- if (err instanceof SocketClosedError || err instanceof SocketTimeoutError)
7451
- return true;
7452
- if (err instanceof SocketWriteNotQueuedError || err instanceof SocketWriteQueuedError)
7453
- return true;
7454
- if (err instanceof SubcCallError)
7455
- return err.kind === "not_sent" || err.kind === "outcome_unknown";
7456
- if (err instanceof AuthError)
7457
- return true;
7458
- if (err instanceof SubcError || err instanceof ConnectionFileError)
7459
- return false;
7460
- const code = errorCode(err);
7461
- return code === "ECONNREFUSED" || code === "ECONNRESET" || code === "EPIPE" || code === "ETIMEDOUT" || code === "ENOENT";
7462
- }
7463
- function isRouteOpenRefusal(err) {
7464
- return err instanceof SubcError && typeof err.code === "string";
7465
- }
7466
- function isRetryableRouteOpenCode(code) {
7467
- if (code === "capability_forbidden")
7468
- return false;
7469
- return code === "unknown_module" || code === "module_reloading" || code === "module_warming" || code === "target_unavailable" || code === "module_timeout";
7470
- }
7471
- async function connectionFileExists(path) {
7472
- try {
7473
- await fs2.access(path);
7474
- return true;
7475
- } catch {
7476
- return false;
7477
- }
7478
- }
7479
- function normalizeConnectOptions(opts) {
7480
- return {
7481
- connectionFile: opts.connectionFile,
7482
- handshakeTimeoutMs: opts.handshakeTimeoutMs,
7483
- identity: opts.identity,
7484
- targetKind: opts.targetKind ?? DEFAULT_MANAGED_TARGET_KIND,
7485
- reconnectBackoff: opts.reconnectBackoff ?? DEFAULT_RECONNECT_BACKOFF,
7486
- sleep: opts.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms))),
7487
- routeOpenRetryDeadlineMs: opts.routeOpenRetryDeadlineMs ?? ROUTE_OPEN_RETRY_DEADLINE_MS,
7488
- timeoutArbitrationGraceMs: opts.timeoutArbitrationGraceMs ?? TIMEOUT_ARBITRATION_GRACE_MS,
7489
- livenessProbeWindowMs: opts.livenessProbeWindowMs ?? LIVENESS_PROBE_WINDOW_MS,
7490
- onControlPush: opts.onControlPush
7491
- };
7492
- }
7493
- function isValidCapabilityIdentifier(identifier) {
7494
- if (/\s/u.test(identifier))
7495
- return false;
7496
- const separator = identifier.indexOf("/v");
7497
- if (separator <= 0 || identifier.indexOf("/v", separator + 1) !== -1)
7498
- return false;
7499
- const name = identifier.slice(0, separator);
7500
- const version = identifier.slice(separator + 2);
7501
- if (new TextEncoder().encode(name).byteLength > 64 || version.length === 0)
7502
- return false;
7503
- if (!/^[a-z][a-z0-9-]*[a-z0-9]$/u.test(name) && !/^[a-z]$/u.test(name))
7504
- return false;
7505
- if (name.includes("--"))
7506
- return false;
7507
- if (!/^\d+$/u.test(version) || version.length > 1 && version.startsWith("0"))
7508
- return false;
7509
- const numericVersion = Number(version);
7510
- return Number.isSafeInteger(numericVersion) && numericVersion >= 1 && numericVersion <= 4294967295;
7511
- }
7512
- function routeCacheKey(target, identity, consumerIdentity) {
7513
- const consumerPart = consumerIdentity ? `${consumerIdentity.module_id}\x00${consumerIdentity.launch_nonce}` : "";
7514
- return `${target.kind}\x00${target.module_id}\x00${identity.project_root}\x00${identity.harness}\x00${identity.session}\x00${consumerPart}`;
7515
- }
7516
- function routeOpenConsumerIdentity(opts = {}) {
7517
- if (opts.consumerIdentity !== undefined)
7518
- return opts.consumerIdentity ?? undefined;
7519
- const moduleId = process.env[SUBC_MODULE_ID_ENV];
7520
- const launchNonce = process.env[SUBC_LAUNCH_NONCE_ENV];
7521
- if (!moduleId || !launchNonce)
7522
- return;
7523
- return { module_id: moduleId, launch_nonce: launchNonce };
7524
- }
7525
- function errorCode(err) {
7526
- if (typeof err === "object" && err !== null && "code" in err) {
7527
- const code = err.code;
7528
- if (typeof code === "string")
7529
- return code;
7530
- }
7531
- return;
7532
- }
7533
- function causeMessage(cause) {
7534
- if (cause === undefined)
7535
- return "";
7536
- return `: ${cause instanceof Error ? cause.message : String(cause)}`;
7537
- }
7538
- function pendingKey(handle, corr) {
7539
- return handle ? `${handle.channel}:${handle.epoch}:${corr}` : `0:0:${corr}`;
7540
- }
7541
- // src/features/magic-context/memory/embedding-synapse.ts
7542
- var SYNAPSE_DEFAULT_MODEL = "gte-modernbert-base-f16";
7543
- var SYNAPSE_DEFAULT_QUERY_TIMEOUT_MS = 3000;
7544
- var SYNAPSE_DEFAULT_BATCH_TIMEOUT_MS = 120000;
7545
- var SYNAPSE_CERTIFICATION_REFUSAL_REASONS = new Set([
7546
- "not_certified",
7547
- "probe_required",
7548
- "migration_required"
7549
- ]);
7550
- var embeddingRowMetadata = new WeakMap;
7551
- function isSynapseEmbeddingTruncated(vector) {
7552
- return embeddingRowMetadata.get(vector)?.truncated === true;
7553
- }
7554
- function toSynapseLaneDescriptor(metadata) {
7555
- const tokenBudget = metadata.recommended_token_budget;
7556
- return {
7557
- lane: metadata.model,
7558
- ...metadata.device_class ? { device_class: metadata.device_class } : {},
7559
- max_tokens: metadata.max_tokens,
7560
- max_tokens_source: metadata.max_tokens_source,
7561
- ...metadata.bucket_ladder ? { bucket_ladder: [...metadata.bucket_ladder] } : {},
7562
- ...metadata.dims ? { dims: metadata.dims } : {},
7563
- ...metadata.dtype ? { dtype: metadata.dtype } : {},
7564
- ...typeof metadata.certified === "boolean" ? { certified: metadata.certified } : {},
7565
- ...metadata.warm_load_cost_hint_ms !== undefined ? { warm_load_cost_hint_ms: metadata.warm_load_cost_hint_ms } : {},
7566
- ...metadata.recommended_batch ? {
7567
- recommended_batch: {
7568
- rows: metadata.recommended_batch,
7569
- ...tokenBudget !== undefined ? { token_budget: tokenBudget } : {}
7570
- }
7571
- } : {},
7572
- warm: metadata.max_tokens_source === "runtime_bucket" || metadata.max_tokens_source === "worker_bucket"
7573
- };
7574
- }
7575
- function formatSynapseLaneDescriptor(descriptor) {
7576
- const certified = descriptor.certified === undefined ? "unknown" : String(descriptor.certified);
7577
- return `lane=${descriptor.lane}; device_class=${descriptor.device_class ?? "unknown"}; ` + `max_tokens=${descriptor.max_tokens} (${descriptor.max_tokens_source}); ` + `certified=${certified}; warm=${descriptor.warm ? "yes" : "no"}; ` + `warm_load_cost_hint_ms=${descriptor.warm_load_cost_hint_ms ?? "unknown"}`;
7578
- }
7579
-
7580
- class SynapseEmbeddingError extends Error {
7581
- code;
7582
- retryAfterMs;
7583
- permanent;
7584
- refusalReason;
7585
- constructor(code, message, options) {
7586
- super(message, options?.cause === undefined ? undefined : { cause: options.cause });
7587
- this.name = "SynapseEmbeddingError";
7588
- this.code = code;
7589
- this.permanent = options?.permanent ?? isPermanentSynapseCode(code);
7590
- this.retryAfterMs = options?.retryAfterMs ?? (this.permanent ? undefined : 100);
7591
- this.refusalReason = options?.refusalReason;
7592
- }
7593
- }
7594
- function isPermanentSynapseCode(code) {
7595
- return code === "artifact_invalid" || code === "substitution_rejected" || code === "not_certified" || code === "probe_required" || code === "idempotency_conflict" || code === "schema_violation" || code === "certification_refused" || code === "needs_reauth";
7596
- }
7597
- function asRecord(value) {
7598
- return value !== null && typeof value === "object" ? value : null;
7599
- }
7600
- function responseBody(value) {
7601
- const record = asRecord(value);
7602
- const result = asRecord(record?.result);
7603
- const payload = asRecord(result?.payload ?? record?.payload);
7604
- return {
7605
- ...record ?? {},
7606
- ...result ?? {},
7607
- ...payload ?? {}
7608
- };
7609
- }
7610
- function readRetryAfter(value) {
7611
- const record = asRecord(value);
7612
- const candidate = record?.retry_after_ms ?? record?.retryAfterMs;
7613
- if (typeof candidate !== "number" || !Number.isFinite(candidate) || candidate < 0)
7614
- return;
7615
- return Math.ceil(candidate);
7616
- }
7617
- function readErrorCode(value) {
7618
- const record = asRecord(value);
7619
- if (typeof record?.code === "string")
7620
- return record.code;
7621
- if (value instanceof Error && "code" in value && typeof value.code === "string") {
7622
- return value.code;
7623
- }
7624
- return;
7625
- }
7626
- function readCertificationRefusalReason(value) {
7627
- if (!(value instanceof SubcCallError))
7628
- return;
7629
- const detail = value.detail;
7630
- if (typeof detail === "string")
7631
- return detail;
7632
- const record = asRecord(detail);
7633
- return typeof record?.reason === "string" ? record.reason : undefined;
7634
- }
7635
- function classifyError(value) {
7636
- if (value instanceof SynapseEmbeddingError)
7637
- return value;
7638
- const code = readErrorCode(value) ?? (value instanceof Error ? value.name : "transport");
7639
- const normalized = code.toLowerCase();
7640
- const refusalReason = readCertificationRefusalReason(value);
7641
- let mapped = "transport";
7642
- if (normalized.includes("queue_full"))
7643
- mapped = "queue_full";
7644
- else if (normalized.includes("model_loading"))
7645
- mapped = "model_loading";
7646
- else if (normalized.includes("timeout") || normalized.includes("deadline"))
7647
- mapped = "timeout";
7648
- else if (normalized.includes("artifact_invalid"))
7649
- mapped = "artifact_invalid";
7650
- else if (normalized.includes("substitution"))
7651
- mapped = "substitution_rejected";
7652
- else if (normalized === "certification_refused")
7653
- mapped = "certification_refused";
7654
- else if (normalized.includes("not_certified"))
7655
- mapped = "not_certified";
7656
- else if (normalized.includes("probe_required"))
7657
- mapped = "probe_required";
7658
- else if (normalized.includes("idempotency_conflict"))
7659
- mapped = "idempotency_conflict";
7660
- else if (normalized.includes("needs_reauth"))
7661
- mapped = "needs_reauth";
7662
- else if (normalized.includes("schema"))
7663
- mapped = "schema_violation";
7664
- else if (normalized.includes("module_restarted") || normalized.includes("module restarted"))
7665
- mapped = "module_restarted";
7666
- const message = value instanceof Error ? value.message : String(value);
7667
- return new SynapseEmbeddingError(mapped, message, {
7668
- retryAfterMs: readRetryAfter(value) ?? (isPermanentSynapseCode(mapped) ? undefined : 100),
7669
- cause: value,
7670
- refusalReason
7671
- });
7672
- }
7673
- function embeddingFailureFor(error) {
7674
- const typedReason = error.refusalReason;
7675
- if (typedReason !== undefined && SYNAPSE_CERTIFICATION_REFUSAL_REASONS.has(typedReason) || error.code === "not_certified" || error.code === "probe_required") {
7676
- return {
7677
- class: "certification_refusal",
7678
- reason: `SYNAPSE certification refused embedding: ${typedReason ?? error.code}`,
7679
- retryable: false
7680
- };
7681
- }
7682
- if (error.code === "certification_refused") {
7683
- return {
7684
- class: "certification_refusal",
7685
- reason: `SYNAPSE certification refused embedding: ${typedReason ?? "unknown reason"}`,
7686
- retryable: false
7687
- };
7688
- }
7689
- if (typedReason === "needs_reauth" || typedReason === "needs_reauth_expired") {
7690
- return {
7691
- class: "credential_required",
7692
- reason: "SYNAPSE requires reauthentication",
7693
- retryable: false
7694
- };
7695
- }
7696
- if (error.code === "substitution_rejected") {
7697
- return { class: "substitution_rejected", reason: error.message, retryable: false };
7698
- }
7699
- if (error.code === "schema_violation" || error.code === "artifact_invalid") {
7700
- return { class: "invalid_envelope", reason: error.message, retryable: false };
7701
- }
7702
- return { class: "transport_error", reason: error.message, retryable: !error.permanent };
7703
- }
7704
- function wait(ms) {
7705
- return new Promise((resolve) => setTimeout(resolve, ms));
7706
- }
7707
- function sha256(value) {
7708
- return createHash("sha256").update(value).digest("hex");
7709
- }
7710
- function stableJson(value) {
7711
- if (Array.isArray(value))
7712
- return `[${value.map(stableJson).join(",")}]`;
7713
- if (value && typeof value === "object") {
7714
- return `{${Object.entries(value).sort(([left], [right]) => left.localeCompare(right)).map(([key, entry]) => `${JSON.stringify(key)}:${stableJson(entry)}`).join(",")}}`;
7715
- }
7716
- return JSON.stringify(value);
7717
- }
7718
- function getSynapseLaneIdentity(model, fingerprint) {
7719
- return `synapse:v1:${sha256(stableJson({ model, fingerprint }))}`;
7720
- }
7721
- function getSynapseBatchRequestKey(args) {
7722
- return sha256(stableJson({
7723
- op: "embed.batch",
7724
- model: args.model,
7725
- required_fingerprint: args.fingerprint,
7726
- required_epoch: args.tableEpoch,
7727
- allow_equivalent: false,
7728
- accept_declared: false,
7729
- ids: args.items.map((item) => item.id),
7730
- content_sha256: args.items.map((item) => item.contentSha256),
7731
- ...args.purpose === "query" ? { purpose: args.purpose } : {}
7732
- }));
7733
- }
7734
- function hashContent(text) {
7735
- return sha256(text);
7736
- }
7737
- function extractCatalogEntries(value) {
7738
- const body = responseBody(value);
7739
- const raw = Array.isArray(body.models) ? body.models : Array.isArray(body.entries) ? body.entries : Array.isArray(value) ? value : [];
7740
- const envelopeEpoch = typeof body.table_epoch === "number" && Number.isInteger(body.table_epoch) ? body.table_epoch : undefined;
7741
- const maxTokenSources = new Set([
7742
- "runtime_bucket",
7743
- "worker_bucket",
7744
- "catalog",
7745
- "catalog_unloaded"
7746
- ]);
7747
- return raw.flatMap((entry) => {
7748
- const record = asRecord(entry);
7749
- if (!record)
7750
- return [];
7751
- const model = typeof record.model === "string" && record.model.length > 0 ? record.model : typeof record.model_id === "string" ? record.model_id : "";
7752
- const fingerprint = typeof record.fingerprint === "string" && record.fingerprint.length > 0 ? record.fingerprint : Array.isArray(record.fingerprints) && typeof record.fingerprints[0] === "string" ? record.fingerprints[0] : "";
7753
- const entryEpoch = record.table_epoch ?? record.tableEpoch;
7754
- const tableEpoch = typeof entryEpoch === "number" && Number.isInteger(entryEpoch) ? entryEpoch : envelopeEpoch;
7755
- const maxTokens = record.max_tokens;
7756
- const maxTokensSource = record.max_tokens_source;
7757
- if (model.length === 0 || fingerprint.length === 0 || typeof tableEpoch !== "number" || !Number.isInteger(tableEpoch) || typeof maxTokens !== "number" || !Number.isInteger(maxTokens) || maxTokens <= 0 || typeof maxTokensSource !== "string" || !maxTokenSources.has(maxTokensSource)) {
7758
- return [];
7759
- }
7760
- const dims = record.dims ?? record.dimensions;
7761
- const rawBatch = record.recommended_batch ?? record.recommendedBatch;
7762
- const batchRecord = asRecord(rawBatch);
7763
- const recommendedBatch = typeof rawBatch === "number" ? rawBatch : batchRecord ? batchRecord.rows : undefined;
7764
- const recommendedTokenBudget = batchRecord ? batchRecord.token_budget : undefined;
7765
- const bucketLadder = Array.isArray(record.bucket_ladder) ? record.bucket_ladder.filter((bucket) => typeof bucket === "number" && Number.isInteger(bucket) && bucket > 0) : undefined;
7766
- const state = typeof record.state === "string" ? record.state : undefined;
7767
- const warmLoadCostHint = record.warm_load_cost_hint_ms;
7768
- return [
7769
- {
7770
- model,
7771
- fingerprint,
7772
- table_epoch: tableEpoch,
7773
- max_tokens: maxTokens,
7774
- max_tokens_source: maxTokensSource,
7775
- ...bucketLadder && bucketLadder.length > 0 ? { bucket_ladder: [...new Set(bucketLadder)].sort((a, b) => a - b) } : {},
7776
- ...typeof dims === "number" && Number.isInteger(dims) && dims > 0 ? { dims } : {},
7777
- ...typeof record.dtype === "string" && record.dtype.length > 0 ? { dtype: record.dtype } : {},
7778
- ...typeof record.device_class === "string" && record.device_class.length > 0 ? { device_class: record.device_class } : {},
7779
- ...typeof recommendedBatch === "number" && recommendedBatch > 0 ? { recommended_batch: Math.floor(recommendedBatch) } : {},
7780
- ...typeof recommendedTokenBudget === "number" && recommendedTokenBudget > 0 ? { recommended_token_budget: Math.floor(recommendedTokenBudget) } : {},
7781
- ...record.provenance !== undefined ? { provenance: record.provenance } : {},
7782
- ...typeof record.certified === "boolean" ? { certified: record.certified } : {},
7783
- ...typeof warmLoadCostHint === "number" && Number.isFinite(warmLoadCostHint) && warmLoadCostHint >= 0 ? { warm_load_cost_hint_ms: warmLoadCostHint } : {},
7784
- ...typeof record.status === "string" ? { status: record.status } : state ? { status: state } : {}
7785
- }
7786
- ];
7787
- });
7788
- }
7789
- function extractVector(value) {
7790
- const body = responseBody(value);
7791
- const item = Array.isArray(body.vectors) ? asRecord(body.vectors[0]) : null;
7792
- const raw = item?.vector;
7793
- if (!item || !Array.isArray(raw) || raw.some((component) => typeof component !== "number" || !Number.isFinite(component))) {
7794
- return null;
7795
- }
7796
- const disclosure = Array.isArray(body.truncation_disclosures) ? asRecord(body.truncation_disclosures[0]) : null;
7797
- return { vector: Float32Array.from(raw), item, disclosure, metadata: body };
7798
- }
7799
- function extractBatchItems(value) {
7800
- const body = responseBody(value);
7801
- const raw = Array.isArray(body.vectors) ? body.vectors : Array.isArray(body.items) ? body.items : Array.isArray(body.results) ? body.results : [];
7802
- return raw.flatMap((item) => {
7803
- const record = asRecord(item);
7804
- return record ? [record] : [];
7805
- });
7806
- }
7807
- function extractTruncationDisclosures(value) {
7808
- const body = responseBody(value);
7809
- if (!Array.isArray(body.truncation_disclosures))
7810
- return [];
7811
- return body.truncation_disclosures.map((disclosure) => asRecord(disclosure));
7812
- }
7813
- function validateWireRow(item, disclosure, expected) {
7814
- const submittedSha256 = item.submitted_sha256;
7815
- const contentSha256 = item.content_sha256;
7816
- const expectedSubmittedSha256 = hashContent(expected.text);
7817
- if (typeof submittedSha256 !== "string") {
7818
- throw new SynapseEmbeddingError("schema_violation", `Synapse item ${expected.id} omitted submitted_sha256`);
7819
- }
7820
- if (submittedSha256 !== expectedSubmittedSha256) {
7821
- throw new SynapseEmbeddingError("schema_violation", `Synapse submitted hash mismatch for item ${expected.id}`);
7822
- }
7823
- if (typeof contentSha256 !== "string") {
7824
- throw new SynapseEmbeddingError("schema_violation", `Synapse item ${expected.id} omitted content_sha256`);
7825
- }
7826
- const hashesDiffer = contentSha256 !== submittedSha256;
7827
- const disclosedTruncation = disclosure?.truncated === true;
7828
- const effectiveTokens = disclosure?.effective_tokens;
7829
- if (disclosure && (typeof disclosure.truncated !== "boolean" || typeof effectiveTokens !== "number" || !Number.isInteger(effectiveTokens) || effectiveTokens < 0)) {
7830
- throw new SynapseEmbeddingError("schema_violation", `Synapse item ${expected.id} returned an invalid truncation disclosure`);
7831
- }
7832
- if (hashesDiffer) {
7833
- if (!disclosedTruncation || typeof effectiveTokens !== "number" || !Number.isInteger(effectiveTokens) || effectiveTokens < 0) {
7834
- throw new SynapseEmbeddingError("schema_violation", `Synapse item ${expected.id} changed content without a valid truncation disclosure`);
7835
- }
7836
- } else if (disclosedTruncation) {
7837
- throw new SynapseEmbeddingError("schema_violation", `Synapse item ${expected.id} disclosed truncation but returned matching hashes`);
7838
- }
7839
- return {
7840
- truncated: hashesDiffer,
7841
- submittedSha256,
7842
- contentSha256,
7843
- ...typeof effectiveTokens === "number" && Number.isInteger(effectiveTokens) && effectiveTokens >= 0 ? { effectiveTokens } : {}
7844
- };
7845
- }
7846
- var sharedClient = null;
7847
- var sharedClientFile = null;
7848
- var sharedClientPromise = null;
7849
- var factoryClients = new WeakMap;
7850
- async function getSharedClient(options) {
7851
- if (options.clientFactory) {
7852
- let promise = factoryClients.get(options.clientFactory);
7853
- if (!promise) {
7854
- promise = options.clientFactory();
7855
- factoryClients.set(options.clientFactory, promise);
7856
- }
7857
- return promise;
7858
- }
7859
- if (sharedClient && sharedClientFile === options.connectionFile)
7860
- return sharedClient;
7861
- if (sharedClientPromise && sharedClientFile === options.connectionFile)
7862
- return sharedClientPromise;
7863
- sharedClientFile = options.connectionFile;
7864
- sharedClientPromise = SubcClient.connect({ connectionFile: options.connectionFile }).then((client) => {
7865
- sharedClient = client;
7866
- return client;
7867
- });
7868
- return sharedClientPromise;
7869
- }
7870
-
7871
- class SynapseEmbeddingProvider {
7872
- modelId;
7873
- metadata;
7874
- get maxInputTokens() {
7875
- return this.metadata?.max_tokens;
7876
- }
7877
- options;
7878
- client = null;
7879
- initialized = false;
7880
- initializing = null;
7881
- permanentFailure = false;
7882
- lastFailureReason = null;
7883
- batchLimit = 16;
7884
- tokenBudget = null;
7885
- constructor(options) {
7886
- this.options = options;
7887
- const model = options.model || SYNAPSE_DEFAULT_MODEL;
7888
- const fingerprint = options.fingerprint ?? "";
7889
- const descriptor = options.descriptor;
7890
- this.metadata = options.metadata ? {
7891
- ...options.metadata,
7892
- bucket_ladder: options.metadata.bucket_ladder ? [...options.metadata.bucket_ladder] : undefined
7893
- } : fingerprint && Number.isInteger(options.tableEpoch) && descriptor ? {
7894
- model,
7895
- fingerprint,
7896
- table_epoch: options.tableEpoch,
7897
- max_tokens: descriptor.max_tokens,
7898
- max_tokens_source: descriptor.max_tokens_source,
7899
- ...descriptor.bucket_ladder ? { bucket_ladder: [...descriptor.bucket_ladder] } : {},
7900
- ...options.dims ?? descriptor.dims ? { dims: options.dims ?? descriptor.dims } : {},
7901
- ...descriptor.dtype ? { dtype: descriptor.dtype } : {},
7902
- ...descriptor.device_class ? { device_class: descriptor.device_class } : {},
7903
- ...options.recommendedBatch ?? descriptor.recommended_batch?.rows ? {
7904
- recommended_batch: Math.max(1, Math.floor(options.recommendedBatch ?? descriptor.recommended_batch?.rows))
7905
- } : {},
7906
- ...options.recommendedTokenBudget ?? descriptor.recommended_batch?.token_budget ? {
7907
- recommended_token_budget: Math.max(1, Math.floor(options.recommendedTokenBudget ?? descriptor.recommended_batch?.token_budget))
7908
- } : {},
7909
- ...options.provenance !== undefined ? { provenance: options.provenance } : {},
7910
- ...typeof descriptor.certified === "boolean" ? { certified: descriptor.certified } : {},
7911
- ...descriptor.warm_load_cost_hint_ms !== undefined ? { warm_load_cost_hint_ms: descriptor.warm_load_cost_hint_ms } : {},
7912
- laneIdentity: getSynapseLaneIdentity(model, fingerprint)
7913
- } : null;
7914
- this.modelId = this.metadata?.laneIdentity ?? "synapse:v1:pending";
7915
- this.batchLimit = this.metadata?.recommended_batch ?? 16;
7916
- this.tokenBudget = this.metadata?.recommended_token_budget ?? null;
7917
- }
7918
- nextPage(items, start) {
7919
- const hardEnd = Math.min(items.length, start + this.batchLimit);
7920
- if (this.tokenBudget === null)
7921
- return items.slice(start, hardEnd);
7922
- let end = start;
7923
- let tokens = 0;
7924
- while (end < hardEnd) {
7925
- tokens += estimateTokens(items[end].text);
7926
- if (tokens > this.tokenBudget && end > start)
7927
- break;
7928
- end += 1;
7929
- }
7930
- return items.slice(start, Math.max(end, start + 1));
7931
- }
7932
- static async discover(options) {
7933
- const provider = new SynapseEmbeddingProvider(options);
7934
- if (!await provider.initialize() || !provider.metadata) {
7935
- throw new SynapseEmbeddingError("not_certified", "Synapse lane is not ready");
7936
- }
7937
- return provider.metadata;
7938
- }
7939
- async initialize() {
7940
- if (this.initialized)
7941
- return true;
7942
- if (this.permanentFailure)
7943
- return false;
7944
- if (this.initializing)
7945
- return this.initializing;
7946
- this.initializing = (async () => {
7947
- try {
7948
- if (!this.options.clientFactory && !await connectionFileExists(this.options.connectionFile)) {
7949
- throw new SynapseEmbeddingError("transport", `Synapse connection file is unavailable: ${this.options.connectionFile}`);
7950
- }
7951
- this.client = await getSharedClient(this.options);
7952
- if (!this.metadata) {
7953
- const discovered = await this.callWithRetry("models.list", {}, this.options.queryTimeoutMs ?? SYNAPSE_DEFAULT_QUERY_TIMEOUT_MS, false);
7954
- const entries = extractCatalogEntries(discovered);
7955
- const requested = this.options.model?.trim() || SYNAPSE_DEFAULT_MODEL;
7956
- const entry = entries.find((candidate) => candidate.model === requested);
7957
- if (!entry) {
7958
- throw new SynapseEmbeddingError("artifact_invalid", `Synapse models.list did not return requested model ${requested}`);
7959
- }
7960
- if (entry.certified === false || entry.status === "not_certified") {
7961
- throw new SynapseEmbeddingError("not_certified", `Synapse model ${entry.model} is not certified`);
7962
- }
7963
- const metadata = {
7964
- ...entry,
7965
- laneIdentity: getSynapseLaneIdentity(entry.model, entry.fingerprint)
7966
- };
7967
- this.metadata = metadata;
7968
- this.modelId = metadata.laneIdentity;
7969
- this.batchLimit = metadata.recommended_batch ?? this.batchLimit;
7970
- this.tokenBudget = metadata.recommended_token_budget ?? this.tokenBudget;
7971
- }
7972
- this.initialized = true;
7973
- this.recordSuccess();
7974
- return true;
7975
- } catch (error) {
7976
- const classified = classifyError(error);
7977
- this.recordFailure(classified);
7978
- if (classified.permanent) {
7979
- this.permanentFailure = true;
7980
- log(`[magic-context] Synapse lane disabled: ${classified.code}: ${classified.message}`);
7981
- } else {
7982
- log(`[magic-context] Synapse lane unavailable: ${classified.message}`);
7983
- }
7984
- this.initialized = false;
7985
- return false;
7986
- } finally {
7987
- this.initializing = null;
7988
- }
7989
- })();
7990
- return this.initializing;
7991
- }
7992
- async embed(text, signal, purpose = "passage") {
7993
- if (!await this.initialize() || signal?.aborted || !this.metadata)
7994
- return null;
7995
- if (estimateTokens(text) > this.metadata.max_tokens)
7996
- return null;
7997
- try {
7998
- const id = "query";
7999
- const value = await this.callWithRetry("embed.query", this.requestConstraints({
8000
- id,
8001
- text,
8002
- purpose,
8003
- deadline_ms: this.options.queryTimeoutMs ?? SYNAPSE_DEFAULT_QUERY_TIMEOUT_MS
8004
- }), this.options.queryTimeoutMs ?? SYNAPSE_DEFAULT_QUERY_TIMEOUT_MS, true, signal);
8005
- const extracted = extractVector(value);
8006
- if (!extracted) {
8007
- throw new SynapseEmbeddingError("schema_violation", "Synapse query returned no vector row");
8008
- }
8009
- if (extracted.item.id !== id) {
8010
- throw new SynapseEmbeddingError("schema_violation", `Synapse query returned unexpected item ${String(extracted.item.id)}`);
8011
- }
8012
- const rowMetadata = validateWireRow(extracted.item, extracted.disclosure, { id, text });
8013
- this.validateResponse(extracted.metadata, extracted.vector.length);
8014
- embeddingRowMetadata.set(extracted.vector, rowMetadata);
8015
- this.recordSuccess();
8016
- return extracted.vector;
8017
- } catch (error) {
8018
- this.logCallFailure(error, "embed.query");
8019
- return null;
8020
- }
8021
- }
8022
- async embedBatch(texts, signal, purpose = "passage") {
8023
- if (texts.length === 0)
8024
- return [];
8025
- const items = texts.map((text, index) => ({
8026
- id: `item:${index}`,
8027
- text,
8028
- contentSha256: hashContent(text)
8029
- }));
8030
- const map = await this.embedItems(items, signal, purpose);
8031
- return items.map((item) => map.get(item.id) ?? null);
8032
- }
8033
- async embedItems(items, signal, purpose = "passage") {
8034
- const output = new Map;
8035
- if (items.length === 0 || !await this.initialize() || !this.metadata || signal?.aborted) {
8036
- return output;
8037
- }
8038
- const maxTokens = this.metadata.max_tokens;
8039
- const eligibleItems = items.filter((item) => estimateTokens(item.text) <= maxTokens).map((item) => ({ ...item, contentSha256: hashContent(item.text) }));
8040
- for (let start = 0;start < eligibleItems.length; ) {
8041
- if (signal?.aborted || this.permanentFailure)
8042
- break;
8043
- const page = this.nextPage(eligibleItems, start);
8044
- start += page.length;
8045
- try {
8046
- const requestKey = this.requestKey(page, purpose);
8047
- let body = {};
8048
- let restarted = false;
8049
- for (;; ) {
8050
- try {
8051
- body = await this.callWithRetry("embed.batch", this.batchRequest(page, requestKey, purpose), this.options.batchTimeoutMs ?? SYNAPSE_DEFAULT_BATCH_TIMEOUT_MS, true, signal);
8052
- const first = responseBody(body);
8053
- const jobId = typeof first.job_id === "string" ? first.job_id : null;
8054
- if (jobId)
8055
- body = await this.pollBatch(jobId, requestKey, signal);
8056
- break;
8057
- } catch (error) {
8058
- const classified = classifyError(error);
8059
- if (classified.code !== "module_restarted" || restarted)
8060
- throw classified;
8061
- restarted = true;
8062
- }
8063
- }
8064
- const batchEnvelope = responseBody(body);
8065
- const disclosures = extractTruncationDisclosures(body);
8066
- for (const [index, item] of extractBatchItems(body).entries()) {
8067
- const id = typeof item.id === "string" ? item.id : "";
8068
- const vector = item.vector ?? item.embedding;
8069
- if (!id || !Array.isArray(vector) || vector.some((component) => typeof component !== "number" || !Number.isFinite(component))) {
8070
- throw new SynapseEmbeddingError("schema_violation", "Synapse batch item is malformed");
8071
- }
8072
- const expected = page.find((candidate) => candidate.id === id);
8073
- if (!expected) {
8074
- throw new SynapseEmbeddingError("schema_violation", `Synapse returned unknown item ${id}`);
8075
- }
8076
- const rowMetadata = validateWireRow(item, disclosures[index] ?? null, expected);
8077
- const vectorArray = Float32Array.from(vector);
8078
- this.validateResponse({ ...batchEnvelope, ...item }, vectorArray.length);
8079
- embeddingRowMetadata.set(vectorArray, rowMetadata);
8080
- output.set(id, vectorArray);
8081
- this.recordSuccess();
8082
- }
8083
- } catch (error) {
8084
- const classified = classifyError(error);
8085
- this.logCallFailure(classified, "embed.batch");
8086
- if (classified.code === "idempotency_conflict" || classified.code === "schema_violation") {
8087
- throw classified;
8088
- }
8089
- if (classified.permanent) {
8090
- this.permanentFailure = true;
8091
- this.initialized = false;
8092
- break;
8093
- }
8094
- }
8095
- }
8096
- return output;
8097
- }
8098
- async dispose() {
8099
- this.initialized = false;
8100
- this.client = null;
8101
- }
8102
- isLoaded() {
8103
- return this.initialized;
8104
- }
8105
- getLastFailureReason() {
8106
- return this.lastFailureReason;
8107
- }
8108
- requestConstraints(extra) {
8109
- const metadata = this.metadata;
8110
- if (!metadata)
8111
- return extra;
8112
- return {
8113
- ...extra,
8114
- model: metadata.model,
8115
- required_fingerprint: metadata.fingerprint,
8116
- required_epoch: metadata.table_epoch,
8117
- allow_equivalent: false,
8118
- accept_declared: false
8119
- };
8120
- }
8121
- batchRequest(items, requestKey, purpose) {
8122
- return this.requestConstraints({
8123
- items: items.map((item) => ({
8124
- id: item.id,
8125
- text: item.text,
8126
- content_sha256: item.contentSha256
8127
- })),
8128
- request_key: requestKey,
8129
- purpose
8130
- });
8131
- }
8132
- requestKey(items, purpose) {
8133
- if (!this.metadata)
8134
- throw new SynapseEmbeddingError("transport", "Synapse metadata is unavailable");
8135
- return getSynapseBatchRequestKey({
8136
- model: this.metadata.model,
8137
- fingerprint: this.metadata.fingerprint,
8138
- tableEpoch: this.metadata.table_epoch,
8139
- items,
8140
- purpose
8141
- });
8142
- }
8143
- async pollBatch(jobId, requestKey, signal) {
8144
- let cursor = null;
8145
- const allItems = [];
8146
- const allDisclosures = [];
8147
- for (;; ) {
8148
- if (signal?.aborted)
8149
- return {};
8150
- const body = await this.callWithRetry("embed.result", this.requestConstraints({
8151
- job_id: jobId,
8152
- cursor,
8153
- request_key: requestKey
8154
- }), this.options.batchTimeoutMs ?? SYNAPSE_DEFAULT_BATCH_TIMEOUT_MS, true, signal);
8155
- const parsed = responseBody(body);
8156
- const items = extractBatchItems(body);
8157
- const disclosures = extractTruncationDisclosures(body);
8158
- allItems.push(...items);
8159
- allDisclosures.push(...items.map((_, index) => disclosures[index] ?? null));
8160
- const nextCursor = parsed.next_cursor ?? parsed.cursor;
8161
- const done = parsed.done === true || parsed.complete === true || nextCursor === undefined || nextCursor === null;
8162
- if (done) {
8163
- return {
8164
- ...parsed,
8165
- vectors: allItems,
8166
- truncation_disclosures: allDisclosures
8167
- };
8168
- }
8169
- cursor = nextCursor;
8170
- }
8171
- }
8172
- async callWithRetry(method, params, timeoutMs, retryEmbeddings, signal) {
8173
- let attempt = 0;
8174
- for (;; ) {
8175
- if (signal?.aborted)
8176
- throw new SynapseEmbeddingError("transport", "Synapse request aborted");
8177
- try {
8178
- if (!this.client)
8179
- throw new SynapseEmbeddingError("transport", "Synapse client is unavailable");
8180
- return await this.client.call(this.options.moduleId ?? "synapse", method, params, {
8181
- timeoutMs,
8182
- targetKind: "management_surface",
8183
- identity: {
8184
- project_root: this.options.projectRoot,
8185
- harness: getHarness(),
8186
- session: this.options.session
8187
- }
8188
- });
8189
- } catch (error) {
8190
- const classified = classifyError(error);
8191
- if (classified.code === "idempotency_conflict")
8192
- throw classified;
8193
- const outcomeUnknown = error instanceof SubcCallError && error.kind === "outcome_unknown";
8194
- const retryable = !classified.permanent && (retryEmbeddings || !outcomeUnknown);
8195
- if (!retryable || attempt >= 3)
8196
- throw classified;
8197
- const delay = classified.retryAfterMs ?? Math.min(2000, 100 * 2 ** attempt);
8198
- attempt += 1;
8199
- await wait(delay);
8200
- }
8201
- }
8202
- }
8203
- validateResponse(body, dims) {
8204
- const metadata = this.metadata;
8205
- if (!metadata) {
8206
- throw new SynapseEmbeddingError("artifact_invalid", "Synapse lane metadata missing");
8207
- }
8208
- if (metadata.dims === undefined) {
8209
- const envelopeDims = body.dims;
8210
- if (typeof envelopeDims === "number" && envelopeDims !== dims) {
8211
- throw new SynapseEmbeddingError("artifact_invalid", `Synapse envelope declares ${envelopeDims} dimensions but the vector has ${dims}`);
8212
- }
8213
- metadata.dims = dims;
8214
- }
8215
- if (dims !== metadata.dims) {
8216
- throw new SynapseEmbeddingError("artifact_invalid", `Synapse returned ${dims} dimensions, expected ${metadata.dims}`);
8217
- }
8218
- const fingerprint = body.fingerprint ?? body.served_fingerprint;
8219
- if (typeof fingerprint !== "string") {
8220
- throw new SynapseEmbeddingError("artifact_invalid", "Synapse response omitted the served fingerprint");
8221
- }
8222
- if (fingerprint !== metadata.fingerprint) {
8223
- throw new SynapseEmbeddingError("substitution_rejected", `Synapse fingerprint changed from ${metadata.fingerprint} to ${fingerprint}`);
8224
- }
8225
- const epoch = body.table_epoch ?? body.tableEpoch;
8226
- if (typeof epoch !== "number") {
8227
- throw new SynapseEmbeddingError("artifact_invalid", "Synapse response omitted the served table epoch");
8228
- }
8229
- if (epoch !== metadata.table_epoch) {
8230
- throw new SynapseEmbeddingError("substitution_rejected", `Synapse table epoch changed from ${metadata.table_epoch} to ${epoch}`);
8231
- }
8232
- }
8233
- logCallFailure(error, operation) {
8234
- const classified = classifyError(error);
8235
- this.recordFailure(classified);
8236
- if (classified.permanent)
8237
- this.permanentFailure = true;
8238
- const suffix = classified.retryAfterMs === undefined ? "" : ` retry_after_ms=${classified.retryAfterMs}`;
8239
- log(`[magic-context] Synapse ${operation} failed: ${classified.code}${suffix}: ${classified.message}`);
8240
- }
8241
- recordFailure(error) {
8242
- this.lastFailureReason = embeddingFailureFor(error);
8243
- }
8244
- recordSuccess() {
8245
- this.lastFailureReason = null;
8246
- }
8247
- }
8248
-
8249
- // src/features/magic-context/memory/normalize-hash.ts
8250
- import { createHash as createHash2 } from "node:crypto";
8251
- function normalizeMemoryContent(content) {
8252
- return content.toLowerCase().replace(/\s+/g, " ").trim();
8253
- }
8254
- function computeNormalizedHash(content) {
8255
- const normalized = normalizeMemoryContent(content);
8256
- return createHash2("md5").update(normalized).digest("hex");
8257
- }
8258
-
8259
- // src/features/magic-context/memory/embedding-identity.ts
8260
- function normalizeEndpoint(endpoint) {
8261
- return endpoint?.trim().replace(/\/+$/, "") ?? "";
8262
- }
8263
- var LOCAL_EMBEDDING_RUNTIME_FINGERPRINT = "transformers@4.3.0;onnxruntime-node@1.30.0;onnxruntime-web@1.26.0-dev.20260416-b7804b056c";
8264
- function getEmbeddingProviderIdentity(config) {
8265
- if (config.provider === "off") {
8266
- return "embedding-provider:off";
8267
- }
8268
- if (config.provider === "synapse") {
8269
- const resolved = config;
8270
- if (!resolved.model || !resolved.synapse_fingerprint)
8271
- return "synapse:v1:pending";
8272
- return getSynapseLaneIdentity(resolved.model, resolved.synapse_fingerprint);
8273
- }
8274
- if (config.provider !== "local" && config.provider !== "openai-compatible") {
8275
- throw new Error("Unknown embedding provider");
8276
- }
8277
- const truncate = config.provider === "openai-compatible" ? config.truncate?.trim() : undefined;
8278
- const documentPrefix = config.provider === "openai-compatible" ? resolveEmbeddingTextPrefixes(config.model, config.query_instruction, config.document_prefix).documentPrefix : "";
8279
- const localDtype = config.provider === "local" && config.local_dtype && config.local_dtype !== "fp32" ? config.local_dtype : undefined;
8280
- const identityInput = config.provider === "openai-compatible" ? {
8281
- provider: "openai-compatible",
8282
- model: config.model.trim(),
8283
- endpoint: normalizeEndpoint(config.endpoint),
8284
- apiKeyPresent: Boolean(config.api_key?.trim()),
8285
- inputType: config.input_type?.trim() || "",
8286
- ...documentPrefix ? { documentPrefix } : {},
8287
- ...truncate ? { truncate } : {}
8288
- } : {
8289
- provider: "local",
8290
- model: config.model?.trim() || DEFAULT_LOCAL_EMBEDDING_MODEL,
8291
- endpoint: "",
8292
- apiKeyPresent: false,
8293
- runtimeFingerprint: LOCAL_EMBEDDING_RUNTIME_FINGERPRINT,
8294
- ...localDtype ? { localDtype } : {}
8295
- };
8296
- return `embedding-provider:${computeNormalizedHash(JSON.stringify(identityInput))}`;
8297
- }
8298
-
8299
- // src/features/magic-context/memory/embedding-worker-client.ts
8300
- import { Worker } from "node:worker_threads";
8301
- class EmbeddingWorkerClient {
8302
- data;
8303
- entry;
8304
- timeoutMs;
8305
- worker = null;
8306
- nextId = 1;
8307
- pending = new Map;
8308
- disposed = false;
8309
- constructor(data, entry = new URL(new URL(import.meta.url).pathname.endsWith(".ts") ? "./embedding-worker.ts" : "./embedding-worker.js", import.meta.url), timeoutMs = 5 * 60000) {
8310
- this.data = data;
8311
- this.entry = entry;
8312
- this.timeoutMs = timeoutMs;
8313
- }
8314
- start() {
8315
- if (this.disposed)
8316
- throw new Error("embedding worker disposed");
8317
- if (this.worker)
8318
- return this.worker;
8319
- const worker = new Worker(this.entry, { workerData: this.data });
8320
- this.worker = worker;
8321
- worker.unref();
8322
- worker.on("message", (reply) => {
8323
- if (this.worker !== worker)
8324
- return;
8325
- const request = this.pending.get(reply.id);
8326
- if (!request)
8327
- return;
8328
- clearTimeout(request.timer);
8329
- this.pending.delete(reply.id);
8330
- if (reply.error)
8331
- request.reject(new Error(reply.error));
8332
- else
8333
- request.resolve(reply);
8334
- if (this.pending.size === 0)
8335
- worker.unref();
8336
- });
8337
- const fail = (error) => {
8338
- if (this.worker !== worker)
8339
- return;
8340
- this.worker = null;
8341
- for (const request of this.pending.values()) {
8342
- clearTimeout(request.timer);
8343
- request.reject(error);
8344
- }
8345
- this.pending.clear();
8346
- log("[magic-context] embedding worker exited unexpectedly:", error);
8347
- worker.terminate();
8348
- };
8349
- worker.on("error", fail);
8350
- worker.on("exit", (code) => fail(new Error(`embedding worker exited (${code})`)));
8351
- return worker;
8352
- }
8353
- isRunning() {
8354
- return this.worker !== null;
8355
- }
8356
- request(texts, signal) {
8357
- if (signal?.aborted)
8358
- return Promise.reject(new Error("embedding request aborted"));
8359
- return new Promise((resolve, reject) => {
8360
- const worker = this.start();
8361
- const id = this.nextId++;
8362
- const timer = setTimeout(() => {
8363
- this.stop(new Error("embedding worker request timed out"));
8364
- }, this.timeoutMs);
8365
- const abort = () => {
8366
- clearTimeout(timer);
8367
- this.pending.delete(id);
8368
- signal?.removeEventListener("abort", abort);
8369
- reject(new Error("embedding request aborted"));
8370
- if (this.pending.size === 0)
8371
- worker.unref();
8372
- };
8373
- signal?.addEventListener("abort", abort, { once: true });
8374
- const cleanup = () => signal?.removeEventListener("abort", abort);
8375
- this.pending.set(id, {
8376
- timer,
8377
- resolve: (reply) => {
8378
- cleanup();
8379
- resolve(reply);
8380
- },
8381
- reject: (error) => {
8382
- cleanup();
8383
- reject(error);
8384
- }
8385
- });
8386
- worker.ref();
8387
- try {
8388
- worker.postMessage({ id, texts });
8389
- } catch (error) {
8390
- this.stop(error instanceof Error ? error : new Error(String(error)));
8391
- }
8392
- });
8393
- }
8394
- async stop(error) {
8395
- const worker = this.worker;
8396
- this.worker = null;
8397
- for (const request of this.pending.values()) {
8398
- clearTimeout(request.timer);
8399
- request.reject(error);
8400
- }
8401
- this.pending.clear();
8402
- await worker?.terminate();
8403
- }
8404
- async dispose() {
8405
- this.disposed = true;
8406
- await this.stop(new Error("embedding worker disposed"));
8407
- }
8408
- }
8409
-
8410
- // src/features/magic-context/memory/transformers-remote-host.ts
8411
- var DEFAULT_TRANSFORMERS_REMOTE_HOST = "https://huggingface.co/";
8412
- function readHuggingFaceEndpoint() {
8413
- return globalThis.process?.env?.HF_ENDPOINT;
8414
- }
8415
- function configureTransformersRemoteHost(env, endpoint = readHuggingFaceEndpoint()) {
8416
- const normalized = endpoint?.trim().replace(/\/+$/, "");
8417
- env.remoteHost = normalized ? `${normalized}/` : DEFAULT_TRANSFORMERS_REMOTE_HOST;
8418
- }
8419
-
8420
- // src/features/magic-context/memory/embedding-local.ts
8421
- var BUN_NAPI_TEARDOWN_FIX_VERSION = [1, 4, 0];
8422
- function currentLocalEmbeddingHost() {
8423
- const bun = globalThis.Bun;
8424
- const hasProcess = typeof process !== "undefined";
8425
- const bunVersion = hasProcess && typeof process.versions?.bun === "string" ? process.versions.bun : undefined;
8426
- return {
8427
- isElectron: hasProcess && Boolean(process.versions?.electron),
8428
- isBun: Boolean(bun) || Boolean(bunVersion),
8429
- bunVersion,
8430
- hasNodeFilesystem: hasProcess && (typeof process.versions?.node === "string" || typeof bunVersion === "string")
8431
- };
8432
- }
8433
- function bunHasNapiTeardownFix(version) {
8434
- const match = version?.match(/^v?(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?(?:\+[0-9A-Za-z.-]+)?$/);
8435
- if (!match || match[4])
8436
- return false;
8437
- const parsed = [Number(match[1]), Number(match[2]), Number(match[3])];
8438
- return parsed.some((part) => !Number.isSafeInteger(part)) ? false : parsed[0] > BUN_NAPI_TEARDOWN_FIX_VERSION[0] || parsed[0] === BUN_NAPI_TEARDOWN_FIX_VERSION[0] && (parsed[1] > BUN_NAPI_TEARDOWN_FIX_VERSION[1] || parsed[1] === BUN_NAPI_TEARDOWN_FIX_VERSION[1] && parsed[2] >= BUN_NAPI_TEARDOWN_FIX_VERSION[2]);
8439
- }
8440
- function resolveLocalEmbeddingRuntime(preference = "auto", host = currentLocalEmbeddingHost()) {
8441
- if (preference === "native" || preference === "wasm")
8442
- return preference;
8443
- if (host.isElectron)
8444
- return "electron";
8445
- if (host.isBun && !bunHasNapiTeardownFix(host.bunVersion))
8446
- return "wasm";
8447
- return "native";
8448
- }
8449
- function resolveLocalEmbeddingWorkerRuntime(preference = "auto", host = currentLocalEmbeddingHost()) {
8450
- if (host.isBun && !bunHasNapiTeardownFix(host.bunVersion) && preference === "native")
8451
- return "wasm";
8452
- return resolveLocalEmbeddingRuntime(preference, host);
8453
- }
8454
- var LOCK_POLL_MS = 150;
8455
- var STALE_LOCK_MS = 3 * 60000;
8456
- var MAX_LOCK_WAIT_MS = 5 * 60000;
8457
- async function acquireModelLoadLock(lockPath) {
8458
- const waitStart = Date.now();
8459
- while (true) {
8460
- try {
8461
- const handle = await open(lockPath, "wx");
8462
- try {
8463
- await handle.writeFile(`pid=${process.pid} started=${Date.now()}
8464
- `);
8465
- } catch {}
8466
- await handle.close();
8467
- return async () => {
8468
- try {
8469
- await unlink(lockPath);
8470
- } catch {}
8471
- };
8472
- } catch (error) {
8473
- const code = error.code;
8474
- if (code !== "EEXIST" && code !== "EPERM") {
8475
- throw error;
8476
- }
8477
- try {
8478
- const info = await stat(lockPath);
8479
- if (Date.now() - info.mtimeMs > STALE_LOCK_MS) {
8480
- log(`[magic-context] embedding-load lock stale (>${STALE_LOCK_MS}ms), taking over`);
8481
- try {
8482
- await unlink(lockPath);
8483
- } catch {}
8484
- continue;
8485
- }
8486
- } catch {
8487
- continue;
8488
- }
8489
- if (Date.now() - waitStart > MAX_LOCK_WAIT_MS) {
8490
- throw new Error(`[magic-context] embedding-load lock wait exceeded ${MAX_LOCK_WAIT_MS}ms; another process is still loading the model. Skipping this init attempt to avoid an unsynchronized native load.`);
8491
- }
8492
- await new Promise((resolve) => setTimeout(resolve, LOCK_POLL_MS));
8493
- }
8494
- }
8495
- }
8496
- function startLockHeartbeat(lockPath) {
8497
- const HEARTBEAT_MS = Math.floor(STALE_LOCK_MS / 3);
8498
- const timer = setInterval(() => {
8499
- writeFile(lockPath, `pid=${process.pid} alive=${Date.now()}
8500
- `).catch(() => {});
8501
- }, HEARTBEAT_MS);
8502
- timer.unref?.();
8503
- return () => clearInterval(timer);
8504
- }
8505
- var ONNX_RUNTIME_WEB_SPECIFIER = "onnxruntime-web";
8506
- var useInThreadTestRuntime = false;
8507
- var workerFactoryForTests;
8508
- var localEmbeddingRuntimeMode = "native";
8509
- var localEmbeddingProcessFailure = null;
8510
- var wasmRuntimeInjected = false;
8511
- var localEmbeddingHostForRuntime = currentLocalEmbeddingHost;
8512
- var resolveWasmOrtForRuntime = () => {
8513
- try {
8514
- return typeof import.meta.resolve === "function" ? import.meta.resolve(ONNX_RUNTIME_WEB_SPECIFIER) : undefined;
8515
- } catch {
8516
- return;
8517
- }
8518
- };
8519
- var importWasmOrtModule = async (specifier) => await import(specifier);
8520
- var importWasmOrtModuleForRuntime = importWasmOrtModule;
8521
- var importWasmOrtForRuntime = async () => {
8522
- const { createRequire: createRequireFn } = await import("node:module");
8523
- const requireFn = createRequireFn(import.meta.url);
8524
- const ortEntry = requireFn.resolve(ONNX_RUNTIME_WEB_SPECIFIER);
8525
- const ortSpecifier = resolveWasmOrtForRuntime() ?? ONNX_RUNTIME_WEB_SPECIFIER;
8526
- return {
8527
- module: await importWasmOrtModuleForRuntime(ortSpecifier),
8528
- entryPath: ortEntry
8529
- };
8530
- };
8531
- var importTransformersForRuntime = async () => {
8532
- return await importPluginModule(() => import("./transformers.node-hj754h7s.js"));
8533
- };
8534
- var importTransformersWasmFallbackForRuntime = async () => {
8535
- const webEntry = new URL(new URL(import.meta.url).pathname.endsWith(".ts") ? "../../../../dist/transformers-web.js" : "./transformers-web.js", import.meta.url).href;
8536
- return await importPluginModule(() => import(webEntry));
8537
- };
8538
- var importTransformersNodeWasmFallbackForRuntime = async () => {
8539
- const nodeWasmEntry = new URL(new URL(import.meta.url).pathname.endsWith(".ts") ? "../../../../dist/transformers-node-wasm.js" : "./transformers-node-wasm.js", import.meta.url).href;
8540
- return await importPluginModule(() => import(nodeWasmEntry));
8541
- };
8542
- var modelCacheDirForRuntime = () => workerData?.magicContextEmbeddingWorker && typeof workerData.modelCacheDir === "string" ? workerData.modelCacheDir : join(getMagicContextStorageDir(), "models");
8543
- var logForRuntime = log;
8544
- var injectWasmOrtForRuntime = injectWasmOrt;
8545
- var loadedLocalEmbeddingRuntimes = new Map;
8546
- var nextLocalEmbeddingRuntimeId = 1;
8547
- function directoryBytes(path) {
8548
- let total = 0;
8549
- try {
8550
- for (const entry of readdirSync(path, { withFileTypes: true })) {
8551
- const entryPath = join(path, entry.name);
8552
- if (entry.isDirectory()) {
8553
- const childBytes = directoryBytes(entryPath);
8554
- if (childBytes === null)
8555
- return null;
8556
- total += childBytes;
8557
- } else if (entry.isFile()) {
8558
- total += statSync(entryPath).size;
8559
- }
8560
- }
8561
- return total;
8562
- } catch (error) {
8563
- return error.code === "ENOENT" ? 0 : null;
8564
- }
8565
- }
8566
- function getLocalEmbeddingNativeMemoryStats() {
8567
- const loaded = [...loadedLocalEmbeddingRuntimes.values()];
8568
- return {
8569
- loaded: loaded.length > 0,
8570
- providerCount: loaded.length,
8571
- models: [...new Set(loaded.map((entry) => entry.model))].sort(),
8572
- runtimes: [...new Set(loaded.map((entry) => entry.runtime))].sort(),
8573
- modelCacheBytes: loaded.length > 0 ? directoryBytes(modelCacheDirForRuntime()) : 0,
8574
- rssDeltaAtLoad: loaded.reduce((sum, entry) => sum + entry.rssDeltaAtLoad, 0),
8575
- externalDeltaAtLoad: loaded.reduce((sum, entry) => sum + entry.externalDeltaAtLoad, 0),
8576
- arrayBuffersDeltaAtLoad: loaded.reduce((sum, entry) => sum + entry.arrayBuffersDeltaAtLoad, 0)
8577
- };
8578
- }
8579
- async function ensureWasmOrtInjected() {
8580
- if (wasmRuntimeInjected)
8581
- return true;
8582
- if (!await injectWasmOrtForRuntime())
8583
- return false;
8584
- wasmRuntimeInjected = true;
8585
- return true;
8586
- }
8587
- async function injectWasmOrt() {
8588
- if (wasmRuntimeInjected)
8589
- return true;
8590
- try {
8591
- const { module: ortWeb, entryPath } = await importWasmOrtForRuntime();
8592
- if (ortWeb.env?.wasm) {
8593
- ortWeb.env.wasm.numThreads = 1;
8594
- ortWeb.env.wasm.wasmPaths = `${pathToFileURL(dirname(entryPath)).href}/`;
8595
- }
8596
- globalThis[Symbol.for("onnxruntime")] = ortWeb;
8597
- wasmRuntimeInjected = true;
8598
- return true;
8599
- } catch (error) {
8600
- log("[magic-context] failed to inject onnxruntime-web:", error instanceof Error ? error.message : String(error));
8601
- return false;
8602
- }
8603
- }
8604
- function likelyMuslHint() {
8605
- if (process.platform !== "linux" || typeof process.report?.getReport !== "function")
8606
- return "";
8607
- try {
8608
- const report = process.report.getReport();
8609
- return typeof report.header?.glibcVersionRuntime === "string" ? "" : " Linux process report has no glibc runtime version (musl likely).";
8610
- } catch {
8611
- return "";
8612
- }
8613
- }
8614
- function localEmbeddingRuntimeIsDisabled() {
8615
- return localEmbeddingRuntimeMode === "disabled";
8616
- }
8617
-
8618
- class LocalEmbeddingFallbackError extends Error {
8619
- nativeError;
8620
- constructor(nativeError, wasmError) {
8621
- super("the native local embedding runtime and its WASM fallback both failed", {
8622
- cause: wasmError
8623
- });
8624
- this.name = "LocalEmbeddingFallbackError";
8625
- this.nativeError = nativeError;
8626
- }
8627
- }
8628
-
8629
- class LocalEmbeddingFsUnavailableError extends Error {
8630
- code = "MC_EMBEDDING_FS_UNAVAILABLE";
8631
- constructor() {
8632
- super("MC_EMBEDDING_FS_UNAVAILABLE: Node WASM bundle has no filesystem cache");
8633
- this.name = "LocalEmbeddingFsUnavailableError";
8634
- }
8635
- }
8636
- async function importWasmTransformersForHost() {
8637
- const host = localEmbeddingHostForRuntime();
8638
- if (host.isElectron) {
8639
- return importTransformersForRuntime();
8640
- }
8641
- return host.hasNodeFilesystem ? importTransformersNodeWasmFallbackForRuntime() : importTransformersWasmFallbackForRuntime();
8642
- }
8643
- function disableLocalEmbeddingsAfterRuntimeFailure(detail) {
8644
- localEmbeddingRuntimeMode = "disabled";
8645
- logForRuntime(`[magic-context] local embeddings are disabled because both the onnxruntime-node native binding and the onnxruntime-web (WASM) fallback failed to load. Native failure: ${detail}. Run \`npx @cortexkit/magic-context@latest doctor\` for diagnostics; reinstalling repairs missing package files but cannot add a native binding that upstream does not ship. Alternatively, configure an \`openai-compatible\` embedding HTTP endpoint. Existing memories are unaffected.`);
8646
- }
8647
- async function loadTransformersForLocalEmbedding(runtimePreference) {
8648
- if (localEmbeddingRuntimeMode === "disabled") {
8649
- throw new Error("local embedding runtime is disabled");
8650
- }
8651
- const resolvedRuntime = resolveLocalEmbeddingRuntime(runtimePreference, localEmbeddingHostForRuntime());
8652
- if (resolvedRuntime === "wasm") {
8653
- if (!await ensureWasmOrtInjected()) {
8654
- disableLocalEmbeddingsAfterRuntimeFailure("the selected WASM runtime is unavailable");
8655
- throw new Error("onnxruntime-web failed to load");
8656
- }
8657
- return { module: await importWasmTransformersForHost(), usesWasm: true };
8658
- }
8659
- if (localEmbeddingRuntimeMode === "wasm") {
8660
- if (!await ensureWasmOrtInjected()) {
8661
- disableLocalEmbeddingsAfterRuntimeFailure("the previously selected WASM runtime is unavailable");
8662
- throw new Error("onnxruntime-web failed to load");
8663
- }
8664
- try {
8665
- return { module: await importWasmTransformersForHost(), usesWasm: true };
8666
- } catch (wasmError) {
8667
- disableLocalEmbeddingsAfterRuntimeFailure("the previously selected WASM runtime failed to load");
8668
- throw wasmError;
8669
- }
8670
- }
8671
- const electron = resolvedRuntime === "electron";
8672
- if (electron) {
8673
- const wasInjected = wasmRuntimeInjected;
8674
- if (await ensureWasmOrtInjected()) {
8675
- if (!wasInjected) {
8676
- logForRuntime("[magic-context] Electron detected — using onnxruntime-web (WASM) for embeddings (bypasses onnxruntime-node native load)");
8677
- }
8678
- return { module: await importTransformersForRuntime(), usesWasm: true };
8679
- }
8680
- }
8681
- try {
8682
- return { module: await importTransformersForRuntime(), usesWasm: false };
8683
- } catch (nativeError) {
8684
- if (!isNativeRuntimeMissingError(nativeError) || electron) {
8685
- throw nativeError;
8686
- }
8687
- if (!await ensureWasmOrtInjected()) {
8688
- disableLocalEmbeddingsAfterRuntimeFailure(nativeError instanceof Error ? nativeError.message : String(nativeError));
8689
- throw nativeError;
8690
- }
8691
- localEmbeddingRuntimeMode = "wasm";
8692
- try {
8693
- const module = await importWasmTransformersForHost();
8694
- logForRuntime("[magic-context] onnxruntime-node failed to load; using onnxruntime-web (WASM) for local embeddings. WASM inference is slower than native; a remote `openai-compatible` provider may be faster." + likelyMuslHint());
8695
- return { module, usesWasm: true };
8696
- } catch (wasmError) {
8697
- disableLocalEmbeddingsAfterRuntimeFailure(nativeError instanceof Error ? nativeError.message : String(nativeError));
8698
- throw new LocalEmbeddingFallbackError(nativeError, wasmError);
8699
- }
8700
- }
8701
- }
8702
- var DEFAULT_LOCAL_DTYPE = "fp32";
8703
- async function withQuietConsole(fn) {
8704
- const origWarn = console.warn;
8705
- const origError = console.error;
8706
- const redirect = (...args) => {
8707
- const message = args.map((a) => typeof a === "string" ? a : String(a)).join(" ");
8708
- log(`[transformers] ${message}`);
8709
- };
8710
- console.warn = redirect;
8711
- console.error = redirect;
8712
- try {
8713
- return await fn();
8714
- } finally {
8715
- console.warn = origWarn;
8716
- console.error = origError;
8717
- }
8718
- }
8719
- function isNativeRuntimeMissingError(error) {
8720
- const message = error instanceof Error ? error.message : String(error ?? "");
8721
- const lower = message.toLowerCase();
8722
- const code = error?.code;
8723
- const name = error?.name;
8724
- if (code === "ERR_DLOPEN_FAILED" && lower.includes("onnxruntime")) {
8725
- return true;
8726
- }
8727
- if (lower.includes('could not load the "sharp" module'))
8728
- return true;
8729
- const mentionsNativeRuntime = lower.includes("onnxruntime-node") || lower.includes("onnxruntime_binding");
8730
- if (!mentionsNativeRuntime)
8731
- return false;
8732
- return code === "ERR_MODULE_NOT_FOUND" || name === "ResolveMessage" || lower.includes("cannot find package") || lower.includes("cannot find module") || lower.includes("err_module_not_found");
8733
- }
8734
- function isTransientLoadError(error) {
8735
- const message = error instanceof Error ? error.message : String(error ?? "");
8736
- if (!message)
8737
- return false;
8738
- const lower = message.toLowerCase();
8739
- return lower.includes("protobuf parsing failed") || lower.includes("unable to get model file path or buffer") || lower.includes("ebusy") || lower.includes("resource busy") || lower.includes("resource temporarily unavailable");
8740
- }
8741
- function isArrayLikeNumber(value) {
8742
- if (typeof value !== "object" || value === null || !("length" in value)) {
8743
- return false;
8744
- }
8745
- const arr = value;
8746
- if (typeof arr.length !== "number") {
8747
- return false;
8748
- }
8749
- return arr.length === 0 || typeof arr[0] === "number";
8750
- }
8751
- function toFloat32Array(values) {
8752
- return values instanceof Float32Array ? new Float32Array(values) : Float32Array.from(Array.from(values));
8753
- }
8754
- function extractBatchEmbeddings(result, expectedCount) {
8755
- const { data } = result;
8756
- if (Array.isArray(data) && data.length === expectedCount && data.every((entry) => typeof entry !== "number" && isArrayLikeNumber(entry))) {
8757
- return data.map((entry) => toFloat32Array(entry));
8758
- }
8759
- if (!isArrayLikeNumber(data)) {
8760
- log("[magic-context] embedding batch returned unexpected data shape");
8761
- return Array.from({ length: expectedCount }, () => null);
8762
- }
8763
- const flatData = toFloat32Array(data);
8764
- const dimension = result.dims?.at(-1) ?? flatData.length / expectedCount;
8765
- if (!Number.isInteger(dimension) || dimension <= 0 || flatData.length !== expectedCount * dimension) {
8766
- log("[magic-context] embedding batch returned invalid dimensions");
8767
- return Array.from({ length: expectedCount }, () => null);
8768
- }
8769
- const embeddings = [];
8770
- for (let index = 0;index < expectedCount; index++) {
8771
- embeddings.push(flatData.slice(index * dimension, (index + 1) * dimension));
8772
- }
8773
- return embeddings;
8774
- }
8775
-
8776
- class LocalEmbeddingProvider {
8777
- modelId;
8778
- maxInputTokens;
8779
- memoryStatsId = nextLocalEmbeddingRuntimeId++;
8780
- model;
8781
- dtype;
8782
- runtimePreference;
8783
- pipeline = null;
8784
- workerClient;
8785
- workerLoaded = false;
8786
- initPromise = null;
8787
- lastFailureReason = null;
8788
- usesWasm = false;
8789
- inFlight = 0;
8790
- disposing = false;
8791
- disposePromise = null;
8792
- inFlightWaiters = [];
8793
- constructor(model = DEFAULT_LOCAL_EMBEDDING_MODEL, maxInputTokens = 512, dtype = DEFAULT_LOCAL_DTYPE, runtimePreference = "auto") {
8794
- this.model = model;
8795
- this.maxInputTokens = maxInputTokens;
8796
- this.dtype = dtype || DEFAULT_LOCAL_DTYPE;
8797
- this.runtimePreference = runtimePreference;
8798
- this.workerClient = !workerData?.magicContextEmbeddingWorker && !useInThreadTestRuntime ? (workerFactoryForTests ?? ((data) => new EmbeddingWorkerClient(data)))({
8799
- magicContextEmbeddingWorker: true,
8800
- modelCacheDir: modelCacheDirForRuntime(),
8801
- enforcePrivateStoragePermissions: shouldEnforcePrivateStoragePermissions(),
8802
- harness: getHarness(),
8803
- model,
8804
- maxInputTokens,
8805
- dtype: this.dtype,
8806
- runtimePreference
8807
- }) : null;
8808
- this.modelId = getEmbeddingProviderIdentity({
8809
- provider: "local",
8810
- model,
8811
- local_runtime: runtimePreference,
8812
- ...dtype && dtype !== DEFAULT_LOCAL_DTYPE ? { local_dtype: dtype } : {}
8813
- });
8814
- }
8815
- async initialize() {
8816
- if (this.workerClient && !this.disposing) {
8817
- if (this.workerLoaded && this.workerClient.isRunning())
8818
- return true;
8819
- try {
8820
- const reply = await this.workerClient.request();
8821
- this.recordWorkerReply(reply);
8822
- return reply.loaded;
8823
- } catch (error) {
8824
- this.recordWorkerFailure(error);
8825
- return false;
8826
- }
8827
- }
8828
- if (this.disposing) {
8829
- return false;
8830
- }
8831
- if (this.pipeline) {
8832
- return true;
8833
- }
8834
- if (localEmbeddingRuntimeMode === "disabled") {
8835
- this.lastFailureReason = localEmbeddingProcessFailure ?? classifyLocalEmbeddingFailure(new Error("local embedding runtime is disabled"));
8836
- return false;
8837
- }
8838
- if (this.initPromise) {
8839
- await this.initPromise;
8840
- return this.pipeline !== null;
8841
- }
8842
- const memoryBeforeLoad = process.memoryUsage();
8843
- this.initPromise = (async () => {
8844
- try {
8845
- if (this.disposing) {
8846
- return;
8847
- }
8848
- const { module: transformersModule, usesWasm } = await loadTransformersForLocalEmbedding(this.runtimePreference);
8849
- this.usesWasm = usesWasm;
8850
- const env = transformersModule.env;
8851
- configureTransformersRemoteHost(env);
8852
- const LogLevel = transformersModule.LogLevel;
8853
- if (LogLevel && "ERROR" in LogLevel) {
8854
- env.logLevel = LogLevel.ERROR;
8855
- }
8856
- const host = localEmbeddingHostForRuntime();
8857
- if (usesWasm && host.hasNodeFilesystem && !host.isElectron && (env.useFS !== true || env.useFSCache !== true)) {
8858
- throw new LocalEmbeddingFsUnavailableError;
8859
- }
8860
- const modelCacheDir = modelCacheDirForRuntime();
8861
- try {
8862
- if (shouldEnforcePrivateStoragePermissions()) {
8863
- mkdirSync(modelCacheDir, { recursive: true, mode: 448 });
8864
- if (process.platform !== "win32") {
8865
- try {
8866
- chmodSync(modelCacheDir, 448);
8867
- } catch {}
8868
- }
8869
- } else {
8870
- mkdirSync(modelCacheDir, { recursive: true });
8871
- }
8872
- env.cacheDir = modelCacheDir;
8873
- } catch {
8874
- log("[magic-context] could not create model cache dir, using library default");
8875
- }
8876
- const createPipeline = transformersModule.pipeline;
8877
- const lockPath = join(modelCacheDir, ".load.lock");
8878
- const releaseLock = await acquireModelLoadLock(lockPath);
8879
- const stopHeartbeat = startLockHeartbeat(lockPath);
8880
- try {
8881
- const MAX_ATTEMPTS = 3;
8882
- let lastError;
8883
- for (let attempt = 1;attempt <= MAX_ATTEMPTS; attempt++) {
8884
- try {
8885
- const pipeline = await withQuietConsole(() => createPipeline("feature-extraction", this.model, {
8886
- dtype: this.dtype,
8887
- ...usesWasm ? { device: "auto" } : {}
8888
- }));
8889
- if (this.disposing) {
8890
- await pipeline.dispose?.();
8891
- this.pipeline = null;
8892
- } else {
8893
- this.pipeline = pipeline;
8894
- }
8895
- lastError = undefined;
8896
- break;
8897
- } catch (error) {
8898
- lastError = error;
8899
- if (!isTransientLoadError(error) || attempt === MAX_ATTEMPTS) {
8900
- break;
8901
- }
8902
- const delayMs = 300 * attempt + Math.floor(Math.random() * 200);
8903
- log(`[magic-context] embedding model load attempt ${attempt}/${MAX_ATTEMPTS} failed transiently, retrying in ${delayMs}ms`);
8904
- await new Promise((resolve) => setTimeout(resolve, delayMs));
8905
- }
8906
- }
8907
- if (this.pipeline) {
8908
- this.lastFailureReason = null;
8909
- localEmbeddingProcessFailure = null;
8910
- const memoryAfterLoad = process.memoryUsage();
8911
- loadedLocalEmbeddingRuntimes.set(this.memoryStatsId, {
8912
- model: this.model,
8913
- runtime: this.usesWasm ? "wasm" : "native",
8914
- rssDeltaAtLoad: memoryAfterLoad.rss - memoryBeforeLoad.rss,
8915
- externalDeltaAtLoad: memoryAfterLoad.external - memoryBeforeLoad.external,
8916
- arrayBuffersDeltaAtLoad: memoryAfterLoad.arrayBuffers - memoryBeforeLoad.arrayBuffers
8917
- });
8918
- log(`[magic-context] embedding model loaded: ${this.model}`);
8919
- } else if (this.disposing) {
8920
- return;
8921
- } else {
8922
- throw lastError ?? new Error("unknown embedding load failure");
8923
- }
8924
- } finally {
8925
- stopHeartbeat();
8926
- await releaseLock();
8927
- }
8928
- } catch (error) {
8929
- const nativeError = error instanceof LocalEmbeddingFallbackError ? error.nativeError : undefined;
8930
- const failure = classifyLocalEmbeddingFailure(error, {
8931
- platform: process.platform,
8932
- arch: process.arch,
8933
- usesWasm: this.usesWasm,
8934
- nativeError
8935
- });
8936
- this.lastFailureReason = failure;
8937
- localEmbeddingProcessFailure = failure;
8938
- if (!localEmbeddingRuntimeIsDisabled() && isNativeRuntimeMissingError(error)) {
8939
- disableLocalEmbeddingsAfterRuntimeFailure(error instanceof Error ? error.message : String(error));
8940
- }
8941
- logForRuntime(`[magic-context] embedding model failed to load (${failure.class}: ${failure.reason}):`, error);
8942
- this.pipeline = null;
8943
- } finally {
8944
- this.initPromise = null;
8945
- }
8946
- })();
8947
- await this.initPromise;
8948
- return this.pipeline !== null;
8949
- }
8950
- waitForInFlightToDrain() {
8951
- if (this.inFlight === 0) {
8952
- return Promise.resolve();
8953
- }
8954
- return new Promise((resolve) => {
8955
- this.inFlightWaiters.push(resolve);
8956
- });
8957
- }
8958
- finishInFlight() {
8959
- this.inFlight = Math.max(0, this.inFlight - 1);
8960
- if (this.inFlight !== 0)
8961
- return;
8962
- const waiters = this.inFlightWaiters.splice(0);
8963
- for (const waiter of waiters) {
8964
- waiter();
8965
- }
8966
- }
8967
- async embed(text, signal, _purpose) {
8968
- if (this.workerClient)
8969
- return (await this.embedBatch([text], signal, _purpose))[0] ?? null;
8970
- if (signal?.aborted)
8971
- return null;
8972
- if (this.disposing)
8973
- return null;
8974
- this.inFlight += 1;
8975
- try {
8976
- if (!await this.initialize()) {
8977
- return null;
8978
- }
8979
- const pipeline = this.pipeline;
8980
- if (!pipeline) {
8981
- return null;
8982
- }
8983
- const result = await withQuietConsole(() => pipeline(text, {
8984
- pooling: "mean",
8985
- normalize: true
8986
- }));
8987
- const embedding = extractBatchEmbeddings(result, 1)[0] ?? null;
8988
- if (!embedding) {
8989
- this.lastFailureReason = classifyLocalEmbeddingFailure(new Error("local embedding pipeline returned no vector"), { usesWasm: this.usesWasm });
8990
- } else {
8991
- this.lastFailureReason = null;
8992
- }
8993
- return embedding;
8994
- } catch (error) {
8995
- const failure = classifyLocalEmbeddingFailure(error, { usesWasm: this.usesWasm });
8996
- this.lastFailureReason = failure;
8997
- logForRuntime(`[magic-context] embedding failed (${failure.class}: ${failure.reason}):`, error);
8998
- return null;
8999
- } finally {
9000
- this.finishInFlight();
9001
- }
9002
- }
9003
- async embedBatch(texts, signal, _purpose) {
9004
- if (this.workerClient) {
9005
- if (!texts.length)
9006
- return [];
9007
- if (signal?.aborted || this.disposing)
9008
- return texts.map(() => null);
9009
- try {
9010
- const reply = await this.workerClient.request(texts, signal);
9011
- this.recordWorkerReply(reply);
9012
- return reply.vectors ?? texts.map(() => null);
9013
- } catch (error) {
9014
- this.recordWorkerFailure(error);
9015
- return texts.map(() => null);
9016
- }
9017
- }
9018
- if (texts.length === 0) {
9019
- return [];
9020
- }
9021
- if (signal?.aborted) {
9022
- return Array.from({ length: texts.length }, () => null);
9023
- }
9024
- if (this.disposing) {
9025
- return Array.from({ length: texts.length }, () => null);
9026
- }
9027
- this.inFlight += 1;
9028
- try {
9029
- if (!await this.initialize()) {
9030
- return Array.from({ length: texts.length }, () => null);
9031
- }
9032
- const pipeline = this.pipeline;
9033
- if (!pipeline) {
9034
- return Array.from({ length: texts.length }, () => null);
9035
- }
9036
- const result = await withQuietConsole(() => pipeline(texts, {
9037
- pooling: "mean",
9038
- normalize: true
9039
- }));
9040
- const embeddings = extractBatchEmbeddings(result, texts.length);
9041
- if (embeddings.every((embedding) => embedding === null)) {
9042
- this.lastFailureReason = classifyLocalEmbeddingFailure(new Error("local embedding pipeline returned no vectors"), { usesWasm: this.usesWasm });
9043
- } else {
9044
- this.lastFailureReason = null;
9045
- }
9046
- return embeddings;
9047
- } catch (error) {
9048
- const failure = classifyLocalEmbeddingFailure(error, { usesWasm: this.usesWasm });
9049
- this.lastFailureReason = failure;
9050
- logForRuntime(`[magic-context] embedding batch failed (${failure.class}: ${failure.reason}):`, error);
9051
- return Array.from({ length: texts.length }, () => null);
9052
- } finally {
9053
- this.finishInFlight();
9054
- }
9055
- }
9056
- recordWorkerReply(reply) {
9057
- this.workerLoaded = reply.loaded;
9058
- this.lastFailureReason = reply.failure ?? null;
9059
- if (reply.loaded && reply.stats) {
9060
- loadedLocalEmbeddingRuntimes.set(this.memoryStatsId, {
9061
- model: this.model,
9062
- runtime: reply.stats.runtimes[0] ?? "wasm",
9063
- rssDeltaAtLoad: reply.stats.rssDeltaAtLoad,
9064
- externalDeltaAtLoad: reply.stats.externalDeltaAtLoad,
9065
- arrayBuffersDeltaAtLoad: reply.stats.arrayBuffersDeltaAtLoad
9066
- });
9067
- } else
9068
- loadedLocalEmbeddingRuntimes.delete(this.memoryStatsId);
9069
- }
9070
- recordWorkerFailure(error) {
9071
- loadedLocalEmbeddingRuntimes.delete(this.memoryStatsId);
9072
- this.workerLoaded = false;
9073
- this.lastFailureReason = classifyLocalEmbeddingFailure(error);
9074
- logForRuntime("[magic-context] embedding worker failed:", error);
9075
- }
9076
- async dispose() {
9077
- if (this.workerClient) {
9078
- this.disposing = true;
9079
- this.workerLoaded = false;
9080
- loadedLocalEmbeddingRuntimes.delete(this.memoryStatsId);
9081
- await this.workerClient.dispose();
9082
- return;
9083
- }
9084
- if (this.disposePromise) {
9085
- return this.disposePromise;
9086
- }
9087
- this.disposing = true;
9088
- this.disposePromise = (async () => {
9089
- if (this.initPromise) {
9090
- await this.initPromise;
9091
- }
9092
- await this.waitForInFlightToDrain();
9093
- const pipelineToDispose = this.pipeline;
9094
- this.pipeline = null;
9095
- this.initPromise = null;
9096
- loadedLocalEmbeddingRuntimes.delete(this.memoryStatsId);
9097
- if (!pipelineToDispose) {
9098
- return;
9099
- }
9100
- try {
9101
- await pipelineToDispose.dispose?.();
9102
- } catch (error) {
9103
- log("[magic-context] embedding model dispose failed:", error);
9104
- }
9105
- })();
9106
- return this.disposePromise;
9107
- }
9108
- isLoaded() {
9109
- return this.workerClient ? this.workerLoaded && this.workerClient.isRunning() : this.pipeline !== null;
9110
- }
9111
- getLastFailureReason() {
9112
- return this.lastFailureReason;
9113
- }
9114
- }
9115
-
9116
- export { string, unknown, array, object, union, tuple, record, withContentLanguageDirective, buildPrimaryLanguageDirective, parseCron, nextOccurrence, nextDueAtMs, promptSurfaceConfigIdentity, resolveModelConfigValue, resolvePromptSurface, DEFAULT_EXECUTE_THRESHOLD_PERCENTAGE, DEFAULT_HISTORIAN_TIMEOUT_MS, PROTECTED_TOKENS_MIN, DEFAULT_LOCAL_EMBEDDING_MODEL, PER_HARNESS_MIGRATION_INVENTORY, PER_HARNESS_MODEL_KEYS, ConfigProfilesSchema, DREAM_TASK_PROMOTION_DEFAULTS, MagicContextConfigSchema, LIVE_RELOAD_CONFIG_PATHS, deriveDefaultProtectedTokens, Priority, AdmissionClass, SocketClosedError, SocketTimeoutError, StaleRouteHandleError, SubcClient, isConsumerReconnectTransient, connectionFileExists, SYNAPSE_DEFAULT_MODEL, isSynapseEmbeddingTruncated, toSynapseLaneDescriptor, formatSynapseLaneDescriptor, getSynapseBatchRequestKey, SynapseEmbeddingProvider, dominantEmbeddingFailure, embeddingModelsMatch, resolveEmbeddingTextPrefixes, computeNormalizedHash, getEmbeddingProviderIdentity, resolveLocalEmbeddingWorkerRuntime, getLocalEmbeddingNativeMemoryStats, LocalEmbeddingProvider };
5771
+ export { string, unknown, array, object, union, tuple, record, withContentLanguageDirective, buildPrimaryLanguageDirective, parseCron, nextOccurrence, nextDueAtMs, promptSurfaceConfigIdentity, resolveModelConfigValue, resolvePromptSurface, DEFAULT_EXECUTE_THRESHOLD_PERCENTAGE, DEFAULT_HISTORIAN_TIMEOUT_MS, PROTECTED_TOKENS_MIN, DEFAULT_LOCAL_EMBEDDING_MODEL, PER_HARNESS_MIGRATION_INVENTORY, PER_HARNESS_MODEL_KEYS, ConfigProfilesSchema, DREAM_TASK_PROMOTION_DEFAULTS, MagicContextConfigSchema, LIVE_RELOAD_CONFIG_PATHS, deriveDefaultProtectedTokens };