@remnic/core 10.0.92 → 10.0.93

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 (486) hide show
  1. package/dist/access-admin-ops-surface.js +331 -58
  2. package/dist/access-authorization-probe.js +2 -283
  3. package/dist/access-boundary.d.ts +1 -1
  4. package/dist/access-boundary.d.ts.map +1 -1
  5. package/dist/access-boundary.js +1 -282
  6. package/dist/access-cli.js +286 -302
  7. package/dist/access-cli.js.map +1 -1
  8. package/dist/access-coding-context-resolution.js +3 -3
  9. package/dist/access-extraction-force-flush.js +331 -58
  10. package/dist/access-http-briefing.js +331 -59
  11. package/dist/access-http-query.js +331 -60
  12. package/dist/access-http.js +329 -111
  13. package/dist/access-identity-continuity-surface.js +331 -58
  14. package/dist/access-lcm-surface.js +331 -58
  15. package/dist/access-mcp-frames.d.ts +20 -6
  16. package/dist/access-mcp-frames.d.ts.map +1 -1
  17. package/dist/access-mcp-frames.js +1 -1
  18. package/dist/access-mcp.d.ts +5 -0
  19. package/dist/access-mcp.d.ts.map +1 -1
  20. package/dist/access-mcp.js +329 -86
  21. package/dist/access-namespace-preflight.js +2 -282
  22. package/dist/access-observe-transcript.js +3 -3
  23. package/dist/access-observe-write-category.js +6 -6
  24. package/dist/access-observe-write-surface.js +331 -58
  25. package/dist/access-offline-manifest.js +12 -11
  26. package/dist/access-operations-batch.js +329 -63
  27. package/dist/access-operations.js +329 -72
  28. package/dist/access-recall-concurrency.js +331 -58
  29. package/dist/access-recall-diagnostics.js +5 -4
  30. package/dist/access-recall-response.js +331 -58
  31. package/dist/access-recall-surface.js +331 -58
  32. package/dist/access-schema.js +2 -2
  33. package/dist/access-service.js +334 -61
  34. package/dist/access-surface-catalog.js +6 -283
  35. package/dist/access-surface-catalog.js.map +1 -1
  36. package/dist/active-context-transform.js +1 -1
  37. package/dist/active-memory-bridge.js +3 -2
  38. package/dist/active-recall.js +35 -36
  39. package/dist/active-recall.js.map +1 -1
  40. package/dist/activity/journal-extract.d.ts +13 -1
  41. package/dist/activity/journal-extract.d.ts.map +1 -1
  42. package/dist/{auto-sync-3AZW7MXI.js → auto-sync-BO5YZKM6.js} +13 -15
  43. package/dist/{auto-sync-3AZW7MXI.js.map → auto-sync-BO5YZKM6.js.map} +1 -1
  44. package/dist/briefing.js +19 -19
  45. package/dist/buffer.js +16 -16
  46. package/dist/calibration.js +10 -10
  47. package/dist/{capsule-merge-2IIXFXN5.js → capsule-merge-6IDAYTKG.js} +6 -6
  48. package/dist/causal-consolidation.js +22 -22
  49. package/dist/{chunk-ATPWZ4F7.js → chunk-2LMA22UU.js} +5 -5
  50. package/dist/{chunk-RGUUBAT5.js → chunk-2WCLTWV2.js} +3 -3
  51. package/dist/{chunk-BQZEGOZ4.js → chunk-2YODOG2O.js} +2 -2
  52. package/dist/{chunk-WYG5UNDY.js → chunk-3AUDELZL.js} +2 -2
  53. package/dist/{chunk-N4KAE2NB.js → chunk-3CYOCE6U.js} +3 -3
  54. package/dist/{chunk-MB6ZJDN6.js → chunk-3FBAEPCU.js} +2 -2
  55. package/dist/{chunk-PIITB2YZ.js → chunk-3ZS3NUEI.js} +4 -4
  56. package/dist/{chunk-ANZZLRUX.js → chunk-4IVRQMZW.js} +2 -2
  57. package/dist/{chunk-63E37JCN.js → chunk-4RAJT5L2.js} +4 -4
  58. package/dist/{chunk-45VUHDV2.js → chunk-5CO5G4MN.js} +2 -2
  59. package/dist/{chunk-BRLXOZLM.js → chunk-5YT2IIFX.js} +729 -17
  60. package/dist/chunk-5YT2IIFX.js.map +1 -0
  61. package/dist/{chunk-E4IRW2FG.js → chunk-622V2AZA.js} +233 -40
  62. package/dist/chunk-622V2AZA.js.map +1 -0
  63. package/dist/{chunk-LUJCQQ3L.js → chunk-65HWAQ4F.js} +2 -2
  64. package/dist/{chunk-T67LUYCR.js → chunk-77NTFICT.js} +5 -5
  65. package/dist/chunk-A2WFUMUN.js +86 -0
  66. package/dist/chunk-A2WFUMUN.js.map +1 -0
  67. package/dist/{chunk-UE6RRXMF.js → chunk-A4F7OIC5.js} +2 -2
  68. package/dist/chunk-AHA5VQGP.js +117 -0
  69. package/dist/chunk-AHA5VQGP.js.map +1 -0
  70. package/dist/{chunk-SUSW74WU.js → chunk-ATG2PQ4V.js} +56 -5
  71. package/dist/chunk-ATG2PQ4V.js.map +1 -0
  72. package/dist/{chunk-U6UNF5ZS.js → chunk-B33YWUJV.js} +3 -3
  73. package/dist/{chunk-RRJBDXAQ.js → chunk-B377OKUP.js} +2 -2
  74. package/dist/{chunk-IUKYFTGW.js → chunk-B3DR2JBZ.js} +140 -125
  75. package/dist/chunk-B3DR2JBZ.js.map +1 -0
  76. package/dist/{chunk-ETZLQOUR.js → chunk-BGHCSLE5.js} +2 -2
  77. package/dist/{chunk-YYOMGOHB.js → chunk-BOK6BN5M.js} +2 -2
  78. package/dist/{chunk-OH7QLI6W.js → chunk-BPPUH5JM.js} +5 -5
  79. package/dist/{chunk-4J363OAA.js → chunk-BTI4C4MA.js} +2 -2
  80. package/dist/{chunk-O6ZSWHVR.js → chunk-C2KE5DMD.js} +4 -4
  81. package/dist/{chunk-47F6WWLQ.js → chunk-C73N66PR.js} +2 -2
  82. package/dist/{chunk-E3A7ELSG.js → chunk-CGJYL633.js} +2 -2
  83. package/dist/{chunk-WRT7GJ2D.js → chunk-CIWMTNHW.js} +4 -4
  84. package/dist/{chunk-O55EKIEC.js → chunk-D3ZKHLN2.js} +2 -2
  85. package/dist/{chunk-CD4BCCNP.js → chunk-DJ7WVEWX.js} +2 -2
  86. package/dist/{chunk-PWXPRVLK.js → chunk-EFL24KOI.js} +2 -2
  87. package/dist/{chunk-4CJTQHEG.js → chunk-ESLOLCD4.js} +3 -3
  88. package/dist/{chunk-6F42QONS.js → chunk-ETBVCRVL.js} +4 -4
  89. package/dist/{chunk-VILPVT4S.js → chunk-EZ47HOJ6.js} +4 -4
  90. package/dist/{chunk-EFYN5I7Z.js → chunk-F4QFU5IZ.js} +2 -2
  91. package/dist/{chunk-T6OZW2WR.js → chunk-FA7SLQ5X.js} +7 -1
  92. package/dist/chunk-FA7SLQ5X.js.map +1 -0
  93. package/dist/{chunk-7W3RXOIG.js → chunk-FMKILENU.js} +14 -14
  94. package/dist/{chunk-YLXETSAH.js → chunk-GCZJ7XRI.js} +2 -2
  95. package/dist/{chunk-5HFXGXE5.js → chunk-GQXOBKPL.js} +7 -9
  96. package/dist/{chunk-5HFXGXE5.js.map → chunk-GQXOBKPL.js.map} +1 -1
  97. package/dist/{chunk-UDKWFDV2.js → chunk-HLUHEMN4.js} +27 -3
  98. package/dist/chunk-HLUHEMN4.js.map +1 -0
  99. package/dist/{chunk-QFEDITXM.js → chunk-JNDMIAJ4.js} +2 -2
  100. package/dist/chunk-JTSSSR4L.js +359 -0
  101. package/dist/chunk-JTSSSR4L.js.map +1 -0
  102. package/dist/{chunk-5KBIOI4G.js → chunk-JVBAPAWZ.js} +217 -13
  103. package/dist/chunk-JVBAPAWZ.js.map +1 -0
  104. package/dist/{chunk-E5PPE4VA.js → chunk-K2VRKCPA.js} +2 -2
  105. package/dist/{chunk-MKRYQROF.js → chunk-LGEHAQHK.js} +4 -4
  106. package/dist/{chunk-7HTUYFR3.js → chunk-LLPMMMWG.js} +27 -10
  107. package/dist/chunk-LLPMMMWG.js.map +1 -0
  108. package/dist/{chunk-XYTQJD7F.js → chunk-LMJVP5CM.js} +2 -2
  109. package/dist/{chunk-FQKBJJYB.js → chunk-LPV72KRQ.js} +2 -2
  110. package/dist/{chunk-2LCRG2YV.js → chunk-M2XR6B6V.js} +2 -2
  111. package/dist/{chunk-P4WNBSTW.js → chunk-MH632KPO.js} +2 -2
  112. package/dist/{chunk-EQ4U73UH.js → chunk-MLAMXQAW.js} +14 -2
  113. package/dist/chunk-MLAMXQAW.js.map +1 -0
  114. package/dist/{chunk-ZU5JDLOH.js → chunk-MMRTPH3J.js} +2 -2
  115. package/dist/{chunk-PMJFRDJI.js → chunk-MUX7IL77.js} +2 -2
  116. package/dist/{chunk-HF3BKUVV.js → chunk-NAQ4A5IX.js} +7 -7
  117. package/dist/{chunk-TVIVY7KU.js → chunk-NED7IR7B.js} +4 -4
  118. package/dist/{chunk-6F5MJFXY.js → chunk-NHVAX7MH.js} +2 -2
  119. package/dist/{chunk-TG3R2SID.js → chunk-NMGHGTVR.js} +5 -5
  120. package/dist/{chunk-YCNIGRRF.js → chunk-NS7U4ZYU.js} +13 -117
  121. package/dist/chunk-NS7U4ZYU.js.map +1 -0
  122. package/dist/{chunk-NGHDW6UU.js → chunk-NUQEREIP.js} +2 -2
  123. package/dist/{chunk-5IIQU4JZ.js → chunk-OB72KNMF.js} +4 -4
  124. package/dist/{chunk-JV4S6VDH.js → chunk-OJXJWNFY.js} +2 -2
  125. package/dist/{chunk-QJPJXCS4.js → chunk-P3WRNWWM.js} +157 -4
  126. package/dist/chunk-P3WRNWWM.js.map +1 -0
  127. package/dist/{chunk-E6M225BJ.js → chunk-PC5DRBGD.js} +18 -8
  128. package/dist/chunk-PC5DRBGD.js.map +1 -0
  129. package/dist/{chunk-Z7JIZ42P.js → chunk-PRAUN6PN.js} +3 -3
  130. package/dist/{chunk-RWGRSKN5.js → chunk-PT4DZDJA.js} +2 -2
  131. package/dist/{chunk-7EPY3IQL.js → chunk-PZJQ46DH.js} +2 -2
  132. package/dist/{chunk-MXHMNKWG.js → chunk-QDESY76F.js} +3 -3
  133. package/dist/{chunk-I6QGI65T.js → chunk-QRMG4HK4.js} +3 -3
  134. package/dist/{chunk-ZU3NJNO7.js → chunk-QSF5SJAM.js} +4 -4
  135. package/dist/{chunk-5IYOKDM4.js → chunk-R23JWJD3.js} +5 -5
  136. package/dist/{chunk-RHQLIHMB.js → chunk-R4BBGPI2.js} +218 -218
  137. package/dist/chunk-R4BBGPI2.js.map +1 -0
  138. package/dist/{chunk-7GLJMDEQ.js → chunk-RM2YUFH6.js} +6 -6
  139. package/dist/{chunk-IPT2OY4B.js → chunk-RQFXZYTF.js} +35 -33
  140. package/dist/chunk-RQFXZYTF.js.map +1 -0
  141. package/dist/{chunk-AP6NCP3V.js → chunk-S3S72HRM.js} +8 -6
  142. package/dist/chunk-S3S72HRM.js.map +1 -0
  143. package/dist/{chunk-RIMK327Y.js → chunk-SGQPR5SX.js} +7 -7
  144. package/dist/{chunk-ZGFLIK5H.js → chunk-SPAKBUJY.js} +2 -2
  145. package/dist/{chunk-ER7XANP3.js → chunk-SQ3GEIEL.js} +4 -4
  146. package/dist/{chunk-BLJT6JP2.js → chunk-SVT5IA2H.js} +2 -2
  147. package/dist/{chunk-HVX4LPNY.js → chunk-T4KY6UYF.js} +5 -3
  148. package/dist/{chunk-HVX4LPNY.js.map → chunk-T4KY6UYF.js.map} +1 -1
  149. package/dist/{chunk-GVGAO3WV.js → chunk-TJ4F6H4H.js} +3 -3
  150. package/dist/{chunk-R6HMAIKM.js → chunk-TOSPNM4T.js} +2 -2
  151. package/dist/{chunk-HH5LY6RR.js → chunk-TRQE3RYR.js} +5 -5
  152. package/dist/{chunk-RMXS4I66.js → chunk-TVDJEUV5.js} +2 -2
  153. package/dist/{chunk-PLCYKAWH.js → chunk-TYRWSE4B.js} +2 -2
  154. package/dist/{chunk-B4QYQFGY.js → chunk-UBEKET2V.js} +383 -36
  155. package/dist/chunk-UBEKET2V.js.map +1 -0
  156. package/dist/{chunk-IQWUACVG.js → chunk-UHMHJX5G.js} +3 -3
  157. package/dist/{chunk-YODUDA6R.js → chunk-UN4RVUG2.js} +22 -22
  158. package/dist/{chunk-E6Z4FBX6.js → chunk-V2QSNFCT.js} +2 -2
  159. package/dist/{chunk-NBH6K6G5.js → chunk-V65H7MI6.js} +345 -16
  160. package/dist/chunk-V65H7MI6.js.map +1 -0
  161. package/dist/chunk-W54Z2MOP.js +4500 -0
  162. package/dist/chunk-W54Z2MOP.js.map +1 -0
  163. package/dist/{chunk-E7YZXWIS.js → chunk-WKSQTMU7.js} +2 -2
  164. package/dist/{chunk-RIZ5NUNN.js → chunk-WQ4XKIOX.js} +4 -4
  165. package/dist/{chunk-FSO3G4JJ.js → chunk-WQURALGV.js} +4995 -2747
  166. package/dist/chunk-WQURALGV.js.map +1 -0
  167. package/dist/{chunk-QEYTRFR3.js → chunk-X26YOFGS.js} +2 -2
  168. package/dist/{chunk-ITHZFHST.js → chunk-X2BVB74H.js} +2 -2
  169. package/dist/{chunk-XYKBWTWI.js → chunk-XIYLWEXC.js} +2 -2
  170. package/dist/{chunk-IBJ6U753.js → chunk-XKZBZOKV.js} +4 -4
  171. package/dist/{chunk-65AUYLU3.js → chunk-XPXHQI6N.js} +2 -2
  172. package/dist/{chunk-EXHXJETE.js → chunk-XRDYRWZI.js} +2 -2
  173. package/dist/chunk-XRWWCW4H.js +102 -0
  174. package/dist/chunk-XRWWCW4H.js.map +1 -0
  175. package/dist/chunk-YKJBSMMP.js +67137 -0
  176. package/dist/chunk-YKJBSMMP.js.map +1 -0
  177. package/dist/{chunk-2JSDPUKD.js → chunk-YMFPFXEX.js} +2 -2
  178. package/dist/{chunk-645WOU5I.js → chunk-ZDZJNXL6.js} +4 -4
  179. package/dist/{chunk-6TCXIRP5.js → chunk-ZKE4CO6B.js} +4 -4
  180. package/dist/{chunk-FNXQZGUS.js → chunk-ZSE774RV.js} +2 -2
  181. package/dist/cli.js +302 -184
  182. package/dist/coding/export-okf-codegraph.js +28 -28
  183. package/dist/compounding/engine.js +22 -23
  184. package/dist/config.js +35 -36
  185. package/dist/connectors/codex-materialize-runner.js +19 -19
  186. package/dist/connectors/index.js +20 -20
  187. package/dist/connectors/live/google-drive.d.ts +2 -0
  188. package/dist/connectors/live/google-drive.d.ts.map +1 -1
  189. package/dist/consolidation-provenance-check.js +4 -4
  190. package/dist/consolidation-undo.js +5 -5
  191. package/dist/contradiction/index.js +7 -6
  192. package/dist/{contradiction-scan-P2MHYFVG.js → contradiction-scan-IBPYGQZF.js} +4 -3
  193. package/dist/convergence-refresh.js +21 -21
  194. package/dist/corpus-watermark.js +22 -22
  195. package/dist/deep-recall-http-glue.js +2 -2
  196. package/dist/deep-recall-policy-llm.js +4 -4
  197. package/dist/direct-answer-wiring.js +2 -2
  198. package/dist/embedding-fallback.js +1 -1
  199. package/dist/entity-retrieval.js +20 -20
  200. package/dist/eval-trajectory-store.js +2 -2
  201. package/dist/eval-trajectory.js +2 -2
  202. package/dist/event-order-recall.js +2 -2
  203. package/dist/explicit-capture.d.ts +3 -2
  204. package/dist/explicit-capture.d.ts.map +1 -1
  205. package/dist/explicit-capture.js +530 -6
  206. package/dist/explicit-cue-recall.js +2 -2
  207. package/dist/external-wiki-access.js +2 -283
  208. package/dist/extraction-faithfulness.js +4 -4
  209. package/dist/extraction-judge.js +5 -5
  210. package/dist/extraction-normalization.js +1 -1
  211. package/dist/extraction-quote-grounding.d.ts.map +1 -1
  212. package/dist/extraction-quote-grounding.js +1 -1
  213. package/dist/extraction-source-grounding-rules.js +2 -2
  214. package/dist/extraction-source-grounding.js +3 -3
  215. package/dist/extraction.js +42 -43
  216. package/dist/fallback-llm-codex-subscription.js +2 -2
  217. package/dist/fallback-llm.js +3 -3
  218. package/dist/{first-start-migration-QFI7B5SH.js → first-start-migration-FILJH3RO.js} +6 -5
  219. package/dist/{first-start-migration-QFI7B5SH.js.map → first-start-migration-FILJH3RO.js.map} +1 -1
  220. package/dist/focused-list-recall.js +2 -2
  221. package/dist/harmonic-retrieval.js +19 -19
  222. package/dist/index.js +772 -793
  223. package/dist/lcm/index.js +2 -2
  224. package/dist/live-connectors-runner.js +2 -3
  225. package/dist/local-llm-config.js +2 -2
  226. package/dist/local-llm-helpers.d.ts +4 -0
  227. package/dist/local-llm-helpers.d.ts.map +1 -1
  228. package/dist/local-llm-helpers.js +3 -1
  229. package/dist/local-llm.d.ts +4 -1
  230. package/dist/local-llm.d.ts.map +1 -1
  231. package/dist/local-llm.js +4 -4
  232. package/dist/location/index.js +26 -28
  233. package/dist/maintenance/memory-governance.js +19 -19
  234. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +19 -19
  235. package/dist/maintenance/rebuild-memory-projection-runner.js +21 -21
  236. package/dist/maintenance/rebuild-memory-projection.js +20 -20
  237. package/dist/memory-browse-operations.js +2 -283
  238. package/dist/memory-browse.js +8 -7
  239. package/dist/memory-controller.js +2 -2
  240. package/dist/memory-subject.js +2 -2
  241. package/dist/namespaces/migrate.js +20 -20
  242. package/dist/namespaces/search.js +5 -5
  243. package/dist/namespaces/storage.js +19 -19
  244. package/dist/offline-sync-changeset-generations.js +1 -1
  245. package/dist/offline-sync-embedding-generation.js +1 -1
  246. package/dist/offline-sync-impression-drain.js +6 -6
  247. package/dist/offline-sync-snapshot-stream.js +1 -1
  248. package/dist/offline-sync.js +1 -1
  249. package/dist/operator-doctor-corpus.js +23 -23
  250. package/dist/operator-toolkit.js +57 -60
  251. package/dist/orchestration/backlog-scheduler.js +277 -293
  252. package/dist/orchestration/backlog-scheduler.js.map +1 -1
  253. package/dist/orchestration/buffer-drain-runner.js +277 -293
  254. package/dist/orchestration/extraction-run.d.ts +4 -0
  255. package/dist/orchestration/extraction-run.d.ts.map +1 -1
  256. package/dist/orchestration/fact-dedup-window.d.ts +1 -1
  257. package/dist/orchestration/fact-dedup-window.d.ts.map +1 -1
  258. package/dist/orchestration/maintenance.js +38 -41
  259. package/dist/orchestrator.d.ts +9 -11
  260. package/dist/orchestrator.d.ts.map +1 -1
  261. package/dist/orchestrator.js +289 -306
  262. package/dist/page-versioning.js +3 -3
  263. package/dist/qmd-daemon-session.js +2 -2
  264. package/dist/qmd.js +3 -3
  265. package/dist/recall-explain-renderer.js +1 -1
  266. package/dist/recall-navigation-operations.js +2 -283
  267. package/dist/recall-navigation.js +331 -58
  268. package/dist/recall-planner-llm.js +3 -3
  269. package/dist/recall-state-view-admission.js +6 -6
  270. package/dist/recall-why-service.js +10 -9
  271. package/dist/recall-why.js +4 -3
  272. package/dist/recall-xray-cli.js +2 -2
  273. package/dist/recall-xray-renderer.js +1 -1
  274. package/dist/reconcile/manifest.js +3 -3
  275. package/dist/{resolution-N7H3F2E4.js → resolution-OVVIF7ZY.js} +8 -7
  276. package/dist/response-guidance-recall.js +2 -2
  277. package/dist/resume-bundles.js +39 -40
  278. package/dist/salvage-envelope.js +4 -4
  279. package/dist/search/factory.js +4 -4
  280. package/dist/search/index.js +4 -4
  281. package/dist/semantic-consolidation.js +22 -22
  282. package/dist/semantic-rule-promotion.js +19 -19
  283. package/dist/semantic-rule-verifier.js +19 -19
  284. package/dist/shared-context/manager.js +2 -3
  285. package/dist/source-agent-qualifier.js +31 -32
  286. package/dist/standup/build.js +19 -19
  287. package/dist/storage/content-hash-index.d.ts +10 -0
  288. package/dist/storage/content-hash-index.d.ts.map +1 -1
  289. package/dist/storage.js +18 -18
  290. package/dist/subject-config.js +3 -3
  291. package/dist/summarizer.d.ts +4 -1
  292. package/dist/summarizer.d.ts.map +1 -1
  293. package/dist/summarizer.js +6 -6
  294. package/dist/support-passport/index.js +53 -297
  295. package/dist/targeted-fact-recall.js +2 -2
  296. package/dist/tier-routing.js +3 -2
  297. package/dist/{tier-stats-FQGQSFET.js → tier-stats-FXEUJN73.js} +6 -5
  298. package/dist/{tier-stats-FQGQSFET.js.map → tier-stats-FXEUJN73.js.map} +1 -1
  299. package/dist/transcript.js +2 -2
  300. package/dist/transfer/capsule-import.js +4 -4
  301. package/dist/transfer/export-okf.js +19 -19
  302. package/dist/verified-recall.js +19 -19
  303. package/dist/wearables/memory-gen.d.ts +5 -1
  304. package/dist/wearables/memory-gen.d.ts.map +1 -1
  305. package/dist/wearables/service.d.ts.map +1 -1
  306. package/dist/who-knows-cli.js +20 -20
  307. package/dist/who-knows.js +19 -19
  308. package/dist/write-envelope.js +3 -3
  309. package/package.json +2 -2
  310. package/src/access-boundary.ts +5 -1
  311. package/src/access-category-alias.test.ts +5 -0
  312. package/src/access-mcp-frames.test.ts +60 -5
  313. package/src/access-mcp-frames.ts +72 -18
  314. package/src/access-mcp.test.ts +66 -2
  315. package/src/access-mcp.ts +19 -13
  316. package/src/access-service-coding-write.test.ts +7 -0
  317. package/src/activity/journal-extract-storage.test.ts +31 -0
  318. package/src/activity/journal-extract.test.ts +1 -0
  319. package/src/activity/journal-extract.ts +24 -3
  320. package/src/connectors/live/google-drive.test.ts +39 -0
  321. package/src/connectors/live/google-drive.ts +41 -12
  322. package/src/explicit-capture.test.ts +109 -17
  323. package/src/explicit-capture.ts +90 -37
  324. package/src/extraction-quote-grounding.test.ts +20 -0
  325. package/src/extraction-quote-grounding.ts +21 -11
  326. package/src/fact-dedup-window.test.ts +37 -0
  327. package/src/local-llm-helpers.ts +12 -0
  328. package/src/local-llm-shutdown.test.ts +194 -0
  329. package/src/local-llm.ts +32 -30
  330. package/src/orchestration/extraction-run.ts +12 -3
  331. package/src/orchestration/fact-dedup-window.ts +5 -1
  332. package/src/orchestrator-connector-dedup.test.ts +9 -5
  333. package/src/orchestrator.ts +47 -50
  334. package/src/storage/content-hash-index.ts +27 -2
  335. package/src/storage-fact-hash-publish-failure.test.ts +87 -0
  336. package/src/summarizer-shutdown.test.ts +195 -0
  337. package/src/summarizer.ts +15 -2
  338. package/src/wearables/memory-gen.test.ts +20 -0
  339. package/src/wearables/memory-gen.ts +14 -7
  340. package/src/wearables/service.ts +14 -1
  341. package/src/wearables/storage-io.test.ts +25 -0
  342. package/dist/chunk-2FGLEF7C.js +0 -61
  343. package/dist/chunk-2FGLEF7C.js.map +0 -1
  344. package/dist/chunk-3RLK65ZK.js +0 -203
  345. package/dist/chunk-3RLK65ZK.js.map +0 -1
  346. package/dist/chunk-4WR2OD7K.js +0 -43
  347. package/dist/chunk-4WR2OD7K.js.map +0 -1
  348. package/dist/chunk-5KBIOI4G.js.map +0 -1
  349. package/dist/chunk-5M5M22GW.js +0 -346
  350. package/dist/chunk-5M5M22GW.js.map +0 -1
  351. package/dist/chunk-7HTUYFR3.js.map +0 -1
  352. package/dist/chunk-AP6NCP3V.js.map +0 -1
  353. package/dist/chunk-B4QYQFGY.js.map +0 -1
  354. package/dist/chunk-BJRTMNCB.js +0 -1919
  355. package/dist/chunk-BJRTMNCB.js.map +0 -1
  356. package/dist/chunk-BRLXOZLM.js.map +0 -1
  357. package/dist/chunk-BSACVS6R.js +0 -621
  358. package/dist/chunk-BSACVS6R.js.map +0 -1
  359. package/dist/chunk-DKAA2IHQ.js +0 -3644
  360. package/dist/chunk-DKAA2IHQ.js.map +0 -1
  361. package/dist/chunk-E4IRW2FG.js.map +0 -1
  362. package/dist/chunk-E6M225BJ.js.map +0 -1
  363. package/dist/chunk-EQ4U73UH.js.map +0 -1
  364. package/dist/chunk-ETSJD5IV.js +0 -361
  365. package/dist/chunk-ETSJD5IV.js.map +0 -1
  366. package/dist/chunk-F55YQP7N.js +0 -336
  367. package/dist/chunk-F55YQP7N.js.map +0 -1
  368. package/dist/chunk-FHGWKODN.js +0 -2300
  369. package/dist/chunk-FHGWKODN.js.map +0 -1
  370. package/dist/chunk-FLRP63GU.js +0 -32219
  371. package/dist/chunk-FLRP63GU.js.map +0 -1
  372. package/dist/chunk-FSO3G4JJ.js.map +0 -1
  373. package/dist/chunk-ID6JGIMD.js +0 -25
  374. package/dist/chunk-ID6JGIMD.js.map +0 -1
  375. package/dist/chunk-IGLJNHOX.js +0 -62
  376. package/dist/chunk-IGLJNHOX.js.map +0 -1
  377. package/dist/chunk-IPT2OY4B.js.map +0 -1
  378. package/dist/chunk-IUKYFTGW.js.map +0 -1
  379. package/dist/chunk-NBH6K6G5.js.map +0 -1
  380. package/dist/chunk-NTRUKAAE.js +0 -223
  381. package/dist/chunk-NTRUKAAE.js.map +0 -1
  382. package/dist/chunk-OGXXGHW6.js +0 -223
  383. package/dist/chunk-OGXXGHW6.js.map +0 -1
  384. package/dist/chunk-PPCLZ4JU.js +0 -28
  385. package/dist/chunk-PPCLZ4JU.js.map +0 -1
  386. package/dist/chunk-QJPJXCS4.js.map +0 -1
  387. package/dist/chunk-R2LBF4HH.js +0 -729
  388. package/dist/chunk-R2LBF4HH.js.map +0 -1
  389. package/dist/chunk-RHQLIHMB.js.map +0 -1
  390. package/dist/chunk-RRTVGD3J.js +0 -792
  391. package/dist/chunk-RRTVGD3J.js.map +0 -1
  392. package/dist/chunk-SUSW74WU.js.map +0 -1
  393. package/dist/chunk-T6OZW2WR.js.map +0 -1
  394. package/dist/chunk-UDKWFDV2.js.map +0 -1
  395. package/dist/chunk-V7IZKJI3.js +0 -22
  396. package/dist/chunk-V7IZKJI3.js.map +0 -1
  397. package/dist/chunk-X562NQFA.js +0 -10144
  398. package/dist/chunk-X562NQFA.js.map +0 -1
  399. package/dist/chunk-XDSCJOH7.js +0 -3991
  400. package/dist/chunk-XDSCJOH7.js.map +0 -1
  401. package/dist/chunk-YCNIGRRF.js.map +0 -1
  402. package/dist/chunk-ZTTCDQ4I.js +0 -18796
  403. package/dist/chunk-ZTTCDQ4I.js.map +0 -1
  404. /package/dist/{capsule-merge-2IIXFXN5.js.map → capsule-merge-6IDAYTKG.js.map} +0 -0
  405. /package/dist/{chunk-ATPWZ4F7.js.map → chunk-2LMA22UU.js.map} +0 -0
  406. /package/dist/{chunk-RGUUBAT5.js.map → chunk-2WCLTWV2.js.map} +0 -0
  407. /package/dist/{chunk-BQZEGOZ4.js.map → chunk-2YODOG2O.js.map} +0 -0
  408. /package/dist/{chunk-WYG5UNDY.js.map → chunk-3AUDELZL.js.map} +0 -0
  409. /package/dist/{chunk-N4KAE2NB.js.map → chunk-3CYOCE6U.js.map} +0 -0
  410. /package/dist/{chunk-MB6ZJDN6.js.map → chunk-3FBAEPCU.js.map} +0 -0
  411. /package/dist/{chunk-PIITB2YZ.js.map → chunk-3ZS3NUEI.js.map} +0 -0
  412. /package/dist/{chunk-ANZZLRUX.js.map → chunk-4IVRQMZW.js.map} +0 -0
  413. /package/dist/{chunk-63E37JCN.js.map → chunk-4RAJT5L2.js.map} +0 -0
  414. /package/dist/{chunk-45VUHDV2.js.map → chunk-5CO5G4MN.js.map} +0 -0
  415. /package/dist/{chunk-LUJCQQ3L.js.map → chunk-65HWAQ4F.js.map} +0 -0
  416. /package/dist/{chunk-T67LUYCR.js.map → chunk-77NTFICT.js.map} +0 -0
  417. /package/dist/{chunk-UE6RRXMF.js.map → chunk-A4F7OIC5.js.map} +0 -0
  418. /package/dist/{chunk-U6UNF5ZS.js.map → chunk-B33YWUJV.js.map} +0 -0
  419. /package/dist/{chunk-RRJBDXAQ.js.map → chunk-B377OKUP.js.map} +0 -0
  420. /package/dist/{chunk-ETZLQOUR.js.map → chunk-BGHCSLE5.js.map} +0 -0
  421. /package/dist/{chunk-YYOMGOHB.js.map → chunk-BOK6BN5M.js.map} +0 -0
  422. /package/dist/{chunk-OH7QLI6W.js.map → chunk-BPPUH5JM.js.map} +0 -0
  423. /package/dist/{chunk-4J363OAA.js.map → chunk-BTI4C4MA.js.map} +0 -0
  424. /package/dist/{chunk-O6ZSWHVR.js.map → chunk-C2KE5DMD.js.map} +0 -0
  425. /package/dist/{chunk-47F6WWLQ.js.map → chunk-C73N66PR.js.map} +0 -0
  426. /package/dist/{chunk-E3A7ELSG.js.map → chunk-CGJYL633.js.map} +0 -0
  427. /package/dist/{chunk-WRT7GJ2D.js.map → chunk-CIWMTNHW.js.map} +0 -0
  428. /package/dist/{chunk-O55EKIEC.js.map → chunk-D3ZKHLN2.js.map} +0 -0
  429. /package/dist/{chunk-CD4BCCNP.js.map → chunk-DJ7WVEWX.js.map} +0 -0
  430. /package/dist/{chunk-PWXPRVLK.js.map → chunk-EFL24KOI.js.map} +0 -0
  431. /package/dist/{chunk-4CJTQHEG.js.map → chunk-ESLOLCD4.js.map} +0 -0
  432. /package/dist/{chunk-6F42QONS.js.map → chunk-ETBVCRVL.js.map} +0 -0
  433. /package/dist/{chunk-VILPVT4S.js.map → chunk-EZ47HOJ6.js.map} +0 -0
  434. /package/dist/{chunk-EFYN5I7Z.js.map → chunk-F4QFU5IZ.js.map} +0 -0
  435. /package/dist/{chunk-7W3RXOIG.js.map → chunk-FMKILENU.js.map} +0 -0
  436. /package/dist/{chunk-YLXETSAH.js.map → chunk-GCZJ7XRI.js.map} +0 -0
  437. /package/dist/{chunk-QFEDITXM.js.map → chunk-JNDMIAJ4.js.map} +0 -0
  438. /package/dist/{chunk-E5PPE4VA.js.map → chunk-K2VRKCPA.js.map} +0 -0
  439. /package/dist/{chunk-MKRYQROF.js.map → chunk-LGEHAQHK.js.map} +0 -0
  440. /package/dist/{chunk-XYTQJD7F.js.map → chunk-LMJVP5CM.js.map} +0 -0
  441. /package/dist/{chunk-FQKBJJYB.js.map → chunk-LPV72KRQ.js.map} +0 -0
  442. /package/dist/{chunk-2LCRG2YV.js.map → chunk-M2XR6B6V.js.map} +0 -0
  443. /package/dist/{chunk-P4WNBSTW.js.map → chunk-MH632KPO.js.map} +0 -0
  444. /package/dist/{chunk-ZU5JDLOH.js.map → chunk-MMRTPH3J.js.map} +0 -0
  445. /package/dist/{chunk-PMJFRDJI.js.map → chunk-MUX7IL77.js.map} +0 -0
  446. /package/dist/{chunk-HF3BKUVV.js.map → chunk-NAQ4A5IX.js.map} +0 -0
  447. /package/dist/{chunk-TVIVY7KU.js.map → chunk-NED7IR7B.js.map} +0 -0
  448. /package/dist/{chunk-6F5MJFXY.js.map → chunk-NHVAX7MH.js.map} +0 -0
  449. /package/dist/{chunk-TG3R2SID.js.map → chunk-NMGHGTVR.js.map} +0 -0
  450. /package/dist/{chunk-NGHDW6UU.js.map → chunk-NUQEREIP.js.map} +0 -0
  451. /package/dist/{chunk-5IIQU4JZ.js.map → chunk-OB72KNMF.js.map} +0 -0
  452. /package/dist/{chunk-JV4S6VDH.js.map → chunk-OJXJWNFY.js.map} +0 -0
  453. /package/dist/{chunk-Z7JIZ42P.js.map → chunk-PRAUN6PN.js.map} +0 -0
  454. /package/dist/{chunk-RWGRSKN5.js.map → chunk-PT4DZDJA.js.map} +0 -0
  455. /package/dist/{chunk-7EPY3IQL.js.map → chunk-PZJQ46DH.js.map} +0 -0
  456. /package/dist/{chunk-MXHMNKWG.js.map → chunk-QDESY76F.js.map} +0 -0
  457. /package/dist/{chunk-I6QGI65T.js.map → chunk-QRMG4HK4.js.map} +0 -0
  458. /package/dist/{chunk-ZU3NJNO7.js.map → chunk-QSF5SJAM.js.map} +0 -0
  459. /package/dist/{chunk-5IYOKDM4.js.map → chunk-R23JWJD3.js.map} +0 -0
  460. /package/dist/{chunk-7GLJMDEQ.js.map → chunk-RM2YUFH6.js.map} +0 -0
  461. /package/dist/{chunk-RIMK327Y.js.map → chunk-SGQPR5SX.js.map} +0 -0
  462. /package/dist/{chunk-ZGFLIK5H.js.map → chunk-SPAKBUJY.js.map} +0 -0
  463. /package/dist/{chunk-ER7XANP3.js.map → chunk-SQ3GEIEL.js.map} +0 -0
  464. /package/dist/{chunk-BLJT6JP2.js.map → chunk-SVT5IA2H.js.map} +0 -0
  465. /package/dist/{chunk-GVGAO3WV.js.map → chunk-TJ4F6H4H.js.map} +0 -0
  466. /package/dist/{chunk-R6HMAIKM.js.map → chunk-TOSPNM4T.js.map} +0 -0
  467. /package/dist/{chunk-HH5LY6RR.js.map → chunk-TRQE3RYR.js.map} +0 -0
  468. /package/dist/{chunk-RMXS4I66.js.map → chunk-TVDJEUV5.js.map} +0 -0
  469. /package/dist/{chunk-PLCYKAWH.js.map → chunk-TYRWSE4B.js.map} +0 -0
  470. /package/dist/{chunk-IQWUACVG.js.map → chunk-UHMHJX5G.js.map} +0 -0
  471. /package/dist/{chunk-YODUDA6R.js.map → chunk-UN4RVUG2.js.map} +0 -0
  472. /package/dist/{chunk-E6Z4FBX6.js.map → chunk-V2QSNFCT.js.map} +0 -0
  473. /package/dist/{chunk-E7YZXWIS.js.map → chunk-WKSQTMU7.js.map} +0 -0
  474. /package/dist/{chunk-RIZ5NUNN.js.map → chunk-WQ4XKIOX.js.map} +0 -0
  475. /package/dist/{chunk-QEYTRFR3.js.map → chunk-X26YOFGS.js.map} +0 -0
  476. /package/dist/{chunk-ITHZFHST.js.map → chunk-X2BVB74H.js.map} +0 -0
  477. /package/dist/{chunk-XYKBWTWI.js.map → chunk-XIYLWEXC.js.map} +0 -0
  478. /package/dist/{chunk-IBJ6U753.js.map → chunk-XKZBZOKV.js.map} +0 -0
  479. /package/dist/{chunk-65AUYLU3.js.map → chunk-XPXHQI6N.js.map} +0 -0
  480. /package/dist/{chunk-EXHXJETE.js.map → chunk-XRDYRWZI.js.map} +0 -0
  481. /package/dist/{chunk-2JSDPUKD.js.map → chunk-YMFPFXEX.js.map} +0 -0
  482. /package/dist/{chunk-645WOU5I.js.map → chunk-ZDZJNXL6.js.map} +0 -0
  483. /package/dist/{chunk-6TCXIRP5.js.map → chunk-ZKE4CO6B.js.map} +0 -0
  484. /package/dist/{chunk-FNXQZGUS.js.map → chunk-ZSE774RV.js.map} +0 -0
  485. /package/dist/{contradiction-scan-P2MHYFVG.js.map → contradiction-scan-IBPYGQZF.js.map} +0 -0
  486. /package/dist/{resolution-N7H3F2E4.js.map → resolution-OVVIF7ZY.js.map} +0 -0
@@ -2,14 +2,14 @@ import {
2
2
  gatherAcrossReadSessions,
3
3
  resolveLcmReadSessionIds
4
4
  } from "./chunk-YVVQUAOO.js";
5
- import {
6
- buildEvidencePack,
7
- insertAfterEvidenceHeading
8
- } from "./chunk-DGFU5MSX.js";
9
5
  import {
10
6
  isSameLcmRow,
11
7
  lcmEvidenceIdentity
12
8
  } from "./chunk-C37ZRXX7.js";
9
+ import {
10
+ buildEvidencePack,
11
+ insertAfterEvidenceHeading
12
+ } from "./chunk-DGFU5MSX.js";
13
13
 
14
14
  // src/focused-list-recall.ts
15
15
  var DEFAULT_MAX_SEARCH_RESULTS = 40;
@@ -923,4 +923,4 @@ export {
923
923
  shouldRecallFocusedListEvidence,
924
924
  buildFocusedListRecallSection
925
925
  };
926
- //# sourceMappingURL=chunk-OH7QLI6W.js.map
926
+ //# sourceMappingURL=chunk-BPPUH5JM.js.map
@@ -2,7 +2,7 @@ import {
2
2
  WHO_KNOWS_DEFAULT_LIMIT,
3
3
  WHO_KNOWS_MAX_LIMIT,
4
4
  validateWhoKnowsInput
5
- } from "./chunk-EXHXJETE.js";
5
+ } from "./chunk-XRDYRWZI.js";
6
6
 
7
7
  // src/who-knows-cli.ts
8
8
  function extractWhoKnowsRawArgs(rest) {
@@ -74,4 +74,4 @@ export {
74
74
  renderWhoKnowsText,
75
75
  renderWhoKnows
76
76
  };
77
- //# sourceMappingURL=chunk-4J363OAA.js.map
77
+ //# sourceMappingURL=chunk-BTI4C4MA.js.map
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  parseTaskLlmConfig
3
3
  } from "./chunk-SK7D34OL.js";
4
- import {
5
- parseBackgroundGeneration
6
- } from "./chunk-27NO2KVB.js";
7
4
  import {
8
5
  coerceNumber
9
6
  } from "./chunk-PQVCH2AE.js";
7
+ import {
8
+ parseBackgroundGeneration
9
+ } from "./chunk-27NO2KVB.js";
10
10
  import {
11
11
  readEnvVar
12
12
  } from "./chunk-P2QRMMVQ.js";
@@ -55,4 +55,4 @@ function parseLocalLlmConfig(cfg, localLlmApiKeyEnv, resolveEnvVars) {
55
55
  export {
56
56
  parseLocalLlmConfig
57
57
  };
58
- //# sourceMappingURL=chunk-O6ZSWHVR.js.map
58
+ //# sourceMappingURL=chunk-C2KE5DMD.js.map
@@ -5,7 +5,7 @@ import {
5
5
  } from "./chunk-TBBDFYXW.js";
6
6
  import {
7
7
  hasLiveSupportPassportCard
8
- } from "./chunk-YCNIGRRF.js";
8
+ } from "./chunk-NS7U4ZYU.js";
9
9
 
10
10
  // src/tier-routing.ts
11
11
  function requiresHotTier(memory) {
@@ -80,4 +80,4 @@ export {
80
80
  computeTierValueScore,
81
81
  decideTierTransition
82
82
  };
83
- //# sourceMappingURL=chunk-47F6WWLQ.js.map
83
+ //# sourceMappingURL=chunk-C73N66PR.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  StorageManager
3
- } from "./chunk-FSO3G4JJ.js";
3
+ } from "./chunk-WQURALGV.js";
4
4
  import {
5
5
  isSafeRouteNamespace
6
6
  } from "./chunk-PCXDUHQH.js";
@@ -416,4 +416,4 @@ export {
416
416
  resolveNamespaceStorageRoot,
417
417
  NamespaceStorageRouter
418
418
  };
419
- //# sourceMappingURL=chunk-E3A7ELSG.js.map
419
+ //# sourceMappingURL=chunk-CGJYL633.js.map
@@ -1,3 +1,6 @@
1
+ import {
2
+ ExtractionDeadlineError
3
+ } from "./chunk-S3S72HRM.js";
1
4
  import {
2
5
  BufferAdmissionRefusedError,
3
6
  canAdmitNewEntryUnlocked
@@ -11,9 +14,6 @@ import {
11
14
  import {
12
15
  scanSignals
13
16
  } from "./chunk-H3FZVNRN.js";
14
- import {
15
- ExtractionDeadlineError
16
- } from "./chunk-AP6NCP3V.js";
17
17
  import {
18
18
  bufferEntryCounts,
19
19
  bufferTurnArrayIsSuffixOfSnapshot,
@@ -926,4 +926,4 @@ var SmartBuffer = class {
926
926
  export {
927
927
  SmartBuffer
928
928
  };
929
- //# sourceMappingURL=chunk-WRT7GJ2D.js.map
929
+ //# sourceMappingURL=chunk-CIWMTNHW.js.map
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  applyExtractionSourceGrounding,
3
3
  filterExtractionResultBySource
4
- } from "./chunk-RWGRSKN5.js";
4
+ } from "./chunk-PT4DZDJA.js";
5
5
  import {
6
6
  delinearize
7
7
  } from "./chunk-VEWZZM3H.js";
@@ -79,4 +79,4 @@ export {
79
79
  attachExtractionProvenance,
80
80
  filterExtractionResultBySource2 as filterExtractionResultBySource
81
81
  };
82
- //# sourceMappingURL=chunk-O55EKIEC.js.map
82
+ //# sourceMappingURL=chunk-D3ZKHLN2.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  ACTIVE_STATUSES
3
- } from "./chunk-RMXS4I66.js";
3
+ } from "./chunk-TVDJEUV5.js";
4
4
 
5
5
  // src/recall-why.ts
6
6
  var RECALL_WHY_STAGES = Object.freeze(["retrieval", "policy-filter", "rerank", "cap", "format"]);
@@ -316,4 +316,4 @@ export {
316
316
  RecallWhyInputError,
317
317
  explainRecallMiss
318
318
  };
319
- //# sourceMappingURL=chunk-CD4BCCNP.js.map
319
+ //# sourceMappingURL=chunk-DJ7WVEWX.js.map
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  rebuildMemoryProjection,
3
3
  watchProjectionRebuildParent
4
- } from "./chunk-HF3BKUVV.js";
4
+ } from "./chunk-NAQ4A5IX.js";
5
5
  import {
6
6
  initLogger,
7
7
  log
@@ -77,4 +77,4 @@ if (invokedAsRunner) {
77
77
  export {
78
78
  PROJECTION_REBUILD_RUNNER_FLAG
79
79
  };
80
- //# sourceMappingURL=chunk-PWXPRVLK.js.map
80
+ //# sourceMappingURL=chunk-EFL24KOI.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  isGenericRecallExcludedPath
3
- } from "./chunk-EFYN5I7Z.js";
3
+ } from "./chunk-F4QFU5IZ.js";
4
4
  import {
5
5
  normalizeProjectionPreview
6
6
  } from "./chunk-SCU65EZI.js";
@@ -9,7 +9,7 @@ import {
9
9
  } from "./chunk-7RJUVTVF.js";
10
10
  import {
11
11
  isSupportPassportPrivateMemory
12
- } from "./chunk-YCNIGRRF.js";
12
+ } from "./chunk-NS7U4ZYU.js";
13
13
  import {
14
14
  RECALL_FALLBACK_DIRS
15
15
  } from "./chunk-VS2IYZRU.js";
@@ -209,4 +209,4 @@ export {
209
209
  browsePatternMatches,
210
210
  runMemoryBrowse
211
211
  };
212
- //# sourceMappingURL=chunk-4CJTQHEG.js.map
212
+ //# sourceMappingURL=chunk-ESLOLCD4.js.map
@@ -1,11 +1,11 @@
1
+ import {
2
+ runPostConsolidationMaterialize
3
+ } from "./chunk-PRAUN6PN.js";
1
4
  import {
2
5
  discoverMemoryExtensions,
3
6
  renderExtensionsBlock,
4
7
  resolveExtensionsRoot
5
8
  } from "./chunk-5JMAGU26.js";
6
- import {
7
- runPostConsolidationMaterialize
8
- } from "./chunk-Z7JIZ42P.js";
9
9
  import {
10
10
  isSemanticConsolidationLlmOperator
11
11
  } from "./chunk-G7D6GZ5J.js";
@@ -220,4 +220,4 @@ export {
220
220
  buildExtensionsBlockForConsolidation,
221
221
  materializeAfterSemanticConsolidation
222
222
  };
223
- //# sourceMappingURL=chunk-6F42QONS.js.map
223
+ //# sourceMappingURL=chunk-ETBVCRVL.js.map
@@ -4,13 +4,13 @@ import {
4
4
  import {
5
5
  launchProcess
6
6
  } from "./chunk-ZEFVK7XC.js";
7
- import {
8
- mergeEnv
9
- } from "./chunk-P2QRMMVQ.js";
10
7
  import {
11
8
  abortError,
12
9
  throwIfAborted
13
10
  } from "./chunk-R2MBW2S4.js";
11
+ import {
12
+ mergeEnv
13
+ } from "./chunk-P2QRMMVQ.js";
14
14
  import {
15
15
  log
16
16
  } from "./chunk-3WCASNQZ.js";
@@ -309,4 +309,4 @@ var QmdDaemonSession = class {
309
309
  export {
310
310
  QmdDaemonSession
311
311
  };
312
- //# sourceMappingURL=chunk-VILPVT4S.js.map
312
+ //# sourceMappingURL=chunk-EZ47HOJ6.js.map
@@ -3,7 +3,7 @@ import {
3
3
  isArtifactMemoryPath,
4
4
  isLocationDayPath,
5
5
  isMeetingRecordPath
6
- } from "./chunk-YYOMGOHB.js";
6
+ } from "./chunk-BOK6BN5M.js";
7
7
  import {
8
8
  isExternalWikiCollectionName
9
9
  } from "./chunk-JV3C2MNQ.js";
@@ -228,4 +228,4 @@ export {
228
228
  isGenericRecallExcludedPath,
229
229
  filterRecallCandidates
230
230
  };
231
- //# sourceMappingURL=chunk-EFYN5I7Z.js.map
231
+ //# sourceMappingURL=chunk-F4QFU5IZ.js.map
@@ -11,6 +11,11 @@ function isAbortError(err) {
11
11
  const maybe = err;
12
12
  return maybe.name === "AbortError" || maybe.message === "This operation was aborted" || maybe.message === "The operation was aborted";
13
13
  }
14
+ function combineClientAbortSignals(caller, shutdown) {
15
+ if (shutdown === void 0) return caller;
16
+ if (caller === void 0) return shutdown;
17
+ return AbortSignal.any([caller, shutdown]);
18
+ }
14
19
  function waitForRetryBackoff(backoffMs, signal) {
15
20
  return new Promise((resolve) => {
16
21
  let settled = false;
@@ -152,6 +157,7 @@ var SingleFlightProbe = class {
152
157
 
153
158
  export {
154
159
  isAbortError,
160
+ combineClientAbortSignals,
155
161
  waitForRetryBackoff,
156
162
  normalizeBackendTripReason,
157
163
  extractNonRecoverableBackendReason,
@@ -161,4 +167,4 @@ export {
161
167
  probeFetch,
162
168
  SingleFlightProbe
163
169
  };
164
- //# sourceMappingURL=chunk-T6OZW2WR.js.map
170
+ //# sourceMappingURL=chunk-FA7SLQ5X.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/local-llm-helpers.ts"],"sourcesContent":["import type { ResponseFormatJSONSchema } from \"openai/resources/shared\";\nimport type { Agent } from \"undici\";\nimport { log } from \"./logger.js\";\nimport { directProbeDispatcher } from \"./local-llm-transport.js\";\nimport type { LocalLlmRequestPriority } from \"./local-llm.js\";\n\nexport interface LocalLlmChatCompletionOptions {\n temperature?: number;\n maxTokens?: number;\n responseFormat?: { type: string } | ResponseFormatJSONSchema;\n timeoutMs?: number;\n operation?: string;\n forceDisableThinking?: boolean;\n disableThinking?: boolean;\n priority?: LocalLlmRequestPriority;\n signal?: AbortSignal;\n redactProviderErrors?: boolean;\n /** Per-request model; defaults to config.localLlmModel. */\n model?: string;\n /**\n * Optional out-box for the terminal failure cause (issue #2891): on a\n * failed request the client records the last provider error here so\n * callers can classify it (e.g. HTTP 429 → rate-limited) in memory\n * instead of seeing only null. Never logged.\n */\n failureDiag?: { lastError?: unknown };\n}\n\nexport interface LocalLlmChatCompletionResult {\n content: string;\n usage?: { promptTokens: number; completionTokens: number; totalTokens: number };\n}\nexport function isAbortError(err: unknown): boolean {\n if (!err || typeof err !== \"object\") return false;\n const maybe = err as { name?: string; message?: string };\n return (\n maybe.name === \"AbortError\" ||\n maybe.message === \"This operation was aborted\" ||\n maybe.message === \"The operation was aborted\"\n );\n}\n\n/** Caller signal combined with a client-wide shutdown signal, so a daemon\n * stop aborts in-flight requests and retry loops at once — even for\n * callers that pass no signal of their own. */\nexport function combineClientAbortSignals(\n caller: AbortSignal | undefined,\n shutdown: AbortSignal | undefined,\n): AbortSignal | undefined {\n if (shutdown === undefined) return caller;\n if (caller === undefined) return shutdown;\n return AbortSignal.any([caller, shutdown]);\n}\n\nexport function waitForRetryBackoff(backoffMs: number, signal?: AbortSignal): Promise<boolean> {\n return new Promise((resolve) => {\n let settled = false;\n let timer: NodeJS.Timeout | undefined;\n const onAbort = (): void => {\n if (settled) return;\n settled = true;\n if (timer) clearTimeout(timer);\n signal?.removeEventListener(\"abort\", onAbort);\n resolve(false);\n };\n const onTimer = (): void => {\n if (settled) return;\n settled = true;\n signal?.removeEventListener(\"abort\", onAbort);\n resolve(true);\n };\n timer = setTimeout(onTimer, backoffMs);\n if (signal) {\n if (signal.aborted) onAbort();\n else signal.addEventListener(\"abort\", onAbort, { once: true });\n }\n });\n}\n\nexport function normalizeBackendTripReason(reason: string): string {\n const cleaned = reason.replace(/\\s+/g, \" \").replace(/^[-:–—\\s]+/, \"\").trim();\n if (!cleaned) return \"unknown local backend failure\";\n return cleaned.length > 160 ? `${cleaned.slice(0, 157)}...` : cleaned;\n}\n\nexport function extractNonRecoverableBackendReason(reason: string): string | null {\n const match = reason.match(\n /Failed to load model|Library not loaded|different Team IDs|code signature|llm_engine_mlx_amphibian/i,\n );\n return match?.[0] ?? null;\n}\n\nexport function extractNonRecoverableBackendReasonFromErrorText(errorText: string): string | null {\n const directReason = extractNonRecoverableBackendReason(errorText);\n if (directReason) return directReason;\n try {\n const parsed = JSON.parse(errorText) as { error?: { message?: string } };\n return extractNonRecoverableBackendReason(parsed?.error?.message ?? \"\");\n } catch {\n return null;\n }\n}\n\n/**\n * Flatten a fetch rejection into one line, including the `cause` undici hides\n * the real reason behind (`fetch failed` alone says nothing).\n */\nexport function describeFetchFailure(err: unknown): string {\n const name = err instanceof Error ? err.name : \"\";\n const message = err instanceof Error ? err.message : String(err);\n const cause: unknown = err instanceof Error ? (err as Error & { cause?: unknown }).cause : undefined;\n const causeText = cause instanceof Error\n ? ` (cause: ${cause.name}: ${cause.message}${\n typeof (cause as Error & { code?: unknown }).code === \"string\"\n ? ` [${String((cause as Error & { code?: unknown }).code)}]`\n : \"\"\n })`\n : cause === undefined\n ? \"\"\n : ` (cause: ${String(cause)})`;\n return `${name ? `${name}: ` : \"\"}${message}${causeText}`;\n}\n\n/**\n * What to record when every availability probe failed.\n *\n * A probe that TIMED OUT is not evidence the backend is down: the budget is a\n * fixed 2s and a busy event loop can burn it before the socket is scheduled,\n * so the backend looks dead while it answers other callers in single-digit ms.\n * Caching that verdict took extraction offline for a whole health-check\n * interval at a time (issue #2210), so a timeout leaves availability UNKNOWN —\n * this call fails, the next one re-probes instead of reading a stale false.\n *\n * A backend that ANSWERED and said no is a real verdict and stays cached, or\n * the daemon re-probes a known-bad endpoint on every request.\n */\nexport function resolveUnavailableVerdict(args: {\n baseUrl: string;\n sawAbortedProbe: boolean;\n wasAvailable: boolean | null;\n}): { cacheVerdict: boolean; warning: string | null } {\n if (args.sawAbortedProbe) {\n return {\n cacheVerdict: false,\n warning:\n `local LLM availability probe timed out at ${args.baseUrl} (event loop busy?); treating availability as ` +\n \"unknown and re-probing on the next request rather than marking the backend down\",\n };\n }\n return {\n cacheVerdict: true,\n // Surfaced at warn, not debug: extraction stops silently when this flips,\n // and the daemon emits no debug at all unless configured for it.\n warning: args.wasAvailable !== false ? `local LLM became unavailable at ${args.baseUrl}` : null,\n };\n}\n\nexport interface ProbeFetchResult {\n ok: boolean;\n data: unknown;\n status: number | null;\n /** The probe hit its own budget rather than getting an answer. */\n aborted?: boolean;\n}\n\n/**\n * One health-probe request.\n *\n * Every failure is logged with its cause: a transport error and a 404 both\n * returned `ok: false` with nothing recorded, so an unreachable backend was\n * indistinguishable from a wrong path and an availability failure had no\n * diagnosable reason at all (§22, issue #2210).\n */\nexport async function probeFetch(\n url: string,\n options: { timeoutMs: number; headers: Record<string, string>; signal?: AbortSignal },\n): Promise<ProbeFetchResult> {\n const controller = new AbortController();\n const requestSignal = options.signal\n ? AbortSignal.any([options.signal, controller.signal])\n : controller.signal;\n const timeout = setTimeout(() => controller.abort(), options.timeoutMs);\n try {\n const init: RequestInit & { dispatcher?: Agent } = { signal: requestSignal, headers: options.headers };\n const dispatcher = directProbeDispatcher();\n if (dispatcher) init.dispatcher = dispatcher;\n const response = await fetch(url, init);\n clearTimeout(timeout);\n if (!response.ok) {\n log.debug(`local LLM probe: ${url} returned HTTP ${response.status}`);\n return { ok: false, data: null, status: response.status };\n }\n const contentType = response.headers.get(\"content-type\");\n const data = contentType?.includes(\"application/json\") ? await response.json() : await response.text();\n return { ok: true, data, status: response.status };\n } catch (err) {\n clearTimeout(timeout);\n const aborted = isAbortError(err);\n log.debug(\n `local LLM probe: ${url} ${aborted ? `timed out after ${options.timeoutMs}ms` : \"failed\"}: ${describeFetchFailure(err)}`,\n );\n return { ok: false, data: null, status: null, aborted };\n }\n}\n\ninterface PendingProbe {\n promise: Promise<boolean>;\n controller: AbortController;\n /** Callers still awaiting this sequence; at zero the sequence is aborted. */\n waiters: number;\n}\n\n/**\n * Collapses concurrent probe sequences onto one in-flight run.\n *\n * A timed-out availability probe deliberately caches nothing (issue #2210),\n * which removed the false verdict that used to absorb concurrent callers:\n * every queued request would then run its own full probe sequence, on a host\n * already slow enough to blow the probe budget.\n *\n * Cancellation is refcounted rather than shared: one caller walking away must\n * not abort a sequence the others are still waiting on, so the underlying task\n * is aborted only once every waiter has gone.\n */\nexport class SingleFlightProbe {\n private pending: PendingProbe | null = null;\n\n run(task: (signal: AbortSignal) => Promise<boolean>, signal?: AbortSignal): Promise<boolean> {\n let active = this.pending;\n if (!active) {\n const controller = new AbortController();\n const created: PendingProbe = { promise: Promise.resolve(false), controller, waiters: 0 };\n created.promise = task(controller.signal).finally(() => {\n if (this.pending === created) this.pending = null;\n });\n this.pending = created;\n active = created;\n }\n const entry = active;\n entry.waiters += 1;\n let released = false;\n const release = () => {\n if (released) return;\n released = true;\n entry.waiters -= 1;\n if (entry.waiters > 0) return;\n // Detach BEFORE aborting. `pending` would otherwise still point at this\n // doomed entry until the task's own `finally` runs a microtask later, and\n // a caller arriving in that window would join an aborted sequence and\n // read its `false` as a verdict.\n if (this.pending === entry) this.pending = null;\n entry.controller.abort();\n };\n if (!signal) return entry.promise.finally(release);\n return new Promise<boolean>((resolve, reject) => {\n const onAbort = () => {\n release();\n resolve(false);\n };\n signal.addEventListener(\"abort\", onAbort, { once: true });\n entry.promise.then(\n (value) => {\n signal.removeEventListener(\"abort\", onAbort);\n release();\n resolve(value);\n },\n (err: unknown) => {\n signal.removeEventListener(\"abort\", onAbort);\n release();\n reject(err instanceof Error ? err : new Error(String(err)));\n },\n );\n });\n }\n}\n"],"mappings":"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","names":[]}
@@ -1,9 +1,12 @@
1
+ import {
2
+ rebuildMemoryLifecycleLedger
3
+ } from "./chunk-WKSQTMU7.js";
1
4
  import {
2
5
  PROJECTION_REBUILD_RUNNER_FLAG
3
- } from "./chunk-PWXPRVLK.js";
6
+ } from "./chunk-EFL24KOI.js";
4
7
  import {
5
8
  startLocationAutoSync
6
- } from "./chunk-2FGLEF7C.js";
9
+ } from "./chunk-ATG2PQ4V.js";
7
10
  import {
8
11
  ensureContradictionScanCron,
9
12
  ensureDaySummaryCron,
@@ -18,17 +21,17 @@ import {
18
21
  isIsoWeekId,
19
22
  msUntilNextIsoWeek,
20
23
  previousIsoWeekId
21
- } from "./chunk-ATPWZ4F7.js";
22
- import {
23
- rebuildMemoryLifecycleLedger
24
- } from "./chunk-E7YZXWIS.js";
24
+ } from "./chunk-2LMA22UU.js";
25
25
  import {
26
26
  planNamespaceMaintenance,
27
27
  runNamespaceMaintenanceBatchPlan
28
- } from "./chunk-R2LBF4HH.js";
28
+ } from "./chunk-5YT2IIFX.js";
29
29
  import {
30
30
  rebuildMemoryProjection
31
- } from "./chunk-HF3BKUVV.js";
31
+ } from "./chunk-NAQ4A5IX.js";
32
+ import {
33
+ LocalLlmClient
34
+ } from "./chunk-RQFXZYTF.js";
32
35
  import {
33
36
  DEFAULT_TIMELINE_CATEGORIES,
34
37
  TIMELINE_RESERVED_IDLE,
@@ -43,15 +46,12 @@ import {
43
46
  import {
44
47
  DEFAULT_PROJECTION_REBUILD_HEAP_USAGE_LIMIT
45
48
  } from "./chunk-EWMRFW3F.js";
46
- import {
47
- LocalLlmClient
48
- } from "./chunk-IPT2OY4B.js";
49
49
  import {
50
50
  FallbackLlmClient
51
- } from "./chunk-ZU5JDLOH.js";
51
+ } from "./chunk-MMRTPH3J.js";
52
52
  import {
53
53
  fallbackLlmRuntimeContextFromConfig
54
- } from "./chunk-ZU3NJNO7.js";
54
+ } from "./chunk-QSF5SJAM.js";
55
55
  import {
56
56
  STATE_FILE_MAX_DECRYPT_BYTES,
57
57
  drainPendingLifecycleLedgerIfAny,
@@ -2874,4 +2874,4 @@ export {
2874
2874
  ActivitySyncScheduler,
2875
2875
  MaintenanceScheduler
2876
2876
  };
2877
- //# sourceMappingURL=chunk-7W3RXOIG.js.map
2877
+ //# sourceMappingURL=chunk-FMKILENU.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  lcmSessionKeyForNamespace
3
- } from "./chunk-63E37JCN.js";
3
+ } from "./chunk-4RAJT5L2.js";
4
4
  import {
5
5
  log
6
6
  } from "./chunk-3WCASNQZ.js";
@@ -77,4 +77,4 @@ export {
77
77
  observeTranscriptSessionKey,
78
78
  ObserveTranscriptPersister
79
79
  };
80
- //# sourceMappingURL=chunk-YLXETSAH.js.map
80
+ //# sourceMappingURL=chunk-GCZJ7XRI.js.map
@@ -1,21 +1,19 @@
1
1
  import {
2
2
  ExtractionDrain,
3
- TurnIngestionCoordinator
4
- } from "./chunk-FLRP63GU.js";
3
+ TurnIngestionCoordinator,
4
+ shouldSkipImplicitExtraction
5
+ } from "./chunk-YKJBSMMP.js";
5
6
  import {
6
7
  headerConnector,
7
8
  renderExtractionConversation,
8
9
  resolveSourceConnector
9
- } from "./chunk-7HTUYFR3.js";
10
+ } from "./chunk-LLPMMMWG.js";
10
11
  import {
11
12
  SmartBuffer
12
- } from "./chunk-WRT7GJ2D.js";
13
- import {
14
- shouldSkipImplicitExtraction
15
- } from "./chunk-RRTVGD3J.js";
13
+ } from "./chunk-CIWMTNHW.js";
16
14
  import {
17
15
  selfDeps
18
- } from "./chunk-FSO3G4JJ.js";
16
+ } from "./chunk-WQURALGV.js";
19
17
  import {
20
18
  describeError,
21
19
  groupTurnsByExtractionScope
@@ -449,4 +447,4 @@ export {
449
447
  ClaimBufferStorage,
450
448
  BufferDrainRunner
451
449
  };
452
- //# sourceMappingURL=chunk-5HFXGXE5.js.map
450
+ //# sourceMappingURL=chunk-GQXOBKPL.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/orchestration/buffer-drain-runner.ts"],"sourcesContent":["/** Claim-backed extraction-buffer drain (`remnic buffer drain` worker AND the */\n\nimport { hostname } from \"node:os\";\nimport type { BufferStorage } from \"../buffer-persistence.js\";\nimport { type ExtractionScopeGroup, describeError, groupTurnsByExtractionScope } from \"../buffer-turn-helpers.js\";\nimport { SmartBuffer } from \"../buffer.js\";\nimport { resolveMemoryLifecycleCapabilities } from \"../capabilities.js\";\nimport { shouldSkipImplicitExtraction } from \"../explicit-capture.js\";\nimport { log } from \"../logger.js\";\nimport type { ResolvedScopeProfilePlan } from \"../namespaces/scope-profiles.js\";\nimport type { Orchestrator } from \"../orchestrator.js\";\nimport { headerConnector, renderExtractionConversation, resolveSourceConnector } from \"../source-agent-qualifier.js\";\nimport type { BufferDrainClaims, DrainLease } from \"../storage/buffer-drain-claims.js\";\nimport type { BufferEntryState, BufferState, BufferTurn, PluginConfig } from \"../types.js\";\nimport { ExtractionDrain } from \"./extraction-drain.js\";\nimport type { ExtractionRunResult } from \"./extraction-run.js\";\nimport { selfDeps } from \"./self-deps.js\";\nimport { TurnIngestionCoordinator, type TurnIngestionDeps } from \"./turn-ingestion.js\";\n\nexport type DrainSessionStatus = \"drained\" | \"deferred\" | \"failed\" | \"skipped\";\n\nexport interface DrainSessionOutcome {\n key: string;\n status: DrainSessionStatus;\n /** Turns the claim held when the drain started. */\n turnsAtStart: number;\n /** Turns still in the claim when the drain stopped. */\n turnsRemaining: number;\n /** Facts the extraction persisted during this run. */\n persistedCount: number;\n /** Durable outputs (memories + entities) the extraction wrote. */\n durableOutputCount: number;\n /** Why the session was skipped or deferred (machine-readable). */\n reason?: string;\n /** Current-policy denials: scope groups whose authorization no longer holds. */\n denied?: { reason: string; turns: number }[];\n}\n\n/** Extraction results that mean \"current policy refuses this scope\": the\n * turns are valid backlog whose captured scope is no longer writable. */\nconst DENIED_SCOPE_REASONS: ReadonlySet<string> = new Set([\n \"pinned_namespace_unavailable\",\n \"namespace_write_revoked\",\n \"scope_profile_revoked\",\n // The resolved profile has no writable layer: the same current-policy\n // refusal family, surfaced from inside the shared runExtraction gate.\n \"scope_profile_no_writable_layer\",\n // captureMode=explicit: ordinary buffered conversation turns never create\n // memories; only deliberately accepted captures drain.\n \"capture_mode_explicit\",\n]);\n\nexport interface BufferDrainRunnerOptions {\n /** Identity of this drainer; owns the lease it takes. */\n ownerId: string;\n /** Lease lifetime in ms. The heartbeat keeps it alive while draining. */\n leaseMs?: number;\n /** Cancels the run at the next chunk boundary. */\n signal?: AbortSignal;\n /** Progress callback (per session, and per claim transition). */\n onEvent?: (event: DrainRunnerEvent) => void;\n}\n\n/** A failed drain run: the reason a chunk or the session could not finish. */\nexport type DrainExtractionError = Error;\n\nexport type DrainRunnerEvent =\n | { type: \"session_started\"; key: string; turns: number }\n | { type: \"session_finished\"; key: string; outcome: DrainSessionOutcome };\n\nconst DEFAULT_LEASE_MS = 120_000;\n\n/**\n * A `BufferStorage` view of one drain claim: the claim file IS the buffer.\n * Writes are the drain's progress (what is left to extract), so every\n * successfully extracted chunk is durably removed before the next one runs.\n *\n * `seen` is the drainer's own view of the claim: the entry it loaded, then the\n * entry it last wrote. Each progress write is diffed against it, so a write\n * records only the turns extracted since the previous one.\n */\nexport class ClaimBufferStorage implements BufferStorage {\n private seen: BufferEntryState;\n\n constructor(\n private readonly claims: BufferDrainClaims,\n private readonly key: string,\n private readonly ownerId: string,\n entry: BufferEntryState\n ) {\n this.seen = entry;\n }\n\n async loadBuffer(): Promise<BufferState> {\n const entries: NonNullable<BufferState[\"entries\"]> = Object.create(null);\n entries[this.key] = {\n turns: this.seen.turns,\n retainedTurns: this.seen.retainedTurns,\n lastExtractionAt: this.seen.lastExtractionAt,\n extractionCount: this.seen.extractionCount,\n };\n return {\n turns: this.seen.turns,\n lastExtractionAt: this.seen.lastExtractionAt,\n extractionCount: this.seen.extractionCount,\n entries,\n };\n }\n\n async saveBuffer(state: BufferState): Promise<void> {\n // Whole-state fallback (the claim covers one session): persist the entry.\n const entry = state.entries?.[this.key];\n await this.writeProgress(entry ?? { turns: [], lastExtractionAt: null, extractionCount: 0 });\n }\n\n async saveBufferSession(key: string, entry: BufferEntryState): Promise<void> {\n if (key !== this.key) {\n await this.claims.writeEntry(key, this.ownerId, entry, undefined);\n return;\n }\n await this.writeProgress(entry);\n }\n\n private async writeProgress(entry: BufferEntryState): Promise<void> {\n await this.claims.writeEntry(this.key, this.ownerId, entry, this.seen);\n // Copy the lists: the buffer keeps mutating its own arrays after a save.\n this.seen = { ...entry, turns: [...entry.turns], retainedTurns: entry.retainedTurns ? [...entry.retainedTurns] : undefined };\n }\n\n async deleteBufferSession(): Promise<void> {\n // The claim is removed by the ack path, never by a buffer eviction: the\n // drain decides when the session is finished.\n }\n}\n\n/** Per-invocation isolated execution context for one claim drain. */\ninterface ClaimDrainExecution {\n claimBuffer: SmartBuffer;\n coordinator: TurnIngestionCoordinator;\n executionDrain: ExtractionDrain;\n}\n\n/** The scopeProfileWritePlan option a scope group forwards to the queue. */\ninterface GroupPlanOption {\n scopeProfileWritePlan?: ResolvedScopeProfilePlan | null;\n}\n\n/** Durable counters a drain pass contributed. */\ninterface GroupCounts {\n persistedCount: number;\n durableOutputCount: number;\n}\n\n/** Pending turns across canonical + retained copies (the honest backlog count). */\nfunction pendingTurnCount(entry: BufferEntryState | undefined): number {\n if (!entry) return 0;\n return entry.turns.length + (entry.retainedTurns?.length ?? 0);\n}\n\n/** Load one claimed session. An unclaimed key is nothing to drain. */\nasync function loadClaimedSession(\n claims: BufferDrainClaims,\n key: string\n): Promise<\n | { kind: \"notClaimed\"; notClaimed: DrainSessionOutcome }\n | { kind: \"claimed\"; claim: { entry: BufferEntryState }; turnsAtStart: number }\n> {\n const claim = await claims.load(key);\n if (!claim) {\n return {\n kind: \"notClaimed\",\n notClaimed: {\n key,\n status: \"skipped\",\n turnsAtStart: 0,\n turnsRemaining: 0,\n persistedCount: 0,\n durableOutputCount: 0,\n reason: \"not_claimed\",\n },\n };\n }\n return { kind: \"claimed\", claim, turnsAtStart: pendingTurnCount(claim.entry) };\n}\n\nfunction busyLeaseOutcome(key: string, turnsAtStart: number): DrainSessionOutcome {\n return {\n key,\n status: \"skipped\",\n turnsAtStart,\n turnsRemaining: turnsAtStart,\n persistedCount: 0,\n durableOutputCount: 0,\n reason: \"claimed_by_another_drain\",\n };\n}\n\n/** Take the lease unless this drainer already holds it. A busy lease means\n * another drainer owns the claim — skip without touching content. */\nasync function adoptLease(\n claims: BufferDrainClaims,\n key: string,\n ownerId: string,\n leaseMs: number\n): Promise<DrainSessionOutcome | null> {\n const held = await claims.adopt(key, {\n ownerId,\n pid: process.pid,\n host: hostname(),\n acquiredAt: new Date().toISOString(),\n heartbeatAt: new Date().toISOString(),\n leaseMs,\n });\n return held === \"busy\" ? busyLeaseOutcome(key, pendingTurnCount((await claims.load(key))?.entry)) : null;\n}\n\nfunction assembleOutcome(\n key: string,\n turnsAtStart: number,\n verdict: { status: DrainSessionStatus; reason?: string; turnsRemaining: number },\n counts: { persistedCount: number; durableOutputCount: number },\n denied: Map<string, number>\n): DrainSessionOutcome {\n const outcome: DrainSessionOutcome = {\n key,\n status: verdict.status,\n turnsAtStart,\n turnsRemaining: verdict.turnsRemaining,\n persistedCount: counts.persistedCount,\n durableOutputCount: counts.durableOutputCount,\n };\n if (denied.size > 0) outcome.denied = [...denied].map(([deniedReason, turns]) => ({ reason: deniedReason, turns }));\n if (verdict.reason !== undefined) outcome.reason = verdict.reason;\n return outcome;\n}\n\n/** Ack an EMPTY claim. The ack verdict is the truth: live ingress can merge\n * between the empty read and the ack — a not_empty ack means pending work\n * exists; reload it, release OUR lease, report deferred, never a false\n * drained. */\nasync function ackEmptyClaim(\n claims: BufferDrainClaims,\n key: string,\n ownerId: string,\n turnsAtStart: number\n): Promise<DrainSessionOutcome> {\n const ackOutcome = await claims.ack(key, ownerId);\n if (ackOutcome !== \"acked\") {\n const reloaded = await claims.load(key);\n const turnsRemaining = pendingTurnCount(reloaded?.entry);\n await claims.releaseLease(key, ownerId);\n return {\n key,\n status: \"deferred\",\n turnsAtStart,\n turnsRemaining,\n persistedCount: 0,\n durableOutputCount: 0,\n reason: ackOutcome === \"not_empty\" ? \"ack_not_empty\" : \"ack_not_owner\",\n };\n }\n return { key, status: \"drained\", turnsAtStart, turnsRemaining: 0, persistedCount: 0, durableOutputCount: 0 };\n}\n\n/** another drainer took the claim, so this run must stop instead of writing */\nfunction startLeaseHeartbeat(\n claims: BufferDrainClaims,\n key: string,\n ownerId: string,\n leaseMs: number,\n abort: AbortController\n): NodeJS.Timeout {\n const heartbeat = setInterval(\n () => {\n void claims\n .heartbeat(key, ownerId, leaseMs)\n .then((state) => {\n if (state === \"lost\") abort.abort(new Error(`buffer drain: lease lost for session ${key}`));\n })\n .catch((err: Error) => {\n // A heartbeat that cannot be renewed is a lease that cannot be held:\n // stop this run cleanly at the next chunk boundary (the next run\n // resumes it).\n abort.abort(new Error(`buffer drain: lease heartbeat failed for session ${key}: ${describeError(err)}`));\n });\n },\n Math.max(1_000, Math.floor(leaseMs / 3))\n );\n heartbeat.unref?.();\n return heartbeat;\n}\n\n/** coordinator bound to it, and the no-drop chunked drain. Built per */\nfunction buildClaimExecution(\n orchestrator: Orchestrator,\n claims: BufferDrainClaims,\n key: string,\n ownerId: string,\n claim: { entry: BufferEntryState }\n): ClaimDrainExecution {\n const claimBuffer = new SmartBuffer(orchestrator.config, new ClaimBufferStorage(claims, key, ownerId, claim.entry));\n const isolatedRun = orchestrator.extractionRunCoordinatorForBuffer(claimBuffer);\n const coordinator = new TurnIngestionCoordinator(selfDeps<TurnIngestionDeps>(orchestrator));\n const config = orchestrator.config;\n const ingestionDeps = selfDeps<TurnIngestionDeps>(orchestrator);\n // No-drop: a repeatedly failing chunk stays in the claim as durable\n // retryable backlog — never side-filed, never counted as processed.\n const executionDrain = new ExtractionDrain(\n {\n config: {\n extractionMinUserTurns: config.extractionMinUserTurns,\n extractionMinChars: config.extractionMinChars,\n extractionMaxTurnChars: config.extractionMaxTurnChars,\n extractionChunkDropAfterFailures: config.extractionChunkDropAfterFailures,\n },\n extractionWindowBudgetChars: () => ingestionDeps.extractionWindowBudgetChars?.() ?? Number.POSITIVE_INFINITY,\n // Render-exact chunk sizing: the model clamp bounds the CONVERSATION\n // (truncateLocalExtractionConversation), so measure exactly that —\n // with the SAME source-classification gate extract() applies when it\n // prepends the connector header (header margin included when the\n // engine would render it).\n measureRenderedTurns: (turns) => {\n const sourceConnector = resolveMemoryLifecycleCapabilities(config).extractionScopeClassification\n ? resolveSourceConnector(turns)\n : undefined;\n return renderExtractionConversation(\n turns.map((turn) => ({ ...turn, content: turn.content.trim().slice(0, config.extractionMaxTurnChars) })),\n headerConnector(sourceConnector)\n ).conversation.length;\n },\n runExtraction: (turns, runOptions) => isolatedRun.runExtraction(turns, runOptions),\n getStorage: () => ingestionDeps.getStorage(),\n buffer: claimBuffer,\n },\n { dropFailedChunks: false }\n );\n return { claimBuffer, coordinator, executionDrain };\n}\n\n/** Plan semantics for one scope group: a pinned plan forwards as-is; a\n * planless ACCEPTED group pins null (existing flush behavior); unpinned\n * legacy groups pass NO option so runExtraction resolves the CURRENT\n * profile. */\nfunction planOptionForGroup(group: ExtractionScopeGroup): GroupPlanOption {\n if (group.scopeProfileWritePlan !== undefined) return { scopeProfileWritePlan: group.scopeProfileWritePlan };\n if (group.turns.some((turn) => turn.acceptedCapture === true)) return { scopeProfileWritePlan: null };\n return {};\n}\n\n/** captureMode=explicit: ordinary buffered conversation turns never create\n * memories — only deliberately accepted captures drain. */\nfunction explicitModeDenied(group: ExtractionScopeGroup, config: PluginConfig): boolean {\n return shouldSkipImplicitExtraction(config) && !group.turns.some((turn) => turn.acceptedCapture === true);\n}\n\ninterface GroupOutcome {\n turns: number;\n result?: ExtractionRunResult;\n}\n\ninterface ScopeDrainContext {\n config: PluginConfig;\n key: string;\n signal: AbortSignal;\n claimBuffer: SmartBuffer;\n coordinator: TurnIngestionCoordinator;\n executionDrain: ExtractionDrain;\n turns: BufferTurn[];\n}\n\n/** Drain a claimed session's turns ONE captured-scope group at a time: each\n * group keeps its own namespace/principal/plan pins, and the shared\n * extraction boundary re-applies CURRENT authorization from the turn's\n * ORIGINAL coding binding before any write. Groups run sequentially (FIFO\n * per key — the queue's same-key exclusion would serialize them anyway); a\n * denied group never blocks or clears the other groups. */\nasync function drainScopeGroups(\n ctx: ScopeDrainContext\n): Promise<{ groupOutcomes: GroupOutcome[]; groupError?: DrainExtractionError }> {\n const groupOutcomes: GroupOutcome[] = [];\n let groupError: DrainExtractionError | undefined;\n for (const group of groupTurnsByExtractionScope(ctx.turns)) {\n if (ctx.signal.aborted) break;\n if (explicitModeDenied(group, ctx.config)) {\n log.warn(\n `buffer drain: session ${ctx.key} denied capture_mode_explicit (${group.turns.length} ordinary turn(s) retained)`\n );\n groupOutcomes.push({\n turns: group.turns.length,\n result: { status: \"skipped\", reason: \"capture_mode_explicit\", persistedCount: 0, durableOutputCount: 0 },\n });\n continue;\n }\n const settleGate = Promise.withResolvers<{ cause?: unknown; result?: ExtractionRunResult }>();\n let done = false;\n const onSettle = (cause: unknown, result?: ExtractionRunResult): void => {\n if (done) return;\n done = true;\n settleGate.resolve({ cause, result });\n };\n // Settlement and callback EXIT are tracked separately: the lease is\n // released only after BOTH the queued closure settled and fully exited\n // (an abort settles through its listener while the closure may still be\n // persisting).\n const exited = Promise.withResolvers<void>();\n void ctx.coordinator\n .queueBufferedExtraction(group.turns, \"trigger_mode\", {\n bufferKey: ctx.key,\n clearBufferAfterExtraction: true,\n clearMatchingTurns: true,\n skipDedupeCheck: true,\n skipCharThreshold: true,\n skipUserTurnThreshold: true,\n // Automatic background work yields to fail-closed foreground flushes\n // (preemptRunning), same as the live trigger path.\n preemptable: true,\n abortSignal: ctx.signal,\n writeNamespaceOverride: group.writeNamespaceOverride,\n principalOverride: group.principalOverride,\n ...planOptionForGroup(group),\n execution: { buffer: ctx.claimBuffer, drain: ctx.executionDrain },\n onTaskSettled: (error, result) => settleGate.resolve({ cause: error, result }),\n onTaskExit: () => exited.resolve(),\n })\n .catch((cause: DrainExtractionError) => onSettle(cause));\n const [verdict] = await Promise.all([settleGate.promise, exited.promise]);\n const settled = verdict;\n if (settled.cause !== undefined) {\n // SAFETY: settle captures whatever the queued closure rejected with;\n // every drain rejection site throws Error values, and a rejection is\n // always a DrainExtractionError in this path.\n groupError = settled.cause as Error;\n break;\n }\n groupOutcomes.push({ turns: group.turns.length, result: settled.result });\n }\n return { groupOutcomes, groupError };\n}\n\n/** Denied scope groups: policy refusals leave their turns pending (the group\n * result's turns were NOT cleared), aggregated per reason so a drain is\n * never reported complete while denied backlog remains. */\nfunction deniedByReason(groupOutcomes: readonly GroupOutcome[]): Map<string, number> {\n const denied = new Map<string, number>();\n for (const entry of groupOutcomes) {\n if (entry.result?.status !== \"skipped\" || !DENIED_SCOPE_REASONS.has(entry.result.reason ?? \"\")) continue;\n denied.set(entry.result.reason!, (denied.get(entry.result.reason!) ?? 0) + entry.turns);\n }\n return denied;\n}\n\nfunction lastGroupReason(groupOutcomes: readonly GroupOutcome[]): string | undefined {\n for (let index = groupOutcomes.length - 1; index >= 0; index -= 1) {\n const reason = groupOutcomes[index]?.result?.reason;\n if (reason !== undefined) return reason;\n }\n return undefined;\n}\n\n/** the session file is gone for good — but the ack verdict is the truth (live */\nasync function settleDrainVerdict(\n claims: BufferDrainClaims,\n key: string,\n ownerId: string,\n groupOutcomes: readonly GroupOutcome[],\n groupError: DrainExtractionError | undefined,\n turnsRemaining: number\n): Promise<{ status: DrainSessionStatus; reason?: string; turnsRemaining: number }> {\n if (turnsRemaining === 0) return await ackOrReload(claims, key, ownerId);\n if (groupError) {\n await claims.releaseLease(key, ownerId);\n return { status: \"failed\", reason: describeError(groupError), turnsRemaining };\n }\n await claims.releaseLease(key, ownerId);\n const reason =\n groupOutcomes.find((entry) => entry.result?.reason !== undefined && DENIED_SCOPE_REASONS.has(entry.result.reason!))\n ?.result?.reason ??\n lastGroupReason(groupOutcomes) ??\n \"deferred\";\n return { status: \"deferred\", reason, turnsRemaining };\n}\n\n/** Ack an emptied claim; a not-acked verdict means live ingress merged (or\n * the lease moved) — reload the honest pending count and release OUR lease,\n * keeping the source. */\nasync function ackOrReload(\n claims: BufferDrainClaims,\n key: string,\n ownerId: string\n): Promise<{ status: DrainSessionStatus; reason?: string; turnsRemaining: number }> {\n const ackOutcome = await claims.ack(key, ownerId);\n if (ackOutcome === \"acked\") return { status: \"drained\", turnsRemaining: 0 };\n const reloaded = await claims.load(key);\n const turnsRemaining = pendingTurnCount(reloaded?.entry);\n await claims.releaseLease(key, ownerId);\n return { status: \"deferred\", reason: ackOutcome === \"not_empty\" ? \"ack_not_empty\" : \"ack_not_owner\", turnsRemaining };\n}\n\nfunction groupCounts(groupOutcomes: readonly GroupOutcome[]): GroupCounts {\n return {\n persistedCount: groupOutcomes.reduce((sum, entry) => sum + (entry.result?.persistedCount ?? 0), 0),\n durableOutputCount: groupOutcomes.reduce((sum, entry) => sum + (entry.result?.durableOutputCount ?? 0), 0),\n };\n}\n\nexport interface DrainScanEntry {\n key: string;\n turns: number;\n claimed: boolean;\n}\n\n/** Session-buffer listings: a claimed session reports its CLAIM's pending\n * count (the live buffer copy may lag the claim), an unclaimed one its\n * buffer entry. */\nasync function bufferSessionListings(\n claims: BufferDrainClaims,\n entries: Record<string, BufferEntryState>\n): Promise<{ listings: DrainScanEntry[]; seen: Set<string> }> {\n const listings: DrainScanEntry[] = [];\n const seen = new Set<string>();\n for (const [key, entry] of Object.entries(entries)) {\n seen.add(key);\n const claim = claims.isClaimed(key) ? await claims.load(key) : null;\n listings.push({\n key,\n turns: claim ? pendingTurnCount(claim.entry) : pendingTurnCount(entry),\n claimed: claim !== null,\n });\n }\n return { listings, seen };\n}\n\n/** Claims the buffer state no longer lists (drained by an earlier run whose\n * claim file outlived its session file). */\nasync function orphanClaimListings(claims: BufferDrainClaims, seen: Set<string>): Promise<DrainScanEntry[]> {\n const out: DrainScanEntry[] = [];\n for (const listed of await claims.list()) {\n if (seen.has(listed.key)) continue;\n out.push({ key: listed.key, turns: listed.turnCount, claimed: true });\n }\n return out;\n}\n\n/** The drain runs on the caller's abort signal combined with this run's own\n * lease-loss controller. */\nfunction drainAbortSignal(callerSignal: AbortSignal | undefined, abort: AbortController): AbortSignal {\n return callerSignal ? AbortSignal.any([callerSignal, abort.signal]) : abort.signal;\n}\n\n/** One heartbeat-protected claim drain: run every scope group, settle the\n * verdict against the claim store, and assemble the honest outcome. The\n * heartbeat is cleared by the caller on every exit path. */\nasync function runClaimDrain(\n ctx: {\n orchestrator: Orchestrator;\n claims: BufferDrainClaims;\n key: string;\n ownerId: string;\n claimBuffer: SmartBuffer;\n coordinator: TurnIngestionCoordinator;\n executionDrain: ExtractionDrain;\n turns: BufferTurn[];\n turnsAtStart: number;\n config: PluginConfig;\n signal: AbortSignal;\n },\n options: BufferDrainRunnerOptions,\n heartbeat: NodeJS.Timeout\n): Promise<DrainSessionOutcome> {\n // Reconcile only identities recorded as durably extracted under this\n // owner's claim lease. The claim lock is released before entering the live\n // buffer mutation queue, preserving the buffer→claim lock order used by\n // concurrent ingress saves.\n const reconcileDrainedTurns = async (): Promise<void> => {\n const drained = await ctx.claims.drainedTurnsForOwner(ctx.key, ctx.ownerId);\n if (drained !== null) await ctx.orchestrator.buffer.save({ key: ctx.key, drained });\n };\n\n // An emptied claim acks here: the ack verdict is the truth (drained), or\n // live ingress merged between the read and the ack — deferred, source kept.\n if (ctx.turns.length === 0) {\n await reconcileDrainedTurns();\n const outcome = await ackEmptyClaim(ctx.claims, ctx.key, ctx.ownerId, ctx.turnsAtStart);\n options.onEvent?.({ type: \"session_finished\", key: ctx.key, outcome });\n return outcome;\n }\n const { groupOutcomes, groupError } = await drainScopeGroups(ctx);\n await reconcileDrainedTurns();\n // Heartbeat cleared on EVERY exit path: a rejected drain must not keep\n // renewing the lease forever (cleared in the caller's finally).\n const remaining = await ctx.claims.load(ctx.key);\n const { status, reason, turnsRemaining } = await settleDrainVerdict(\n ctx.claims,\n ctx.key,\n ctx.ownerId,\n groupOutcomes,\n groupError,\n pendingTurnCount(remaining?.entry)\n );\n const outcome = assembleOutcome(\n ctx.key,\n ctx.turnsAtStart,\n { status, reason, turnsRemaining },\n groupCounts(groupOutcomes),\n deniedByReason(groupOutcomes)\n );\n log.info(`buffer drain: session ${ctx.key} ${status} (${outcome.turnsRemaining} turn(s) remaining)`);\n options.onEvent?.({ type: \"session_finished\", key: ctx.key, outcome });\n return outcome;\n}\n\nexport class BufferDrainRunner {\n constructor(private readonly orchestrator: Orchestrator) {}\n\n /** The claim store of this orchestrator's memory root. */\n get claims(): BufferDrainClaims {\n return this.orchestrator.storage.bufferDrainClaims();\n }\n\n /**\n * Drain one claimed session. The caller owns the lease (it may have taken\n * it already); this method verifies ownership before touching content.\n */\n async drainSession(key: string, options: BufferDrainRunnerOptions): Promise<DrainSessionOutcome> {\n const claims = this.claims;\n const leaseMs = options.leaseMs ?? DEFAULT_LEASE_MS;\n const claimed = await loadClaimedSession(claims, key);\n if (claimed.kind === \"notClaimed\") return claimed.notClaimed;\n const { claim, turnsAtStart } = claimed;\n options.onEvent?.({ type: \"session_started\", key, turns: turnsAtStart });\n\n // Take the lease unless this drainer already holds it.\n const busy = await adoptLease(claims, key, options.ownerId, leaseMs);\n if (busy !== null) {\n const outcome = busy;\n options.onEvent?.({ type: \"session_finished\", key, outcome });\n return outcome;\n }\n\n // The claim is the buffer for this run: every successful chunk is removed\n // from it, so a kill leaves exactly the un-extracted turns.\n const { claimBuffer, coordinator, executionDrain } = buildClaimExecution(\n this.orchestrator,\n claims,\n key,\n options.ownerId,\n claim\n );\n await claimBuffer.load();\n\n // The claim's turns (retained first, like the live buffer's order).\n const turns = [...(claim.entry.retainedTurns ?? []), ...claim.entry.turns];\n\n // A lost lease means another drainer took the claim: stop instead of\n // writing progress into a claim this run no longer owns.\n const abort = new AbortController();\n const signal = drainAbortSignal(options.signal, abort);\n const heartbeat = startLeaseHeartbeat(claims, key, options.ownerId, leaseMs, abort);\n try {\n return await runClaimDrain(\n {\n orchestrator: this.orchestrator,\n claims,\n key,\n ownerId: options.ownerId,\n claimBuffer,\n coordinator,\n executionDrain,\n turns,\n turnsAtStart,\n config: this.orchestrator.config,\n signal,\n },\n options,\n heartbeat\n );\n } finally {\n clearInterval(heartbeat);\n }\n }\n\n /** Claim a session file for the drain. Returns false when it is not claimable. */\n async claim(key: string, ownerId: string, leaseMs = DEFAULT_LEASE_MS): Promise<boolean> {\n const lease: DrainLease = {\n ownerId,\n pid: process.pid,\n host: hostname(),\n acquiredAt: new Date().toISOString(),\n heartbeatAt: new Date().toISOString(),\n leaseMs,\n };\n return (await this.claims.claimFromSessionFile(key, lease)) === \"claimed\";\n }\n\n /** Sessions with buffered turns, claimed or not (CLI scan). */\n async scan(): Promise<DrainScanEntry[]> {\n const sessions = await this.orchestrator.storage.loadBuffer();\n const { listings, seen } = await bufferSessionListings(this.claims, sessions.entries ?? {});\n return [...listings, ...(await orphanClaimListings(this.claims, seen))];\n }\n}\n"],"mappings":"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","names":["outcome"]}
1
+ {"version":3,"sources":["../src/orchestration/buffer-drain-runner.ts"],"sourcesContent":["/** Claim-backed extraction-buffer drain (`remnic buffer drain` worker AND the */\n\nimport { hostname } from \"node:os\";\nimport type { BufferStorage } from \"../buffer-persistence.js\";\nimport { type ExtractionScopeGroup, describeError, groupTurnsByExtractionScope } from \"../buffer-turn-helpers.js\";\nimport { SmartBuffer } from \"../buffer.js\";\nimport { resolveMemoryLifecycleCapabilities } from \"../capabilities.js\";\nimport { shouldSkipImplicitExtraction } from \"../explicit-capture.js\";\nimport { log } from \"../logger.js\";\nimport type { ResolvedScopeProfilePlan } from \"../namespaces/scope-profiles.js\";\nimport type { Orchestrator } from \"../orchestrator.js\";\nimport { headerConnector, renderExtractionConversation, resolveSourceConnector } from \"../source-agent-qualifier.js\";\nimport type { BufferDrainClaims, DrainLease } from \"../storage/buffer-drain-claims.js\";\nimport type { BufferEntryState, BufferState, BufferTurn, PluginConfig } from \"../types.js\";\nimport { ExtractionDrain } from \"./extraction-drain.js\";\nimport type { ExtractionRunResult } from \"./extraction-run.js\";\nimport { selfDeps } from \"./self-deps.js\";\nimport { TurnIngestionCoordinator, type TurnIngestionDeps } from \"./turn-ingestion.js\";\n\nexport type DrainSessionStatus = \"drained\" | \"deferred\" | \"failed\" | \"skipped\";\n\nexport interface DrainSessionOutcome {\n key: string;\n status: DrainSessionStatus;\n /** Turns the claim held when the drain started. */\n turnsAtStart: number;\n /** Turns still in the claim when the drain stopped. */\n turnsRemaining: number;\n /** Facts the extraction persisted during this run. */\n persistedCount: number;\n /** Durable outputs (memories + entities) the extraction wrote. */\n durableOutputCount: number;\n /** Why the session was skipped or deferred (machine-readable). */\n reason?: string;\n /** Current-policy denials: scope groups whose authorization no longer holds. */\n denied?: { reason: string; turns: number }[];\n}\n\n/** Extraction results that mean \"current policy refuses this scope\": the\n * turns are valid backlog whose captured scope is no longer writable. */\nconst DENIED_SCOPE_REASONS: ReadonlySet<string> = new Set([\n \"pinned_namespace_unavailable\",\n \"namespace_write_revoked\",\n \"scope_profile_revoked\",\n // The resolved profile has no writable layer: the same current-policy\n // refusal family, surfaced from inside the shared runExtraction gate.\n \"scope_profile_no_writable_layer\",\n // captureMode=explicit: ordinary buffered conversation turns never create\n // memories; only deliberately accepted captures drain.\n \"capture_mode_explicit\",\n]);\n\nexport interface BufferDrainRunnerOptions {\n /** Identity of this drainer; owns the lease it takes. */\n ownerId: string;\n /** Lease lifetime in ms. The heartbeat keeps it alive while draining. */\n leaseMs?: number;\n /** Cancels the run at the next chunk boundary. */\n signal?: AbortSignal;\n /** Progress callback (per session, and per claim transition). */\n onEvent?: (event: DrainRunnerEvent) => void;\n}\n\n/** A failed drain run: the reason a chunk or the session could not finish. */\nexport type DrainExtractionError = Error;\n\nexport type DrainRunnerEvent =\n | { type: \"session_started\"; key: string; turns: number }\n | { type: \"session_finished\"; key: string; outcome: DrainSessionOutcome };\n\nconst DEFAULT_LEASE_MS = 120_000;\n\n/**\n * A `BufferStorage` view of one drain claim: the claim file IS the buffer.\n * Writes are the drain's progress (what is left to extract), so every\n * successfully extracted chunk is durably removed before the next one runs.\n *\n * `seen` is the drainer's own view of the claim: the entry it loaded, then the\n * entry it last wrote. Each progress write is diffed against it, so a write\n * records only the turns extracted since the previous one.\n */\nexport class ClaimBufferStorage implements BufferStorage {\n private seen: BufferEntryState;\n\n constructor(\n private readonly claims: BufferDrainClaims,\n private readonly key: string,\n private readonly ownerId: string,\n entry: BufferEntryState\n ) {\n this.seen = entry;\n }\n\n async loadBuffer(): Promise<BufferState> {\n const entries: NonNullable<BufferState[\"entries\"]> = Object.create(null);\n entries[this.key] = {\n turns: this.seen.turns,\n retainedTurns: this.seen.retainedTurns,\n lastExtractionAt: this.seen.lastExtractionAt,\n extractionCount: this.seen.extractionCount,\n };\n return {\n turns: this.seen.turns,\n lastExtractionAt: this.seen.lastExtractionAt,\n extractionCount: this.seen.extractionCount,\n entries,\n };\n }\n\n async saveBuffer(state: BufferState): Promise<void> {\n // Whole-state fallback (the claim covers one session): persist the entry.\n const entry = state.entries?.[this.key];\n await this.writeProgress(entry ?? { turns: [], lastExtractionAt: null, extractionCount: 0 });\n }\n\n async saveBufferSession(key: string, entry: BufferEntryState): Promise<void> {\n if (key !== this.key) {\n await this.claims.writeEntry(key, this.ownerId, entry, undefined);\n return;\n }\n await this.writeProgress(entry);\n }\n\n private async writeProgress(entry: BufferEntryState): Promise<void> {\n await this.claims.writeEntry(this.key, this.ownerId, entry, this.seen);\n // Copy the lists: the buffer keeps mutating its own arrays after a save.\n this.seen = { ...entry, turns: [...entry.turns], retainedTurns: entry.retainedTurns ? [...entry.retainedTurns] : undefined };\n }\n\n async deleteBufferSession(): Promise<void> {\n // The claim is removed by the ack path, never by a buffer eviction: the\n // drain decides when the session is finished.\n }\n}\n\n/** Per-invocation isolated execution context for one claim drain. */\ninterface ClaimDrainExecution {\n claimBuffer: SmartBuffer;\n coordinator: TurnIngestionCoordinator;\n executionDrain: ExtractionDrain;\n}\n\n/** The scopeProfileWritePlan option a scope group forwards to the queue. */\ninterface GroupPlanOption {\n scopeProfileWritePlan?: ResolvedScopeProfilePlan | null;\n}\n\n/** Durable counters a drain pass contributed. */\ninterface GroupCounts {\n persistedCount: number;\n durableOutputCount: number;\n}\n\n/** Pending turns across canonical + retained copies (the honest backlog count). */\nfunction pendingTurnCount(entry: BufferEntryState | undefined): number {\n if (!entry) return 0;\n return entry.turns.length + (entry.retainedTurns?.length ?? 0);\n}\n\n/** Load one claimed session. An unclaimed key is nothing to drain. */\nasync function loadClaimedSession(\n claims: BufferDrainClaims,\n key: string\n): Promise<\n | { kind: \"notClaimed\"; notClaimed: DrainSessionOutcome }\n | { kind: \"claimed\"; claim: { entry: BufferEntryState }; turnsAtStart: number }\n> {\n const claim = await claims.load(key);\n if (!claim) {\n return {\n kind: \"notClaimed\",\n notClaimed: {\n key,\n status: \"skipped\",\n turnsAtStart: 0,\n turnsRemaining: 0,\n persistedCount: 0,\n durableOutputCount: 0,\n reason: \"not_claimed\",\n },\n };\n }\n return { kind: \"claimed\", claim, turnsAtStart: pendingTurnCount(claim.entry) };\n}\n\nfunction busyLeaseOutcome(key: string, turnsAtStart: number): DrainSessionOutcome {\n return {\n key,\n status: \"skipped\",\n turnsAtStart,\n turnsRemaining: turnsAtStart,\n persistedCount: 0,\n durableOutputCount: 0,\n reason: \"claimed_by_another_drain\",\n };\n}\n\n/** Take the lease unless this drainer already holds it. A busy lease means\n * another drainer owns the claim — skip without touching content. */\nasync function adoptLease(\n claims: BufferDrainClaims,\n key: string,\n ownerId: string,\n leaseMs: number\n): Promise<DrainSessionOutcome | null> {\n const held = await claims.adopt(key, {\n ownerId,\n pid: process.pid,\n host: hostname(),\n acquiredAt: new Date().toISOString(),\n heartbeatAt: new Date().toISOString(),\n leaseMs,\n });\n return held === \"busy\" ? busyLeaseOutcome(key, pendingTurnCount((await claims.load(key))?.entry)) : null;\n}\n\nfunction assembleOutcome(\n key: string,\n turnsAtStart: number,\n verdict: { status: DrainSessionStatus; reason?: string; turnsRemaining: number },\n counts: { persistedCount: number; durableOutputCount: number },\n denied: Map<string, number>\n): DrainSessionOutcome {\n const outcome: DrainSessionOutcome = {\n key,\n status: verdict.status,\n turnsAtStart,\n turnsRemaining: verdict.turnsRemaining,\n persistedCount: counts.persistedCount,\n durableOutputCount: counts.durableOutputCount,\n };\n if (denied.size > 0) outcome.denied = [...denied].map(([deniedReason, turns]) => ({ reason: deniedReason, turns }));\n if (verdict.reason !== undefined) outcome.reason = verdict.reason;\n return outcome;\n}\n\n/** Ack an EMPTY claim. The ack verdict is the truth: live ingress can merge\n * between the empty read and the ack — a not_empty ack means pending work\n * exists; reload it, release OUR lease, report deferred, never a false\n * drained. */\nasync function ackEmptyClaim(\n claims: BufferDrainClaims,\n key: string,\n ownerId: string,\n turnsAtStart: number\n): Promise<DrainSessionOutcome> {\n const ackOutcome = await claims.ack(key, ownerId);\n if (ackOutcome !== \"acked\") {\n const reloaded = await claims.load(key);\n const turnsRemaining = pendingTurnCount(reloaded?.entry);\n await claims.releaseLease(key, ownerId);\n return {\n key,\n status: \"deferred\",\n turnsAtStart,\n turnsRemaining,\n persistedCount: 0,\n durableOutputCount: 0,\n reason: ackOutcome === \"not_empty\" ? \"ack_not_empty\" : \"ack_not_owner\",\n };\n }\n return { key, status: \"drained\", turnsAtStart, turnsRemaining: 0, persistedCount: 0, durableOutputCount: 0 };\n}\n\n/** another drainer took the claim, so this run must stop instead of writing */\nfunction startLeaseHeartbeat(\n claims: BufferDrainClaims,\n key: string,\n ownerId: string,\n leaseMs: number,\n abort: AbortController\n): NodeJS.Timeout {\n const heartbeat = setInterval(\n () => {\n void claims\n .heartbeat(key, ownerId, leaseMs)\n .then((state) => {\n if (state === \"lost\") abort.abort(new Error(`buffer drain: lease lost for session ${key}`));\n })\n .catch((err: Error) => {\n // A heartbeat that cannot be renewed is a lease that cannot be held:\n // stop this run cleanly at the next chunk boundary (the next run\n // resumes it).\n abort.abort(new Error(`buffer drain: lease heartbeat failed for session ${key}: ${describeError(err)}`));\n });\n },\n Math.max(1_000, Math.floor(leaseMs / 3))\n );\n heartbeat.unref?.();\n return heartbeat;\n}\n\n/** coordinator bound to it, and the no-drop chunked drain. Built per */\nfunction buildClaimExecution(\n orchestrator: Orchestrator,\n claims: BufferDrainClaims,\n key: string,\n ownerId: string,\n claim: { entry: BufferEntryState }\n): ClaimDrainExecution {\n const claimBuffer = new SmartBuffer(orchestrator.config, new ClaimBufferStorage(claims, key, ownerId, claim.entry));\n const isolatedRun = orchestrator.extractionRunCoordinatorForBuffer(claimBuffer);\n const coordinator = new TurnIngestionCoordinator(selfDeps<TurnIngestionDeps>(orchestrator));\n const config = orchestrator.config;\n const ingestionDeps = selfDeps<TurnIngestionDeps>(orchestrator);\n // No-drop: a repeatedly failing chunk stays in the claim as durable\n // retryable backlog — never side-filed, never counted as processed.\n const executionDrain = new ExtractionDrain(\n {\n config: {\n extractionMinUserTurns: config.extractionMinUserTurns,\n extractionMinChars: config.extractionMinChars,\n extractionMaxTurnChars: config.extractionMaxTurnChars,\n extractionChunkDropAfterFailures: config.extractionChunkDropAfterFailures,\n },\n extractionWindowBudgetChars: () => ingestionDeps.extractionWindowBudgetChars?.() ?? Number.POSITIVE_INFINITY,\n // Render-exact chunk sizing: the model clamp bounds the CONVERSATION\n // (truncateLocalExtractionConversation), so measure exactly that —\n // with the SAME source-classification gate extract() applies when it\n // prepends the connector header (header margin included when the\n // engine would render it).\n measureRenderedTurns: (turns) => {\n const sourceConnector = resolveMemoryLifecycleCapabilities(config).extractionScopeClassification\n ? resolveSourceConnector(turns)\n : undefined;\n return renderExtractionConversation(\n turns.map((turn) => ({ ...turn, content: turn.content.trim().slice(0, config.extractionMaxTurnChars) })),\n headerConnector(sourceConnector)\n ).conversation.length;\n },\n runExtraction: (turns, runOptions) => isolatedRun.runExtraction(turns, runOptions),\n getStorage: () => ingestionDeps.getStorage(),\n buffer: claimBuffer,\n },\n { dropFailedChunks: false }\n );\n return { claimBuffer, coordinator, executionDrain };\n}\n\n/** Plan semantics for one scope group: a pinned plan forwards as-is; a\n * planless ACCEPTED group pins null (existing flush behavior); unpinned\n * legacy groups pass NO option so runExtraction resolves the CURRENT\n * profile. */\nfunction planOptionForGroup(group: ExtractionScopeGroup): GroupPlanOption {\n if (group.scopeProfileWritePlan !== undefined) return { scopeProfileWritePlan: group.scopeProfileWritePlan };\n if (group.turns.some((turn) => turn.acceptedCapture === true)) return { scopeProfileWritePlan: null };\n return {};\n}\n\n/** captureMode=explicit: ordinary buffered conversation turns never create\n * memories — only deliberately accepted captures drain. */\nfunction explicitModeDenied(group: ExtractionScopeGroup, config: PluginConfig): boolean {\n return shouldSkipImplicitExtraction(config) && !group.turns.some((turn) => turn.acceptedCapture === true);\n}\n\ninterface GroupOutcome {\n turns: number;\n result?: ExtractionRunResult;\n}\n\ninterface ScopeDrainContext {\n config: PluginConfig;\n key: string;\n signal: AbortSignal;\n claimBuffer: SmartBuffer;\n coordinator: TurnIngestionCoordinator;\n executionDrain: ExtractionDrain;\n turns: BufferTurn[];\n}\n\n/** Drain a claimed session's turns ONE captured-scope group at a time: each\n * group keeps its own namespace/principal/plan pins, and the shared\n * extraction boundary re-applies CURRENT authorization from the turn's\n * ORIGINAL coding binding before any write. Groups run sequentially (FIFO\n * per key — the queue's same-key exclusion would serialize them anyway); a\n * denied group never blocks or clears the other groups. */\nasync function drainScopeGroups(\n ctx: ScopeDrainContext\n): Promise<{ groupOutcomes: GroupOutcome[]; groupError?: DrainExtractionError }> {\n const groupOutcomes: GroupOutcome[] = [];\n let groupError: DrainExtractionError | undefined;\n for (const group of groupTurnsByExtractionScope(ctx.turns)) {\n if (ctx.signal.aborted) break;\n if (explicitModeDenied(group, ctx.config)) {\n log.warn(\n `buffer drain: session ${ctx.key} denied capture_mode_explicit (${group.turns.length} ordinary turn(s) retained)`\n );\n groupOutcomes.push({\n turns: group.turns.length,\n result: { status: \"skipped\", reason: \"capture_mode_explicit\", persistedCount: 0, durableOutputCount: 0 },\n });\n continue;\n }\n const settleGate = Promise.withResolvers<{ cause?: unknown; result?: ExtractionRunResult }>();\n let done = false;\n const onSettle = (cause: unknown, result?: ExtractionRunResult): void => {\n if (done) return;\n done = true;\n settleGate.resolve({ cause, result });\n };\n // Settlement and callback EXIT are tracked separately: the lease is\n // released only after BOTH the queued closure settled and fully exited\n // (an abort settles through its listener while the closure may still be\n // persisting).\n const exited = Promise.withResolvers<void>();\n void ctx.coordinator\n .queueBufferedExtraction(group.turns, \"trigger_mode\", {\n bufferKey: ctx.key,\n clearBufferAfterExtraction: true,\n clearMatchingTurns: true,\n skipDedupeCheck: true,\n skipCharThreshold: true,\n skipUserTurnThreshold: true,\n // Automatic background work yields to fail-closed foreground flushes\n // (preemptRunning), same as the live trigger path.\n preemptable: true,\n abortSignal: ctx.signal,\n writeNamespaceOverride: group.writeNamespaceOverride,\n principalOverride: group.principalOverride,\n ...planOptionForGroup(group),\n execution: { buffer: ctx.claimBuffer, drain: ctx.executionDrain },\n onTaskSettled: (error, result) => settleGate.resolve({ cause: error, result }),\n onTaskExit: () => exited.resolve(),\n })\n .catch((cause: DrainExtractionError) => onSettle(cause));\n const [verdict] = await Promise.all([settleGate.promise, exited.promise]);\n const settled = verdict;\n if (settled.cause !== undefined) {\n // SAFETY: settle captures whatever the queued closure rejected with;\n // every drain rejection site throws Error values, and a rejection is\n // always a DrainExtractionError in this path.\n groupError = settled.cause as Error;\n break;\n }\n groupOutcomes.push({ turns: group.turns.length, result: settled.result });\n }\n return { groupOutcomes, groupError };\n}\n\n/** Denied scope groups: policy refusals leave their turns pending (the group\n * result's turns were NOT cleared), aggregated per reason so a drain is\n * never reported complete while denied backlog remains. */\nfunction deniedByReason(groupOutcomes: readonly GroupOutcome[]): Map<string, number> {\n const denied = new Map<string, number>();\n for (const entry of groupOutcomes) {\n if (entry.result?.status !== \"skipped\" || !DENIED_SCOPE_REASONS.has(entry.result.reason ?? \"\")) continue;\n denied.set(entry.result.reason!, (denied.get(entry.result.reason!) ?? 0) + entry.turns);\n }\n return denied;\n}\n\nfunction lastGroupReason(groupOutcomes: readonly GroupOutcome[]): string | undefined {\n for (let index = groupOutcomes.length - 1; index >= 0; index -= 1) {\n const reason = groupOutcomes[index]?.result?.reason;\n if (reason !== undefined) return reason;\n }\n return undefined;\n}\n\n/** the session file is gone for good — but the ack verdict is the truth (live */\nasync function settleDrainVerdict(\n claims: BufferDrainClaims,\n key: string,\n ownerId: string,\n groupOutcomes: readonly GroupOutcome[],\n groupError: DrainExtractionError | undefined,\n turnsRemaining: number\n): Promise<{ status: DrainSessionStatus; reason?: string; turnsRemaining: number }> {\n if (turnsRemaining === 0) return await ackOrReload(claims, key, ownerId);\n if (groupError) {\n await claims.releaseLease(key, ownerId);\n return { status: \"failed\", reason: describeError(groupError), turnsRemaining };\n }\n await claims.releaseLease(key, ownerId);\n const reason =\n groupOutcomes.find((entry) => entry.result?.reason !== undefined && DENIED_SCOPE_REASONS.has(entry.result.reason!))\n ?.result?.reason ??\n lastGroupReason(groupOutcomes) ??\n \"deferred\";\n return { status: \"deferred\", reason, turnsRemaining };\n}\n\n/** Ack an emptied claim; a not-acked verdict means live ingress merged (or\n * the lease moved) — reload the honest pending count and release OUR lease,\n * keeping the source. */\nasync function ackOrReload(\n claims: BufferDrainClaims,\n key: string,\n ownerId: string\n): Promise<{ status: DrainSessionStatus; reason?: string; turnsRemaining: number }> {\n const ackOutcome = await claims.ack(key, ownerId);\n if (ackOutcome === \"acked\") return { status: \"drained\", turnsRemaining: 0 };\n const reloaded = await claims.load(key);\n const turnsRemaining = pendingTurnCount(reloaded?.entry);\n await claims.releaseLease(key, ownerId);\n return { status: \"deferred\", reason: ackOutcome === \"not_empty\" ? \"ack_not_empty\" : \"ack_not_owner\", turnsRemaining };\n}\n\nfunction groupCounts(groupOutcomes: readonly GroupOutcome[]): GroupCounts {\n return {\n persistedCount: groupOutcomes.reduce((sum, entry) => sum + (entry.result?.persistedCount ?? 0), 0),\n durableOutputCount: groupOutcomes.reduce((sum, entry) => sum + (entry.result?.durableOutputCount ?? 0), 0),\n };\n}\n\nexport interface DrainScanEntry {\n key: string;\n turns: number;\n claimed: boolean;\n}\n\n/** Session-buffer listings: a claimed session reports its CLAIM's pending\n * count (the live buffer copy may lag the claim), an unclaimed one its\n * buffer entry. */\nasync function bufferSessionListings(\n claims: BufferDrainClaims,\n entries: Record<string, BufferEntryState>\n): Promise<{ listings: DrainScanEntry[]; seen: Set<string> }> {\n const listings: DrainScanEntry[] = [];\n const seen = new Set<string>();\n for (const [key, entry] of Object.entries(entries)) {\n seen.add(key);\n const claim = claims.isClaimed(key) ? await claims.load(key) : null;\n listings.push({\n key,\n turns: claim ? pendingTurnCount(claim.entry) : pendingTurnCount(entry),\n claimed: claim !== null,\n });\n }\n return { listings, seen };\n}\n\n/** Claims the buffer state no longer lists (drained by an earlier run whose\n * claim file outlived its session file). */\nasync function orphanClaimListings(claims: BufferDrainClaims, seen: Set<string>): Promise<DrainScanEntry[]> {\n const out: DrainScanEntry[] = [];\n for (const listed of await claims.list()) {\n if (seen.has(listed.key)) continue;\n out.push({ key: listed.key, turns: listed.turnCount, claimed: true });\n }\n return out;\n}\n\n/** The drain runs on the caller's abort signal combined with this run's own\n * lease-loss controller. */\nfunction drainAbortSignal(callerSignal: AbortSignal | undefined, abort: AbortController): AbortSignal {\n return callerSignal ? AbortSignal.any([callerSignal, abort.signal]) : abort.signal;\n}\n\n/** One heartbeat-protected claim drain: run every scope group, settle the\n * verdict against the claim store, and assemble the honest outcome. The\n * heartbeat is cleared by the caller on every exit path. */\nasync function runClaimDrain(\n ctx: {\n orchestrator: Orchestrator;\n claims: BufferDrainClaims;\n key: string;\n ownerId: string;\n claimBuffer: SmartBuffer;\n coordinator: TurnIngestionCoordinator;\n executionDrain: ExtractionDrain;\n turns: BufferTurn[];\n turnsAtStart: number;\n config: PluginConfig;\n signal: AbortSignal;\n },\n options: BufferDrainRunnerOptions,\n heartbeat: NodeJS.Timeout\n): Promise<DrainSessionOutcome> {\n // Reconcile only identities recorded as durably extracted under this\n // owner's claim lease. The claim lock is released before entering the live\n // buffer mutation queue, preserving the buffer→claim lock order used by\n // concurrent ingress saves.\n const reconcileDrainedTurns = async (): Promise<void> => {\n const drained = await ctx.claims.drainedTurnsForOwner(ctx.key, ctx.ownerId);\n if (drained !== null) await ctx.orchestrator.buffer.save({ key: ctx.key, drained });\n };\n\n // An emptied claim acks here: the ack verdict is the truth (drained), or\n // live ingress merged between the read and the ack — deferred, source kept.\n if (ctx.turns.length === 0) {\n await reconcileDrainedTurns();\n const outcome = await ackEmptyClaim(ctx.claims, ctx.key, ctx.ownerId, ctx.turnsAtStart);\n options.onEvent?.({ type: \"session_finished\", key: ctx.key, outcome });\n return outcome;\n }\n const { groupOutcomes, groupError } = await drainScopeGroups(ctx);\n await reconcileDrainedTurns();\n // Heartbeat cleared on EVERY exit path: a rejected drain must not keep\n // renewing the lease forever (cleared in the caller's finally).\n const remaining = await ctx.claims.load(ctx.key);\n const { status, reason, turnsRemaining } = await settleDrainVerdict(\n ctx.claims,\n ctx.key,\n ctx.ownerId,\n groupOutcomes,\n groupError,\n pendingTurnCount(remaining?.entry)\n );\n const outcome = assembleOutcome(\n ctx.key,\n ctx.turnsAtStart,\n { status, reason, turnsRemaining },\n groupCounts(groupOutcomes),\n deniedByReason(groupOutcomes)\n );\n log.info(`buffer drain: session ${ctx.key} ${status} (${outcome.turnsRemaining} turn(s) remaining)`);\n options.onEvent?.({ type: \"session_finished\", key: ctx.key, outcome });\n return outcome;\n}\n\nexport class BufferDrainRunner {\n constructor(private readonly orchestrator: Orchestrator) {}\n\n /** The claim store of this orchestrator's memory root. */\n get claims(): BufferDrainClaims {\n return this.orchestrator.storage.bufferDrainClaims();\n }\n\n /**\n * Drain one claimed session. The caller owns the lease (it may have taken\n * it already); this method verifies ownership before touching content.\n */\n async drainSession(key: string, options: BufferDrainRunnerOptions): Promise<DrainSessionOutcome> {\n const claims = this.claims;\n const leaseMs = options.leaseMs ?? DEFAULT_LEASE_MS;\n const claimed = await loadClaimedSession(claims, key);\n if (claimed.kind === \"notClaimed\") return claimed.notClaimed;\n const { claim, turnsAtStart } = claimed;\n options.onEvent?.({ type: \"session_started\", key, turns: turnsAtStart });\n\n // Take the lease unless this drainer already holds it.\n const busy = await adoptLease(claims, key, options.ownerId, leaseMs);\n if (busy !== null) {\n const outcome = busy;\n options.onEvent?.({ type: \"session_finished\", key, outcome });\n return outcome;\n }\n\n // The claim is the buffer for this run: every successful chunk is removed\n // from it, so a kill leaves exactly the un-extracted turns.\n const { claimBuffer, coordinator, executionDrain } = buildClaimExecution(\n this.orchestrator,\n claims,\n key,\n options.ownerId,\n claim\n );\n await claimBuffer.load();\n\n // The claim's turns (retained first, like the live buffer's order).\n const turns = [...(claim.entry.retainedTurns ?? []), ...claim.entry.turns];\n\n // A lost lease means another drainer took the claim: stop instead of\n // writing progress into a claim this run no longer owns.\n const abort = new AbortController();\n const signal = drainAbortSignal(options.signal, abort);\n const heartbeat = startLeaseHeartbeat(claims, key, options.ownerId, leaseMs, abort);\n try {\n return await runClaimDrain(\n {\n orchestrator: this.orchestrator,\n claims,\n key,\n ownerId: options.ownerId,\n claimBuffer,\n coordinator,\n executionDrain,\n turns,\n turnsAtStart,\n config: this.orchestrator.config,\n signal,\n },\n options,\n heartbeat\n );\n } finally {\n clearInterval(heartbeat);\n }\n }\n\n /** Claim a session file for the drain. Returns false when it is not claimable. */\n async claim(key: string, ownerId: string, leaseMs = DEFAULT_LEASE_MS): Promise<boolean> {\n const lease: DrainLease = {\n ownerId,\n pid: process.pid,\n host: hostname(),\n acquiredAt: new Date().toISOString(),\n heartbeatAt: new Date().toISOString(),\n leaseMs,\n };\n return (await this.claims.claimFromSessionFile(key, lease)) === \"claimed\";\n }\n\n /** Sessions with buffered turns, claimed or not (CLI scan). */\n async scan(): Promise<DrainScanEntry[]> {\n const sessions = await this.orchestrator.storage.loadBuffer();\n const { listings, seen } = await bufferSessionListings(this.claims, sessions.entries ?? {});\n return [...listings, ...(await orphanClaimListings(this.claims, seen))];\n }\n}\n"],"mappings":"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","names":["outcome"]}