@remnic/core 10.0.92 → 10.0.94
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.
- package/dist/access-admin-ops-surface.js +332 -59
- package/dist/access-authorization-probe.js +2 -283
- package/dist/access-boundary.d.ts +1 -1
- package/dist/access-boundary.d.ts.map +1 -1
- package/dist/access-boundary.js +1 -282
- package/dist/access-cli.js +287 -303
- package/dist/access-cli.js.map +1 -1
- package/dist/access-coding-context-resolution.js +3 -3
- package/dist/access-extraction-force-flush.js +332 -59
- package/dist/access-http-briefing.js +332 -60
- package/dist/access-http-query.js +332 -61
- package/dist/access-http.js +330 -112
- package/dist/access-identity-continuity-surface.js +332 -59
- package/dist/access-lcm-surface.js +332 -59
- package/dist/access-mcp-frames.d.ts +20 -6
- package/dist/access-mcp-frames.d.ts.map +1 -1
- package/dist/access-mcp-frames.js +1 -1
- package/dist/access-mcp.d.ts +5 -0
- package/dist/access-mcp.d.ts.map +1 -1
- package/dist/access-mcp.js +330 -87
- package/dist/access-namespace-preflight.js +2 -282
- package/dist/access-observe-transcript.js +3 -3
- package/dist/access-observe-write-category.js +6 -6
- package/dist/access-observe-write-surface.js +332 -59
- package/dist/access-offline-manifest.js +12 -11
- package/dist/access-operations-batch.js +330 -64
- package/dist/access-operations.js +330 -73
- package/dist/access-recall-concurrency.js +332 -59
- package/dist/access-recall-diagnostics.js +5 -4
- package/dist/access-recall-response.js +332 -59
- package/dist/access-recall-surface.js +332 -59
- package/dist/access-schema.js +2 -2
- package/dist/access-service.js +335 -62
- package/dist/access-surface-catalog.js +6 -283
- package/dist/access-surface-catalog.js.map +1 -1
- package/dist/active-context-transform.js +1 -1
- package/dist/active-memory-bridge.js +3 -2
- package/dist/active-recall.js +36 -37
- package/dist/active-recall.js.map +1 -1
- package/dist/activity/journal-extract.d.ts +13 -1
- package/dist/activity/journal-extract.d.ts.map +1 -1
- package/dist/{auto-sync-3AZW7MXI.js → auto-sync-BO5YZKM6.js} +13 -15
- package/dist/{auto-sync-3AZW7MXI.js.map → auto-sync-BO5YZKM6.js.map} +1 -1
- package/dist/briefing.js +20 -20
- package/dist/buffer.js +16 -16
- package/dist/calibration.js +10 -10
- package/dist/{capsule-merge-2IIXFXN5.js → capsule-merge-6IDAYTKG.js} +6 -6
- package/dist/causal-consolidation.js +23 -23
- package/dist/{chunk-RGUUBAT5.js → chunk-2WCLTWV2.js} +3 -3
- package/dist/{chunk-BQZEGOZ4.js → chunk-2YODOG2O.js} +2 -2
- package/dist/{chunk-WYG5UNDY.js → chunk-3AUDELZL.js} +2 -2
- package/dist/{chunk-MB6ZJDN6.js → chunk-3FBAEPCU.js} +2 -2
- package/dist/{chunk-PIITB2YZ.js → chunk-3ZS3NUEI.js} +4 -4
- package/dist/{chunk-ATPWZ4F7.js → chunk-4EZWSDFL.js} +5 -5
- package/dist/{chunk-ANZZLRUX.js → chunk-4IVRQMZW.js} +2 -2
- package/dist/{chunk-63E37JCN.js → chunk-4RAJT5L2.js} +4 -4
- package/dist/{chunk-45VUHDV2.js → chunk-5CO5G4MN.js} +2 -2
- package/dist/{chunk-LUJCQQ3L.js → chunk-65HWAQ4F.js} +2 -2
- package/dist/{chunk-T67LUYCR.js → chunk-77NTFICT.js} +5 -5
- package/dist/chunk-A2WFUMUN.js +86 -0
- package/dist/chunk-A2WFUMUN.js.map +1 -0
- package/dist/{chunk-UE6RRXMF.js → chunk-A4F7OIC5.js} +2 -2
- package/dist/chunk-AHA5VQGP.js +117 -0
- package/dist/chunk-AHA5VQGP.js.map +1 -0
- package/dist/{chunk-RRJBDXAQ.js → chunk-B377OKUP.js} +2 -2
- package/dist/{chunk-IUKYFTGW.js → chunk-B3DR2JBZ.js} +140 -125
- package/dist/chunk-B3DR2JBZ.js.map +1 -0
- package/dist/{chunk-Z7JIZ42P.js → chunk-BN2EBCLB.js} +3 -3
- package/dist/{chunk-YYOMGOHB.js → chunk-BOK6BN5M.js} +2 -2
- package/dist/{chunk-U6UNF5ZS.js → chunk-BPK32FRM.js} +3 -3
- package/dist/{chunk-OH7QLI6W.js → chunk-BPPUH5JM.js} +5 -5
- package/dist/{chunk-O6ZSWHVR.js → chunk-C2KE5DMD.js} +4 -4
- package/dist/{chunk-47F6WWLQ.js → chunk-C73N66PR.js} +2 -2
- package/dist/{chunk-WRT7GJ2D.js → chunk-CIWMTNHW.js} +4 -4
- package/dist/{chunk-HF3BKUVV.js → chunk-CL4JU3DF.js} +7 -7
- package/dist/{chunk-O55EKIEC.js → chunk-D3ZKHLN2.js} +2 -2
- package/dist/chunk-D5S6RL32.js +67137 -0
- package/dist/chunk-D5S6RL32.js.map +1 -0
- package/dist/{chunk-ETZLQOUR.js → chunk-D5XG2KPS.js} +2 -2
- package/dist/{chunk-CD4BCCNP.js → chunk-DJ7WVEWX.js} +2 -2
- package/dist/{chunk-PWXPRVLK.js → chunk-DNY63QWJ.js} +2 -2
- package/dist/{chunk-4CJTQHEG.js → chunk-ESLOLCD4.js} +3 -3
- package/dist/{chunk-VILPVT4S.js → chunk-EZ47HOJ6.js} +4 -4
- package/dist/{chunk-EFYN5I7Z.js → chunk-F4QFU5IZ.js} +2 -2
- package/dist/{chunk-T6OZW2WR.js → chunk-FA7SLQ5X.js} +7 -1
- package/dist/chunk-FA7SLQ5X.js.map +1 -0
- package/dist/{chunk-BRLXOZLM.js → chunk-FQAQ63QA.js} +729 -17
- package/dist/chunk-FQAQ63QA.js.map +1 -0
- package/dist/{chunk-FSO3G4JJ.js → chunk-FWRXW7CZ.js} +5000 -2748
- package/dist/chunk-FWRXW7CZ.js.map +1 -0
- package/dist/{chunk-XYKBWTWI.js → chunk-FZZMLGWQ.js} +2 -2
- package/dist/{chunk-FNXQZGUS.js → chunk-GBJUTX44.js} +2 -2
- package/dist/{chunk-YLXETSAH.js → chunk-GCZJ7XRI.js} +2 -2
- package/dist/{chunk-UDKWFDV2.js → chunk-HLUHEMN4.js} +27 -3
- package/dist/chunk-HLUHEMN4.js.map +1 -0
- package/dist/{chunk-SUSW74WU.js → chunk-IL3RHBWM.js} +56 -5
- package/dist/chunk-IL3RHBWM.js.map +1 -0
- package/dist/{chunk-JV4S6VDH.js → chunk-ILY5SSOM.js} +2 -2
- package/dist/{chunk-EXHXJETE.js → chunk-IQ55QGY5.js} +2 -2
- package/dist/{chunk-4J363OAA.js → chunk-J7BIFOYP.js} +2 -2
- package/dist/{chunk-QFEDITXM.js → chunk-JNDMIAJ4.js} +2 -2
- package/dist/chunk-JTSSSR4L.js +359 -0
- package/dist/chunk-JTSSSR4L.js.map +1 -0
- package/dist/{chunk-5KBIOI4G.js → chunk-JVBAPAWZ.js} +217 -13
- package/dist/chunk-JVBAPAWZ.js.map +1 -0
- package/dist/{chunk-E5PPE4VA.js → chunk-K2VRKCPA.js} +2 -2
- package/dist/{chunk-MKRYQROF.js → chunk-LGEHAQHK.js} +4 -4
- package/dist/{chunk-7HTUYFR3.js → chunk-LLPMMMWG.js} +27 -10
- package/dist/chunk-LLPMMMWG.js.map +1 -0
- package/dist/{chunk-XYTQJD7F.js → chunk-LMJVP5CM.js} +2 -2
- package/dist/{chunk-E7YZXWIS.js → chunk-LNGELD2M.js} +2 -2
- package/dist/{chunk-FQKBJJYB.js → chunk-LPV72KRQ.js} +2 -2
- package/dist/{chunk-2LCRG2YV.js → chunk-M2XR6B6V.js} +2 -2
- package/dist/{chunk-EQ4U73UH.js → chunk-MLAMXQAW.js} +14 -2
- package/dist/chunk-MLAMXQAW.js.map +1 -0
- package/dist/{chunk-ZU5JDLOH.js → chunk-MMRTPH3J.js} +2 -2
- package/dist/{chunk-TVIVY7KU.js → chunk-NED7IR7B.js} +4 -4
- package/dist/{chunk-6F5MJFXY.js → chunk-NHVAX7MH.js} +2 -2
- package/dist/{chunk-TG3R2SID.js → chunk-NMGHGTVR.js} +5 -5
- package/dist/{chunk-YCNIGRRF.js → chunk-NS7U4ZYU.js} +13 -117
- package/dist/chunk-NS7U4ZYU.js.map +1 -0
- package/dist/{chunk-NGHDW6UU.js → chunk-NUQEREIP.js} +2 -2
- package/dist/{chunk-5IIQU4JZ.js → chunk-OB72KNMF.js} +4 -4
- package/dist/{chunk-RIMK327Y.js → chunk-OUVYYKYU.js} +7 -7
- package/dist/{chunk-QJPJXCS4.js → chunk-P3WRNWWM.js} +157 -4
- package/dist/chunk-P3WRNWWM.js.map +1 -0
- package/dist/{chunk-E6M225BJ.js → chunk-PC5DRBGD.js} +18 -8
- package/dist/chunk-PC5DRBGD.js.map +1 -0
- package/dist/{chunk-RWGRSKN5.js → chunk-PT4DZDJA.js} +2 -2
- package/dist/{chunk-7EPY3IQL.js → chunk-PZJQ46DH.js} +2 -2
- package/dist/{chunk-MXHMNKWG.js → chunk-QDESY76F.js} +3 -3
- package/dist/{chunk-E3A7ELSG.js → chunk-QHARXWTC.js} +2 -2
- package/dist/{chunk-BLJT6JP2.js → chunk-QMFAMOT2.js} +2 -2
- package/dist/{chunk-I6QGI65T.js → chunk-QRMG4HK4.js} +3 -3
- package/dist/{chunk-ZU3NJNO7.js → chunk-QSF5SJAM.js} +4 -4
- package/dist/{chunk-5IYOKDM4.js → chunk-R23JWJD3.js} +5 -5
- package/dist/{chunk-RHQLIHMB.js → chunk-R4BBGPI2.js} +218 -218
- package/dist/chunk-R4BBGPI2.js.map +1 -0
- package/dist/{chunk-NT7F7WJQ.js → chunk-RFUL2ZIQ.js} +291 -93
- package/dist/chunk-RFUL2ZIQ.js.map +1 -0
- package/dist/{chunk-E4IRW2FG.js → chunk-RKABLU5M.js} +233 -40
- package/dist/chunk-RKABLU5M.js.map +1 -0
- package/dist/{chunk-P4WNBSTW.js → chunk-RNG7S3FY.js} +2 -2
- package/dist/{chunk-IPT2OY4B.js → chunk-RQFXZYTF.js} +35 -33
- package/dist/chunk-RQFXZYTF.js.map +1 -0
- package/dist/{chunk-5HFXGXE5.js → chunk-RUTN5MMC.js} +7 -9
- package/dist/{chunk-5HFXGXE5.js.map → chunk-RUTN5MMC.js.map} +1 -1
- package/dist/{chunk-AP6NCP3V.js → chunk-S3S72HRM.js} +8 -6
- package/dist/chunk-S3S72HRM.js.map +1 -0
- package/dist/{chunk-ZGFLIK5H.js → chunk-SPAKBUJY.js} +2 -2
- package/dist/{chunk-ER7XANP3.js → chunk-SQ3GEIEL.js} +4 -4
- package/dist/{chunk-PMJFRDJI.js → chunk-SUTEBYGI.js} +2 -2
- package/dist/{chunk-HVX4LPNY.js → chunk-T4KY6UYF.js} +5 -3
- package/dist/{chunk-HVX4LPNY.js.map → chunk-T4KY6UYF.js.map} +1 -1
- package/dist/{chunk-R6HMAIKM.js → chunk-TOSPNM4T.js} +2 -2
- package/dist/{chunk-RMXS4I66.js → chunk-TVDJEUV5.js} +2 -2
- package/dist/{chunk-PLCYKAWH.js → chunk-TYRWSE4B.js} +2 -2
- package/dist/{chunk-B4QYQFGY.js → chunk-UBEKET2V.js} +383 -36
- package/dist/chunk-UBEKET2V.js.map +1 -0
- package/dist/{chunk-IQWUACVG.js → chunk-UHMHJX5G.js} +3 -3
- package/dist/{chunk-YODUDA6R.js → chunk-UN4RVUG2.js} +22 -22
- package/dist/{chunk-E6Z4FBX6.js → chunk-V2QSNFCT.js} +2 -2
- package/dist/{chunk-NBH6K6G5.js → chunk-V65H7MI6.js} +345 -16
- package/dist/chunk-V65H7MI6.js.map +1 -0
- package/dist/chunk-W54Z2MOP.js +4500 -0
- package/dist/chunk-W54Z2MOP.js.map +1 -0
- package/dist/{chunk-7W3RXOIG.js → chunk-WGGRZYSQ.js} +14 -14
- package/dist/{chunk-RIZ5NUNN.js → chunk-WQ4XKIOX.js} +4 -4
- package/dist/{chunk-QEYTRFR3.js → chunk-X26YOFGS.js} +2 -2
- package/dist/{chunk-ITHZFHST.js → chunk-X2BVB74H.js} +2 -2
- package/dist/{chunk-6F42QONS.js → chunk-X5HGU2EM.js} +4 -4
- package/dist/{chunk-GVGAO3WV.js → chunk-XJ2S5UBF.js} +3 -3
- package/dist/{chunk-IBJ6U753.js → chunk-XKZBZOKV.js} +4 -4
- package/dist/{chunk-65AUYLU3.js → chunk-XPXHQI6N.js} +2 -2
- package/dist/chunk-XRWWCW4H.js +102 -0
- package/dist/chunk-XRWWCW4H.js.map +1 -0
- package/dist/{chunk-HH5LY6RR.js → chunk-YIXJSW5M.js} +5 -5
- package/dist/{chunk-2JSDPUKD.js → chunk-YMFPFXEX.js} +2 -2
- package/dist/{chunk-N4KAE2NB.js → chunk-Z3FTSHT5.js} +3 -3
- package/dist/{chunk-7GLJMDEQ.js → chunk-ZDV5YWID.js} +6 -6
- package/dist/{chunk-645WOU5I.js → chunk-ZDZJNXL6.js} +4 -4
- package/dist/{chunk-6TCXIRP5.js → chunk-ZKE4CO6B.js} +4 -4
- package/dist/cli.js +303 -185
- package/dist/coding/export-okf-codegraph.js +29 -29
- package/dist/compounding/engine.js +23 -24
- package/dist/config.js +36 -37
- package/dist/connectors/codex-materialize-runner.js +20 -20
- package/dist/connectors/index.js +21 -21
- package/dist/connectors/live/google-drive.d.ts +2 -0
- package/dist/connectors/live/google-drive.d.ts.map +1 -1
- package/dist/consolidation-provenance-check.js +4 -4
- package/dist/consolidation-undo.js +5 -5
- package/dist/contradiction/index.js +7 -6
- package/dist/{contradiction-scan-P2MHYFVG.js → contradiction-scan-IBPYGQZF.js} +4 -3
- package/dist/convergence-refresh.js +22 -22
- package/dist/corpus-watermark.js +23 -23
- package/dist/deep-recall-http-glue.js +2 -2
- package/dist/deep-recall-policy-llm.js +4 -4
- package/dist/direct-answer-wiring.js +2 -2
- package/dist/embedding-fallback.js +1 -1
- package/dist/entity-retrieval.js +21 -21
- package/dist/eval-trajectory-store.js +2 -2
- package/dist/eval-trajectory.js +2 -2
- package/dist/event-order-recall.js +2 -2
- package/dist/explicit-capture.d.ts +3 -2
- package/dist/explicit-capture.d.ts.map +1 -1
- package/dist/explicit-capture.js +530 -6
- package/dist/explicit-cue-recall.js +2 -2
- package/dist/external-wiki-access.js +2 -283
- package/dist/extraction-faithfulness.js +4 -4
- package/dist/extraction-judge.js +5 -5
- package/dist/extraction-normalization.js +1 -1
- package/dist/extraction-quote-grounding.d.ts.map +1 -1
- package/dist/extraction-quote-grounding.js +1 -1
- package/dist/extraction-source-grounding-rules.js +2 -2
- package/dist/extraction-source-grounding.js +3 -3
- package/dist/extraction.js +43 -44
- package/dist/fallback-llm-codex-subscription.js +2 -2
- package/dist/fallback-llm.js +3 -3
- package/dist/{first-start-migration-QFI7B5SH.js → first-start-migration-FILJH3RO.js} +6 -5
- package/dist/{first-start-migration-QFI7B5SH.js.map → first-start-migration-FILJH3RO.js.map} +1 -1
- package/dist/focused-list-recall.js +2 -2
- package/dist/harmonic-retrieval.js +20 -20
- package/dist/index.js +773 -794
- package/dist/lcm/index.js +2 -2
- package/dist/live-connectors-runner.js +2 -3
- package/dist/local-llm-config.js +2 -2
- package/dist/local-llm-helpers.d.ts +4 -0
- package/dist/local-llm-helpers.d.ts.map +1 -1
- package/dist/local-llm-helpers.js +3 -1
- package/dist/local-llm.d.ts +4 -1
- package/dist/local-llm.d.ts.map +1 -1
- package/dist/local-llm.js +4 -4
- package/dist/location/index.js +27 -29
- package/dist/maintenance/memory-governance.js +20 -20
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +20 -20
- package/dist/maintenance/rebuild-memory-projection-runner.js +22 -22
- package/dist/maintenance/rebuild-memory-projection.js +21 -21
- package/dist/memory-browse-operations.js +2 -283
- package/dist/memory-browse.js +8 -7
- package/dist/memory-controller.js +2 -2
- package/dist/memory-subject.js +2 -2
- package/dist/namespaces/migrate.js +21 -21
- package/dist/namespaces/search.js +5 -5
- package/dist/namespaces/storage.js +20 -20
- package/dist/offline-sync-changeset-generations.js +1 -1
- package/dist/offline-sync-embedding-generation.js +1 -1
- package/dist/offline-sync-impression-drain.js +6 -6
- package/dist/offline-sync-snapshot-stream.js +1 -1
- package/dist/offline-sync.js +1 -1
- package/dist/operator-doctor-corpus.js +24 -24
- package/dist/operator-toolkit.js +58 -61
- package/dist/orchestration/backlog-scheduler.js +278 -294
- package/dist/orchestration/backlog-scheduler.js.map +1 -1
- package/dist/orchestration/buffer-drain-runner.js +278 -294
- package/dist/orchestration/extraction-run.d.ts +4 -0
- package/dist/orchestration/extraction-run.d.ts.map +1 -1
- package/dist/orchestration/fact-dedup-window.d.ts +1 -1
- package/dist/orchestration/fact-dedup-window.d.ts.map +1 -1
- package/dist/orchestration/maintenance.js +39 -42
- package/dist/orchestrator.d.ts +9 -11
- package/dist/orchestrator.d.ts.map +1 -1
- package/dist/orchestrator.js +290 -307
- package/dist/page-versioning.js +3 -3
- package/dist/qmd-daemon-session.js +2 -2
- package/dist/qmd.js +3 -3
- package/dist/recall-explain-renderer.js +1 -1
- package/dist/recall-navigation-operations.js +2 -283
- package/dist/recall-navigation.js +332 -59
- package/dist/recall-planner-llm.js +3 -3
- package/dist/recall-state-view-admission.js +6 -6
- package/dist/recall-why-service.js +10 -9
- package/dist/recall-why.js +4 -3
- package/dist/recall-xray-cli.js +2 -2
- package/dist/recall-xray-renderer.js +1 -1
- package/dist/reconcile/manifest.js +3 -3
- package/dist/{resolution-N7H3F2E4.js → resolution-OVVIF7ZY.js} +8 -7
- package/dist/response-guidance-recall.js +2 -2
- package/dist/resume-bundles.js +40 -41
- package/dist/salvage-envelope.js +4 -4
- package/dist/search/factory.js +4 -4
- package/dist/search/index.js +4 -4
- package/dist/semantic-consolidation.js +23 -23
- package/dist/semantic-rule-promotion.js +20 -20
- package/dist/semantic-rule-verifier.js +20 -20
- package/dist/shared-context/manager.js +2 -3
- package/dist/source-agent-qualifier.js +32 -33
- package/dist/standup/build.js +20 -20
- package/dist/storage/buffer-drain-claims.d.ts +97 -12
- package/dist/storage/buffer-drain-claims.d.ts.map +1 -1
- package/dist/storage/buffer-drain-claims.js +1 -1
- package/dist/storage/buffer-session-files.d.ts +4 -0
- package/dist/storage/buffer-session-files.d.ts.map +1 -1
- package/dist/storage/buffer-session-files.js +1 -1
- package/dist/storage/content-hash-index.d.ts +10 -0
- package/dist/storage/content-hash-index.d.ts.map +1 -1
- package/dist/storage.d.ts.map +1 -1
- package/dist/storage.js +19 -19
- package/dist/subject-config.js +3 -3
- package/dist/summarizer.d.ts +4 -1
- package/dist/summarizer.d.ts.map +1 -1
- package/dist/summarizer.js +6 -6
- package/dist/support-passport/index.js +53 -297
- package/dist/targeted-fact-recall.js +2 -2
- package/dist/tier-routing.js +3 -2
- package/dist/{tier-stats-FQGQSFET.js → tier-stats-FXEUJN73.js} +6 -5
- package/dist/{tier-stats-FQGQSFET.js.map → tier-stats-FXEUJN73.js.map} +1 -1
- package/dist/transcript.js +2 -2
- package/dist/transfer/capsule-import.js +4 -4
- package/dist/transfer/export-okf.js +20 -20
- package/dist/verified-recall.js +20 -20
- package/dist/wearables/memory-gen.d.ts +5 -1
- package/dist/wearables/memory-gen.d.ts.map +1 -1
- package/dist/wearables/service.d.ts.map +1 -1
- package/dist/who-knows-cli.js +21 -21
- package/dist/who-knows.js +20 -20
- package/dist/write-envelope.js +3 -3
- package/package.json +2 -2
- package/src/access-boundary.ts +5 -1
- package/src/access-category-alias.test.ts +5 -0
- package/src/access-mcp-frames.test.ts +60 -5
- package/src/access-mcp-frames.ts +72 -18
- package/src/access-mcp.test.ts +66 -2
- package/src/access-mcp.ts +19 -13
- package/src/access-service-coding-write.test.ts +7 -0
- package/src/activity/journal-extract-storage.test.ts +31 -0
- package/src/activity/journal-extract.test.ts +1 -0
- package/src/activity/journal-extract.ts +24 -3
- package/src/buffer-drain-handover.test.ts +5 -1
- package/src/connectors/live/google-drive.test.ts +39 -0
- package/src/connectors/live/google-drive.ts +41 -12
- package/src/explicit-capture.test.ts +109 -17
- package/src/explicit-capture.ts +90 -37
- package/src/extraction-quote-grounding.test.ts +20 -0
- package/src/extraction-quote-grounding.ts +21 -11
- package/src/fact-dedup-window.test.ts +37 -0
- package/src/local-llm-helpers.ts +12 -0
- package/src/local-llm-shutdown.test.ts +194 -0
- package/src/local-llm.ts +32 -30
- package/src/orchestration/extraction-run.ts +12 -3
- package/src/orchestration/fact-dedup-window.ts +5 -1
- package/src/orchestrator-connector-dedup.test.ts +9 -5
- package/src/orchestrator.ts +47 -50
- package/src/storage/buffer-drain-claims.test.ts +385 -1
- package/src/storage/buffer-drain-claims.ts +380 -97
- package/src/storage/buffer-session-files.ts +4 -0
- package/src/storage/content-hash-index.ts +27 -2
- package/src/storage-fact-hash-publish-failure.test.ts +87 -0
- package/src/storage.ts +5 -1
- package/src/summarizer-shutdown.test.ts +195 -0
- package/src/summarizer.ts +15 -2
- package/src/wearables/memory-gen.test.ts +20 -0
- package/src/wearables/memory-gen.ts +14 -7
- package/src/wearables/service.ts +14 -1
- package/src/wearables/storage-io.test.ts +25 -0
- package/dist/chunk-2FGLEF7C.js +0 -61
- package/dist/chunk-2FGLEF7C.js.map +0 -1
- package/dist/chunk-3RLK65ZK.js +0 -203
- package/dist/chunk-3RLK65ZK.js.map +0 -1
- package/dist/chunk-4WR2OD7K.js +0 -43
- package/dist/chunk-4WR2OD7K.js.map +0 -1
- package/dist/chunk-5KBIOI4G.js.map +0 -1
- package/dist/chunk-5M5M22GW.js +0 -346
- package/dist/chunk-5M5M22GW.js.map +0 -1
- package/dist/chunk-7HTUYFR3.js.map +0 -1
- package/dist/chunk-AP6NCP3V.js.map +0 -1
- package/dist/chunk-B4QYQFGY.js.map +0 -1
- package/dist/chunk-BJRTMNCB.js +0 -1919
- package/dist/chunk-BJRTMNCB.js.map +0 -1
- package/dist/chunk-BRLXOZLM.js.map +0 -1
- package/dist/chunk-BSACVS6R.js +0 -621
- package/dist/chunk-BSACVS6R.js.map +0 -1
- package/dist/chunk-DKAA2IHQ.js +0 -3644
- package/dist/chunk-DKAA2IHQ.js.map +0 -1
- package/dist/chunk-E4IRW2FG.js.map +0 -1
- package/dist/chunk-E6M225BJ.js.map +0 -1
- package/dist/chunk-EQ4U73UH.js.map +0 -1
- package/dist/chunk-ETSJD5IV.js +0 -361
- package/dist/chunk-ETSJD5IV.js.map +0 -1
- package/dist/chunk-F55YQP7N.js +0 -336
- package/dist/chunk-F55YQP7N.js.map +0 -1
- package/dist/chunk-FHGWKODN.js +0 -2300
- package/dist/chunk-FHGWKODN.js.map +0 -1
- package/dist/chunk-FLRP63GU.js +0 -32219
- package/dist/chunk-FLRP63GU.js.map +0 -1
- package/dist/chunk-FSO3G4JJ.js.map +0 -1
- package/dist/chunk-ID6JGIMD.js +0 -25
- package/dist/chunk-ID6JGIMD.js.map +0 -1
- package/dist/chunk-IGLJNHOX.js +0 -62
- package/dist/chunk-IGLJNHOX.js.map +0 -1
- package/dist/chunk-IPT2OY4B.js.map +0 -1
- package/dist/chunk-IUKYFTGW.js.map +0 -1
- package/dist/chunk-NBH6K6G5.js.map +0 -1
- package/dist/chunk-NT7F7WJQ.js.map +0 -1
- package/dist/chunk-NTRUKAAE.js +0 -223
- package/dist/chunk-NTRUKAAE.js.map +0 -1
- package/dist/chunk-OGXXGHW6.js +0 -223
- package/dist/chunk-OGXXGHW6.js.map +0 -1
- package/dist/chunk-PPCLZ4JU.js +0 -28
- package/dist/chunk-PPCLZ4JU.js.map +0 -1
- package/dist/chunk-QJPJXCS4.js.map +0 -1
- package/dist/chunk-R2LBF4HH.js +0 -729
- package/dist/chunk-R2LBF4HH.js.map +0 -1
- package/dist/chunk-RHQLIHMB.js.map +0 -1
- package/dist/chunk-RRTVGD3J.js +0 -792
- package/dist/chunk-RRTVGD3J.js.map +0 -1
- package/dist/chunk-SUSW74WU.js.map +0 -1
- package/dist/chunk-T6OZW2WR.js.map +0 -1
- package/dist/chunk-UDKWFDV2.js.map +0 -1
- package/dist/chunk-V7IZKJI3.js +0 -22
- package/dist/chunk-V7IZKJI3.js.map +0 -1
- package/dist/chunk-X562NQFA.js +0 -10144
- package/dist/chunk-X562NQFA.js.map +0 -1
- package/dist/chunk-XDSCJOH7.js +0 -3991
- package/dist/chunk-XDSCJOH7.js.map +0 -1
- package/dist/chunk-YCNIGRRF.js.map +0 -1
- package/dist/chunk-ZTTCDQ4I.js +0 -18796
- package/dist/chunk-ZTTCDQ4I.js.map +0 -1
- /package/dist/{capsule-merge-2IIXFXN5.js.map → capsule-merge-6IDAYTKG.js.map} +0 -0
- /package/dist/{chunk-RGUUBAT5.js.map → chunk-2WCLTWV2.js.map} +0 -0
- /package/dist/{chunk-BQZEGOZ4.js.map → chunk-2YODOG2O.js.map} +0 -0
- /package/dist/{chunk-WYG5UNDY.js.map → chunk-3AUDELZL.js.map} +0 -0
- /package/dist/{chunk-MB6ZJDN6.js.map → chunk-3FBAEPCU.js.map} +0 -0
- /package/dist/{chunk-PIITB2YZ.js.map → chunk-3ZS3NUEI.js.map} +0 -0
- /package/dist/{chunk-ATPWZ4F7.js.map → chunk-4EZWSDFL.js.map} +0 -0
- /package/dist/{chunk-ANZZLRUX.js.map → chunk-4IVRQMZW.js.map} +0 -0
- /package/dist/{chunk-63E37JCN.js.map → chunk-4RAJT5L2.js.map} +0 -0
- /package/dist/{chunk-45VUHDV2.js.map → chunk-5CO5G4MN.js.map} +0 -0
- /package/dist/{chunk-LUJCQQ3L.js.map → chunk-65HWAQ4F.js.map} +0 -0
- /package/dist/{chunk-T67LUYCR.js.map → chunk-77NTFICT.js.map} +0 -0
- /package/dist/{chunk-UE6RRXMF.js.map → chunk-A4F7OIC5.js.map} +0 -0
- /package/dist/{chunk-RRJBDXAQ.js.map → chunk-B377OKUP.js.map} +0 -0
- /package/dist/{chunk-Z7JIZ42P.js.map → chunk-BN2EBCLB.js.map} +0 -0
- /package/dist/{chunk-YYOMGOHB.js.map → chunk-BOK6BN5M.js.map} +0 -0
- /package/dist/{chunk-U6UNF5ZS.js.map → chunk-BPK32FRM.js.map} +0 -0
- /package/dist/{chunk-OH7QLI6W.js.map → chunk-BPPUH5JM.js.map} +0 -0
- /package/dist/{chunk-O6ZSWHVR.js.map → chunk-C2KE5DMD.js.map} +0 -0
- /package/dist/{chunk-47F6WWLQ.js.map → chunk-C73N66PR.js.map} +0 -0
- /package/dist/{chunk-WRT7GJ2D.js.map → chunk-CIWMTNHW.js.map} +0 -0
- /package/dist/{chunk-HF3BKUVV.js.map → chunk-CL4JU3DF.js.map} +0 -0
- /package/dist/{chunk-O55EKIEC.js.map → chunk-D3ZKHLN2.js.map} +0 -0
- /package/dist/{chunk-ETZLQOUR.js.map → chunk-D5XG2KPS.js.map} +0 -0
- /package/dist/{chunk-CD4BCCNP.js.map → chunk-DJ7WVEWX.js.map} +0 -0
- /package/dist/{chunk-PWXPRVLK.js.map → chunk-DNY63QWJ.js.map} +0 -0
- /package/dist/{chunk-4CJTQHEG.js.map → chunk-ESLOLCD4.js.map} +0 -0
- /package/dist/{chunk-VILPVT4S.js.map → chunk-EZ47HOJ6.js.map} +0 -0
- /package/dist/{chunk-EFYN5I7Z.js.map → chunk-F4QFU5IZ.js.map} +0 -0
- /package/dist/{chunk-XYKBWTWI.js.map → chunk-FZZMLGWQ.js.map} +0 -0
- /package/dist/{chunk-FNXQZGUS.js.map → chunk-GBJUTX44.js.map} +0 -0
- /package/dist/{chunk-YLXETSAH.js.map → chunk-GCZJ7XRI.js.map} +0 -0
- /package/dist/{chunk-JV4S6VDH.js.map → chunk-ILY5SSOM.js.map} +0 -0
- /package/dist/{chunk-EXHXJETE.js.map → chunk-IQ55QGY5.js.map} +0 -0
- /package/dist/{chunk-4J363OAA.js.map → chunk-J7BIFOYP.js.map} +0 -0
- /package/dist/{chunk-QFEDITXM.js.map → chunk-JNDMIAJ4.js.map} +0 -0
- /package/dist/{chunk-E5PPE4VA.js.map → chunk-K2VRKCPA.js.map} +0 -0
- /package/dist/{chunk-MKRYQROF.js.map → chunk-LGEHAQHK.js.map} +0 -0
- /package/dist/{chunk-XYTQJD7F.js.map → chunk-LMJVP5CM.js.map} +0 -0
- /package/dist/{chunk-E7YZXWIS.js.map → chunk-LNGELD2M.js.map} +0 -0
- /package/dist/{chunk-FQKBJJYB.js.map → chunk-LPV72KRQ.js.map} +0 -0
- /package/dist/{chunk-2LCRG2YV.js.map → chunk-M2XR6B6V.js.map} +0 -0
- /package/dist/{chunk-ZU5JDLOH.js.map → chunk-MMRTPH3J.js.map} +0 -0
- /package/dist/{chunk-TVIVY7KU.js.map → chunk-NED7IR7B.js.map} +0 -0
- /package/dist/{chunk-6F5MJFXY.js.map → chunk-NHVAX7MH.js.map} +0 -0
- /package/dist/{chunk-TG3R2SID.js.map → chunk-NMGHGTVR.js.map} +0 -0
- /package/dist/{chunk-NGHDW6UU.js.map → chunk-NUQEREIP.js.map} +0 -0
- /package/dist/{chunk-5IIQU4JZ.js.map → chunk-OB72KNMF.js.map} +0 -0
- /package/dist/{chunk-RIMK327Y.js.map → chunk-OUVYYKYU.js.map} +0 -0
- /package/dist/{chunk-RWGRSKN5.js.map → chunk-PT4DZDJA.js.map} +0 -0
- /package/dist/{chunk-7EPY3IQL.js.map → chunk-PZJQ46DH.js.map} +0 -0
- /package/dist/{chunk-MXHMNKWG.js.map → chunk-QDESY76F.js.map} +0 -0
- /package/dist/{chunk-E3A7ELSG.js.map → chunk-QHARXWTC.js.map} +0 -0
- /package/dist/{chunk-BLJT6JP2.js.map → chunk-QMFAMOT2.js.map} +0 -0
- /package/dist/{chunk-I6QGI65T.js.map → chunk-QRMG4HK4.js.map} +0 -0
- /package/dist/{chunk-ZU3NJNO7.js.map → chunk-QSF5SJAM.js.map} +0 -0
- /package/dist/{chunk-5IYOKDM4.js.map → chunk-R23JWJD3.js.map} +0 -0
- /package/dist/{chunk-P4WNBSTW.js.map → chunk-RNG7S3FY.js.map} +0 -0
- /package/dist/{chunk-ZGFLIK5H.js.map → chunk-SPAKBUJY.js.map} +0 -0
- /package/dist/{chunk-ER7XANP3.js.map → chunk-SQ3GEIEL.js.map} +0 -0
- /package/dist/{chunk-PMJFRDJI.js.map → chunk-SUTEBYGI.js.map} +0 -0
- /package/dist/{chunk-R6HMAIKM.js.map → chunk-TOSPNM4T.js.map} +0 -0
- /package/dist/{chunk-RMXS4I66.js.map → chunk-TVDJEUV5.js.map} +0 -0
- /package/dist/{chunk-PLCYKAWH.js.map → chunk-TYRWSE4B.js.map} +0 -0
- /package/dist/{chunk-IQWUACVG.js.map → chunk-UHMHJX5G.js.map} +0 -0
- /package/dist/{chunk-YODUDA6R.js.map → chunk-UN4RVUG2.js.map} +0 -0
- /package/dist/{chunk-E6Z4FBX6.js.map → chunk-V2QSNFCT.js.map} +0 -0
- /package/dist/{chunk-7W3RXOIG.js.map → chunk-WGGRZYSQ.js.map} +0 -0
- /package/dist/{chunk-RIZ5NUNN.js.map → chunk-WQ4XKIOX.js.map} +0 -0
- /package/dist/{chunk-QEYTRFR3.js.map → chunk-X26YOFGS.js.map} +0 -0
- /package/dist/{chunk-ITHZFHST.js.map → chunk-X2BVB74H.js.map} +0 -0
- /package/dist/{chunk-6F42QONS.js.map → chunk-X5HGU2EM.js.map} +0 -0
- /package/dist/{chunk-GVGAO3WV.js.map → chunk-XJ2S5UBF.js.map} +0 -0
- /package/dist/{chunk-IBJ6U753.js.map → chunk-XKZBZOKV.js.map} +0 -0
- /package/dist/{chunk-65AUYLU3.js.map → chunk-XPXHQI6N.js.map} +0 -0
- /package/dist/{chunk-HH5LY6RR.js.map → chunk-YIXJSW5M.js.map} +0 -0
- /package/dist/{chunk-2JSDPUKD.js.map → chunk-YMFPFXEX.js.map} +0 -0
- /package/dist/{chunk-N4KAE2NB.js.map → chunk-Z3FTSHT5.js.map} +0 -0
- /package/dist/{chunk-7GLJMDEQ.js.map → chunk-ZDV5YWID.js.map} +0 -0
- /package/dist/{chunk-645WOU5I.js.map → chunk-ZDZJNXL6.js.map} +0 -0
- /package/dist/{chunk-6TCXIRP5.js.map → chunk-ZKE4CO6B.js.map} +0 -0
- /package/dist/{contradiction-scan-P2MHYFVG.js.map → contradiction-scan-IBPYGQZF.js.map} +0 -0
- /package/dist/{resolution-N7H3F2E4.js.map → resolution-OVVIF7ZY.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/storage/buffer-drain-claims.ts","../src/storage/buffer-session-files.ts"],"sourcesContent":["/**\n * Durable drain claims for the extraction buffer (`remnic buffer drain`).\n *\n * A claim is the atomic handover of one session's buffered turns from the\n * live buffer (daemon or CLI process) to a drain worker, so extraction can\n * run out of process without a live buffer owner resurrecting or losing the\n * turns. Files under `<stateDir>/buffer/drain/`:\n *\n * s-<sha256(key)>.json claim content: { key, entry, claimedAt }\n * — the turns NOT yet extracted. Renamed into\n * place from the session file (atomic on one\n * filesystem), rewritten atomically as chunks\n * drain.\n * s-<sha256(key)>.lease.json { ownerId, pid, acquiredAt, heartbeatAt,\n * leaseMs } — created with exclusive-create so\n * exactly one drainer holds a key.\n * s-<sha256(key)>.json.inbox.jsonl\n * append-only hand-ins from a live buffer owner,\n * one `\\n`-prefixed JSON record per line:\n * { id, key, ...entry }. mergeIntoClaim only\n * appends here (O(incoming)); the claim a reader\n * sees is the body with every record folded in\n * by the identity-aware merge. The drainer's\n * progress write (and ack) folds the inbox into\n * the body, lists the folded ids in the body's\n * `foldedRecords`, and only then deletes the\n * inbox, so a kill between the two replays\n * nothing. A torn last line is skipped: its\n * owner never saw the append succeed.\n * s-<sha256(key)>.json.count cached { pending, drained } turn counts of the\n * body, valid while the body's size and mtime\n * match, so listings and the hand-over gate\n * never parse a body.\n *\n * Rolling back to a build that predates the inbox: run `foldAllInboxes()` (CLI:\n * `remnic buffer drain --fold-inboxes`) first; that build never reads an inbox.\n *\n * Invariants (see the buffer-drain PR for the full protocol):\n * - At every instant the claim (body plus unfolded inbox) holds exactly the\n * turns whose extraction is not durably finished, so a kill at any point\n * loses nothing and the next run resumes.\n * - A live buffer owner that must persist a claimed session hands its\n * in-memory entry INTO the claim (identity-aware, occurrence-preserving\n * merge) instead of writing a session file — it can never resurrect\n * turns the drain already finished.\n * - Claims are idempotent: re-claiming, double-draining, and two\n * concurrent drainers are all safe (per-key mutation lock + exclusive\n * lease; the lock also fences lease takeover and progress writes).\n *\n * All content reads/writes go through the storage's secure file I/O\n * (`BufferFileIo`); only lease/existence checks and the count summary touch\n * raw paths, and claim rewrites and inbox appends serialize on a cross-process\n * held file lock.\n */\n\nimport { randomUUID } from \"node:crypto\";\nimport { hostname } from \"node:os\";\nimport { z } from \"zod\";\nimport { existsSync } from \"node:fs\";\nimport { mkdir, readdir, readFile, rename, stat, unlink, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\n\nimport { bufferSessionFileName, type BufferFileIo } from \"./buffer-session-files.js\";\nimport { bufferTurnIdentityKey, subtractBufferTurns, type DrainedTurnSets } from \"../buffer-turn-helpers.js\";\nimport { log } from \"../logger.js\";\nimport { isErrnoCode } from \"../utils/errno.js\";\nimport { withHeldFileLock } from \"../utils/serialize-mutations.js\";\nimport type { BufferEntryState, BufferTurn } from \"../types.js\";\n\n/** Result of persisting one session's entry. */\nexport interface BufferSessionSaveOutcome {\n /** \"saved\": the session file holds the entry. \"handed_over\": the entry moved into a drain claim. */\n status: \"saved\" | \"handed_over\";\n /** Tombstoned turn identities by their original active/retained list. */\n drainedTurns?: DrainedTurnSets;\n}\n\nexport interface DrainLease {\n /** Unique fencing token for one scheduler/process identity; never reuse it after restart. */\n ownerId: string;\n pid: number;\n /** Host the owner runs on: a takeover may only judge liveness on that host. */\n host: string;\n acquiredAt: string;\n heartbeatAt: string;\n leaseMs: number;\n}\n\nexport interface DrainClaimFile {\n key: string;\n entry: BufferEntryState;\n claimedAt: string;\n /**\n * Turns the drain already extracted. Non-empty means the session was\n * drained and the claim is a TOMBSTONE: a live buffer owner subtracts\n * these from its (possibly stale) copy instead of writing them back, so\n * drained turns can never be resurrected.\n */\n drained?: BufferTurn[];\n /** Same tombstone for turns the drain extracted from `retainedTurns`. */\n drainedRetained?: BufferTurn[];\n /**\n * Pending turns whose only copy sits in the other list than the one they\n * were claimed into (active to retained or back). When such a turn is\n * extracted, its tombstone goes to BOTH lists: a live owner still holds\n * the stale copy in the list the turn started in.\n */\n movedTurns?: BufferTurn[];\n /**\n * Ids of the inbox records the latest compaction folded into this body. The\n * inbox file is deleted AFTER the body write, so a kill in between leaves\n * records that are already in the body; readers skip exactly these ids.\n */\n foldedRecords?: string[];\n}\n\n/** One hand-in appended to the claim's inbox by a live buffer owner. */\ninterface InboxRecord {\n id: string;\n entry: BufferEntryState;\n}\n\n/** A claim's turn counts, cached beside the body so listings never parse it. */\ninterface ClaimSummary {\n key: string;\n /** Identity of the body the counts describe; any rewrite invalidates them. */\n size: number;\n mtimeMs: number;\n pending: number;\n drained: number;\n}\n\nexport type ClaimFromSessionOutcome = \"claimed\" | \"empty\" | \"already_claimed\";\nexport type AdoptOutcome = \"adopted\" | \"busy\";\nexport type AckOutcome = \"acked\" | \"not_empty\" | \"busy\";\n\nexport interface DrainClaimListing {\n key: string;\n turnCount: number;\n leased: boolean;\n leaseExpired: boolean;\n}\n\n/** Lock while a claim is read-modify-written; released on settle. */\nconst CLAIM_LOCK_STALE_MS = 120_000;\nconst CLAIM_LOCK_MAX_WAIT_MS = 120_000;\n\nfunction emptyEntry(): BufferEntryState {\n return { turns: [], lastExtractionAt: null, extractionCount: 0 };\n}\n\nfunction turnCounts(turns: readonly BufferTurn[]): Map<string, number> {\n const counts = new Map<string, number>();\n for (const turn of turns) {\n const key = bufferTurnIdentityKey(turn);\n counts.set(key, (counts.get(key) ?? 0) + 1);\n }\n return counts;\n}\n\n/**\n * Append the incoming occurrences the claim does not hold yet. `counts` is the\n * claim's per-identity occurrence count at the START of this merge (it is\n * updated after, not during, so two equal incoming turns can both land) and\n * stays in step across successive merges, so folding N records costs one pass\n * over the claim instead of N.\n */\nfunction appendNewOccurrences(target: BufferTurn[], counts: Map<string, number>, incoming: readonly BufferTurn[]): void {\n const incomingCounts = new Map<string, number>();\n const added: string[] = [];\n for (const turn of incoming) {\n const key = bufferTurnIdentityKey(turn);\n const count = (incomingCounts.get(key) ?? 0) + 1;\n incomingCounts.set(key, count);\n if (count > (counts.get(key) ?? 0)) {\n target.push(turn);\n added.push(key);\n }\n }\n for (const key of added) counts.set(key, (counts.get(key) ?? 0) + 1);\n}\n\nfunction preserveSourceOccurrences(\n target: BufferTurn[],\n source: readonly BufferTurn[],\n identity: string,\n): void {\n const targetCount = turnCounts(target).get(identity) ?? 0;\n let sourceCount = 0;\n for (const turn of source) {\n if (bufferTurnIdentityKey(turn) !== identity) continue;\n sourceCount += 1;\n if (sourceCount > targetCount) target.push(turn);\n }\n}\n\nfunction appendUnmatched(\n snapshot: readonly BufferTurn[],\n matchedCounts: ReadonlyMap<string, number>,\n unmatched: BufferTurn[],\n): void {\n const remaining = new Map(matchedCounts);\n for (const turn of snapshot) {\n const key = bufferTurnIdentityKey(turn);\n const matched = remaining.get(key) ?? 0;\n if (matched > 0) remaining.set(key, matched - 1);\n else unmatched.push(turn);\n }\n}\n\nfunction removeOneByIdentity(turns: BufferTurn[], identity: string): boolean {\n const index = turns.findIndex((turn) => bufferTurnIdentityKey(turn) === identity);\n if (index < 0) return false;\n turns.splice(index, 1);\n return true;\n}\n\nfunction takeByIdentity(source: readonly BufferTurn[], identity: string, count: number): BufferTurn[] {\n return source.filter((turn) => bufferTurnIdentityKey(turn) === identity).slice(0, count);\n}\n\n/**\n * The claim a reader sees: the body with every not-yet-compacted inbox record\n * merged in order. A record whose id the body already lists (`foldedRecords`)\n * was consumed by a compaction whose inbox delete never ran, so it is skipped\n * exactly. The claim's own lists already exclude what was extracted; each\n * tombstone applies only to the incoming copy in the list the turn was\n * extracted from.\n */\nfunction foldRecords(claim: DrainClaimFile, records: readonly InboxRecord[]): DrainClaimFile {\n const consumed = new Set(claim.foldedRecords);\n const fresh = records.filter((record) => !consumed.has(record.id));\n if (fresh.length === 0) return claim;\n const turns = [...claim.entry.turns];\n const retainedTurns = [...(claim.entry.retainedTurns ?? [])];\n const activeCounts = turnCounts(turns);\n const retainedCounts = turnCounts(retainedTurns);\n const entry = emptyEntry();\n entry.lastExtractionAt = claim.entry.lastExtractionAt;\n entry.extractionCount = claim.entry.extractionCount;\n for (const { entry: incoming } of fresh) {\n appendNewOccurrences(turns, activeCounts, subtractBufferTurns(incoming.turns, claim.drained ?? []));\n appendNewOccurrences(retainedTurns, retainedCounts, subtractBufferTurns(incoming.retainedTurns ?? [], claim.drainedRetained ?? []));\n const stamps = [entry.lastExtractionAt, incoming.lastExtractionAt].filter(\n (value): value is string => value !== null && value !== undefined,\n );\n entry.lastExtractionAt = stamps.sort().at(-1) ?? null;\n entry.extractionCount = Math.max(entry.extractionCount, incoming.extractionCount);\n }\n entry.turns = turns;\n if (retainedTurns.length > 0) entry.retainedTurns = retainedTurns;\n return { ...claim, entry };\n}\n\n/**\n * Is the lease owner still running? Only decidable on the owner's host; a\n * lease from another host counts as alive (its expiry decides).\n */\nfunction isOwnerAlive(lease: DrainLease): boolean {\n if (lease.host !== hostname()) return true;\n if (!Number.isInteger(lease.pid) || lease.pid <= 0) return true;\n try {\n process.kill(lease.pid, 0);\n return true;\n } catch (err) {\n // EPERM: the process exists but belongs to another user.\n // SAFETY: the value comes from this module's own write path; the shape is checked above.\n return (err as NodeJS.ErrnoException)?.code === \"EPERM\";\n }\n}\n\nfunction isLeaseExpired(lease: DrainLease, now = Date.now()): boolean {\n const heartbeat = Date.parse(lease.heartbeatAt);\n return !Number.isFinite(heartbeat) || now - heartbeat > lease.leaseMs;\n}\n\nconst claimBodySchema = z.object({\n key: z.string().min(1),\n entry: z.object({\n turns: z.array(z.unknown()),\n retainedTurns: z.array(z.unknown()).optional(),\n lastExtractionAt: z.string().nullable().optional(),\n extractionCount: z.number().optional(),\n }).optional(),\n turns: z.array(z.unknown()).optional(),\n retainedTurns: z.array(z.unknown()).optional(),\n lastExtractionAt: z.string().nullable().optional(),\n extractionCount: z.number().optional(),\n claimedAt: z.string().optional(),\n drained: z.array(z.unknown()).optional(),\n drainedRetained: z.array(z.unknown()).optional(),\n movedTurns: z.array(z.unknown()).optional(),\n foldedRecords: z.array(z.string()).optional(),\n});\n\nfunction parseBody(raw: string): DrainClaimFile | null {\n let body: z.infer<typeof claimBodySchema>;\n try {\n body = claimBodySchema.parse(JSON.parse(raw));\n } catch {\n return null;\n }\n // Two on-disk shapes, one format: a claim born from rename keeps the flat\n // session-file shape ({key, turns, ...}) until its first rewrite, which\n // nests under `entry`. Accept both.\n const source = body.entry && Array.isArray(body.entry.turns) ? body.entry : body;\n if (!Array.isArray(source.turns)) return null;\n const entry = emptyEntry();\n // SAFETY: the schema parsed these as an array of unknown; the claim file\n // is written only by this module (BufferSessionFiles.save), so the entries\n // are BufferTurn values.\n // SAFETY: the claim file is written only by this module, so the parsed\n // turn arrays hold BufferTurn values.\n // SAFETY: the value comes from this module's own write path; the shape is checked above.\n entry.turns = source.turns as BufferTurn[];\n if (source.retainedTurns) {\n // SAFETY: same boundary as the turns above (this module writes the file).\n entry.retainedTurns = source.retainedTurns as BufferTurn[];\n }\n entry.lastExtractionAt = source.lastExtractionAt ?? null;\n entry.extractionCount = Number.isFinite(source.extractionCount) ? Number(source.extractionCount) : 0;\n const claim: DrainClaimFile = {\n key: body.key,\n entry,\n claimedAt: body.claimedAt ?? new Date().toISOString(),\n };\n if (Array.isArray(body.drained)) {\n // SAFETY: same boundary as the turns above (this module writes the file).\n claim.drained = body.drained as BufferTurn[];\n }\n if (Array.isArray(body.drainedRetained)) {\n // SAFETY: same boundary as the turns above (this module writes the file).\n claim.drainedRetained = body.drainedRetained as BufferTurn[];\n }\n if (Array.isArray(body.movedTurns)) {\n // SAFETY: same boundary as the turns above (this module writes the file).\n claim.movedTurns = body.movedTurns as BufferTurn[];\n }\n if (body.foldedRecords) claim.foldedRecords = body.foldedRecords;\n return claim;\n}\n\nconst inboxRecordSchema = z.object({\n id: z.string().min(1),\n turns: z.array(z.unknown()),\n retainedTurns: z.array(z.unknown()).optional(),\n lastExtractionAt: z.string().nullable().optional(),\n extractionCount: z.number().optional(),\n});\n\n/**\n * Parse an inbox file: one JSON record per line. A record that does not parse\n * (a torn tail from a kill mid-append) is skipped: its owner never saw the\n * append succeed and keeps the save pending. Records are newline-PREFIXED, so\n * a torn tail can never fuse with the next record.\n */\nfunction parseInbox(raw: string): InboxRecord[] {\n const records: InboxRecord[] = [];\n for (const line of raw.split(\"\\n\")) {\n if (line.length === 0) continue;\n let record: z.infer<typeof inboxRecordSchema>;\n try {\n record = inboxRecordSchema.parse(JSON.parse(line));\n } catch {\n continue;\n }\n // SAFETY: the inbox is written only by mergeIntoClaim from a BufferEntryState, same boundary as claim bodies.\n const turns = record.turns as BufferTurn[];\n const entry: BufferEntryState = {\n turns,\n lastExtractionAt: record.lastExtractionAt ?? null,\n extractionCount: Number.isFinite(record.extractionCount) ? Number(record.extractionCount) : 0,\n };\n if (record.retainedTurns) {\n // SAFETY: same boundary as the turns above.\n entry.retainedTurns = record.retainedTurns as BufferTurn[];\n }\n records.push({ id: record.id, entry });\n }\n return records;\n}\n\nfunction pendingTurns(entry: BufferEntryState): number {\n return entry.turns.length + (entry.retainedTurns?.length ?? 0);\n}\n\nconst summarySchema = z.object({\n key: z.string().min(1),\n size: z.number(),\n mtimeMs: z.number(),\n pending: z.number(),\n drained: z.number(),\n});\n\nconst leaseSchema = z.object({\n ownerId: z.string().min(1),\n pid: z.number().optional(),\n host: z.string().optional(),\n acquiredAt: z.string().optional(),\n heartbeatAt: z.string(),\n leaseMs: z.number(),\n});\n\nfunction parseLease(raw: string): DrainLease | null {\n let lease: z.infer<typeof leaseSchema>;\n try {\n lease = leaseSchema.parse(JSON.parse(raw));\n } catch {\n return null;\n }\n return {\n ownerId: lease.ownerId,\n pid: lease.pid ?? 0,\n host: lease.host ?? \"\",\n acquiredAt: lease.acquiredAt ?? lease.heartbeatAt,\n heartbeatAt: lease.heartbeatAt,\n leaseMs: lease.leaseMs,\n };\n}\nfunction leaseBelongsToProcess(lease: DrainLease | null, ownerId: string): boolean {\n return lease !== null && lease.ownerId === ownerId && lease.pid === process.pid && lease.host === hostname();\n}\n\n\n/** Hand-in log beside a claim body; `.jsonl`, so claim-directory scans (`.json`) never mistake it for a claim. */\nconst INBOX_SUFFIX = \".inbox.jsonl\";\n/** Cached turn counts beside a claim body (see `ClaimSummary`). */\nconst COUNT_SUFFIX = \".count\";\n\n/** Claim bodies `listPage` may read per requested entry: bounds one scan's\n * I/O even when the directory is mostly empty tombstones. */\nconst LIST_PAGE_SCAN_FACTOR = 8;\n\nexport class BufferDrainClaims {\n constructor(\n private readonly stateDir: string,\n private readonly io: BufferFileIo,\n ) {}\n\n private get dir(): string {\n return path.join(this.stateDir, \"buffer\", \"drain\");\n }\n\n private fileFor(key: string): string {\n return path.join(this.dir, bufferSessionFileName(key));\n }\n\n private leaseFileFor(key: string): string {\n return `${this.fileFor(key)}.lease.json`;\n }\n\n private lockFileFor(key: string): string {\n return `${this.fileFor(key)}.lock`;\n }\n\n /** Append-only hand-in log next to the body (see the file header). */\n private inboxFor(key: string): string {\n return `${this.fileFor(key)}${INBOX_SUFFIX}`;\n }\n\n /** Sync existence check for hot-path gates (`SmartBuffer.isSessionClaimed`). */\n isClaimed(key: string): boolean {\n return existsSync(this.fileFor(key));\n }\n\n /** Test + CLI seam: the lease file path for direct inspection. */\n leasePathForTest(key: string): string {\n return this.leaseFileFor(key);\n }\n\n private async readClaimBody(key: string): Promise<DrainClaimFile | null> {\n try {\n return parseBody(await this.io.read(this.fileFor(key)));\n } catch {\n return null;\n }\n }\n\n /**\n * Every inbox record, oldest first. Only \"no inbox\" reads as empty: any\n * other failure (a locked or undecryptable store) propagates, because a\n * compaction that mistook an unreadable inbox for an empty one would delete\n * the handed-in turns.\n */\n private async readInbox(key: string): Promise<InboxRecord[]> {\n try {\n return parseInbox(await this.io.read(this.inboxFor(key)));\n } catch (err) {\n if (isErrnoCode(err, \"ENOENT\")) return [];\n throw err;\n }\n }\n\n /**\n * The body with its inbox folded in, plus the ids of every record the inbox\n * holds (what a compaction must list as consumed). The inbox is read BEFORE\n * the body: a compaction landing between the two reads leaves records the\n * newer body already lists, which the fold skips by id, whereas the reverse\n * order could pair an old body with a deleted inbox and lose their turns.\n */\n private async readFolded(key: string): Promise<{ claim: DrainClaimFile; consumed: string[] } | null> {\n const records = await this.readInbox(key);\n const body = await this.readClaimBody(key);\n if (!body) return null;\n return { claim: foldRecords(body, records), consumed: records.map((record) => record.id) };\n }\n\n /** The claim content for `key` (body plus inbox), or null when it is not claimed. */\n async load(key: string): Promise<DrainClaimFile | null> {\n return (await this.readFolded(key))?.claim ?? null;\n }\n\n /**\n * Rewrite the body from a folded claim and consume the inbox it folded.\n * Order is the crash contract: body first (it lists `consumed` so a replay\n * skips them), then the summary, then the inbox delete. Callers hold the\n * claim lock, so no append can land between the read and the delete.\n */\n private async writeClaimBody(key: string, claim: DrainClaimFile, consumed: readonly string[] = []): Promise<void> {\n await mkdir(this.dir, { recursive: true });\n const bodyPath = this.fileFor(key);\n const foldedRecords = consumed.length > 0 ? [...consumed] : undefined;\n await this.io.write(bodyPath, JSON.stringify({ ...claim, key, foldedRecords }));\n await stat(bodyPath).then((identity) => this.writeSummary(bodyPath, claim, identity), () => {});\n await unlink(this.inboxFor(key)).catch(() => {});\n }\n\n /**\n * Best-effort: a missing or stale summary only costs one body parse.\n * `identity` MUST come from a stat taken before `claim` was read (or while\n * the lock holds the body still), never after, or the counts could be\n * tagged with a newer body's identity.\n */\n private async writeSummary(bodyPath: string, claim: DrainClaimFile, identity: { size: number; mtimeMs: number }): Promise<ClaimSummary> {\n const summary: ClaimSummary = {\n key: claim.key,\n size: identity.size,\n mtimeMs: identity.mtimeMs,\n pending: pendingTurns(claim.entry),\n drained: (claim.drained?.length ?? 0) + (claim.drainedRetained?.length ?? 0),\n };\n try {\n await writeFile(`${bodyPath}${COUNT_SUFFIX}`, JSON.stringify(summary));\n } catch (err) {\n log.debug(`buffer drain: claim summary write skipped for ${claim.key}: ${err instanceof Error ? err.message : String(err)}`);\n }\n return summary;\n }\n\n /**\n * Turn counts of the BODY at `bodyPath` without parsing it: the summary file\n * is trusted only while the body's size and mtime still match the ones it\n * was written against; otherwise the body is parsed once and the summary\n * refreshed. Null when the claim body is absent or unreadable.\n */\n private async readSummary(bodyPath: string): Promise<ClaimSummary | null> {\n let identity;\n try {\n identity = await stat(bodyPath);\n } catch {\n return null;\n }\n try {\n const cached = summarySchema.parse(JSON.parse(await readFile(`${bodyPath}${COUNT_SUFFIX}`, \"utf8\")));\n if (cached.size === identity.size && cached.mtimeMs === identity.mtimeMs) return cached;\n } catch {\n // No usable summary: fall through to the body.\n }\n let claim: DrainClaimFile | null;\n try {\n claim = parseBody(await this.io.read(bodyPath));\n } catch (err) {\n log.debug(`buffer drain: skipping unreadable claim file ${path.basename(bodyPath)}: ${err instanceof Error ? err.message : String(err)}`);\n return null;\n }\n return claim ? await this.writeSummary(bodyPath, claim, identity) : null;\n }\n\n private async readLease(key: string): Promise<DrainLease | null> {\n try {\n return parseLease(await this.io.read(this.leaseFileFor(key)));\n } catch {\n return null;\n }\n }\n\n private async writeLease(key: string, lease: DrainLease): Promise<void> {\n await mkdir(this.dir, { recursive: true });\n await this.io.write(this.leaseFileFor(key), JSON.stringify(lease));\n }\n\n /**\n * Atomically move a session's persisted file into a claim. The rename is\n * the handover: after it settles the turns exist ONLY as a claim, so no\n * crash window can lose them or leave them in both places. Callers that\n * lose the race (`already_claimed`) simply skip the key.\n *\n * The whole handover runs under the claim's mutation lock, so a claim\n * create can never land on top of an existing claim (POSIX rename would\n * silently replace it) and the lease write cannot race an adopter.\n */\n async claimFromSessionFile(key: string, lease: DrainLease): Promise<ClaimFromSessionOutcome> {\n await mkdir(this.dir, { recursive: true });\n const sessionPath = path.join(this.stateDir, \"buffer\", bufferSessionFileName(key));\n if (existsSync(sessionPath)) {\n // Advisory pre-read: an empty live session belongs to its owner, not\n // the drain. A turn landing between this read and the rename is fine —\n // the rename moves whatever is there and the claim drains it.\n try {\n const seeded = parseBody(await this.io.read(sessionPath));\n if (seeded && seeded.entry.turns.length === 0 && (seeded.entry.retainedTurns?.length ?? 0) === 0) {\n return \"empty\";\n }\n } catch {\n // Unreadable live file: proceed with the rename and let the claim\n // path report it loudly, like the loader skips corrupt files.\n }\n }\n return await withHeldFileLock(\n this.lockFileFor(key),\n { staleMs: CLAIM_LOCK_STALE_MS, maxWaitMs: CLAIM_LOCK_MAX_WAIT_MS },\n async (acquired) => {\n if (!acquired) return \"already_claimed\";\n // Under the lock the claim check is authoritative: an existing claim\n // keeps its content and its lease; the session file stays with its\n // owner (their next save merges into the claim).\n if (this.isClaimed(key)) return \"already_claimed\";\n // No claim exists, so an inbox here is an orphan from a crash between\n // a release's deletes: the new claim must not replay it.\n await unlink(this.inboxFor(key)).catch(() => {});\n try {\n await rename(sessionPath, this.fileFor(key));\n } catch (err) {\n // The session file is gone: either it never existed, or another\n // drainer claimed it first.\n if (!existsSync(sessionPath)) {\n if (this.isClaimed(key)) return \"already_claimed\";\n return \"empty\";\n }\n throw err;\n }\n const claim = await this.readClaimBody(key);\n if (!claim || pendingTurns(claim.entry) === 0) {\n // Empty content: nothing to drain. Delete the moved file so the\n // empty entry keeps living with its owner, not as a stale claim.\n await unlink(this.fileFor(key)).catch(() => {});\n return \"empty\";\n }\n await stat(this.fileFor(key)).then((identity) => this.writeSummary(this.fileFor(key), claim, identity), () => {});\n await this.writeLease(key, lease);\n return \"claimed\";\n },\n );\n }\n\n /**\n * Take over a claim whose lease is missing, expired, or whose owner died.\n * The whole judgement runs under the claim's mutation lock and re-reads\n * the lease inside it, so exactly one concurrent adopter wins: the loser\n * re-reads the winner's fresh lease and reports \"busy\" instead of\n * unlinking it. A lease whose owner died is taken over in the same call.\n */\n async adopt(key: string, lease: DrainLease): Promise<AdoptOutcome> {\n if (!this.isClaimed(key)) return \"busy\";\n return await withHeldFileLock(\n this.lockFileFor(key),\n { staleMs: CLAIM_LOCK_STALE_MS, maxWaitMs: CLAIM_LOCK_MAX_WAIT_MS },\n async (acquired) => {\n if (!acquired) return \"busy\";\n const existing = await this.readLease(key);\n if (existing?.ownerId === lease.ownerId && existing.pid === lease.pid && existing.host === lease.host) {\n // Reuse the token only from the same process identity.\n await this.writeLease(key, { ...existing, heartbeatAt: new Date().toISOString(), leaseMs: lease.leaseMs });\n return \"adopted\";\n }\n if (existing && !isLeaseExpired(existing)) {\n if (isOwnerAlive(existing)) return \"busy\";\n // The owner died without releasing the claim (killed worker):\n // take it over now instead of waiting for the lease to expire.\n await unlink(this.leaseFileFor(key)).catch(() => {});\n } else if (existing) {\n // Expired lease: clear it before the exclusive create. We hold the\n // lock, so no concurrent adopter can interleave its own unlink/create.\n await unlink(this.leaseFileFor(key)).catch(() => {});\n }\n try {\n await writeFile(this.leaseFileFor(key), JSON.stringify(lease), { flag: \"wx\" });\n } catch (err) {\n // The lease file exists: another drainer took it first.\n if (existsSync(this.leaseFileFor(key))) return \"busy\";\n throw err;\n }\n return \"adopted\";\n },\n );\n }\n\n /**\n * Hand a live owner's in-memory entry to the claim (the path a buffer owner\n * takes instead of persisting a claimed session): ONE append to the inbox,\n * O(incoming), never a read or rewrite of the claim body. Readers fold the\n * inbox over the body with the identity-aware merge and the drainer's next\n * progress write compacts it. The lock serializes the append against that\n * compaction, so a record can never land between its read and its delete.\n */\n async mergeIntoClaim(key: string, incoming: BufferEntryState): Promise<void> {\n await withHeldFileLock(this.lockFileFor(key), { staleMs: CLAIM_LOCK_STALE_MS, maxWaitMs: CLAIM_LOCK_MAX_WAIT_MS }, async (acquired) => {\n if (!acquired) {\n // Never fall back to a session-file write behind a held claim lock:\n // that would resurrect claimed turns. Fail so the owner's save stays\n // pending and retries (SmartBuffer keeps pending state on failure).\n throw new Error(`buffer drain claim for ${key} is busy; retrying the save later`);\n }\n // The claim vanished (acked between the isClaimed check and now):\n // nothing to hand over; the drain already owns everything.\n if (!this.isClaimed(key)) return;\n // Leading newline: a torn tail from a kill mid-append ends at this\n // record's newline instead of fusing into it.\n await this.io.append(this.inboxFor(key), `\\n${JSON.stringify({ id: randomUUID(), key, ...incoming })}`);\n });\n }\n\n /** Drainer progress: replace the claim content with what is left to do.\n *\n * Fenced: `ownerId` must still match the claim's lease (checked under the\n * same lock), so a drainer that lost its lease cannot write progress that\n * would restore turns the new owner already extracted.\n *\n * `seen` is the entry the drainer LOADED (its snapshot of the claim). Only\n * turns that were in that snapshot and are absent from BOTH of the\n * drainer's lists were actually extracted and move to the tombstones — a\n * turn the drainer moved into `entry.retainedTurns` is retained for retry,\n * not extracted. Turns a live owner merged into the claim afterwards stay\n * pending. Without `seen` the pre-existing behavior is kept (every claim\n * turn missing from `entry` counts as extracted).\n */\n async writeEntry(key: string, ownerId: string, entry: BufferEntryState, seen?: BufferEntryState): Promise<void> {\n await withHeldFileLock(this.lockFileFor(key), { staleMs: CLAIM_LOCK_STALE_MS, maxWaitMs: CLAIM_LOCK_MAX_WAIT_MS }, async (acquired) => {\n if (!acquired) throw new Error(`buffer drain claim for ${key} is busy; progress write skipped`);\n const lease = await this.readLease(key);\n if (!leaseBelongsToProcess(lease, ownerId)) {\n throw new Error(`buffer drain claim for ${key} is no longer owned by ${ownerId}; progress write skipped`);\n }\n const folded = await this.readFolded(key);\n if (!folded) return;\n const { claim, consumed } = folded;\n const seenTurns = seen?.turns ?? claim.entry.turns;\n const seenRetained = seen?.retainedTurns ?? claim.entry.retainedTurns ?? [];\n const entryRetained = entry.retainedTurns ?? [];\n const seenActiveCounts = turnCounts(seenTurns);\n const seenRetainedCounts = turnCounts(seenRetained);\n const activeOutputCounts = turnCounts(entry.turns);\n const retainedOutputCounts = turnCounts(entryRetained);\n const matchedActiveCounts = new Map<string, number>();\n const matchedRetainedCounts = new Map<string, number>();\n const ambiguousIdentities = new Set<string>();\n const identityKeys = new Set([\n ...seenActiveCounts.keys(),\n ...seenRetainedCounts.keys(),\n ]);\n const crossedCounts = new Map<string, number>();\n for (const identity of identityKeys) {\n const seenActive = seenActiveCounts.get(identity) ?? 0;\n const seenRetainedCount = seenRetainedCounts.get(identity) ?? 0;\n const activeOutput = activeOutputCounts.get(identity) ?? 0;\n const retainedOutput = retainedOutputCounts.get(identity) ?? 0;\n if (seenActive > 0 && seenRetainedCount > 0 && activeOutput + retainedOutput > 0) {\n // Equal identities across source lists cannot reveal which original\n // occurrence survived a cross-list move. Keep both source lists\n // pending until a later progress write removes every copy.\n matchedActiveCounts.set(identity, seenActive);\n matchedRetainedCounts.set(identity, seenRetainedCount);\n ambiguousIdentities.add(identity);\n continue;\n }\n const matchedActive = Math.min(seenActive, activeOutput);\n const matchedRetained = Math.min(seenRetainedCount, retainedOutput);\n const activeMovedToRetained = Math.min(\n seenActive - matchedActive,\n retainedOutput - matchedRetained,\n );\n const retainedMovedToActive = Math.min(\n seenRetainedCount - matchedRetained,\n activeOutput - matchedActive,\n );\n matchedActiveCounts.set(identity, matchedActive + activeMovedToRetained);\n matchedRetainedCounts.set(identity, matchedRetained + retainedMovedToActive);\n const crossed = activeMovedToRetained + retainedMovedToActive;\n if (crossed > 0) crossedCounts.set(identity, crossed);\n }\n // A pending copy that crossed lists stays tombstoned in its ORIGINAL\n // list too once it is extracted. A copy that crosses back is home again.\n const moved = [...(claim.movedTurns ?? [])];\n for (const [identity, crossed] of crossedCounts) {\n let returned = 0;\n while (returned < crossed && removeOneByIdentity(moved, identity)) returned += 1;\n moved.push(...takeByIdentity([...seenTurns, ...seenRetained], identity, crossed - returned));\n }\n const extractedActive: BufferTurn[] = [];\n appendUnmatched(seenTurns, matchedActiveCounts, extractedActive);\n const extractedRetained: BufferTurn[] = [];\n appendUnmatched(seenRetained, matchedRetainedCounts, extractedRetained);\n const drained = [...(claim.drained ?? []), ...extractedActive];\n const drainedRetained = [...(claim.drainedRetained ?? []), ...extractedRetained];\n for (const turn of extractedActive) {\n if (removeOneByIdentity(moved, bufferTurnIdentityKey(turn))) drainedRetained.push(turn);\n }\n for (const turn of extractedRetained) {\n if (removeOneByIdentity(moved, bufferTurnIdentityKey(turn))) drained.push(turn);\n }\n // Source occurrences of an ambiguous identity are restored BEFORE late\n // arrivals are appended, so a late equal turn cannot stand in for them.\n const keptTurns = [...entry.turns];\n const keptRetained = [...entryRetained];\n for (const identity of ambiguousIdentities) {\n preserveSourceOccurrences(keptTurns, seenTurns, identity);\n preserveSourceOccurrences(keptRetained, seenRetained, identity);\n }\n const late = subtractBufferTurns(claim.entry.turns, seenTurns);\n const lateRetained = subtractBufferTurns(claim.entry.retainedTurns ?? [], seenRetained);\n const next: BufferEntryState = { ...entry, turns: [...keptTurns, ...late] };\n const nextRetained = [...keptRetained, ...lateRetained];\n if (nextRetained.length > 0) next.retainedTurns = nextRetained;\n await this.writeClaimBody(key, {\n ...claim,\n entry: next,\n drained,\n drainedRetained,\n movedTurns: moved.length > 0 ? moved : undefined,\n }, consumed);\n });\n }\n\n /** Extend the lease. \"lost\" means another drainer took the claim over.\n * Serialized on the claim lock so a stale heartbeat can never overwrite a\n * new owner's lease mid-takeover; a contended lock just skips this tick\n * (usually the drainer's own progress write holds it). */\n async heartbeat(key: string, ownerId: string, leaseMs: number): Promise<\"ok\" | \"lost\"> {\n return await withHeldFileLock(this.lockFileFor(key), { staleMs: CLAIM_LOCK_STALE_MS, maxWaitMs: CLAIM_LOCK_MAX_WAIT_MS }, async (acquired) => {\n if (!acquired) return \"ok\";\n const lease = await this.readLease(key);\n if (!lease || !leaseBelongsToProcess(lease, ownerId)) return \"lost\";\n await this.writeLease(key, { ...lease, heartbeatAt: new Date().toISOString(), leaseMs });\n return \"ok\";\n });\n }\n\n /** Give the key back (content stays; the next run resumes it). */\n async releaseLease(key: string, ownerId: string): Promise<void> {\n await withHeldFileLock(\n this.lockFileFor(key),\n { staleMs: CLAIM_LOCK_STALE_MS, maxWaitMs: CLAIM_LOCK_MAX_WAIT_MS },\n async (acquired) => {\n if (!acquired) return;\n const lease = await this.readLease(key);\n if (!leaseBelongsToProcess(lease, ownerId)) return;\n await unlink(this.leaseFileFor(key)).catch(() => {});\n },\n );\n }\n\n /**\n * Finish a claim: only its owner may ack, and only when nothing is left to\n * extract. Non-empty claims stay (deferred content is never dropped here).\n */\n async ack(key: string, ownerId: string): Promise<AckOutcome> {\n return await withHeldFileLock(\n this.lockFileFor(key),\n { staleMs: CLAIM_LOCK_STALE_MS, maxWaitMs: CLAIM_LOCK_MAX_WAIT_MS },\n async (acquired) => {\n if (!acquired) return \"busy\";\n const lease = await this.readLease(key);\n if (!leaseBelongsToProcess(lease, ownerId)) return \"busy\";\n const folded = await this.readFolded(key);\n if (!folded) {\n await unlink(this.leaseFileFor(key)).catch(() => {});\n return \"acked\";\n }\n // Compact here too: a claim whose inbox only repeats drained turns\n // would otherwise keep reading as unfinished forever.\n if (folded.consumed.length > 0) await this.writeClaimBody(key, folded.claim, folded.consumed);\n if (pendingTurns(folded.claim.entry) > 0) return \"not_empty\";\n // Keep the empty claim as a tombstone until its live owner consumes it.\n await unlink(this.leaseFileFor(key)).catch(() => {});\n return \"acked\";\n },\n );\n }\n\n /** Return extracted identities with their active/retained provenance intact. */\n async drainedTurns(key: string): Promise<DrainedTurnSets> {\n const claim = await this.readClaimBody(key);\n return {\n turns: claim?.drained ?? [],\n retainedTurns: claim?.drainedRetained ?? [],\n };\n }\n\n /** Return this lease owner's progress, fenced against claim takeover. */\n async drainedTurnsForOwner(key: string, ownerId: string): Promise<DrainedTurnSets | null> {\n return await withHeldFileLock(\n this.lockFileFor(key),\n { staleMs: CLAIM_LOCK_STALE_MS, maxWaitMs: CLAIM_LOCK_MAX_WAIT_MS },\n async (acquired) => {\n if (!acquired) throw new Error(`buffer drain claim for ${key} is busy; cannot reconcile progress`);\n const lease = await this.readLease(key);\n if (!leaseBelongsToProcess(lease, ownerId)) return null;\n const claim = await this.readClaimBody(key);\n return claim ? { turns: claim.drained ?? [], retainedTurns: claim.drainedRetained ?? [] } : null;\n }\n );\n }\n\n /**\n * Is the drain for `key` FINISHED (acked): the claim holds extracted turns\n * and nothing pending, and the drainer dropped its lease. A claim with\n * partial progress or a live lease is still being drained — its owner must\n * merge into it, never release it.\n */\n async isDrained(key: string): Promise<boolean> {\n if ((await this.readLease(key)) !== null) return false;\n // This runs on every hand-over save. The cached counts may only answer\n // FALSE (pending turns, nothing drained): a stale cache in that direction\n // costs a deferred tombstone. They must never answer TRUE, because the\n // caller then releases the claim and unlinks whatever is still pending, and\n // a same-size rewrite inside one mtime tick can leave a stale cache that\n // says \"nothing pending\". So a TRUE is verified by one real fold, once per\n // finished drain.\n const summary = await this.readSummary(this.fileFor(key));\n if (!summary || summary.drained === 0 || summary.pending > 0) return false;\n const claim = await this.load(key);\n return claim !== null && (claim.drained?.length ?? 0) + (claim.drainedRetained?.length ?? 0) > 0 && pendingTurns(claim.entry) === 0;\n }\n\n /** Drop the claim entirely (its owner consumed the tombstone), inbox and summary included. */\n async release(key: string): Promise<void> {\n const bodyPath = this.fileFor(key);\n for (const file of [this.inboxFor(key), bodyPath, `${bodyPath}${COUNT_SUFFIX}`, this.leaseFileFor(key)]) {\n await unlink(file).catch(() => {});\n }\n }\n\n /** Claim body file names in the drain directory (no leases, inboxes, summaries or locks). */\n private async claimNames(): Promise<string[] | null> {\n try {\n return (await readdir(this.dir)).filter((name) => name.endsWith(\".json\") && !name.endsWith(\".lease.json\")).sort();\n } catch (err) {\n // SAFETY: readdir rejects with NodeJS system errors; only the ENOENT\n // (no claims directory yet) case maps to an empty listing.\n if ((err as NodeJS.ErrnoException | undefined)?.code === \"ENOENT\") return null;\n throw err;\n }\n }\n\n /**\n * One claim's listing from its summary plus its inbox: the body is never\n * parsed for a count. While an inbox is unfolded the turn count is an UPPER\n * bound (records can repeat turns the body holds or already drained); the\n * drain that picks the claim up folds exactly and its ack compacts the\n * inbox, so an over-count costs one cheap drain run, never a lost turn.\n */\n private async describeClaim(name: string): Promise<DrainClaimListing | null> {\n const summary = await this.readSummary(path.join(this.dir, name));\n if (!summary) return null;\n let inboxTurns = 0;\n try {\n for (const record of await this.readInbox(summary.key)) inboxTurns += pendingTurns(record.entry);\n } catch (err) {\n log.debug(`buffer drain: skipping claim ${name} with an unreadable inbox: ${err instanceof Error ? err.message : String(err)}`);\n return null;\n }\n const lease = await this.readLease(summary.key);\n return {\n key: summary.key,\n turnCount: summary.pending + inboxTurns,\n leased: lease !== null,\n leaseExpired: lease !== null ? isLeaseExpired(lease) : true,\n };\n }\n\n /** Every claim with its lease state (CLI scan + summaries). */\n async list(): Promise<DrainClaimListing[]> {\n const out: DrainClaimListing[] = [];\n for (const name of (await this.claimNames()) ?? []) {\n const listing = await this.describeClaim(name);\n if (listing) out.push(listing);\n }\n return out;\n }\n\n /**\n * Paged listing for bounded periodic scans: at most `limit` claims with\n * pending turns, starting AFTER `afterName` (a raw entry name returned as\n * `nextCursor` by a previous page — file-name order is stable, so a\n * rotating cursor visits every claim fairly without ever materializing\n * the whole directory's bodies). Empty tombstones never count toward the\n * limit; the number of claims examined per call is bounded separately\n * (`LIST_PAGE_SCAN_FACTOR` per requested entry), and the cursor advances\n * past every scanned name so a long tombstone run is crossed over several\n * pages instead of starving the pending claims behind it.\n */\n async listPage(afterName: string | undefined, limit: number): Promise<{ entries: DrainClaimListing[]; nextCursor?: string }> {\n const names = await this.claimNames();\n if (names === null) return { entries: [] };\n const start = afterName === undefined ? 0 : names.findIndex((name) => name > afterName);\n const out: DrainClaimListing[] = [];\n // The cursor is the LAST CONSUMED entry name: the next page starts\n // strictly after it, so the first unconsumed name is never skipped.\n // Returning the first unconsumed name instead would make every page\n // boundary permanently skip one claim.\n let cursor: string | undefined;\n const scanBudget = Math.max(limit, 1) * LIST_PAGE_SCAN_FACTOR;\n let scanned = 0;\n for (let index = start < 0 ? names.length : start; index < names.length; index += 1) {\n if (out.length >= limit || scanned >= scanBudget) break;\n const name = names[index]!;\n scanned += 1;\n cursor = name;\n const listing = await this.describeClaim(name);\n if (listing && listing.turnCount > 0) out.push(listing);\n }\n return { entries: out, nextCursor: cursor };\n }\n\n /**\n * Rollback helper: fold every claim's inbox into its body and delete the\n * inboxes, so a build that predates the inbox (it never reads one) sees every\n * handed-in turn. Run it with the daemon stopped, BEFORE downgrading; the\n * same fold is what compaction does, so it is safe to run on a live store.\n * Returns how many inboxes were folded.\n */\n async foldAllInboxes(): Promise<number> {\n let names: string[];\n try {\n names = (await readdir(this.dir)).filter((name) => name.endsWith(INBOX_SUFFIX));\n } catch (err) {\n if (isErrnoCode(err, \"ENOENT\")) return 0;\n throw err;\n }\n let folded = 0;\n for (const name of names) {\n const claim = await this.readClaimBodyByName(name.slice(0, -INBOX_SUFFIX.length));\n if (!claim) continue;\n folded += await withHeldFileLock(\n this.lockFileFor(claim.key),\n { staleMs: CLAIM_LOCK_STALE_MS, maxWaitMs: CLAIM_LOCK_MAX_WAIT_MS },\n async (acquired) => {\n if (!acquired) throw new Error(`buffer drain claim for ${claim.key} is busy; its inbox was not folded`);\n const current = await this.readFolded(claim.key);\n if (!current) return 0;\n if (current.consumed.length === 0) {\n await unlink(this.inboxFor(claim.key)).catch(() => {});\n return 0;\n }\n await this.writeClaimBody(claim.key, current.claim, current.consumed);\n return 1;\n },\n );\n }\n return folded;\n }\n\n private async readClaimBodyByName(name: string): Promise<DrainClaimFile | null> {\n try {\n return parseBody(await this.io.read(path.join(this.dir, name)));\n } catch (err) {\n log.debug(`buffer drain: skipping unreadable claim file ${name}: ${err instanceof Error ? err.message : String(err)}`);\n return null;\n }\n }\n}\n","import { BufferDrainClaims, type BufferSessionSaveOutcome } from \"./buffer-drain-claims.js\";\nimport { createHash } from \"node:crypto\";\nimport type { Stats } from \"node:fs\";\nimport { lstat, readdir, unlink } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { subtractBufferTurns } from \"../buffer-turn-helpers.js\";\nimport { log } from \"../logger.js\";\nimport { SecureStoreDecryptError, SecureStoreLockedError } from \"../secure-store/secure-fs.js\";\nimport type { BufferEntryState, BufferState, BufferTurn } from \"../types.js\";\n\n/** The secure-store file I/O the owning StorageManager already provides. */\nexport interface BufferFileIo {\n read(filePath: string): Promise<string>;\n write(filePath: string, content: string): Promise<void>;\n /** Durable append (drain-claim inboxes). Implementations must persist\n * `content` before resolving; a whole-file read+concat+write rewrite is\n * acceptable — inbox files stay small between drainer compactions. */\n append(filePath: string, content: string): Promise<void>;\n}\n\ntype FsError = NodeJS.ErrnoException;\n\nfunction isMissing(err: FsError | null): boolean {\n return err?.code === \"ENOENT\";\n}\n\nfunction asFsError(err: Error): FsError {\n return err;\n}\n\n/**\n * Case-independent, collision-free file name for a buffer key: the lowercase\n * hex SHA-256 of the key under a fixed prefix. Hex has no case and no path\n * characters, so `Session-A` and `session-a` get different names even on\n * case-insensitive filesystems, every key (short or long) lives in the same\n * naming domain, and the key itself is stored inside the file (loading never\n * inverts the hash).\n */\nexport function bufferSessionFileName(key: string): string {\n return `s-${createHash(\"sha256\").update(key).digest(\"hex\")}.json`;\n}\n\n/** Flatten a legacy BufferState into per-session entries (top-level fields\n * are the legacy mirror of the \"default\" entry). */\nexport function legacyStateToEntries(state: BufferState): Map<string, BufferEntryState> {\n const entries = new Map<string, BufferEntryState>();\n for (const [key, value] of Object.entries(state.entries ?? {})) {\n if (value && Array.isArray(value.turns)) entries.set(key, value);\n }\n if (!entries.has(\"default\")) {\n entries.set(\"default\", {\n turns: Array.isArray(state.turns) ? state.turns : [],\n lastExtractionAt: state.lastExtractionAt ?? null,\n extractionCount: Number.isFinite(state.extractionCount) ? state.extractionCount : 0,\n });\n }\n return entries;\n}\n\n/** What a per-session file contains once parsed (written only by this module). */\ninterface SessionFileBody {\n key?: string;\n turns?: BufferTurn[];\n retainedTurns?: BufferTurn[];\n lastExtractionAt?: string | null;\n extractionCount?: number;\n}\n\nfunction entryFromBody(body: SessionFileBody): { key: string; entry: BufferEntryState } | null {\n if (!body || !Array.isArray(body.turns) || (body.key?.length ?? 0) === 0) return null;\n const entry: BufferEntryState = {\n turns: body.turns,\n lastExtractionAt: body.lastExtractionAt ?? null,\n extractionCount: Number.isFinite(body.extractionCount) ? Number(body.extractionCount) : 0,\n };\n if (Array.isArray(body.retainedTurns)) entry.retainedTurns = body.retainedTurns;\n return { key: String(body.key), entry };\n}\n\n/**\n * One file per buffer session under `<stateDir>/buffer/`, so the observe hot\n * path persists only the session that changed. All writes happen under\n * SmartBuffer's serialized mutation chain (one writer per process).\n *\n * Sessions claimed by `remnic buffer drain` (see buffer-drain-claims.ts) are\n * owned by the drain: `save` hands the in-memory entry INTO the claim\n * (identity-deduped merge) instead of writing a session file, so a live\n * buffer owner can never resurrect claimed turns.\n */\nexport class BufferSessionFiles {\n private dirVerified = false;\n private readonly claimsStore: BufferDrainClaims;\n\n constructor(\n private readonly stateDir: string,\n private readonly io: BufferFileIo,\n ) {\n this.claimsStore = new BufferDrainClaims(stateDir, io);\n }\n\n /** The drain-claim store for this state dir (CLI scan + claim ops). */\n get claims(): BufferDrainClaims {\n return this.claimsStore;\n }\n\n /** Sync gate check: is this session claimed by a buffer drain? */\n isClaimed(key: string): boolean {\n return this.claimsStore.isClaimed(key);\n }\n\n private get dir(): string {\n return path.join(this.stateDir, \"buffer\");\n }\n\n private fileFor(key: string): string {\n return path.join(this.dir, bufferSessionFileName(key));\n }\n\n /**\n * Refuse a symlinked buffer directory: following it would send buffered\n * conversation data (and deletions) outside the memory root. One lstat of\n * one directory, cached after it passes, so the observe path pays nothing\n * per write; the cache is dropped on any failure.\n */\n private async assertDirSafe(): Promise<void> {\n if (this.dirVerified) return;\n let stat: Stats | null = null;\n try {\n stat = await lstat(this.dir);\n } catch (err) {\n if (!(err instanceof Error) || !isMissing(asFsError(err))) throw err;\n }\n if (stat && (stat.isSymbolicLink() || !stat.isDirectory())) {\n throw new Error(`buffer session directory must be a real directory, not a symlink or file: ${this.dir}`);\n }\n this.dirVerified = stat !== null;\n }\n\n /** Persist ONE session atomically. Compact JSON: machine-read state, and\n * pretty-printing a large buffer costs CPU and bytes on every observe.\n * A drain-claimed session is handed over instead (see class doc). */\n async save(key: string, entry: BufferEntryState): Promise<BufferSessionSaveOutcome> {\n if (this.isClaimed(key)) {\n // Consume the tombstone ONLY when the drain finished (acked: extracted\n // turns recorded, nothing pending, no lease). Partial `drained` just\n // means chunks completed — the drainer may still be running, and\n // releasing here would unlink its claim and turn its later writes into\n // no-ops.\n if (await this.claimsStore.isDrained(key)) {\n const drained = await this.claimsStore.drainedTurns(key);\n // The drain finished this session: the claim is a tombstone. Write\n // the owner's fresh remainder back as a session file (the drained\n // turns are subtracted here too, so a caller that did not subtract\n // them cannot resurrect them) and release the tombstone.\n const fresh: BufferEntryState = { ...entry, turns: subtractBufferTurns(entry.turns, drained.turns) };\n if (entry.retainedTurns && entry.retainedTurns.length > 0) {\n fresh.retainedTurns = subtractBufferTurns(entry.retainedTurns, drained.retainedTurns);\n if (fresh.retainedTurns.length === 0) delete fresh.retainedTurns;\n }\n await this.assertDirSafe();\n await this.io.write(this.fileFor(key), JSON.stringify({ key, ...fresh }));\n await this.claimsStore.release(key);\n return { status: \"saved\", drainedTurns: drained };\n }\n await this.claimsStore.mergeIntoClaim(key, entry);\n return { status: \"handed_over\" };\n }\n await this.assertDirSafe();\n await this.io.write(this.fileFor(key), JSON.stringify({ key, ...entry }));\n return { status: \"saved\" };\n }\n\n /** Remove one session's file. Idempotent: an absent file is fine. */\n async remove(key: string): Promise<void> {\n await this.assertDirSafe();\n try {\n await unlink(this.fileFor(key));\n } catch (err) {\n if (!(err instanceof Error) || !isMissing(asFsError(err))) throw err;\n }\n }\n\n private async listFiles(): Promise<string[]> {\n await this.assertDirSafe();\n try {\n const dirents = await readdir(this.dir, { withFileTypes: true });\n // Regular files only: a symlink inside the directory is never followed.\n return dirents.filter((d) => d.isFile() && d.name.endsWith(\".json\")).map((d) => d.name);\n } catch (err) {\n if (err instanceof Error && isMissing(asFsError(err))) return [];\n throw err;\n }\n }\n\n /** Read every per-session file. Corrupt files are skipped (and logged) so\n * one bad file cannot nuke the other sessions' buffered turns. */\n private async readAll(): Promise<{ entries: Map<string, BufferEntryState>; fileCount: number }> {\n const names = await this.listFiles();\n const entries = new Map<string, BufferEntryState>();\n for (const name of names) {\n try {\n const body: SessionFileBody = JSON.parse(await this.io.read(path.join(this.dir, name)));\n const parsed = entryFromBody(body);\n if (!parsed) throw new Error(\"invalid buffer session file shape\");\n if (entries.has(parsed.key)) {\n log.warn(`buffer: duplicate session file for key ${parsed.key} (${name}); keeping the first`);\n continue;\n }\n entries.set(parsed.key, parsed.entry);\n } catch (err) {\n // A locked store or a wrong key is not a corrupt file: reading it as empty would let\n // later saves replace the real encrypted session.\n if (err instanceof SecureStoreLockedError || err instanceof SecureStoreDecryptError) throw err;\n log.warn(`buffer: skipping unreadable per-session buffer file ${name}: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n return { entries, fileCount: names.length };\n }\n\n /**\n * Read the legacy single-file buffer.json for migration. Null when absent,\n * or unreadable while session files exist (they are authoritative; a\n * corrupt leftover must not block startup). With no session files a corrupt\n * legacy file THROWS, preserving the old contract so callers can reset it.\n */\n private async readLegacy(hasSessionFiles: boolean): Promise<BufferState | null> {\n let raw: string;\n try {\n raw = await this.io.read(path.join(this.stateDir, \"buffer.json\"));\n } catch (err) {\n if (err instanceof SecureStoreLockedError) throw err;\n if (err instanceof Error && isMissing(asFsError(err))) return null;\n throw err;\n }\n try {\n const legacy: BufferState = JSON.parse(raw);\n return legacy;\n } catch (err) {\n if (!hasSessionFiles) throw err;\n log.warn(\n `buffer: legacy buffer.json is unreadable but per-session buffer files exist; ` +\n `ignoring the legacy file (${err instanceof Error ? err.message : String(err)})`,\n );\n return null;\n }\n }\n\n /**\n * Load the whole buffer, migrating a legacy buffer.json once. A per-session\n * file that parsed wins over the legacy snapshot (a crash mid-migration\n * leaves exactly that pair); legacy entries without a usable file are\n * written out, then the legacy file is retired. Both steps are idempotent.\n */\n async load(): Promise<BufferState> {\n const { entries, fileCount } = await this.readAll();\n const legacy = await this.readLegacy(fileCount > 0);\n if (legacy !== null) {\n for (const [key, entry] of legacyStateToEntries(legacy)) {\n if (entries.has(key)) continue;\n entries.set(key, entry);\n await this.save(key, entry);\n }\n try {\n await unlink(path.join(this.stateDir, \"buffer.json\"));\n } catch (err) {\n if (!(err instanceof Error) || !isMissing(asFsError(err))) throw err;\n }\n }\n const out: NonNullable<BufferState[\"entries\"]> = Object.create(null);\n for (const [key, entry] of entries) out[key] = entry;\n const def = entries.get(\"default\");\n return {\n turns: def?.turns ?? [],\n lastExtractionAt: def?.lastExtractionAt ?? null,\n extractionCount: def?.extractionCount ?? 0,\n entries: out,\n };\n }\n\n /**\n * Reconcile the files with a WHOLE buffer state: write every entry, then\n * delete files for keys no longer present. Writes first, deletes last: a\n * crash leaves stale extra files (removed by the next reconcile) but never\n * loses sessions the state says exist. Not on the observe hot path.\n */\n async reconcile(state: BufferState): Promise<void> {\n const entries = legacyStateToEntries(state);\n const existing = await this.listFiles();\n for (const [key, entry] of entries) await this.save(key, entry);\n const live = new Set([...entries.keys()].map((key) => bufferSessionFileName(key)));\n for (const name of existing) {\n if (live.has(name)) continue;\n try {\n await unlink(path.join(this.dir, name));\n } catch (err) {\n if (!(err instanceof Error) || !isMissing(asFsError(err))) throw err;\n }\n }\n }\n}\n"],"mappings":"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","names":["readdir","unlink","path","stat","path","unlink","readdir"]}
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
readNamespaceMaintenanceLastRanStatuses,
|
|
4
4
|
readNamespaceMaintenanceStatuses,
|
|
5
5
|
runNamespaceMaintenancePlan
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-FQAQ63QA.js";
|
|
7
7
|
import {
|
|
8
8
|
analyzeSessionIntegrity,
|
|
9
9
|
applySessionRepair,
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
} from "./chunk-CMTINOFS.js";
|
|
15
15
|
import {
|
|
16
16
|
summarizeCorpusAndReplica
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-GBJUTX44.js";
|
|
18
18
|
import {
|
|
19
19
|
readJudgeVerdictStats
|
|
20
20
|
} from "./chunk-OZKOPQCM.js";
|
|
@@ -25,6 +25,16 @@ import {
|
|
|
25
25
|
runEvalBenchmarkCiGate,
|
|
26
26
|
validateEvalBenchmarkPack
|
|
27
27
|
} from "./chunk-JKMIGCK6.js";
|
|
28
|
+
import {
|
|
29
|
+
resolveCorpusNamespaceRoots
|
|
30
|
+
} from "./chunk-D5XG2KPS.js";
|
|
31
|
+
import {
|
|
32
|
+
listNamespaces
|
|
33
|
+
} from "./chunk-XJ2S5UBF.js";
|
|
34
|
+
import {
|
|
35
|
+
listMemoryGovernanceRuns,
|
|
36
|
+
readMemoryGovernanceRunArtifact
|
|
37
|
+
} from "./chunk-ZDV5YWID.js";
|
|
28
38
|
import {
|
|
29
39
|
resolveCuratedIncludeFilesStatePath,
|
|
30
40
|
resolveNativeKnowledgeStatePath,
|
|
@@ -32,38 +42,31 @@ import {
|
|
|
32
42
|
} from "./chunk-2DQ2XREU.js";
|
|
33
43
|
import {
|
|
34
44
|
runConsolidationProvenanceCheck
|
|
35
|
-
} from "./chunk-
|
|
45
|
+
} from "./chunk-TYRWSE4B.js";
|
|
46
|
+
import {
|
|
47
|
+
analyzeGraphHealth
|
|
48
|
+
} from "./chunk-M4IEZGCK.js";
|
|
36
49
|
import {
|
|
37
50
|
reportBufferSurpriseDistribution
|
|
38
51
|
} from "./chunk-YBPYIAA5.js";
|
|
39
52
|
import {
|
|
40
53
|
parseConfig
|
|
41
|
-
} from "./chunk-
|
|
42
|
-
import {
|
|
43
|
-
readAggregateExtractionWatermark
|
|
44
|
-
} from "./chunk-3RLK65ZK.js";
|
|
45
|
-
import {
|
|
46
|
-
listNamespaces
|
|
47
|
-
} from "./chunk-GVGAO3WV.js";
|
|
48
|
-
import {
|
|
49
|
-
listMemoryGovernanceRuns,
|
|
50
|
-
readMemoryGovernanceRunArtifact
|
|
51
|
-
} from "./chunk-7GLJMDEQ.js";
|
|
52
|
-
import {
|
|
53
|
-
analyzeGraphHealth
|
|
54
|
-
} from "./chunk-M4IEZGCK.js";
|
|
54
|
+
} from "./chunk-UBEKET2V.js";
|
|
55
55
|
import {
|
|
56
56
|
summarizeExtractionLiveness
|
|
57
57
|
} from "./chunk-AWD36R4D.js";
|
|
58
58
|
import {
|
|
59
59
|
StorageManager
|
|
60
|
-
} from "./chunk-
|
|
60
|
+
} from "./chunk-FWRXW7CZ.js";
|
|
61
61
|
import {
|
|
62
62
|
lintWorkspaceFiles
|
|
63
63
|
} from "./chunk-DM2T26WE.js";
|
|
64
64
|
import {
|
|
65
65
|
probeProjectionHealth
|
|
66
66
|
} from "./chunk-AL3UYZ5N.js";
|
|
67
|
+
import {
|
|
68
|
+
normalizeNamespaceIdentity
|
|
69
|
+
} from "./chunk-VUFL7X3H.js";
|
|
67
70
|
import {
|
|
68
71
|
resolveAccessSetupCapabilities,
|
|
69
72
|
resolveCapabilities,
|
|
@@ -75,16 +78,205 @@ import {
|
|
|
75
78
|
resolvePresentationCapabilities,
|
|
76
79
|
resolveQmdCapabilities
|
|
77
80
|
} from "./chunk-C5LWPYS3.js";
|
|
81
|
+
import {
|
|
82
|
+
capabilityAllowsNamespace
|
|
83
|
+
} from "./chunk-OGBQMY46.js";
|
|
78
84
|
import {
|
|
79
85
|
readEnvVar,
|
|
80
86
|
resolveHomeDir
|
|
81
87
|
} from "./chunk-P2QRMMVQ.js";
|
|
82
88
|
|
|
83
89
|
// src/operator-toolkit.ts
|
|
84
|
-
import
|
|
90
|
+
import path2 from "path";
|
|
85
91
|
import { constants as fsConstants } from "fs";
|
|
86
92
|
import { access, mkdir, readFile, readdir, stat, unlink, writeFile } from "fs/promises";
|
|
87
93
|
|
|
94
|
+
// src/orchestration/extraction-watermark.ts
|
|
95
|
+
import path from "path";
|
|
96
|
+
function readFailure(reason) {
|
|
97
|
+
return {
|
|
98
|
+
lastExtractionAt: null,
|
|
99
|
+
readFailed: true,
|
|
100
|
+
readError: reason
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
function errorMessage(error) {
|
|
104
|
+
return error instanceof Error ? error.message : String(error);
|
|
105
|
+
}
|
|
106
|
+
var ISO_TIMESTAMP_PATTERN = /^([+-]?\d{4,6})-(\d{2})-(\d{2})T(\d{2}):(\d{2})(?::(\d{2}))?(?:\.(\d+))?(Z|[+-]\d{2}:?\d{2})$/i;
|
|
107
|
+
function validatedTimestampMs(value) {
|
|
108
|
+
const match = ISO_TIMESTAMP_PATTERN.exec(value);
|
|
109
|
+
const parsed = Date.parse(value);
|
|
110
|
+
if (!match || !Number.isFinite(parsed)) return null;
|
|
111
|
+
const [, yearText, monthText, dayText, hourText, minuteText, secondText, fraction, zone] = match;
|
|
112
|
+
const normalizedZone = zone.toUpperCase();
|
|
113
|
+
const offsetMinuteText = normalizedZone.includes(":") ? normalizedZone.slice(4, 6) : normalizedZone.slice(3, 5);
|
|
114
|
+
const year = Number(yearText);
|
|
115
|
+
const month = Number(monthText);
|
|
116
|
+
const day = Number(dayText);
|
|
117
|
+
const hour = Number(hourText);
|
|
118
|
+
const minute = Number(minuteText);
|
|
119
|
+
const second = secondText !== void 0 ? Number(secondText) : 0;
|
|
120
|
+
const leapYear = year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0);
|
|
121
|
+
const daysInMonth = [31, leapYear ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
|
|
122
|
+
if (month < 1 || month > 12 || day < 1 || day > daysInMonth[month - 1]) return null;
|
|
123
|
+
if (hour === 24) {
|
|
124
|
+
const isEndOfDay = minute === 0 && second === 0 && /^0*$/.test(fraction ?? "");
|
|
125
|
+
return isEndOfDay ? parsed : null;
|
|
126
|
+
}
|
|
127
|
+
const zoneSign = normalizedZone === "Z" || normalizedZone[0] === "+" ? 1 : -1;
|
|
128
|
+
const offsetMinutes = normalizedZone === "Z" ? 0 : zoneSign * (Number(normalizedZone.slice(1, 3)) * 60 + Number(offsetMinuteText));
|
|
129
|
+
const representedCalendar = new Date(parsed + offsetMinutes * 6e4);
|
|
130
|
+
const millisecond = Number((fraction ?? "").padEnd(3, "0").slice(0, 3));
|
|
131
|
+
const expected = [
|
|
132
|
+
year,
|
|
133
|
+
month,
|
|
134
|
+
day,
|
|
135
|
+
hour,
|
|
136
|
+
minute,
|
|
137
|
+
second,
|
|
138
|
+
millisecond
|
|
139
|
+
];
|
|
140
|
+
const actual = [
|
|
141
|
+
representedCalendar.getUTCFullYear(),
|
|
142
|
+
representedCalendar.getUTCMonth() + 1,
|
|
143
|
+
representedCalendar.getUTCDate(),
|
|
144
|
+
representedCalendar.getUTCHours(),
|
|
145
|
+
representedCalendar.getUTCMinutes(),
|
|
146
|
+
representedCalendar.getUTCSeconds(),
|
|
147
|
+
representedCalendar.getUTCMilliseconds()
|
|
148
|
+
];
|
|
149
|
+
return actual.every((part, index) => part === expected[index]) ? parsed : null;
|
|
150
|
+
}
|
|
151
|
+
function mergeRootStats(current, candidate) {
|
|
152
|
+
if (!current && !candidate) return void 0;
|
|
153
|
+
const currentCount = current?.extractionCount;
|
|
154
|
+
const candidateCount = candidate?.extractionCount;
|
|
155
|
+
const extractionCount = currentCount === void 0 && candidateCount === void 0 ? void 0 : (currentCount ?? 0) + (candidateCount ?? 0);
|
|
156
|
+
const currentConsolidation = current?.lastConsolidationAt;
|
|
157
|
+
const candidateConsolidation = candidate?.lastConsolidationAt;
|
|
158
|
+
const hasConsolidation = currentConsolidation !== void 0 || candidateConsolidation !== void 0;
|
|
159
|
+
return {
|
|
160
|
+
...extractionCount === void 0 ? {} : { extractionCount },
|
|
161
|
+
...hasConsolidation ? {
|
|
162
|
+
lastConsolidationAt: newerWatermark(
|
|
163
|
+
currentConsolidation ?? null,
|
|
164
|
+
candidateConsolidation ?? null
|
|
165
|
+
)
|
|
166
|
+
} : {}
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
function watermarkFromMeta(meta, name) {
|
|
170
|
+
if (meta.lastExtractionAt !== null && meta.lastExtractionAt !== void 0 && validatedTimestampMs(meta.lastExtractionAt) === null) {
|
|
171
|
+
return readFailure(`${name} watermark timestamp invalid`);
|
|
172
|
+
}
|
|
173
|
+
if (meta.lastConsolidationAt !== null && meta.lastConsolidationAt !== void 0 && validatedTimestampMs(meta.lastConsolidationAt) === null) {
|
|
174
|
+
return readFailure(`${name} consolidation timestamp invalid`);
|
|
175
|
+
}
|
|
176
|
+
const hasRootStats = meta.extractionCount !== void 0 || meta.lastConsolidationAt !== void 0;
|
|
177
|
+
return {
|
|
178
|
+
lastExtractionAt: meta.lastExtractionAt ?? null,
|
|
179
|
+
readFailed: false,
|
|
180
|
+
...hasRootStats ? {
|
|
181
|
+
rootStats: {
|
|
182
|
+
extractionCount: meta.extractionCount,
|
|
183
|
+
lastConsolidationAt: meta.lastConsolidationAt
|
|
184
|
+
}
|
|
185
|
+
} : {}
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
async function readWatermark(storage, name) {
|
|
189
|
+
try {
|
|
190
|
+
return watermarkFromMeta(await storage.loadMeta(), name);
|
|
191
|
+
} catch (error) {
|
|
192
|
+
return readFailure(`${name} watermark unreadable: ${errorMessage(error)}`);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
async function resolveRoots(options) {
|
|
196
|
+
const compute = () => resolveCorpusNamespaceRoots({
|
|
197
|
+
config: options.config,
|
|
198
|
+
propagateDiscoveryErrors: true
|
|
199
|
+
});
|
|
200
|
+
if (options.rootsCache) {
|
|
201
|
+
const { roots, refreshError } = options.rootsCache.getResolvedRootsStatus(compute);
|
|
202
|
+
if (refreshError !== void 0) {
|
|
203
|
+
return readFailure(`namespace watermark enumeration failed: ${errorMessage(refreshError)}`);
|
|
204
|
+
}
|
|
205
|
+
return roots ?? { lastExtractionAt: null, readFailed: false, pending: true };
|
|
206
|
+
}
|
|
207
|
+
try {
|
|
208
|
+
return await compute();
|
|
209
|
+
} catch (error) {
|
|
210
|
+
return readFailure(`namespace watermark enumeration failed: ${errorMessage(error)}`);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
function isReadFailure(value) {
|
|
214
|
+
return !Array.isArray(value);
|
|
215
|
+
}
|
|
216
|
+
function newerWatermark(current, candidate) {
|
|
217
|
+
if (candidate === null) return current;
|
|
218
|
+
const candidateMs = validatedTimestampMs(candidate);
|
|
219
|
+
if (candidateMs === null) return current;
|
|
220
|
+
if (current === null) return candidate;
|
|
221
|
+
const currentMs = validatedTimestampMs(current);
|
|
222
|
+
return currentMs === null || candidateMs > currentMs ? candidate : current;
|
|
223
|
+
}
|
|
224
|
+
async function readAggregateExtractionWatermark(options) {
|
|
225
|
+
if (!resolveNamespaceCapabilities(options.config).namespaces) {
|
|
226
|
+
return options.rootMeta ? watermarkFromMeta(options.rootMeta, "root store") : readWatermark(options.rootStorage, "root store");
|
|
227
|
+
}
|
|
228
|
+
const resolved = await resolveRoots(options);
|
|
229
|
+
if (isReadFailure(resolved)) return resolved;
|
|
230
|
+
const rootDir = path.resolve(options.rootStorage.dir);
|
|
231
|
+
const seenDirs = /* @__PURE__ */ new Set([rootDir]);
|
|
232
|
+
const targets = [];
|
|
233
|
+
for (const root of resolved) {
|
|
234
|
+
if (options.caps && !root.namespaces.some(
|
|
235
|
+
(ns) => capabilityAllowsNamespace(options.caps, normalizeNamespaceIdentity(ns))
|
|
236
|
+
)) {
|
|
237
|
+
continue;
|
|
238
|
+
}
|
|
239
|
+
const resolvedDir = path.resolve(root.rootDir);
|
|
240
|
+
if (seenDirs.has(resolvedDir)) continue;
|
|
241
|
+
seenDirs.add(resolvedDir);
|
|
242
|
+
targets.push(root);
|
|
243
|
+
}
|
|
244
|
+
const defaultNamespace = normalizeNamespaceIdentity(options.config.defaultNamespace);
|
|
245
|
+
const hasMigratedDefault = resolved.some(
|
|
246
|
+
(root) => path.resolve(root.rootDir) !== rootDir && root.namespaces.some((namespace) => normalizeNamespaceIdentity(namespace) === defaultNamespace)
|
|
247
|
+
);
|
|
248
|
+
const canAccessRoot = !hasMigratedDefault && (!options.caps || capabilityAllowsNamespace(options.caps, defaultNamespace));
|
|
249
|
+
let rootRead = { lastExtractionAt: null, readFailed: false };
|
|
250
|
+
if (canAccessRoot) {
|
|
251
|
+
rootRead = options.rootMeta ? watermarkFromMeta(options.rootMeta, "root store") : await readWatermark(options.rootStorage, "root store");
|
|
252
|
+
if (rootRead.readFailed) return rootRead;
|
|
253
|
+
}
|
|
254
|
+
let lastExtractionAt = rootRead.lastExtractionAt;
|
|
255
|
+
let rootStats = rootRead.rootStats;
|
|
256
|
+
const reads = await Promise.all(
|
|
257
|
+
targets.map(async (target) => {
|
|
258
|
+
try {
|
|
259
|
+
const storage = await options.storageForNamespace(target.namespace, target.rootDir);
|
|
260
|
+
return await readWatermark(storage, "namespace");
|
|
261
|
+
} catch (error) {
|
|
262
|
+
return readFailure(`namespace watermark storage unavailable: ${errorMessage(error)}`);
|
|
263
|
+
}
|
|
264
|
+
})
|
|
265
|
+
);
|
|
266
|
+
for (const read of reads) {
|
|
267
|
+
if (read.readFailed) {
|
|
268
|
+
return readFailure(read.readError ?? "namespace watermark unreadable");
|
|
269
|
+
}
|
|
270
|
+
lastExtractionAt = newerWatermark(lastExtractionAt, read.lastExtractionAt);
|
|
271
|
+
rootStats = mergeRootStats(rootStats, read.rootStats);
|
|
272
|
+
}
|
|
273
|
+
return {
|
|
274
|
+
lastExtractionAt,
|
|
275
|
+
readFailed: false,
|
|
276
|
+
...rootStats ? { rootStats } : {}
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
|
|
88
280
|
// src/maintenance/namespace-maintenance-fanout.ts
|
|
89
281
|
var NAMESPACE_MAINTENANCE_JOBS = [
|
|
90
282
|
"qmd",
|
|
@@ -251,7 +443,7 @@ function resolveConfigPath(explicitPath) {
|
|
|
251
443
|
if (explicitPath && explicitPath.trim().length > 0) return explicitPath.trim();
|
|
252
444
|
const configured = readEnvVar("OPENCLAW_CONFIG_PATH") || readEnvVar("OPENCLAW_ENGRAM_CONFIG_PATH");
|
|
253
445
|
if (configured && configured.trim().length > 0) return configured.trim();
|
|
254
|
-
return
|
|
446
|
+
return path2.join(resolveHomeDir(), ".openclaw", "openclaw.json");
|
|
255
447
|
}
|
|
256
448
|
async function loadCliPluginConfig(configPath) {
|
|
257
449
|
const resolvedPath = resolveConfigPath(configPath);
|
|
@@ -322,12 +514,12 @@ function getSetupPaths(config) {
|
|
|
322
514
|
return [
|
|
323
515
|
config.memoryDir,
|
|
324
516
|
config.workspaceDir,
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
517
|
+
path2.join(config.memoryDir, "facts"),
|
|
518
|
+
path2.join(config.memoryDir, "entities"),
|
|
519
|
+
path2.join(config.memoryDir, "state"),
|
|
520
|
+
path2.join(config.memoryDir, "questions"),
|
|
521
|
+
path2.join(config.memoryDir, "artifacts"),
|
|
522
|
+
path2.join(config.memoryDir, "config")
|
|
331
523
|
];
|
|
332
524
|
}
|
|
333
525
|
async function readJsonIfExists(filePath) {
|
|
@@ -340,9 +532,9 @@ async function readJsonIfExists(filePath) {
|
|
|
340
532
|
async function summarizeNativeKnowledgeStatus(config) {
|
|
341
533
|
const nativeKnowledge = config.nativeKnowledge;
|
|
342
534
|
const nativeKnowledgeStateDir = nativeKnowledge?.stateDir ?? "state/native-knowledge";
|
|
343
|
-
const curatedStatePath = nativeKnowledge ? resolveCuratedIncludeFilesStatePath(config.memoryDir, nativeKnowledge) :
|
|
344
|
-
const obsidianStatePath = nativeKnowledge ? resolveNativeKnowledgeStatePath(config.memoryDir, nativeKnowledge) :
|
|
345
|
-
const openclawStatePath = nativeKnowledge ? resolveOpenClawWorkspaceStatePath(config.memoryDir, nativeKnowledge) :
|
|
535
|
+
const curatedStatePath = nativeKnowledge ? resolveCuratedIncludeFilesStatePath(config.memoryDir, nativeKnowledge) : path2.join(config.memoryDir, nativeKnowledgeStateDir, "curated-include-sync.json");
|
|
536
|
+
const obsidianStatePath = nativeKnowledge ? resolveNativeKnowledgeStatePath(config.memoryDir, nativeKnowledge) : path2.join(config.memoryDir, nativeKnowledgeStateDir, "obsidian-sync.json");
|
|
537
|
+
const openclawStatePath = nativeKnowledge ? resolveOpenClawWorkspaceStatePath(config.memoryDir, nativeKnowledge) : path2.join(config.memoryDir, nativeKnowledgeStateDir, "openclaw-workspace-sync.json");
|
|
346
538
|
const [curatedRaw, obsidianRaw, openclawRaw] = await Promise.all([
|
|
347
539
|
readJsonIfExists(curatedStatePath),
|
|
348
540
|
readJsonIfExists(obsidianStatePath),
|
|
@@ -480,7 +672,7 @@ async function runOperatorSetup(options) {
|
|
|
480
672
|
options.orchestrator.config.qmdCollection
|
|
481
673
|
) : "skipped";
|
|
482
674
|
const nativeKnowledgeStatus = await summarizeNativeKnowledgeStatus(options.orchestrator.config);
|
|
483
|
-
const memoryDocPath =
|
|
675
|
+
const memoryDocPath = path2.join(options.orchestrator.config.workspaceDir, "MEMORY.md");
|
|
484
676
|
const captureInstructionsMode = options.captureInstructionsMode ?? (options.installCaptureInstructions ? "install" : void 0);
|
|
485
677
|
let memoryDocExists = false;
|
|
486
678
|
try {
|
|
@@ -621,9 +813,9 @@ async function buildOperatorConfigReviewReport(input) {
|
|
|
621
813
|
const findings = [];
|
|
622
814
|
const searchBackend = config.searchBackend ?? "qmd";
|
|
623
815
|
const workspaceBootstrapFiles = [
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
816
|
+
path2.join(config.workspaceDir, "IDENTITY.md"),
|
|
817
|
+
path2.join(config.workspaceDir, "MEMORY.md"),
|
|
818
|
+
path2.join(config.workspaceDir, "USER.md")
|
|
627
819
|
];
|
|
628
820
|
const workspaceBootstrapExists = (await Promise.all(workspaceBootstrapFiles.map(pathExists))).some(Boolean);
|
|
629
821
|
if (config.memoryOsPreset !== "conservative" && config.memoryOsPreset !== "balanced" && config.memoryOsPreset !== "research-max" && config.memoryOsPreset !== "local-llm-heavy" && resolveIndexingCapabilities(config).queryAwareIndexing === false && resolvePresentationCapabilities(config).verbatimArtifacts === false && !caps.rerank) {
|
|
@@ -1109,10 +1301,10 @@ async function summarizeGraphEdgeDecayStatus(config) {
|
|
|
1109
1301
|
}
|
|
1110
1302
|
async function summarizeTierDistribution(storage) {
|
|
1111
1303
|
try {
|
|
1112
|
-
const { summarizeTiers } = await import("./tier-stats-
|
|
1304
|
+
const { summarizeTiers } = await import("./tier-stats-FXEUJN73.js");
|
|
1113
1305
|
const summary = await summarizeTiers(storage);
|
|
1114
1306
|
const storageDir = storage.dir ?? "";
|
|
1115
|
-
const journalPath = storageDir.length > 0 ?
|
|
1307
|
+
const journalPath = storageDir.length > 0 ? path2.join(storageDir, "state", "tier-migration-journal.jsonl") : null;
|
|
1116
1308
|
let recentMigrations = 0;
|
|
1117
1309
|
const demotionReasons = {};
|
|
1118
1310
|
const sevenDaysAgoMs = Date.now() - 7 * 864e5;
|
|
@@ -1170,11 +1362,11 @@ async function summarizeDreamsPhases(config, storage = new StorageManager(config
|
|
|
1170
1362
|
let deepSleepLastRun = null;
|
|
1171
1363
|
let deepSleepLastRunWarning = null;
|
|
1172
1364
|
try {
|
|
1173
|
-
const runsDir =
|
|
1365
|
+
const runsDir = path2.join(config.memoryDir, "state", "memory-governance", "runs");
|
|
1174
1366
|
const runIds = (await readdir(runsDir)).sort().reverse();
|
|
1175
1367
|
if (runIds.length > 0) {
|
|
1176
1368
|
const latestRunId = runIds[0];
|
|
1177
|
-
const manifestPath =
|
|
1369
|
+
const manifestPath = path2.join(
|
|
1178
1370
|
runsDir,
|
|
1179
1371
|
latestRunId,
|
|
1180
1372
|
"manifest.json"
|
|
@@ -1421,7 +1613,7 @@ async function dirSize(targetPath) {
|
|
|
1421
1613
|
return 0;
|
|
1422
1614
|
}
|
|
1423
1615
|
for (const entry of entries) {
|
|
1424
|
-
total += await dirSize(
|
|
1616
|
+
total += await dirSize(path2.join(targetPath, entry.name));
|
|
1425
1617
|
}
|
|
1426
1618
|
return total;
|
|
1427
1619
|
}
|
|
@@ -1441,7 +1633,7 @@ async function summarizeStorageFootprint(memoryDir) {
|
|
|
1441
1633
|
const byTopLevel = {};
|
|
1442
1634
|
let bytes = 0;
|
|
1443
1635
|
for (const name of topLevel) {
|
|
1444
|
-
const size = await dirSize(
|
|
1636
|
+
const size = await dirSize(path2.join(memoryDir, name));
|
|
1445
1637
|
if (size > 0) {
|
|
1446
1638
|
byTopLevel[name] = size;
|
|
1447
1639
|
bytes += size;
|
|
@@ -1664,6 +1856,7 @@ async function runOperatorRepair(options) {
|
|
|
1664
1856
|
}
|
|
1665
1857
|
|
|
1666
1858
|
export {
|
|
1859
|
+
readAggregateExtractionWatermark,
|
|
1667
1860
|
runNamespaceMaintenanceFanout,
|
|
1668
1861
|
summarizeNamespaceMaintenanceHealth,
|
|
1669
1862
|
formatNamespaceMaintenanceHealthText,
|
|
@@ -1683,4 +1876,4 @@ export {
|
|
|
1683
1876
|
runBenchmarkRecall,
|
|
1684
1877
|
runOperatorRepair
|
|
1685
1878
|
};
|
|
1686
|
-
//# sourceMappingURL=chunk-
|
|
1879
|
+
//# sourceMappingURL=chunk-RKABLU5M.js.map
|