@remnic/core 10.0.59 → 10.0.61

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 (370) hide show
  1. package/dist/access-admin-ops-surface.js +53 -50
  2. package/dist/access-authorization-probe.js +54 -51
  3. package/dist/access-boundary.js +53 -50
  4. package/dist/access-cli.js +143 -140
  5. package/dist/access-cli.js.map +1 -1
  6. package/dist/access-extraction-force-flush.js +53 -50
  7. package/dist/access-http-briefing.js +54 -51
  8. package/dist/access-http-query.js +55 -52
  9. package/dist/access-http.js +76 -73
  10. package/dist/access-identity-continuity-surface.js +53 -50
  11. package/dist/access-lcm-surface.js +53 -50
  12. package/dist/access-mcp.js +64 -61
  13. package/dist/access-namespace-preflight.js +53 -50
  14. package/dist/access-observe-write-category.js +10 -10
  15. package/dist/access-observe-write-surface.js +53 -50
  16. package/dist/access-offline-manifest.js +7 -7
  17. package/dist/access-operations-batch.js +56 -53
  18. package/dist/access-operations.js +63 -60
  19. package/dist/access-recall-concurrency.js +53 -50
  20. package/dist/access-recall-response.js +53 -50
  21. package/dist/access-recall-surface.js +53 -50
  22. package/dist/access-schema.js +9 -9
  23. package/dist/access-service.js +53 -50
  24. package/dist/access-surface-catalog.js +55 -52
  25. package/dist/access-surface-catalog.js.map +1 -1
  26. package/dist/active-recall.js +24 -20
  27. package/dist/active-recall.js.map +1 -1
  28. package/dist/adapters/index.js +7 -7
  29. package/dist/adapters/registry.js +3 -3
  30. package/dist/briefing.js +16 -12
  31. package/dist/buffer-persistence.d.ts +14 -3
  32. package/dist/buffer-persistence.d.ts.map +1 -1
  33. package/dist/buffer-persistence.js +1 -1
  34. package/dist/buffer-turn-helpers.d.ts +7 -0
  35. package/dist/buffer-turn-helpers.d.ts.map +1 -1
  36. package/dist/buffer-turn-helpers.js +5 -3
  37. package/dist/buffer.d.ts +2 -0
  38. package/dist/buffer.d.ts.map +1 -1
  39. package/dist/buffer.js +7 -7
  40. package/dist/{capsule-crypto-7FJQINUR.js → capsule-crypto-GWVG7LGC.js} +2 -2
  41. package/dist/causal-behavior.js +2 -2
  42. package/dist/causal-chain.js +2 -2
  43. package/dist/causal-consolidation.js +19 -15
  44. package/dist/causal-consolidation.js.map +1 -1
  45. package/dist/causal-retrieval.js +2 -2
  46. package/dist/causal-trajectory-graph.js +2 -2
  47. package/dist/causal-trajectory.js +1 -1
  48. package/dist/{chunk-ZAZZOQAQ.js → chunk-23OEPU3K.js} +2 -2
  49. package/dist/{chunk-XDKEHZUC.js → chunk-264B57GV.js} +2 -2
  50. package/dist/{chunk-5U2BBF7E.js → chunk-46U6L5DM.js} +20 -10
  51. package/dist/chunk-46U6L5DM.js.map +1 -0
  52. package/dist/chunk-4LZ7SVKM.js +211 -0
  53. package/dist/chunk-4LZ7SVKM.js.map +1 -0
  54. package/dist/{chunk-NRGQ5HJO.js → chunk-4P4VLPGB.js} +1 -1
  55. package/dist/{chunk-GIRWNTMV.js → chunk-4PG5R6BJ.js} +2 -2
  56. package/dist/{chunk-52II7PB6.js → chunk-645WOU5I.js} +4 -4
  57. package/dist/{chunk-RG3I2663.js → chunk-64JLBFCQ.js} +2 -2
  58. package/dist/{chunk-G3T6YMBO.js → chunk-64S6X4IU.js} +7 -7
  59. package/dist/{chunk-WASVDS6G.js → chunk-6HTEPYOI.js} +4 -4
  60. package/dist/{chunk-6AEKSOWV.js → chunk-6I6DFULH.js} +8 -8
  61. package/dist/{chunk-DJR37Q37.js → chunk-6T4CMKNP.js} +2 -2
  62. package/dist/{chunk-RHJ5VGB3.js → chunk-73A2DDDR.js} +2 -2
  63. package/dist/{chunk-4B73TQQV.js → chunk-7AKPLEJV.js} +2 -2
  64. package/dist/{chunk-UHH67NLU.js → chunk-7OKYO2UC.js} +2 -2
  65. package/dist/{chunk-KAL5SXPP.js → chunk-7ULSP7AU.js} +6 -6
  66. package/dist/{chunk-USNU3BEQ.js → chunk-A4FZLM6Q.js} +2 -2
  67. package/dist/{chunk-VV73XT3A.js → chunk-BJLCV2P3.js} +2 -2
  68. package/dist/{chunk-KQAFEZQX.js → chunk-BUKK5SWA.js} +2 -2
  69. package/dist/{chunk-DJFULNXK.js → chunk-C2AYUXEF.js} +2 -2
  70. package/dist/{chunk-QY24FSXT.js → chunk-D3BYJSHX.js} +51 -51
  71. package/dist/{chunk-JZRQY7ZQ.js → chunk-D4WR56FR.js} +2 -2
  72. package/dist/{chunk-3E3Z6UA3.js → chunk-DMYNM3WG.js} +124 -97
  73. package/dist/chunk-DMYNM3WG.js.map +1 -0
  74. package/dist/{chunk-FB4JQEFS.js → chunk-DP22K7IC.js} +2 -2
  75. package/dist/{chunk-EJFOGYF3.js → chunk-DTQJ7BRN.js} +3 -3
  76. package/dist/{chunk-MLUPSZFK.js → chunk-DZL5PBEJ.js} +2 -2
  77. package/dist/{chunk-JD5F5MYN.js → chunk-EGCC5OJE.js} +3 -3
  78. package/dist/{chunk-IQSRVR6Z.js → chunk-EJ4RS7I7.js} +2 -2
  79. package/dist/{chunk-WBN66HPI.js → chunk-ELHJK7LM.js} +6 -6
  80. package/dist/{chunk-EH46DHBU.js → chunk-ENAPZQA6.js} +2 -2
  81. package/dist/{chunk-LLG5VNK7.js → chunk-F2UAAI6B.js} +2 -2
  82. package/dist/{chunk-YZNTAOPZ.js → chunk-FKNNWH7P.js} +2 -2
  83. package/dist/{chunk-AAANTXCQ.js → chunk-FZVZYU5C.js} +2 -2
  84. package/dist/{chunk-ON77FQXH.js → chunk-G6GMZJQ4.js} +2 -2
  85. package/dist/{chunk-OL7A7NKH.js → chunk-GNP4BV4Z.js} +2 -2
  86. package/dist/{chunk-GDYLZ6FR.js → chunk-HJ3UTGIW.js} +3 -3
  87. package/dist/{chunk-CCL2OXFO.js → chunk-HSHLDSPX.js} +3 -3
  88. package/dist/{chunk-R4BR62UO.js → chunk-HWMGQDZI.js} +2 -2
  89. package/dist/{chunk-BPIAXMGC.js → chunk-IIUEHIQ2.js} +2 -2
  90. package/dist/{chunk-RTJJPW3C.js → chunk-ILMB3X4X.js} +5 -5
  91. package/dist/{chunk-RFT4OPYI.js → chunk-IPN67KVR.js} +2 -2
  92. package/dist/chunk-JCL7RO2G.js +674 -0
  93. package/dist/chunk-JCL7RO2G.js.map +1 -0
  94. package/dist/{chunk-IEW6NDHX.js → chunk-JGSWWD33.js} +9 -9
  95. package/dist/{chunk-A3UFV4K3.js → chunk-JIYJIH5N.js} +2 -2
  96. package/dist/{chunk-4G2A7MH3.js → chunk-JKUVPVKR.js} +3 -3
  97. package/dist/{chunk-YJHOVA42.js → chunk-JL5FHZ7O.js} +30 -6
  98. package/dist/chunk-JL5FHZ7O.js.map +1 -0
  99. package/dist/{chunk-VCLNU6MY.js → chunk-L2HSSVVD.js} +2 -2
  100. package/dist/{chunk-U2A56LLF.js → chunk-L334PSLW.js} +8 -8
  101. package/dist/{chunk-HQUYENKK.js → chunk-LIUI46BX.js} +3 -3
  102. package/dist/{chunk-ERMT5WQM.js → chunk-MKE5DP3S.js} +2 -2
  103. package/dist/{chunk-4OFXLQJD.js → chunk-MPDLLLOG.js} +8 -3
  104. package/dist/chunk-MPDLLLOG.js.map +1 -0
  105. package/dist/{chunk-6BO27AWQ.js → chunk-MPJ7VHHA.js} +2 -2
  106. package/dist/{chunk-WXBVGKS6.js → chunk-N7RAABFM.js} +182 -421
  107. package/dist/chunk-N7RAABFM.js.map +1 -0
  108. package/dist/{chunk-KMJDH4KX.js → chunk-NSUGAIIB.js} +16 -16
  109. package/dist/{chunk-7NT3FKAF.js → chunk-NXHBQC2O.js} +2 -2
  110. package/dist/{chunk-JEX2JL3U.js → chunk-OH55F76C.js} +2 -2
  111. package/dist/{chunk-37VTMUAL.js → chunk-OUJ4DVR5.js} +2 -2
  112. package/dist/{chunk-2NLLXCJG.js → chunk-OWHERGF2.js} +2 -2
  113. package/dist/{chunk-2IVK5IDY.js → chunk-P5F7ISLV.js} +2 -2
  114. package/dist/{chunk-PM4PKC3Y.js → chunk-PNVQNAJM.js} +3 -3
  115. package/dist/{chunk-FXWX7VD3.js → chunk-PRYDNBCO.js} +12 -12
  116. package/dist/{chunk-YDDLSGYE.js → chunk-PUTH5REB.js} +2 -2
  117. package/dist/{chunk-GFAEKSFR.js → chunk-QBK3IM6W.js} +5 -5
  118. package/dist/{chunk-KRAMCBIW.js → chunk-QKXPOLQD.js} +4 -4
  119. package/dist/{chunk-YDT3OEYF.js → chunk-R4ZHF4K2.js} +2 -2
  120. package/dist/{chunk-ISNPYOXR.js → chunk-RBUR6USI.js} +5 -5
  121. package/dist/{chunk-WZYAXOGO.js → chunk-RZSHIJYY.js} +2 -2
  122. package/dist/{chunk-TYSD7UQO.js → chunk-SVTIWBSA.js} +2 -2
  123. package/dist/{chunk-AMKIIRLL.js → chunk-TBFAQHQZ.js} +2 -2
  124. package/dist/{chunk-ZE5N4JSY.js → chunk-TKCJI7WA.js} +2 -2
  125. package/dist/{chunk-RYB553SS.js → chunk-TLOAAOT3.js} +2 -2
  126. package/dist/{chunk-RKRX4C4H.js → chunk-TPKB7T6Z.js} +2 -2
  127. package/dist/{chunk-JZCBMKR5.js → chunk-TUCEP2LS.js} +5 -5
  128. package/dist/{chunk-KZMRMKC7.js → chunk-U7MIMS2Y.js} +11 -1
  129. package/dist/chunk-U7MIMS2Y.js.map +1 -0
  130. package/dist/{chunk-OMWQO7H6.js → chunk-UEDC2VGP.js} +2 -2
  131. package/dist/{chunk-X7Y7WX73.js → chunk-UVYI6VIX.js} +1 -1
  132. package/dist/{chunk-JY2BGCYN.js → chunk-VCYH2XUY.js} +2 -2
  133. package/dist/{chunk-NGH74LDV.js → chunk-WD2QH3JM.js} +9 -9
  134. package/dist/{chunk-G6A3SGCE.js → chunk-WVEEVYMH.js} +8 -25
  135. package/dist/chunk-WVEEVYMH.js.map +1 -0
  136. package/dist/{chunk-UGTYADB4.js → chunk-WWSJQ7MP.js} +3 -3
  137. package/dist/{chunk-UQBOPCDK.js → chunk-X4PAATLA.js} +2 -2
  138. package/dist/{chunk-KBOQQEVC.js → chunk-XAFSZ4DP.js} +2 -2
  139. package/dist/{chunk-2S6JADBB.js → chunk-XICJL56Z.js} +2 -2
  140. package/dist/{chunk-Y5KESB7T.js → chunk-XJDSZFBZ.js} +45 -45
  141. package/dist/{chunk-24SIB3EW.js → chunk-XWE3EOWX.js} +2 -2
  142. package/dist/{chunk-Y77FXULH.js → chunk-XWXBXBOX.js} +2 -2
  143. package/dist/{chunk-VKQI47DJ.js → chunk-Y7427SL7.js} +4 -4
  144. package/dist/{chunk-TEH5MDX5.js → chunk-YH7HJNWV.js} +22 -22
  145. package/dist/chunk-YHTG64XV.js +117 -0
  146. package/dist/chunk-YHTG64XV.js.map +1 -0
  147. package/dist/{chunk-EZ25VE3G.js → chunk-YNDLCWXS.js} +4 -4
  148. package/dist/{chunk-2M36PR7R.js → chunk-Z2T5BPOZ.js} +2 -2
  149. package/dist/cli.js +100 -97
  150. package/dist/coding/export-okf-codegraph.js +15 -11
  151. package/dist/coding/export-okf-codegraph.js.map +1 -1
  152. package/dist/coding/pre-action-gate.js +2 -2
  153. package/dist/compounding/engine.js +17 -13
  154. package/dist/config.js +24 -20
  155. package/dist/connectors/codex-materialize-runner.js +16 -12
  156. package/dist/connectors/index.js +16 -12
  157. package/dist/convergence-refresh.js +18 -14
  158. package/dist/corpus-scan-worker-host.d.ts +109 -0
  159. package/dist/corpus-scan-worker-host.d.ts.map +1 -0
  160. package/dist/corpus-scan-worker-host.js +15 -0
  161. package/dist/corpus-scan-worker.entry.d.ts +21 -0
  162. package/dist/corpus-scan-worker.entry.d.ts.map +1 -0
  163. package/dist/corpus-scan-worker.entry.js +60 -0
  164. package/dist/corpus-scan-worker.entry.js.map +1 -0
  165. package/dist/corpus-scan-worker.entry.mjs +176 -0
  166. package/dist/corpus-scan.d.ts +71 -0
  167. package/dist/corpus-scan.d.ts.map +1 -0
  168. package/dist/corpus-scan.js +16 -0
  169. package/dist/corpus-watermark.d.ts.map +1 -1
  170. package/dist/corpus-watermark.js +18 -14
  171. package/dist/dashboard-runtime.js +2 -2
  172. package/dist/deep-recall-http-glue.js +10 -10
  173. package/dist/embedding-fallback.js +2 -2
  174. package/dist/{entity-canonical-id-migration-F3JVG6K6.js → entity-canonical-id-migration-CUDCKWPF.js} +4 -2
  175. package/dist/entity-canonical-id-migration-CUDCKWPF.js.map +1 -0
  176. package/dist/entity-retrieval.js +18 -14
  177. package/dist/event-order-recall.js +3 -3
  178. package/dist/external-wiki-access.js +54 -51
  179. package/dist/extraction.js +21 -17
  180. package/dist/{graph-edge-decay-IU75NV42.js → graph-edge-decay-2BZTY2IM.js} +5 -5
  181. package/dist/graph-edge-decay-2BZTY2IM.js.map +1 -0
  182. package/dist/graph-jsonl.js +3 -3
  183. package/dist/graph-snapshot.js +3 -3
  184. package/dist/graph.js +2 -2
  185. package/dist/harmonic-retrieval.js +16 -12
  186. package/dist/index.d.ts +1 -1
  187. package/dist/index.d.ts.map +1 -1
  188. package/dist/index.js +174 -169
  189. package/dist/lcm/engine.js +2 -2
  190. package/dist/lcm/index.js +5 -5
  191. package/dist/location/index.js +18 -14
  192. package/dist/maintenance/memory-governance.js +16 -12
  193. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +16 -12
  194. package/dist/maintenance/rebuild-memory-projection-runner.js +18 -14
  195. package/dist/maintenance/rebuild-memory-projection.js +17 -13
  196. package/dist/memory-browse-operations.js +54 -51
  197. package/dist/memory-browse.js +5 -5
  198. package/dist/namespaces/migrate.js +17 -13
  199. package/dist/namespaces/search.js +7 -7
  200. package/dist/namespaces/storage.js +16 -12
  201. package/dist/offline-sync-changeset-generations.js +4 -4
  202. package/dist/offline-sync-embedding-generation.js +3 -3
  203. package/dist/offline-sync-snapshot-stream.js +7 -7
  204. package/dist/offline-sync.js +6 -6
  205. package/dist/operator-doctor-corpus.js +19 -15
  206. package/dist/operator-toolkit.js +35 -31
  207. package/dist/orchestration/buffer-drain-gate.d.ts +21 -0
  208. package/dist/orchestration/buffer-drain-gate.d.ts.map +1 -0
  209. package/dist/orchestration/buffer-drain-runner.d.ts +79 -0
  210. package/dist/orchestration/buffer-drain-runner.d.ts.map +1 -0
  211. package/dist/orchestration/buffer-drain-runner.js +780 -0
  212. package/dist/orchestration/buffer-drain-runner.js.map +1 -0
  213. package/dist/orchestration/buffer-swap.d.ts +12 -0
  214. package/dist/orchestration/buffer-swap.d.ts.map +1 -0
  215. package/dist/orchestration/maintenance.js +26 -22
  216. package/dist/orchestration/turn-ingestion.d.ts.map +1 -1
  217. package/dist/orchestrator.d.ts +4 -1
  218. package/dist/orchestrator.d.ts.map +1 -1
  219. package/dist/orchestrator.js +143 -140
  220. package/dist/qmd.js +4 -4
  221. package/dist/recall-navigation-operations.js +54 -51
  222. package/dist/recall-navigation.js +53 -50
  223. package/dist/recall-state-view-admission.js +5 -5
  224. package/dist/recall-why-service.js +5 -5
  225. package/dist/resume-bundles.js +25 -21
  226. package/dist/search/factory.js +6 -6
  227. package/dist/search/index.js +12 -12
  228. package/dist/semantic-consolidation.js +17 -13
  229. package/dist/semantic-rule-promotion.js +16 -12
  230. package/dist/semantic-rule-verifier.js +16 -12
  231. package/dist/source-agent-qualifier.js +19 -15
  232. package/dist/standup/build.js +16 -12
  233. package/dist/storage/buffer-drain-claims.d.ts +159 -0
  234. package/dist/storage/buffer-drain-claims.d.ts.map +1 -0
  235. package/dist/storage/buffer-drain-claims.js +18 -0
  236. package/dist/storage/buffer-drain-claims.js.map +1 -0
  237. package/dist/storage/buffer-session-files.d.ts +14 -2
  238. package/dist/storage/buffer-session-files.d.ts.map +1 -1
  239. package/dist/storage/buffer-session-files.js +22 -0
  240. package/dist/storage/buffer-session-files.js.map +1 -0
  241. package/dist/storage/entity-canonical-id-migration.d.ts.map +1 -1
  242. package/dist/storage/memory-read-store.d.ts +5 -9
  243. package/dist/storage/memory-read-store.d.ts.map +1 -1
  244. package/dist/storage.d.ts +6 -1
  245. package/dist/storage.d.ts.map +1 -1
  246. package/dist/storage.js +17 -13
  247. package/dist/support-passport/index.js +56 -53
  248. package/dist/transfer/backup.js +2 -2
  249. package/dist/transfer/capsule-export.js +2 -2
  250. package/dist/transfer/capsule-import.js +2 -2
  251. package/dist/transfer/export-okf.js +16 -12
  252. package/dist/verified-recall.js +16 -12
  253. package/dist/who-knows-cli.js +17 -13
  254. package/dist/who-knows.js +16 -12
  255. package/package.json +32 -2
  256. package/scripts/build-with-heap.mjs +8 -0
  257. package/src/buffer-drain-handover.test.ts +307 -0
  258. package/src/buffer-persistence.ts +27 -5
  259. package/src/buffer-turn-helpers.ts +16 -0
  260. package/src/buffer.ts +32 -2
  261. package/src/corpus-scan-worker-host.ts +314 -0
  262. package/src/corpus-scan-worker.entry.mjs +176 -0
  263. package/src/corpus-scan-worker.entry.ts +95 -0
  264. package/src/corpus-scan.ts +215 -0
  265. package/src/corpus-watermark.ts +28 -12
  266. package/src/index.ts +1 -1
  267. package/src/orchestration/buffer-drain-gate.test.ts +40 -0
  268. package/src/orchestration/buffer-drain-gate.ts +38 -0
  269. package/src/orchestration/buffer-drain-runner.ts +312 -0
  270. package/src/orchestration/buffer-swap.ts +27 -0
  271. package/src/orchestration/turn-ingestion.ts +2 -0
  272. package/src/orchestrator.ts +9 -6
  273. package/src/storage/buffer-drain-claims.test.ts +448 -0
  274. package/src/storage/buffer-drain-claims.ts +593 -0
  275. package/src/storage/buffer-session-files.ts +50 -3
  276. package/src/storage/entity-canonical-id-migration.ts +4 -26
  277. package/src/storage/memory-read-store.ts +17 -99
  278. package/src/storage.ts +8 -11
  279. package/src/testing/subjects/extraction-lifecycle.test.ts +34 -0
  280. package/dist/chunk-3E3Z6UA3.js.map +0 -1
  281. package/dist/chunk-4OFXLQJD.js.map +0 -1
  282. package/dist/chunk-5U2BBF7E.js.map +0 -1
  283. package/dist/chunk-G6A3SGCE.js.map +0 -1
  284. package/dist/chunk-KZMRMKC7.js.map +0 -1
  285. package/dist/chunk-WXBVGKS6.js.map +0 -1
  286. package/dist/chunk-YJHOVA42.js.map +0 -1
  287. /package/dist/{capsule-crypto-7FJQINUR.js.map → capsule-crypto-GWVG7LGC.js.map} +0 -0
  288. /package/dist/{chunk-ZAZZOQAQ.js.map → chunk-23OEPU3K.js.map} +0 -0
  289. /package/dist/{chunk-XDKEHZUC.js.map → chunk-264B57GV.js.map} +0 -0
  290. /package/dist/{chunk-NRGQ5HJO.js.map → chunk-4P4VLPGB.js.map} +0 -0
  291. /package/dist/{chunk-GIRWNTMV.js.map → chunk-4PG5R6BJ.js.map} +0 -0
  292. /package/dist/{chunk-52II7PB6.js.map → chunk-645WOU5I.js.map} +0 -0
  293. /package/dist/{chunk-RG3I2663.js.map → chunk-64JLBFCQ.js.map} +0 -0
  294. /package/dist/{chunk-G3T6YMBO.js.map → chunk-64S6X4IU.js.map} +0 -0
  295. /package/dist/{chunk-WASVDS6G.js.map → chunk-6HTEPYOI.js.map} +0 -0
  296. /package/dist/{chunk-6AEKSOWV.js.map → chunk-6I6DFULH.js.map} +0 -0
  297. /package/dist/{chunk-DJR37Q37.js.map → chunk-6T4CMKNP.js.map} +0 -0
  298. /package/dist/{chunk-RHJ5VGB3.js.map → chunk-73A2DDDR.js.map} +0 -0
  299. /package/dist/{chunk-4B73TQQV.js.map → chunk-7AKPLEJV.js.map} +0 -0
  300. /package/dist/{chunk-UHH67NLU.js.map → chunk-7OKYO2UC.js.map} +0 -0
  301. /package/dist/{chunk-KAL5SXPP.js.map → chunk-7ULSP7AU.js.map} +0 -0
  302. /package/dist/{chunk-USNU3BEQ.js.map → chunk-A4FZLM6Q.js.map} +0 -0
  303. /package/dist/{chunk-VV73XT3A.js.map → chunk-BJLCV2P3.js.map} +0 -0
  304. /package/dist/{chunk-KQAFEZQX.js.map → chunk-BUKK5SWA.js.map} +0 -0
  305. /package/dist/{chunk-DJFULNXK.js.map → chunk-C2AYUXEF.js.map} +0 -0
  306. /package/dist/{chunk-QY24FSXT.js.map → chunk-D3BYJSHX.js.map} +0 -0
  307. /package/dist/{chunk-JZRQY7ZQ.js.map → chunk-D4WR56FR.js.map} +0 -0
  308. /package/dist/{chunk-FB4JQEFS.js.map → chunk-DP22K7IC.js.map} +0 -0
  309. /package/dist/{chunk-EJFOGYF3.js.map → chunk-DTQJ7BRN.js.map} +0 -0
  310. /package/dist/{chunk-MLUPSZFK.js.map → chunk-DZL5PBEJ.js.map} +0 -0
  311. /package/dist/{chunk-JD5F5MYN.js.map → chunk-EGCC5OJE.js.map} +0 -0
  312. /package/dist/{chunk-IQSRVR6Z.js.map → chunk-EJ4RS7I7.js.map} +0 -0
  313. /package/dist/{chunk-WBN66HPI.js.map → chunk-ELHJK7LM.js.map} +0 -0
  314. /package/dist/{chunk-EH46DHBU.js.map → chunk-ENAPZQA6.js.map} +0 -0
  315. /package/dist/{chunk-LLG5VNK7.js.map → chunk-F2UAAI6B.js.map} +0 -0
  316. /package/dist/{chunk-YZNTAOPZ.js.map → chunk-FKNNWH7P.js.map} +0 -0
  317. /package/dist/{chunk-AAANTXCQ.js.map → chunk-FZVZYU5C.js.map} +0 -0
  318. /package/dist/{chunk-ON77FQXH.js.map → chunk-G6GMZJQ4.js.map} +0 -0
  319. /package/dist/{chunk-OL7A7NKH.js.map → chunk-GNP4BV4Z.js.map} +0 -0
  320. /package/dist/{chunk-GDYLZ6FR.js.map → chunk-HJ3UTGIW.js.map} +0 -0
  321. /package/dist/{chunk-CCL2OXFO.js.map → chunk-HSHLDSPX.js.map} +0 -0
  322. /package/dist/{chunk-R4BR62UO.js.map → chunk-HWMGQDZI.js.map} +0 -0
  323. /package/dist/{chunk-BPIAXMGC.js.map → chunk-IIUEHIQ2.js.map} +0 -0
  324. /package/dist/{chunk-RTJJPW3C.js.map → chunk-ILMB3X4X.js.map} +0 -0
  325. /package/dist/{chunk-RFT4OPYI.js.map → chunk-IPN67KVR.js.map} +0 -0
  326. /package/dist/{chunk-IEW6NDHX.js.map → chunk-JGSWWD33.js.map} +0 -0
  327. /package/dist/{chunk-A3UFV4K3.js.map → chunk-JIYJIH5N.js.map} +0 -0
  328. /package/dist/{chunk-4G2A7MH3.js.map → chunk-JKUVPVKR.js.map} +0 -0
  329. /package/dist/{chunk-VCLNU6MY.js.map → chunk-L2HSSVVD.js.map} +0 -0
  330. /package/dist/{chunk-U2A56LLF.js.map → chunk-L334PSLW.js.map} +0 -0
  331. /package/dist/{chunk-HQUYENKK.js.map → chunk-LIUI46BX.js.map} +0 -0
  332. /package/dist/{chunk-ERMT5WQM.js.map → chunk-MKE5DP3S.js.map} +0 -0
  333. /package/dist/{chunk-6BO27AWQ.js.map → chunk-MPJ7VHHA.js.map} +0 -0
  334. /package/dist/{chunk-KMJDH4KX.js.map → chunk-NSUGAIIB.js.map} +0 -0
  335. /package/dist/{chunk-7NT3FKAF.js.map → chunk-NXHBQC2O.js.map} +0 -0
  336. /package/dist/{chunk-JEX2JL3U.js.map → chunk-OH55F76C.js.map} +0 -0
  337. /package/dist/{chunk-37VTMUAL.js.map → chunk-OUJ4DVR5.js.map} +0 -0
  338. /package/dist/{chunk-2NLLXCJG.js.map → chunk-OWHERGF2.js.map} +0 -0
  339. /package/dist/{chunk-2IVK5IDY.js.map → chunk-P5F7ISLV.js.map} +0 -0
  340. /package/dist/{chunk-PM4PKC3Y.js.map → chunk-PNVQNAJM.js.map} +0 -0
  341. /package/dist/{chunk-FXWX7VD3.js.map → chunk-PRYDNBCO.js.map} +0 -0
  342. /package/dist/{chunk-YDDLSGYE.js.map → chunk-PUTH5REB.js.map} +0 -0
  343. /package/dist/{chunk-GFAEKSFR.js.map → chunk-QBK3IM6W.js.map} +0 -0
  344. /package/dist/{chunk-KRAMCBIW.js.map → chunk-QKXPOLQD.js.map} +0 -0
  345. /package/dist/{chunk-YDT3OEYF.js.map → chunk-R4ZHF4K2.js.map} +0 -0
  346. /package/dist/{chunk-ISNPYOXR.js.map → chunk-RBUR6USI.js.map} +0 -0
  347. /package/dist/{chunk-WZYAXOGO.js.map → chunk-RZSHIJYY.js.map} +0 -0
  348. /package/dist/{chunk-TYSD7UQO.js.map → chunk-SVTIWBSA.js.map} +0 -0
  349. /package/dist/{chunk-AMKIIRLL.js.map → chunk-TBFAQHQZ.js.map} +0 -0
  350. /package/dist/{chunk-ZE5N4JSY.js.map → chunk-TKCJI7WA.js.map} +0 -0
  351. /package/dist/{chunk-RYB553SS.js.map → chunk-TLOAAOT3.js.map} +0 -0
  352. /package/dist/{chunk-RKRX4C4H.js.map → chunk-TPKB7T6Z.js.map} +0 -0
  353. /package/dist/{chunk-JZCBMKR5.js.map → chunk-TUCEP2LS.js.map} +0 -0
  354. /package/dist/{chunk-OMWQO7H6.js.map → chunk-UEDC2VGP.js.map} +0 -0
  355. /package/dist/{chunk-X7Y7WX73.js.map → chunk-UVYI6VIX.js.map} +0 -0
  356. /package/dist/{chunk-JY2BGCYN.js.map → chunk-VCYH2XUY.js.map} +0 -0
  357. /package/dist/{chunk-NGH74LDV.js.map → chunk-WD2QH3JM.js.map} +0 -0
  358. /package/dist/{chunk-UGTYADB4.js.map → chunk-WWSJQ7MP.js.map} +0 -0
  359. /package/dist/{chunk-UQBOPCDK.js.map → chunk-X4PAATLA.js.map} +0 -0
  360. /package/dist/{chunk-KBOQQEVC.js.map → chunk-XAFSZ4DP.js.map} +0 -0
  361. /package/dist/{chunk-2S6JADBB.js.map → chunk-XICJL56Z.js.map} +0 -0
  362. /package/dist/{chunk-Y5KESB7T.js.map → chunk-XJDSZFBZ.js.map} +0 -0
  363. /package/dist/{chunk-24SIB3EW.js.map → chunk-XWE3EOWX.js.map} +0 -0
  364. /package/dist/{chunk-Y77FXULH.js.map → chunk-XWXBXBOX.js.map} +0 -0
  365. /package/dist/{chunk-VKQI47DJ.js.map → chunk-Y7427SL7.js.map} +0 -0
  366. /package/dist/{chunk-TEH5MDX5.js.map → chunk-YH7HJNWV.js.map} +0 -0
  367. /package/dist/{chunk-EZ25VE3G.js.map → chunk-YNDLCWXS.js.map} +0 -0
  368. /package/dist/{chunk-2M36PR7R.js.map → chunk-Z2T5BPOZ.js.map} +0 -0
  369. /package/dist/{entity-canonical-id-migration-F3JVG6K6.js.map → corpus-scan-worker-host.js.map} +0 -0
  370. /package/dist/{graph-edge-decay-IU75NV42.js.map → corpus-scan.js.map} +0 -0
@@ -0,0 +1,674 @@
1
+ import {
2
+ bufferTurnsEqual,
3
+ subtractBufferTurns
4
+ } from "./chunk-U7MIMS2Y.js";
5
+ import {
6
+ withHeldFileLock
7
+ } from "./chunk-EBRG7ZIK.js";
8
+ import {
9
+ SecureStoreDecryptError,
10
+ SecureStoreLockedError
11
+ } from "./chunk-EYGOM6AI.js";
12
+ import {
13
+ log
14
+ } from "./chunk-3WCASNQZ.js";
15
+
16
+ // src/storage/buffer-drain-claims.ts
17
+ import { hostname } from "os";
18
+ import { z } from "zod";
19
+ import { existsSync } from "fs";
20
+ import { mkdir, readdir as readdir2, rename, unlink as unlink2, writeFile } from "fs/promises";
21
+ import path2 from "path";
22
+
23
+ // src/storage/buffer-session-files.ts
24
+ import { createHash } from "crypto";
25
+ import { lstat, readdir, unlink } from "fs/promises";
26
+ import path from "path";
27
+ function isMissing(err) {
28
+ return err?.code === "ENOENT";
29
+ }
30
+ function asFsError(err) {
31
+ return err;
32
+ }
33
+ function bufferSessionFileName(key) {
34
+ return `s-${createHash("sha256").update(key).digest("hex")}.json`;
35
+ }
36
+ function legacyStateToEntries(state) {
37
+ const entries = /* @__PURE__ */ new Map();
38
+ for (const [key, value] of Object.entries(state.entries ?? {})) {
39
+ if (value && Array.isArray(value.turns)) entries.set(key, value);
40
+ }
41
+ if (!entries.has("default")) {
42
+ entries.set("default", {
43
+ turns: Array.isArray(state.turns) ? state.turns : [],
44
+ lastExtractionAt: state.lastExtractionAt ?? null,
45
+ extractionCount: Number.isFinite(state.extractionCount) ? state.extractionCount : 0
46
+ });
47
+ }
48
+ return entries;
49
+ }
50
+ function entryFromBody(body) {
51
+ if (!body || !Array.isArray(body.turns) || (body.key?.length ?? 0) === 0) return null;
52
+ const entry = {
53
+ turns: body.turns,
54
+ lastExtractionAt: body.lastExtractionAt ?? null,
55
+ extractionCount: Number.isFinite(body.extractionCount) ? Number(body.extractionCount) : 0
56
+ };
57
+ if (Array.isArray(body.retainedTurns)) entry.retainedTurns = body.retainedTurns;
58
+ return { key: String(body.key), entry };
59
+ }
60
+ var BufferSessionFiles = class {
61
+ constructor(stateDir, io) {
62
+ this.stateDir = stateDir;
63
+ this.io = io;
64
+ this.claimsStore = new BufferDrainClaims(stateDir, io);
65
+ }
66
+ stateDir;
67
+ io;
68
+ dirVerified = false;
69
+ claimsStore;
70
+ /** The drain-claim store for this state dir (CLI scan + claim ops). */
71
+ get claims() {
72
+ return this.claimsStore;
73
+ }
74
+ /** Sync gate check: is this session claimed by a buffer drain? */
75
+ isClaimed(key) {
76
+ return this.claimsStore.isClaimed(key);
77
+ }
78
+ get dir() {
79
+ return path.join(this.stateDir, "buffer");
80
+ }
81
+ fileFor(key) {
82
+ return path.join(this.dir, bufferSessionFileName(key));
83
+ }
84
+ /**
85
+ * Refuse a symlinked buffer directory: following it would send buffered
86
+ * conversation data (and deletions) outside the memory root. One lstat of
87
+ * one directory, cached after it passes, so the observe path pays nothing
88
+ * per write; the cache is dropped on any failure.
89
+ */
90
+ async assertDirSafe() {
91
+ if (this.dirVerified) return;
92
+ let stat = null;
93
+ try {
94
+ stat = await lstat(this.dir);
95
+ } catch (err) {
96
+ if (!(err instanceof Error) || !isMissing(asFsError(err))) throw err;
97
+ }
98
+ if (stat && (stat.isSymbolicLink() || !stat.isDirectory())) {
99
+ throw new Error(`buffer session directory must be a real directory, not a symlink or file: ${this.dir}`);
100
+ }
101
+ this.dirVerified = stat !== null;
102
+ }
103
+ /** Persist ONE session atomically. Compact JSON: machine-read state, and
104
+ * pretty-printing a large buffer costs CPU and bytes on every observe.
105
+ * A drain-claimed session is handed over instead (see class doc). */
106
+ async save(key, entry) {
107
+ if (this.isClaimed(key)) {
108
+ if (await this.claimsStore.isDrained(key)) {
109
+ const drained = await this.claimsStore.drainedTurns(key);
110
+ const fresh = { ...entry, turns: subtractBufferTurns(entry.turns, drained) };
111
+ if (entry.retainedTurns && entry.retainedTurns.length > 0) {
112
+ fresh.retainedTurns = subtractBufferTurns(entry.retainedTurns, drained);
113
+ if (fresh.retainedTurns.length === 0) delete fresh.retainedTurns;
114
+ }
115
+ await this.assertDirSafe();
116
+ await this.io.write(this.fileFor(key), JSON.stringify({ key, ...fresh }));
117
+ await this.claimsStore.release(key);
118
+ return { status: "saved", drainedTurns: drained };
119
+ }
120
+ await this.claimsStore.mergeIntoClaim(key, entry);
121
+ return { status: "handed_over" };
122
+ }
123
+ await this.assertDirSafe();
124
+ await this.io.write(this.fileFor(key), JSON.stringify({ key, ...entry }));
125
+ return { status: "saved" };
126
+ }
127
+ /** Remove one session's file. Idempotent: an absent file is fine. */
128
+ async remove(key) {
129
+ await this.assertDirSafe();
130
+ try {
131
+ await unlink(this.fileFor(key));
132
+ } catch (err) {
133
+ if (!(err instanceof Error) || !isMissing(asFsError(err))) throw err;
134
+ }
135
+ }
136
+ async listFiles() {
137
+ await this.assertDirSafe();
138
+ try {
139
+ const dirents = await readdir(this.dir, { withFileTypes: true });
140
+ return dirents.filter((d) => d.isFile() && d.name.endsWith(".json")).map((d) => d.name);
141
+ } catch (err) {
142
+ if (err instanceof Error && isMissing(asFsError(err))) return [];
143
+ throw err;
144
+ }
145
+ }
146
+ /** Read every per-session file. Corrupt files are skipped (and logged) so
147
+ * one bad file cannot nuke the other sessions' buffered turns. */
148
+ async readAll() {
149
+ const names = await this.listFiles();
150
+ const entries = /* @__PURE__ */ new Map();
151
+ for (const name of names) {
152
+ try {
153
+ const body = JSON.parse(await this.io.read(path.join(this.dir, name)));
154
+ const parsed = entryFromBody(body);
155
+ if (!parsed) throw new Error("invalid buffer session file shape");
156
+ if (entries.has(parsed.key)) {
157
+ log.warn(`buffer: duplicate session file for key ${parsed.key} (${name}); keeping the first`);
158
+ continue;
159
+ }
160
+ entries.set(parsed.key, parsed.entry);
161
+ } catch (err) {
162
+ if (err instanceof SecureStoreLockedError || err instanceof SecureStoreDecryptError) throw err;
163
+ log.warn(`buffer: skipping unreadable per-session buffer file ${name}: ${err instanceof Error ? err.message : String(err)}`);
164
+ }
165
+ }
166
+ return { entries, fileCount: names.length };
167
+ }
168
+ /**
169
+ * Read the legacy single-file buffer.json for migration. Null when absent,
170
+ * or unreadable while session files exist (they are authoritative; a
171
+ * corrupt leftover must not block startup). With no session files a corrupt
172
+ * legacy file THROWS, preserving the old contract so callers can reset it.
173
+ */
174
+ async readLegacy(hasSessionFiles) {
175
+ let raw;
176
+ try {
177
+ raw = await this.io.read(path.join(this.stateDir, "buffer.json"));
178
+ } catch (err) {
179
+ if (err instanceof SecureStoreLockedError) throw err;
180
+ if (err instanceof Error && isMissing(asFsError(err))) return null;
181
+ throw err;
182
+ }
183
+ try {
184
+ const legacy = JSON.parse(raw);
185
+ return legacy;
186
+ } catch (err) {
187
+ if (!hasSessionFiles) throw err;
188
+ log.warn(
189
+ `buffer: legacy buffer.json is unreadable but per-session buffer files exist; ignoring the legacy file (${err instanceof Error ? err.message : String(err)})`
190
+ );
191
+ return null;
192
+ }
193
+ }
194
+ /**
195
+ * Load the whole buffer, migrating a legacy buffer.json once. A per-session
196
+ * file that parsed wins over the legacy snapshot (a crash mid-migration
197
+ * leaves exactly that pair); legacy entries without a usable file are
198
+ * written out, then the legacy file is retired. Both steps are idempotent.
199
+ */
200
+ async load() {
201
+ const { entries, fileCount } = await this.readAll();
202
+ const legacy = await this.readLegacy(fileCount > 0);
203
+ if (legacy !== null) {
204
+ for (const [key, entry] of legacyStateToEntries(legacy)) {
205
+ if (entries.has(key)) continue;
206
+ entries.set(key, entry);
207
+ await this.save(key, entry);
208
+ }
209
+ try {
210
+ await unlink(path.join(this.stateDir, "buffer.json"));
211
+ } catch (err) {
212
+ if (!(err instanceof Error) || !isMissing(asFsError(err))) throw err;
213
+ }
214
+ }
215
+ const out = /* @__PURE__ */ Object.create(null);
216
+ for (const [key, entry] of entries) out[key] = entry;
217
+ const def = entries.get("default");
218
+ return {
219
+ turns: def?.turns ?? [],
220
+ lastExtractionAt: def?.lastExtractionAt ?? null,
221
+ extractionCount: def?.extractionCount ?? 0,
222
+ entries: out
223
+ };
224
+ }
225
+ /**
226
+ * Reconcile the files with a WHOLE buffer state: write every entry, then
227
+ * delete files for keys no longer present. Writes first, deletes last: a
228
+ * crash leaves stale extra files (removed by the next reconcile) but never
229
+ * loses sessions the state says exist. Not on the observe hot path.
230
+ */
231
+ async reconcile(state) {
232
+ const entries = legacyStateToEntries(state);
233
+ const existing = await this.listFiles();
234
+ for (const [key, entry] of entries) await this.save(key, entry);
235
+ const live = new Set([...entries.keys()].map((key) => bufferSessionFileName(key)));
236
+ for (const name of existing) {
237
+ if (live.has(name)) continue;
238
+ try {
239
+ await unlink(path.join(this.dir, name));
240
+ } catch (err) {
241
+ if (!(err instanceof Error) || !isMissing(asFsError(err))) throw err;
242
+ }
243
+ }
244
+ }
245
+ };
246
+
247
+ // src/storage/buffer-drain-claims.ts
248
+ var CLAIM_LOCK_STALE_MS = 12e4;
249
+ var CLAIM_LOCK_MAX_WAIT_MS = 12e4;
250
+ function emptyEntry() {
251
+ return { turns: [], lastExtractionAt: null, extractionCount: 0 };
252
+ }
253
+ function mergeTurns(existing, incoming, isEqual) {
254
+ const merged = [...existing];
255
+ for (const turn of incoming) {
256
+ if (merged.some((kept) => isEqual(kept, turn))) continue;
257
+ merged.push(turn);
258
+ }
259
+ return merged;
260
+ }
261
+ function mergeEntries(claim, incoming) {
262
+ const entry = emptyEntry();
263
+ const gone = [...claim.drained ?? [], ...claim.drainedRetained ?? []];
264
+ entry.turns = mergeTurns(
265
+ subtractBufferTurns(claim.entry.turns, gone),
266
+ subtractBufferTurns(incoming.turns, gone),
267
+ bufferTurnsEqual
268
+ );
269
+ const retained = [
270
+ ...subtractBufferTurns(claim.entry.retainedTurns ?? [], gone),
271
+ ...subtractBufferTurns(incoming.retainedTurns ?? [], gone)
272
+ ];
273
+ const dedupedRetained = mergeTurns([], retained, bufferTurnsEqual);
274
+ if (dedupedRetained.length > 0) entry.retainedTurns = dedupedRetained;
275
+ const stamps = [claim.entry.lastExtractionAt, incoming.lastExtractionAt].filter(
276
+ (value) => value !== null && value !== void 0
277
+ );
278
+ entry.lastExtractionAt = stamps.sort().at(-1) ?? null;
279
+ entry.extractionCount = Math.max(claim.entry.extractionCount, incoming.extractionCount);
280
+ return { ...claim, entry };
281
+ }
282
+ function isOwnerAlive(lease) {
283
+ if (lease.host !== hostname()) return true;
284
+ if (!Number.isInteger(lease.pid) || lease.pid <= 0) return true;
285
+ try {
286
+ process.kill(lease.pid, 0);
287
+ return true;
288
+ } catch (err) {
289
+ return err?.code === "EPERM";
290
+ }
291
+ }
292
+ function isLeaseExpired(lease, now = Date.now()) {
293
+ const heartbeat = Date.parse(lease.heartbeatAt);
294
+ return !Number.isFinite(heartbeat) || now - heartbeat > lease.leaseMs;
295
+ }
296
+ var claimBodySchema = z.object({
297
+ key: z.string().min(1),
298
+ entry: z.object({
299
+ turns: z.array(z.unknown()),
300
+ retainedTurns: z.array(z.unknown()).optional(),
301
+ lastExtractionAt: z.string().nullable().optional(),
302
+ extractionCount: z.number().optional()
303
+ }).optional(),
304
+ turns: z.array(z.unknown()).optional(),
305
+ retainedTurns: z.array(z.unknown()).optional(),
306
+ lastExtractionAt: z.string().nullable().optional(),
307
+ extractionCount: z.number().optional(),
308
+ claimedAt: z.string().optional(),
309
+ drained: z.array(z.unknown()).optional(),
310
+ drainedRetained: z.array(z.unknown()).optional()
311
+ });
312
+ function parseBody(raw) {
313
+ let body;
314
+ try {
315
+ body = claimBodySchema.parse(JSON.parse(raw));
316
+ } catch {
317
+ return null;
318
+ }
319
+ const source = body.entry && Array.isArray(body.entry.turns) ? body.entry : body;
320
+ if (!Array.isArray(source.turns)) return null;
321
+ const entry = emptyEntry();
322
+ entry.turns = source.turns;
323
+ if (source.retainedTurns) {
324
+ entry.retainedTurns = source.retainedTurns;
325
+ }
326
+ entry.lastExtractionAt = source.lastExtractionAt ?? null;
327
+ entry.extractionCount = Number.isFinite(source.extractionCount) ? Number(source.extractionCount) : 0;
328
+ const claim = {
329
+ key: body.key,
330
+ entry,
331
+ claimedAt: body.claimedAt ?? (/* @__PURE__ */ new Date()).toISOString()
332
+ };
333
+ if (Array.isArray(body.drained)) {
334
+ claim.drained = body.drained;
335
+ }
336
+ if (Array.isArray(body.drainedRetained)) {
337
+ claim.drainedRetained = body.drainedRetained;
338
+ }
339
+ return claim;
340
+ }
341
+ var leaseSchema = z.object({
342
+ ownerId: z.string().min(1),
343
+ pid: z.number().optional(),
344
+ host: z.string().optional(),
345
+ acquiredAt: z.string().optional(),
346
+ heartbeatAt: z.string(),
347
+ leaseMs: z.number()
348
+ });
349
+ function parseLease(raw) {
350
+ let lease;
351
+ try {
352
+ lease = leaseSchema.parse(JSON.parse(raw));
353
+ } catch {
354
+ return null;
355
+ }
356
+ return {
357
+ ownerId: lease.ownerId,
358
+ pid: lease.pid ?? 0,
359
+ host: lease.host ?? "",
360
+ acquiredAt: lease.acquiredAt ?? lease.heartbeatAt,
361
+ heartbeatAt: lease.heartbeatAt,
362
+ leaseMs: lease.leaseMs
363
+ };
364
+ }
365
+ var BufferDrainClaims = class {
366
+ constructor(stateDir, io) {
367
+ this.stateDir = stateDir;
368
+ this.io = io;
369
+ }
370
+ stateDir;
371
+ io;
372
+ get dir() {
373
+ return path2.join(this.stateDir, "buffer", "drain");
374
+ }
375
+ fileFor(key) {
376
+ return path2.join(this.dir, bufferSessionFileName(key));
377
+ }
378
+ leaseFileFor(key) {
379
+ return `${this.fileFor(key)}.lease.json`;
380
+ }
381
+ lockFileFor(key) {
382
+ return `${this.fileFor(key)}.lock`;
383
+ }
384
+ /** Sync existence check for hot-path gates (`SmartBuffer.isSessionClaimed`). */
385
+ isClaimed(key) {
386
+ return existsSync(this.fileFor(key));
387
+ }
388
+ /** Test + CLI seam: the lease file path for direct inspection. */
389
+ leasePathForTest(key) {
390
+ return this.leaseFileFor(key);
391
+ }
392
+ async readClaimBody(key) {
393
+ try {
394
+ return parseBody(await this.io.read(this.fileFor(key)));
395
+ } catch {
396
+ return null;
397
+ }
398
+ }
399
+ /** The claim content for `key`, or null when the key is not claimed. */
400
+ load(key) {
401
+ return this.readClaimBody(key);
402
+ }
403
+ async writeClaimBody(key, claim) {
404
+ await mkdir(this.dir, { recursive: true });
405
+ await this.io.write(this.fileFor(key), JSON.stringify({ ...claim, key }));
406
+ }
407
+ async readLease(key) {
408
+ try {
409
+ return parseLease(await this.io.read(this.leaseFileFor(key)));
410
+ } catch {
411
+ return null;
412
+ }
413
+ }
414
+ async writeLease(key, lease) {
415
+ await mkdir(this.dir, { recursive: true });
416
+ await this.io.write(this.leaseFileFor(key), JSON.stringify(lease));
417
+ }
418
+ /**
419
+ * Atomically move a session's persisted file into a claim. The rename is
420
+ * the handover: after it settles the turns exist ONLY as a claim, so no
421
+ * crash window can lose them or leave them in both places. Callers that
422
+ * lose the race (`already_claimed`) simply skip the key.
423
+ *
424
+ * The whole handover runs under the claim's mutation lock, so a claim
425
+ * create can never land on top of an existing claim (POSIX rename would
426
+ * silently replace it) and the lease write cannot race an adopter.
427
+ */
428
+ async claimFromSessionFile(key, lease) {
429
+ await mkdir(this.dir, { recursive: true });
430
+ const sessionPath = path2.join(this.stateDir, "buffer", bufferSessionFileName(key));
431
+ if (existsSync(sessionPath)) {
432
+ try {
433
+ const seeded = parseBody(await this.io.read(sessionPath));
434
+ if (seeded && seeded.entry.turns.length === 0 && (seeded.entry.retainedTurns?.length ?? 0) === 0) {
435
+ return "empty";
436
+ }
437
+ } catch {
438
+ }
439
+ }
440
+ return await withHeldFileLock(
441
+ this.lockFileFor(key),
442
+ { staleMs: CLAIM_LOCK_STALE_MS, maxWaitMs: CLAIM_LOCK_MAX_WAIT_MS },
443
+ async (acquired) => {
444
+ if (!acquired) return "already_claimed";
445
+ if (this.isClaimed(key)) return "already_claimed";
446
+ try {
447
+ await rename(sessionPath, this.fileFor(key));
448
+ } catch (err) {
449
+ if (!existsSync(sessionPath)) {
450
+ if (this.isClaimed(key)) return "already_claimed";
451
+ return "empty";
452
+ }
453
+ throw err;
454
+ }
455
+ const claim = await this.readClaimBody(key);
456
+ if (!claim || claim.entry.turns.length === 0 && (claim.entry.retainedTurns?.length ?? 0) === 0) {
457
+ await unlink2(this.fileFor(key)).catch(() => {
458
+ });
459
+ return "empty";
460
+ }
461
+ await this.writeLease(key, lease);
462
+ return "claimed";
463
+ }
464
+ );
465
+ }
466
+ /**
467
+ * Take over a claim whose lease is missing, expired, or whose owner died.
468
+ * The whole judgement runs under the claim's mutation lock and re-reads
469
+ * the lease inside it, so exactly one concurrent adopter wins: the loser
470
+ * re-reads the winner's fresh lease and reports "busy" instead of
471
+ * unlinking it. A lease whose owner died is taken over in the same call.
472
+ */
473
+ async adopt(key, lease) {
474
+ if (!this.isClaimed(key)) return "busy";
475
+ return await withHeldFileLock(
476
+ this.lockFileFor(key),
477
+ { staleMs: CLAIM_LOCK_STALE_MS, maxWaitMs: CLAIM_LOCK_MAX_WAIT_MS },
478
+ async (acquired) => {
479
+ if (!acquired) return "busy";
480
+ const existing = await this.readLease(key);
481
+ if (existing && !isLeaseExpired(existing)) {
482
+ if (existing.ownerId === lease.ownerId) {
483
+ await this.writeLease(key, { ...existing, heartbeatAt: (/* @__PURE__ */ new Date()).toISOString(), leaseMs: lease.leaseMs });
484
+ return "adopted";
485
+ }
486
+ if (isOwnerAlive(existing)) return "busy";
487
+ await unlink2(this.leaseFileFor(key)).catch(() => {
488
+ });
489
+ } else if (existing) {
490
+ await unlink2(this.leaseFileFor(key)).catch(() => {
491
+ });
492
+ }
493
+ try {
494
+ await writeFile(this.leaseFileFor(key), JSON.stringify(lease), { flag: "wx" });
495
+ } catch (err) {
496
+ if (existsSync(this.leaseFileFor(key))) return "busy";
497
+ throw err;
498
+ }
499
+ return "adopted";
500
+ }
501
+ );
502
+ }
503
+ /**
504
+ * Merge a live owner's in-memory entry INTO the claim (the handover path a
505
+ * buffer owner takes instead of persisting a claimed session). Serialized
506
+ * against drainer progress writes on the same lock.
507
+ */
508
+ async mergeIntoClaim(key, incoming) {
509
+ await withHeldFileLock(this.lockFileFor(key), { staleMs: CLAIM_LOCK_STALE_MS, maxWaitMs: CLAIM_LOCK_MAX_WAIT_MS }, async (acquired) => {
510
+ if (!acquired) {
511
+ throw new Error(`buffer drain claim for ${key} is busy; retrying the save later`);
512
+ }
513
+ const claim = await this.readClaimBody(key);
514
+ if (!claim) {
515
+ return;
516
+ }
517
+ await this.writeClaimBody(key, mergeEntries(claim, incoming));
518
+ });
519
+ }
520
+ /** Drainer progress: replace the claim content with what is left to do.
521
+ *
522
+ * Fenced: `ownerId` must still match the claim's lease (checked under the
523
+ * same lock), so a drainer that lost its lease cannot write progress that
524
+ * would restore turns the new owner already extracted.
525
+ *
526
+ * `seen` is the entry the drainer LOADED (its snapshot of the claim). Only
527
+ * turns that were in that snapshot and are absent from BOTH of the
528
+ * drainer's lists were actually extracted and move to the tombstones — a
529
+ * turn the drainer moved into `entry.retainedTurns` is retained for retry,
530
+ * not extracted. Turns a live owner merged into the claim afterwards stay
531
+ * pending. Without `seen` the pre-existing behavior is kept (every claim
532
+ * turn missing from `entry` counts as extracted).
533
+ */
534
+ async writeEntry(key, ownerId, entry, seen) {
535
+ await withHeldFileLock(this.lockFileFor(key), { staleMs: CLAIM_LOCK_STALE_MS, maxWaitMs: CLAIM_LOCK_MAX_WAIT_MS }, async (acquired) => {
536
+ if (!acquired) throw new Error(`buffer drain claim for ${key} is busy; progress write skipped`);
537
+ const lease = await this.readLease(key);
538
+ if (!lease || lease.ownerId !== ownerId) {
539
+ throw new Error(`buffer drain claim for ${key} is no longer owned by ${ownerId}; progress write skipped`);
540
+ }
541
+ const claim = await this.readClaimBody(key);
542
+ if (!claim) return;
543
+ const seenTurns = seen?.turns ?? claim.entry.turns;
544
+ const seenRetained = seen?.retainedTurns ?? claim.entry.retainedTurns ?? [];
545
+ const entryRetained = entry.retainedTurns ?? [];
546
+ const kept = (turn) => entry.turns.some((held) => bufferTurnsEqual(held, turn)) || entryRetained.some((held) => bufferTurnsEqual(held, turn));
547
+ const drained = [...claim.drained ?? []];
548
+ for (const turn of claim.entry.turns) {
549
+ const extracted = seenTurns.some((snapshot) => bufferTurnsEqual(snapshot, turn)) && !kept(turn);
550
+ if (!extracted) continue;
551
+ if (drained.some((gone) => bufferTurnsEqual(gone, turn))) continue;
552
+ drained.push(turn);
553
+ }
554
+ const drainedRetained = [...claim.drainedRetained ?? []];
555
+ for (const turn of claim.entry.retainedTurns ?? []) {
556
+ const extracted = seenRetained.some((snapshot) => bufferTurnsEqual(snapshot, turn)) && !kept(turn);
557
+ if (!extracted) continue;
558
+ if (drained.some((gone) => bufferTurnsEqual(gone, turn)) || drainedRetained.some((gone) => bufferTurnsEqual(gone, turn))) continue;
559
+ drainedRetained.push(turn);
560
+ }
561
+ const late = claim.entry.turns.filter(
562
+ (turn) => !seenTurns.some((snapshot) => bufferTurnsEqual(snapshot, turn)) && !kept(turn)
563
+ );
564
+ const next = { ...entry, turns: [...entry.turns, ...late] };
565
+ const lateRetained = (claim.entry.retainedTurns ?? []).filter(
566
+ (turn) => !seenRetained.some((snapshot) => bufferTurnsEqual(snapshot, turn)) && !kept(turn)
567
+ );
568
+ if (lateRetained.length > 0) next.retainedTurns = mergeTurns(entryRetained, lateRetained, bufferTurnsEqual);
569
+ await this.writeClaimBody(key, { ...claim, entry: next, drained, drainedRetained });
570
+ });
571
+ }
572
+ /** Extend the lease. "lost" means another drainer took the claim over.
573
+ * Serialized on the claim lock so a stale heartbeat can never overwrite a
574
+ * new owner's lease mid-takeover; a contended lock just skips this tick
575
+ * (usually the drainer's own progress write holds it). */
576
+ async heartbeat(key, ownerId, leaseMs) {
577
+ return await withHeldFileLock(this.lockFileFor(key), { staleMs: CLAIM_LOCK_STALE_MS, maxWaitMs: CLAIM_LOCK_MAX_WAIT_MS }, async (acquired) => {
578
+ if (!acquired) return "ok";
579
+ const lease = await this.readLease(key);
580
+ if (!lease || lease.ownerId !== ownerId) return "lost";
581
+ await this.writeLease(key, { ...lease, heartbeatAt: (/* @__PURE__ */ new Date()).toISOString(), leaseMs });
582
+ return "ok";
583
+ });
584
+ }
585
+ /** Give the key back (content stays; the next run resumes it). */
586
+ async releaseLease(key, ownerId) {
587
+ const lease = await this.readLease(key);
588
+ if (!lease || lease.ownerId !== ownerId) return;
589
+ await unlink2(this.leaseFileFor(key)).catch(() => {
590
+ });
591
+ }
592
+ /**
593
+ * Finish a claim: only its owner may ack, and only when nothing is left to
594
+ * extract. Non-empty claims stay (deferred content is never dropped here).
595
+ */
596
+ async ack(key, ownerId) {
597
+ const lease = await this.readLease(key);
598
+ if (!lease || lease.ownerId !== ownerId) return "busy";
599
+ const claim = await this.readClaimBody(key);
600
+ if (!claim) {
601
+ await unlink2(this.leaseFileFor(key)).catch(() => {
602
+ });
603
+ return "acked";
604
+ }
605
+ if (claim.entry.turns.length > 0 || (claim.entry.retainedTurns?.length ?? 0) > 0) return "not_empty";
606
+ await unlink2(this.leaseFileFor(key)).catch(() => {
607
+ });
608
+ return "acked";
609
+ }
610
+ /** The turns a drain already extracted for `key` (tombstone content). */
611
+ async drainedTurns(key) {
612
+ const claim = await this.readClaimBody(key);
613
+ return claim?.drained ?? [];
614
+ }
615
+ /**
616
+ * Is the drain for `key` FINISHED (acked): the claim holds extracted turns
617
+ * and nothing pending, and the drainer dropped its lease. A claim with
618
+ * partial progress or a live lease is still being drained — its owner must
619
+ * merge into it, never release it.
620
+ */
621
+ async isDrained(key) {
622
+ const claim = await this.readClaimBody(key);
623
+ if (!claim) return false;
624
+ if ((claim.drained?.length ?? 0) === 0 && (claim.drainedRetained?.length ?? 0) === 0) return false;
625
+ if (claim.entry.turns.length > 0 || (claim.entry.retainedTurns?.length ?? 0) > 0) return false;
626
+ return await this.readLease(key) === null;
627
+ }
628
+ /** Drop the claim file entirely (its owner consumed the tombstone). */
629
+ async release(key) {
630
+ await unlink2(this.fileFor(key)).catch(() => {
631
+ });
632
+ await unlink2(this.leaseFileFor(key)).catch(() => {
633
+ });
634
+ }
635
+ /** Every claim with its lease state (CLI scan + summaries). */
636
+ async list() {
637
+ let names;
638
+ try {
639
+ names = (await readdir2(this.dir)).filter((name) => name.endsWith(".json") && !name.endsWith(".lease.json"));
640
+ } catch (err) {
641
+ if (err?.code === "ENOENT") return [];
642
+ throw err;
643
+ }
644
+ const out = [];
645
+ for (const name of names) {
646
+ const claim = await this.readClaimBodyByKey(name);
647
+ if (!claim) continue;
648
+ const lease = await this.readLease(claim.key);
649
+ out.push({
650
+ key: claim.key,
651
+ turnCount: claim.entry.turns.length + (claim.entry.retainedTurns?.length ?? 0),
652
+ leased: lease !== null,
653
+ leaseExpired: lease !== null ? isLeaseExpired(lease) : true
654
+ });
655
+ }
656
+ return out;
657
+ }
658
+ async readClaimBodyByKey(name) {
659
+ try {
660
+ return parseBody(await this.io.read(path2.join(this.dir, name)));
661
+ } catch (err) {
662
+ log.debug(`buffer drain: skipping unreadable claim file ${name}: ${err instanceof Error ? err.message : String(err)}`);
663
+ return null;
664
+ }
665
+ }
666
+ };
667
+
668
+ export {
669
+ BufferDrainClaims,
670
+ bufferSessionFileName,
671
+ legacyStateToEntries,
672
+ BufferSessionFiles
673
+ };
674
+ //# sourceMappingURL=chunk-JCL7RO2G.js.map