@remnic/core 10.0.28 → 10.0.30
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 +47 -46
- package/dist/access-authorization-probe.js +48 -47
- package/dist/access-boundary.js +47 -46
- package/dist/access-citation-namespace.js +3 -2
- package/dist/access-cli.js +96 -95
- package/dist/access-cli.js.map +1 -1
- package/dist/access-extraction-force-flush.js +47 -46
- package/dist/access-http-briefing.js +48 -47
- package/dist/access-http-query.js +49 -48
- package/dist/access-http.js +65 -64
- package/dist/access-identity-continuity-surface.js +47 -46
- package/dist/access-lcm-surface.js +47 -46
- package/dist/access-mcp.js +57 -56
- package/dist/access-namespace-preflight.js +47 -46
- package/dist/access-observe-write-category.js +11 -11
- package/dist/access-observe-write-surface.js +47 -46
- package/dist/access-offline-manifest.js +10 -10
- package/dist/access-operations-batch.js +49 -48
- package/dist/access-operations.js +56 -55
- package/dist/access-recall-concurrency.js +47 -46
- package/dist/access-recall-response.js +47 -46
- package/dist/access-recall-surface.js +47 -46
- package/dist/access-schema.js +6 -5
- package/dist/access-service.js +47 -46
- package/dist/access-surface-catalog.js +49 -48
- package/dist/access-surface-catalog.js.map +1 -1
- package/dist/active-recall.js +23 -22
- package/dist/active-recall.js.map +1 -1
- package/dist/{auto-sync-UQESPLCB.js → auto-sync-MX2AHVPQ.js} +8 -8
- package/dist/briefing.js +19 -18
- package/dist/buffer.js +8 -8
- package/dist/{capsule-merge-LGYURS3C.js → capsule-merge-LGYZAMO4.js} +3 -3
- package/dist/causal-consolidation.js +21 -20
- package/dist/causal-consolidation.js.map +1 -1
- package/dist/{chunk-2TGDT37F.js → chunk-27OJ5G3D.js} +13 -13
- package/dist/{chunk-5LRV557D.js → chunk-2FIJQNL7.js} +2 -2
- package/dist/{chunk-ETPIYK4J.js → chunk-2VBDSZ7U.js} +2 -2
- package/dist/{chunk-QLI74KWK.js → chunk-2XVLY424.js} +3 -3
- package/dist/{chunk-P55FACBG.js → chunk-3BOQPLCF.js} +6 -6
- package/dist/{chunk-3LRBJQZE.js → chunk-3CHHQXAR.js} +2 -2
- package/dist/{chunk-3GYSZHMT.js → chunk-3CZRBTJK.js} +2 -2
- package/dist/{chunk-HFSPY26A.js → chunk-3IXNL6SK.js} +2 -2
- package/dist/{chunk-4DQ4VEIQ.js → chunk-3SN2D43X.js} +2 -2
- package/dist/{chunk-QMYB3N7X.js → chunk-4HNINU7Q.js} +28 -28
- package/dist/{chunk-LW6UHNWA.js → chunk-4HYP4OKH.js} +2 -2
- package/dist/{chunk-GKJJNO7C.js → chunk-4OE4UE2Y.js} +6 -6
- package/dist/{chunk-5SMR542T.js → chunk-5GT4ESLR.js} +2 -2
- package/dist/{chunk-DWL6YIZH.js → chunk-5JI3XWI2.js} +2 -2
- package/dist/{chunk-PDN6MRWF.js → chunk-5NPZFXQH.js} +2 -2
- package/dist/{chunk-Y6IF6H2U.js → chunk-5SMHQW45.js} +2 -2
- package/dist/{chunk-PRUXE3RC.js → chunk-654GT5UP.js} +2 -2
- package/dist/{chunk-3E6DGSGZ.js → chunk-6MC7UQ6D.js} +2 -2
- package/dist/{chunk-655FVTCD.js → chunk-74IN6PV5.js} +2 -2
- package/dist/{chunk-XOSCGZEV.js → chunk-7FZ4YVOH.js} +2 -2
- package/dist/{chunk-MWWAQXZ6.js → chunk-7HFTCBCZ.js} +2 -2
- package/dist/{chunk-NDZ7APNY.js → chunk-7VB3Y5OL.js} +3 -3
- package/dist/{chunk-YEF5AAWN.js → chunk-A54E2ZTD.js} +2 -2
- package/dist/{chunk-DEY7B77Y.js → chunk-AHCELJMH.js} +2 -2
- package/dist/{chunk-PIWFNPQT.js → chunk-AL3TCNSJ.js} +4 -4
- package/dist/{chunk-KNWC2EPP.js → chunk-AUYFUBBE.js} +5 -5
- package/dist/{chunk-XN6ABQGM.js → chunk-BIE3ZH3N.js} +27 -27
- package/dist/{chunk-A3IURDU2.js → chunk-C2AOL6MK.js} +3 -3
- package/dist/{chunk-J4PILQJG.js → chunk-C2QVDLQV.js} +2 -2
- package/dist/{chunk-RKB4JZEM.js → chunk-CKR7LXEK.js} +67 -45
- package/dist/chunk-CKR7LXEK.js.map +1 -0
- package/dist/{chunk-AWLQNLTM.js → chunk-CSGFGQBI.js} +2 -2
- package/dist/{chunk-HZKDYR3Z.js → chunk-D4RV54HH.js} +2 -2
- package/dist/{chunk-OKNB2II7.js → chunk-DDLRKPR2.js} +6 -6
- package/dist/{chunk-3X3PNU3T.js → chunk-DLH3ECZP.js} +5 -5
- package/dist/chunk-DNIG3JME.js +892 -0
- package/dist/chunk-DNIG3JME.js.map +1 -0
- package/dist/{chunk-SA6GMZJY.js → chunk-DP3TSAYT.js} +2 -2
- package/dist/{chunk-XAJH5H3Z.js → chunk-FN6OFDBZ.js} +2 -2
- package/dist/{chunk-SUZG7UUK.js → chunk-G6DAE2LT.js} +2 -2
- package/dist/{chunk-AUPL775F.js → chunk-GSKW64NB.js} +2 -2
- package/dist/{chunk-3Z5LSDKR.js → chunk-GWB7ZD2A.js} +2 -2
- package/dist/{chunk-XOWR3I2W.js → chunk-HG2VVIKI.js} +9 -9
- package/dist/{chunk-23ZQPP2G.js → chunk-HOSJESKO.js} +3 -3
- package/dist/{chunk-EU6IRUCY.js → chunk-IDPZCHET.js} +2 -2
- package/dist/{chunk-3EE7EHFX.js → chunk-IO2UQVR2.js} +2 -2
- package/dist/{chunk-BWXKJDDH.js → chunk-ISMZ5UNE.js} +3 -3
- package/dist/{chunk-SX4QDWXK.js → chunk-IWUFKS4J.js} +2 -2
- package/dist/{chunk-MIIZAEJD.js → chunk-IY7DGT2Z.js} +2 -2
- package/dist/{chunk-STBX5X6B.js → chunk-JAYNUYSJ.js} +2 -2
- package/dist/{chunk-GV2V4CX6.js → chunk-K2REHR42.js} +2 -2
- package/dist/{chunk-NRG67KMO.js → chunk-KFKFK6G6.js} +10 -10
- package/dist/{chunk-FDPE6OIK.js → chunk-LDEKVBVO.js} +4 -4
- package/dist/{chunk-C2J4LBNB.js → chunk-M236YHUH.js} +5 -5
- package/dist/{chunk-L5VCT7LU.js → chunk-MCLZM5G7.js} +2 -2
- package/dist/{chunk-7Z3DLNSD.js → chunk-MGKH5KO3.js} +2 -2
- package/dist/{chunk-PUDYANAX.js → chunk-MMBLOJJB.js} +2 -2
- package/dist/{chunk-EFHNFTWB.js → chunk-MND4YJSX.js} +2 -2
- package/dist/{chunk-BQOGQULP.js → chunk-MZZEMPCI.js} +2 -2
- package/dist/{chunk-CQBNFDSG.js → chunk-NAPHQ2MG.js} +2 -2
- package/dist/{chunk-B6VPA3PF.js → chunk-NB2YX6X2.js} +6 -6
- package/dist/{chunk-PCSPXMPD.js → chunk-NCPR2FOJ.js} +3 -3
- package/dist/{chunk-67F6SBCJ.js → chunk-NOMHXZD7.js} +2 -2
- package/dist/{chunk-LWFWZTWX.js → chunk-NQV6G6MU.js} +2 -2
- package/dist/{chunk-JSFU7AFZ.js → chunk-OANSZGAG.js} +2 -2
- package/dist/{chunk-364M2T3D.js → chunk-OIIAIY7J.js} +3 -3
- package/dist/{chunk-IP5QGSNH.js → chunk-OXX4ORRL.js} +15 -15
- package/dist/{chunk-RTTPBBAN.js → chunk-OXYXMGRH.js} +4 -4
- package/dist/{chunk-K7BN34IA.js → chunk-PL26BCRN.js} +5 -5
- package/dist/{chunk-PM72NSEW.js → chunk-PYCTZ2HX.js} +2 -2
- package/dist/{chunk-P3NXZAV7.js → chunk-PZEADMX4.js} +2 -2
- package/dist/{chunk-QPH52AZB.js → chunk-QNDOTDJK.js} +2 -2
- package/dist/{chunk-LZACDIM2.js → chunk-RBGRQEW3.js} +4 -4
- package/dist/{chunk-V4JZCTMK.js → chunk-TKBW4YLS.js} +2 -2
- package/dist/{chunk-4D2YH47Z.js → chunk-TRW7N4FS.js} +2 -2
- package/dist/{chunk-XALR4DOQ.js → chunk-TTIEXXL3.js} +365 -1108
- package/dist/chunk-TTIEXXL3.js.map +1 -0
- package/dist/{chunk-OQJKY3Z5.js → chunk-UAAAXSKQ.js} +2 -2
- package/dist/{chunk-4LJSCW24.js → chunk-UM73Q46J.js} +2 -2
- package/dist/{chunk-7EJCAFMS.js → chunk-UTXYOWDR.js} +2 -2
- package/dist/{chunk-OGOADX26.js → chunk-UUYAW3JH.js} +2 -2
- package/dist/{chunk-UTGHW2Y5.js → chunk-UVUBLLM3.js} +3 -3
- package/dist/{chunk-4GGTC2AX.js → chunk-V4FI2TG6.js} +3 -3
- package/dist/{chunk-MO6N4QYY.js → chunk-VARNSLUW.js} +4 -4
- package/dist/{chunk-RQUF3FXK.js → chunk-VEB7NEON.js} +4 -4
- package/dist/{chunk-SSFO7B7H.js → chunk-VLBFSD7B.js} +2 -2
- package/dist/{chunk-NZFFGO5O.js → chunk-VXWOJPSY.js} +36 -3
- package/dist/chunk-VXWOJPSY.js.map +1 -0
- package/dist/{chunk-JNIVZNIB.js → chunk-WKVL2G7X.js} +4 -4
- package/dist/{chunk-KJXP6RUG.js → chunk-WNEVEMJ3.js} +4 -4
- package/dist/{chunk-I4MYLDRY.js → chunk-WQIYGYY6.js} +2 -2
- package/dist/{chunk-GQJKVQJR.js → chunk-WYLBEJQI.js} +2 -2
- package/dist/{chunk-JCPR47NY.js → chunk-XNROYP5E.js} +2 -2
- package/dist/{chunk-XNAOCY67.js → chunk-XVZIBMSY.js} +3 -3
- package/dist/{chunk-TZZFGR4E.js → chunk-YGVZ4QOZ.js} +4 -4
- package/dist/{chunk-C5JXYJHN.js → chunk-YZTFQBYY.js} +4 -4
- package/dist/{chunk-JTLXVXYH.js → chunk-ZCRDYQL6.js} +2 -2
- package/dist/{chunk-MAAL6OZV.js → chunk-ZG3HZZ6K.js} +90 -36
- package/dist/chunk-ZG3HZZ6K.js.map +1 -0
- package/dist/{chunk-CRVL6SLC.js → chunk-ZXTAHSQU.js} +2 -2
- package/dist/cli.js +80 -79
- package/dist/coding/export-okf-codegraph.js +20 -19
- package/dist/coding/export-okf-codegraph.js.map +1 -1
- package/dist/compounding/engine.js +22 -21
- package/dist/config.js +23 -22
- package/dist/connectors/codex-materialize-runner.js +20 -19
- package/dist/connectors/codex-materialize.js +2 -2
- package/dist/connectors/index.js +20 -19
- package/dist/consolidation-provenance-check.js +3 -3
- package/dist/consolidation-undo.js +2 -2
- package/dist/contradiction/index.js +6 -5
- package/dist/convergence-refresh.js +21 -20
- package/dist/corpus-watermark.js +21 -20
- package/dist/deep-recall-http-glue.js +7 -6
- package/dist/entity-canonical-id-migration-GD5MPFUF.js +28 -0
- package/dist/entity-retrieval.js +19 -18
- package/dist/explicit-capture.js +8 -7
- package/dist/external-wiki-access.js +48 -47
- package/dist/extraction.js +24 -23
- package/dist/harmonic-retrieval.js +20 -19
- package/dist/harmonic-source-lookup.js +3 -2
- package/dist/index.js +96 -95
- package/dist/location/index.js +22 -21
- package/dist/maintenance/memory-governance.js +19 -18
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +19 -18
- package/dist/maintenance/rebuild-memory-projection-runner.js +21 -20
- package/dist/maintenance/rebuild-memory-projection.js +20 -19
- package/dist/memory-browse-operations.js +48 -47
- package/dist/memory-subject.js +4 -3
- package/dist/namespaces/migrate.js +20 -19
- package/dist/namespaces/search.js +7 -7
- package/dist/namespaces/storage.js +19 -18
- package/dist/offline-sync-file-io.js +3 -2
- package/dist/offline-sync-impression-drain.js +4 -4
- package/dist/offline-sync-snapshot-stream.js +6 -5
- package/dist/offline-sync-upload-staging.js +4 -3
- package/dist/offline-sync.js +5 -4
- package/dist/operator-doctor-corpus.js +22 -21
- package/dist/operator-toolkit.js +33 -32
- package/dist/orchestration/maintenance.js +32 -31
- package/dist/orchestration/orchestrator-init.d.ts +3 -0
- package/dist/orchestration/orchestrator-init.d.ts.map +1 -1
- package/dist/orchestrator.d.ts.map +1 -1
- package/dist/orchestrator.js +96 -95
- package/dist/page-versioning.js +2 -2
- package/dist/recall-navigation-operations.js +48 -47
- package/dist/recall-navigation.js +47 -46
- package/dist/recall-state.js +2 -2
- package/dist/reconcile/manifest.js +4 -3
- package/dist/{resolution-ZU5BIAJA.js → resolution-AMYTPT5X.js} +7 -6
- package/dist/resolution-AMYTPT5X.js.map +1 -0
- package/dist/resume-bundles.js +24 -23
- package/dist/retrieval-agents.js +3 -2
- package/dist/salvage-envelope.js +6 -5
- package/dist/search/document-scanner.js +2 -2
- package/dist/search/factory.js +6 -6
- package/dist/search/index.js +6 -6
- package/dist/search/lancedb-backend.js +3 -3
- package/dist/search/meilisearch-backend.js +3 -3
- package/dist/search/orama-backend.js +3 -3
- package/dist/secure-store/entity-file-read.d.ts +9 -0
- package/dist/secure-store/entity-file-read.d.ts.map +1 -0
- package/dist/secure-store/index.js +3 -2
- package/dist/secure-store/secure-fs.d.ts.map +1 -1
- package/dist/semantic-consolidation.js +21 -20
- package/dist/semantic-rule-promotion.js +19 -18
- package/dist/semantic-rule-verifier.js +19 -18
- package/dist/shared-context/manager.js +2 -2
- package/dist/source-agent-qualifier.js +23 -22
- package/dist/standup/build.js +19 -18
- package/dist/storage/entity-canonical-id-migration-runner.d.ts +12 -0
- package/dist/storage/entity-canonical-id-migration-runner.d.ts.map +1 -1
- package/dist/storage/entity-canonical-id-migration.d.ts +1 -0
- package/dist/storage/entity-canonical-id-migration.d.ts.map +1 -1
- package/dist/storage/entity-canonical-id-references.d.ts +14 -0
- package/dist/storage/entity-canonical-id-references.d.ts.map +1 -1
- package/dist/storage/entity-store.d.ts +4 -0
- package/dist/storage/entity-store.d.ts.map +1 -1
- package/dist/storage.d.ts +7 -2
- package/dist/storage.d.ts.map +1 -1
- package/dist/storage.js +18 -17
- package/dist/subject-config.js +5 -4
- package/dist/support-passport/index.js +50 -49
- package/dist/transfer/capsule-import.js +3 -3
- package/dist/transfer/export-okf.js +20 -19
- package/dist/verified-recall.js +19 -18
- package/dist/who-knows-cli.js +20 -19
- package/dist/who-knows.js +19 -18
- package/dist/write-envelope.js +5 -4
- package/package.json +2 -2
- package/src/orchestration/orchestrator-init.ts +26 -3
- package/src/orchestrator.ts +1 -0
- package/src/secure-store/entity-file-read.ts +55 -0
- package/src/secure-store/secure-fs.ts +2 -1
- package/src/storage/entity-canonical-id-migration-runner.ts +36 -0
- package/src/storage/entity-canonical-id-migration.ts +1 -1
- package/src/storage/entity-canonical-id-references.ts +57 -2
- package/src/storage/entity-store.ts +138 -25
- package/src/storage.ts +15 -15
- package/dist/chunk-MAAL6OZV.js.map +0 -1
- package/dist/chunk-NZFFGO5O.js.map +0 -1
- package/dist/chunk-RKB4JZEM.js.map +0 -1
- package/dist/chunk-XALR4DOQ.js.map +0 -1
- /package/dist/{auto-sync-UQESPLCB.js.map → auto-sync-MX2AHVPQ.js.map} +0 -0
- /package/dist/{capsule-merge-LGYURS3C.js.map → capsule-merge-LGYZAMO4.js.map} +0 -0
- /package/dist/{chunk-2TGDT37F.js.map → chunk-27OJ5G3D.js.map} +0 -0
- /package/dist/{chunk-5LRV557D.js.map → chunk-2FIJQNL7.js.map} +0 -0
- /package/dist/{chunk-ETPIYK4J.js.map → chunk-2VBDSZ7U.js.map} +0 -0
- /package/dist/{chunk-QLI74KWK.js.map → chunk-2XVLY424.js.map} +0 -0
- /package/dist/{chunk-P55FACBG.js.map → chunk-3BOQPLCF.js.map} +0 -0
- /package/dist/{chunk-3LRBJQZE.js.map → chunk-3CHHQXAR.js.map} +0 -0
- /package/dist/{chunk-3GYSZHMT.js.map → chunk-3CZRBTJK.js.map} +0 -0
- /package/dist/{chunk-HFSPY26A.js.map → chunk-3IXNL6SK.js.map} +0 -0
- /package/dist/{chunk-4DQ4VEIQ.js.map → chunk-3SN2D43X.js.map} +0 -0
- /package/dist/{chunk-QMYB3N7X.js.map → chunk-4HNINU7Q.js.map} +0 -0
- /package/dist/{chunk-LW6UHNWA.js.map → chunk-4HYP4OKH.js.map} +0 -0
- /package/dist/{chunk-GKJJNO7C.js.map → chunk-4OE4UE2Y.js.map} +0 -0
- /package/dist/{chunk-5SMR542T.js.map → chunk-5GT4ESLR.js.map} +0 -0
- /package/dist/{chunk-DWL6YIZH.js.map → chunk-5JI3XWI2.js.map} +0 -0
- /package/dist/{chunk-PDN6MRWF.js.map → chunk-5NPZFXQH.js.map} +0 -0
- /package/dist/{chunk-Y6IF6H2U.js.map → chunk-5SMHQW45.js.map} +0 -0
- /package/dist/{chunk-PRUXE3RC.js.map → chunk-654GT5UP.js.map} +0 -0
- /package/dist/{chunk-3E6DGSGZ.js.map → chunk-6MC7UQ6D.js.map} +0 -0
- /package/dist/{chunk-655FVTCD.js.map → chunk-74IN6PV5.js.map} +0 -0
- /package/dist/{chunk-XOSCGZEV.js.map → chunk-7FZ4YVOH.js.map} +0 -0
- /package/dist/{chunk-MWWAQXZ6.js.map → chunk-7HFTCBCZ.js.map} +0 -0
- /package/dist/{chunk-NDZ7APNY.js.map → chunk-7VB3Y5OL.js.map} +0 -0
- /package/dist/{chunk-YEF5AAWN.js.map → chunk-A54E2ZTD.js.map} +0 -0
- /package/dist/{chunk-DEY7B77Y.js.map → chunk-AHCELJMH.js.map} +0 -0
- /package/dist/{chunk-PIWFNPQT.js.map → chunk-AL3TCNSJ.js.map} +0 -0
- /package/dist/{chunk-KNWC2EPP.js.map → chunk-AUYFUBBE.js.map} +0 -0
- /package/dist/{chunk-XN6ABQGM.js.map → chunk-BIE3ZH3N.js.map} +0 -0
- /package/dist/{chunk-A3IURDU2.js.map → chunk-C2AOL6MK.js.map} +0 -0
- /package/dist/{chunk-J4PILQJG.js.map → chunk-C2QVDLQV.js.map} +0 -0
- /package/dist/{chunk-AWLQNLTM.js.map → chunk-CSGFGQBI.js.map} +0 -0
- /package/dist/{chunk-HZKDYR3Z.js.map → chunk-D4RV54HH.js.map} +0 -0
- /package/dist/{chunk-OKNB2II7.js.map → chunk-DDLRKPR2.js.map} +0 -0
- /package/dist/{chunk-3X3PNU3T.js.map → chunk-DLH3ECZP.js.map} +0 -0
- /package/dist/{chunk-SA6GMZJY.js.map → chunk-DP3TSAYT.js.map} +0 -0
- /package/dist/{chunk-XAJH5H3Z.js.map → chunk-FN6OFDBZ.js.map} +0 -0
- /package/dist/{chunk-SUZG7UUK.js.map → chunk-G6DAE2LT.js.map} +0 -0
- /package/dist/{chunk-AUPL775F.js.map → chunk-GSKW64NB.js.map} +0 -0
- /package/dist/{chunk-3Z5LSDKR.js.map → chunk-GWB7ZD2A.js.map} +0 -0
- /package/dist/{chunk-XOWR3I2W.js.map → chunk-HG2VVIKI.js.map} +0 -0
- /package/dist/{chunk-23ZQPP2G.js.map → chunk-HOSJESKO.js.map} +0 -0
- /package/dist/{chunk-EU6IRUCY.js.map → chunk-IDPZCHET.js.map} +0 -0
- /package/dist/{chunk-3EE7EHFX.js.map → chunk-IO2UQVR2.js.map} +0 -0
- /package/dist/{chunk-BWXKJDDH.js.map → chunk-ISMZ5UNE.js.map} +0 -0
- /package/dist/{chunk-SX4QDWXK.js.map → chunk-IWUFKS4J.js.map} +0 -0
- /package/dist/{chunk-MIIZAEJD.js.map → chunk-IY7DGT2Z.js.map} +0 -0
- /package/dist/{chunk-STBX5X6B.js.map → chunk-JAYNUYSJ.js.map} +0 -0
- /package/dist/{chunk-GV2V4CX6.js.map → chunk-K2REHR42.js.map} +0 -0
- /package/dist/{chunk-NRG67KMO.js.map → chunk-KFKFK6G6.js.map} +0 -0
- /package/dist/{chunk-FDPE6OIK.js.map → chunk-LDEKVBVO.js.map} +0 -0
- /package/dist/{chunk-C2J4LBNB.js.map → chunk-M236YHUH.js.map} +0 -0
- /package/dist/{chunk-L5VCT7LU.js.map → chunk-MCLZM5G7.js.map} +0 -0
- /package/dist/{chunk-7Z3DLNSD.js.map → chunk-MGKH5KO3.js.map} +0 -0
- /package/dist/{chunk-PUDYANAX.js.map → chunk-MMBLOJJB.js.map} +0 -0
- /package/dist/{chunk-EFHNFTWB.js.map → chunk-MND4YJSX.js.map} +0 -0
- /package/dist/{chunk-BQOGQULP.js.map → chunk-MZZEMPCI.js.map} +0 -0
- /package/dist/{chunk-CQBNFDSG.js.map → chunk-NAPHQ2MG.js.map} +0 -0
- /package/dist/{chunk-B6VPA3PF.js.map → chunk-NB2YX6X2.js.map} +0 -0
- /package/dist/{chunk-PCSPXMPD.js.map → chunk-NCPR2FOJ.js.map} +0 -0
- /package/dist/{chunk-67F6SBCJ.js.map → chunk-NOMHXZD7.js.map} +0 -0
- /package/dist/{chunk-LWFWZTWX.js.map → chunk-NQV6G6MU.js.map} +0 -0
- /package/dist/{chunk-JSFU7AFZ.js.map → chunk-OANSZGAG.js.map} +0 -0
- /package/dist/{chunk-364M2T3D.js.map → chunk-OIIAIY7J.js.map} +0 -0
- /package/dist/{chunk-IP5QGSNH.js.map → chunk-OXX4ORRL.js.map} +0 -0
- /package/dist/{chunk-RTTPBBAN.js.map → chunk-OXYXMGRH.js.map} +0 -0
- /package/dist/{chunk-K7BN34IA.js.map → chunk-PL26BCRN.js.map} +0 -0
- /package/dist/{chunk-PM72NSEW.js.map → chunk-PYCTZ2HX.js.map} +0 -0
- /package/dist/{chunk-P3NXZAV7.js.map → chunk-PZEADMX4.js.map} +0 -0
- /package/dist/{chunk-QPH52AZB.js.map → chunk-QNDOTDJK.js.map} +0 -0
- /package/dist/{chunk-LZACDIM2.js.map → chunk-RBGRQEW3.js.map} +0 -0
- /package/dist/{chunk-V4JZCTMK.js.map → chunk-TKBW4YLS.js.map} +0 -0
- /package/dist/{chunk-4D2YH47Z.js.map → chunk-TRW7N4FS.js.map} +0 -0
- /package/dist/{chunk-OQJKY3Z5.js.map → chunk-UAAAXSKQ.js.map} +0 -0
- /package/dist/{chunk-4LJSCW24.js.map → chunk-UM73Q46J.js.map} +0 -0
- /package/dist/{chunk-7EJCAFMS.js.map → chunk-UTXYOWDR.js.map} +0 -0
- /package/dist/{chunk-OGOADX26.js.map → chunk-UUYAW3JH.js.map} +0 -0
- /package/dist/{chunk-UTGHW2Y5.js.map → chunk-UVUBLLM3.js.map} +0 -0
- /package/dist/{chunk-4GGTC2AX.js.map → chunk-V4FI2TG6.js.map} +0 -0
- /package/dist/{chunk-MO6N4QYY.js.map → chunk-VARNSLUW.js.map} +0 -0
- /package/dist/{chunk-RQUF3FXK.js.map → chunk-VEB7NEON.js.map} +0 -0
- /package/dist/{chunk-SSFO7B7H.js.map → chunk-VLBFSD7B.js.map} +0 -0
- /package/dist/{chunk-JNIVZNIB.js.map → chunk-WKVL2G7X.js.map} +0 -0
- /package/dist/{chunk-KJXP6RUG.js.map → chunk-WNEVEMJ3.js.map} +0 -0
- /package/dist/{chunk-I4MYLDRY.js.map → chunk-WQIYGYY6.js.map} +0 -0
- /package/dist/{chunk-GQJKVQJR.js.map → chunk-WYLBEJQI.js.map} +0 -0
- /package/dist/{chunk-JCPR47NY.js.map → chunk-XNROYP5E.js.map} +0 -0
- /package/dist/{chunk-XNAOCY67.js.map → chunk-XVZIBMSY.js.map} +0 -0
- /package/dist/{chunk-TZZFGR4E.js.map → chunk-YGVZ4QOZ.js.map} +0 -0
- /package/dist/{chunk-C5JXYJHN.js.map → chunk-YZTFQBYY.js.map} +0 -0
- /package/dist/{chunk-JTLXVXYH.js.map → chunk-ZCRDYQL6.js.map} +0 -0
- /package/dist/{chunk-CRVL6SLC.js.map → chunk-ZXTAHSQU.js.map} +0 -0
- /package/dist/{resolution-ZU5BIAJA.js.map → entity-canonical-id-migration-GD5MPFUF.js.map} +0 -0
|
@@ -15,9 +15,14 @@ import {
|
|
|
15
15
|
buildRetiredFactTombstoneInputs,
|
|
16
16
|
collectRetiredMemoriesForRebuild
|
|
17
17
|
} from "./chunk-TRMJ6BYC.js";
|
|
18
|
+
import {
|
|
19
|
+
getFingerprint,
|
|
20
|
+
migrateLegacyEntityCanonicalIds,
|
|
21
|
+
validateRoots
|
|
22
|
+
} from "./chunk-DNIG3JME.js";
|
|
18
23
|
import {
|
|
19
24
|
normalizeQmdResultPath
|
|
20
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-7HFTCBCZ.js";
|
|
21
26
|
import {
|
|
22
27
|
withholdToolScopedFromSharedNamespace
|
|
23
28
|
} from "./chunk-S2V7RUCL.js";
|
|
@@ -64,7 +69,7 @@ import {
|
|
|
64
69
|
invalidationCommitFingerprint,
|
|
65
70
|
parseTombstoneBlockedOfflineSyncMemory,
|
|
66
71
|
withCasCommitReceipt
|
|
67
|
-
} from "./chunk-
|
|
72
|
+
} from "./chunk-WKVL2G7X.js";
|
|
68
73
|
import {
|
|
69
74
|
normalizeEntityName
|
|
70
75
|
} from "./chunk-YXZG5TVN.js";
|
|
@@ -97,7 +102,7 @@ import {
|
|
|
97
102
|
} from "./chunk-G7D6GZ5J.js";
|
|
98
103
|
import {
|
|
99
104
|
createVersion
|
|
100
|
-
} from "./chunk-
|
|
105
|
+
} from "./chunk-3CZRBTJK.js";
|
|
101
106
|
import {
|
|
102
107
|
attachInFlightReader,
|
|
103
108
|
beginCoalescedScan,
|
|
@@ -106,23 +111,19 @@ import {
|
|
|
106
111
|
deleteInFlightReadsForDir
|
|
107
112
|
} from "./chunk-RBOJCG4T.js";
|
|
108
113
|
import {
|
|
109
|
-
ENTITY_CANONICAL_ID_MIGRATION_FILE,
|
|
110
|
-
ENTITY_CANONICAL_ID_RECONCILE_CONSUMING_MARKER,
|
|
111
|
-
ENTITY_CANONICAL_ID_RECONCILE_MARKER,
|
|
112
114
|
HistoricalEntityCanonicalIdCache,
|
|
113
115
|
appendCanonicalizedTombstone,
|
|
114
116
|
assertSafeEntityId,
|
|
115
117
|
canonicalizeEntityRefFrontmatter,
|
|
116
118
|
canonicalizeEntityRefOption,
|
|
119
|
+
memoizedJournalCompletion,
|
|
117
120
|
reconcileIfJournalMovedSync,
|
|
118
121
|
repairEntityRefAfterJournalMove,
|
|
119
122
|
requestEntityCanonicalIdReconcileSync,
|
|
120
123
|
resolveHistoricalEntityCanonicalId,
|
|
121
124
|
withEntityCanonicalMutationLock
|
|
122
|
-
} from "./chunk-
|
|
125
|
+
} from "./chunk-VXWOJPSY.js";
|
|
123
126
|
import {
|
|
124
|
-
computeSupersessionKey,
|
|
125
|
-
normalizeSupersessionKey,
|
|
126
127
|
supersessionKeysForFact
|
|
127
128
|
} from "./chunk-5WITETWU.js";
|
|
128
129
|
import {
|
|
@@ -167,7 +168,7 @@ import {
|
|
|
167
168
|
composeMemoryEnvelope,
|
|
168
169
|
isSealedMemoryEnvelope,
|
|
169
170
|
sealedWriteToLegacyArgs
|
|
170
|
-
} from "./chunk-
|
|
171
|
+
} from "./chunk-2FIJQNL7.js";
|
|
171
172
|
import {
|
|
172
173
|
DEFAULT_CITATION_FORMAT,
|
|
173
174
|
hasCitationForTemplate,
|
|
@@ -188,7 +189,7 @@ import {
|
|
|
188
189
|
readMemoryActionEventRowsFromLines,
|
|
189
190
|
readProjectionRebuiltAt,
|
|
190
191
|
serializeLifecycleAppendPayload
|
|
191
|
-
} from "./chunk-
|
|
192
|
+
} from "./chunk-3BOQPLCF.js";
|
|
192
193
|
import {
|
|
193
194
|
assertMemoryFrontmatterId,
|
|
194
195
|
warnProjectionFallback
|
|
@@ -209,15 +210,11 @@ import {
|
|
|
209
210
|
import {
|
|
210
211
|
isSupportPassportPrivateMemory
|
|
211
212
|
} from "./chunk-PWPIERBM.js";
|
|
212
|
-
import {
|
|
213
|
-
assertPathInsideRoot,
|
|
214
|
-
pathIsInside
|
|
215
|
-
} from "./chunk-C7HJ3NEI.js";
|
|
216
213
|
import {
|
|
217
214
|
CONTENT_HASH_INDEX_RETRY_MAX_DELAY_MS,
|
|
218
215
|
ContentHashIndex,
|
|
219
216
|
FactHashIndexNotAuthoritativeError
|
|
220
|
-
} from "./chunk-
|
|
217
|
+
} from "./chunk-AHCELJMH.js";
|
|
221
218
|
import {
|
|
222
219
|
computeLegacyContentHash
|
|
223
220
|
} from "./chunk-5FVVY2EB.js";
|
|
@@ -229,9 +226,6 @@ import {
|
|
|
229
226
|
import {
|
|
230
227
|
sanitizeMemoryContent
|
|
231
228
|
} from "./chunk-5GKPFL3S.js";
|
|
232
|
-
import {
|
|
233
|
-
withHeldFileLock
|
|
234
|
-
} from "./chunk-5B5WYAHQ.js";
|
|
235
229
|
import {
|
|
236
230
|
parseFlexibleIsoTimestamp
|
|
237
231
|
} from "./chunk-P7FMDTKL.js";
|
|
@@ -256,13 +250,18 @@ import {
|
|
|
256
250
|
} from "./chunk-LDPPTPO5.js";
|
|
257
251
|
import {
|
|
258
252
|
MAGIC_HEADER_SIZE,
|
|
253
|
+
SecureStoreDecryptError,
|
|
259
254
|
SecureStoreLockedError,
|
|
260
255
|
isEncryptedFile,
|
|
261
256
|
probeEncryptedRegularFileHeader,
|
|
262
257
|
readMaybeEncryptedFile,
|
|
263
258
|
readMaybeEncryptedFileBuffer,
|
|
264
259
|
writeMaybeEncryptedFile
|
|
265
|
-
} from "./chunk-
|
|
260
|
+
} from "./chunk-ZG3HZZ6K.js";
|
|
261
|
+
import {
|
|
262
|
+
assertPathInsideRoot,
|
|
263
|
+
pathIsInside
|
|
264
|
+
} from "./chunk-C7HJ3NEI.js";
|
|
266
265
|
import {
|
|
267
266
|
ALL_CATEGORY_DIRS,
|
|
268
267
|
RECALL_FALLBACK_DIRS,
|
|
@@ -278,19 +277,19 @@ import {
|
|
|
278
277
|
|
|
279
278
|
// src/storage.ts
|
|
280
279
|
import {
|
|
281
|
-
lstat as
|
|
282
|
-
readdir as
|
|
283
|
-
readFile
|
|
284
|
-
realpath as
|
|
280
|
+
lstat as lstat3,
|
|
281
|
+
readdir as readdir5,
|
|
282
|
+
readFile,
|
|
283
|
+
realpath as realpath3,
|
|
285
284
|
stat as stat3,
|
|
286
|
-
writeFile
|
|
285
|
+
writeFile,
|
|
287
286
|
mkdir,
|
|
288
|
-
unlink as
|
|
287
|
+
unlink as unlink3,
|
|
289
288
|
appendFile,
|
|
290
289
|
open
|
|
291
290
|
} from "fs/promises";
|
|
292
291
|
import { appendFileSync, createReadStream, mkdirSync, statSync as statSync2 } from "fs";
|
|
293
|
-
import { createHash as
|
|
292
|
+
import { createHash as createHash5 } from "crypto";
|
|
294
293
|
|
|
295
294
|
// src/preferences/drift-types.ts
|
|
296
295
|
function serializeDriftProvenance(fm) {
|
|
@@ -314,7 +313,7 @@ function parseDriftProvenance(fm) {
|
|
|
314
313
|
}
|
|
315
314
|
|
|
316
315
|
// src/storage.ts
|
|
317
|
-
import
|
|
316
|
+
import path12 from "path";
|
|
318
317
|
|
|
319
318
|
// src/storage/tombstone-migration-sources.ts
|
|
320
319
|
import { statSync } from "fs";
|
|
@@ -1975,18 +1974,49 @@ var EntityStore = class {
|
|
|
1975
1974
|
log.debug(`wrote entity ${normalized}`);
|
|
1976
1975
|
return normalized;
|
|
1977
1976
|
}
|
|
1978
|
-
async
|
|
1979
|
-
const filePath = this.deps.resolveEntityFilePath(name);
|
|
1980
|
-
if (filePath === null) {
|
|
1981
|
-
return "";
|
|
1982
|
-
}
|
|
1977
|
+
async readEntityFileResolvingRename(firstPath, entityId) {
|
|
1983
1978
|
try {
|
|
1984
|
-
return await this.deps.readStorageSecureFile(
|
|
1979
|
+
return { id: entityId, content: await this.deps.readStorageSecureFile(firstPath) };
|
|
1985
1980
|
} catch (err) {
|
|
1986
1981
|
if (err instanceof SecureStoreLockedError) throw err;
|
|
1982
|
+
if (isErrnoCode(err, "ELOOP")) return null;
|
|
1987
1983
|
if (!isErrnoCode(err, "ENOENT")) throw err;
|
|
1984
|
+
}
|
|
1985
|
+
const historicalIds = this.deps.currentHistoricalIds();
|
|
1986
|
+
const canonical = resolveHistoricalEntityCanonicalId(entityId, historicalIds);
|
|
1987
|
+
const candidates = /* @__PURE__ */ new Set([canonical]);
|
|
1988
|
+
for (const legacy of Object.keys(historicalIds)) {
|
|
1989
|
+
if (resolveHistoricalEntityCanonicalId(legacy, historicalIds) === canonical) candidates.add(legacy);
|
|
1990
|
+
}
|
|
1991
|
+
candidates.delete(entityId);
|
|
1992
|
+
for (const candidate of candidates) {
|
|
1993
|
+
try {
|
|
1994
|
+
return { id: candidate, content: await this.deps.readStorageSecureFile(
|
|
1995
|
+
path5.join(this.deps.entitiesDir, `${candidate}.md`)
|
|
1996
|
+
) };
|
|
1997
|
+
} catch (err) {
|
|
1998
|
+
if (err instanceof SecureStoreLockedError) throw err;
|
|
1999
|
+
if (isErrnoCode(err, "ENOENT") || isErrnoCode(err, "ELOOP")) continue;
|
|
2000
|
+
throw err;
|
|
2001
|
+
}
|
|
2002
|
+
}
|
|
2003
|
+
return null;
|
|
2004
|
+
}
|
|
2005
|
+
async readEntity(name) {
|
|
2006
|
+
const filePath = this.deps.resolveEntityFilePath(name);
|
|
2007
|
+
if (filePath === null) {
|
|
1988
2008
|
return "";
|
|
1989
2009
|
}
|
|
2010
|
+
if (this.deps.entityCanonicalMigrationComplete()) {
|
|
2011
|
+
try {
|
|
2012
|
+
return await this.deps.readStorageSecureFile(filePath);
|
|
2013
|
+
} catch (err) {
|
|
2014
|
+
if (err instanceof SecureStoreLockedError) throw err;
|
|
2015
|
+
if (isErrnoCode(err, "ENOENT") || isErrnoCode(err, "ELOOP")) return "";
|
|
2016
|
+
throw err;
|
|
2017
|
+
}
|
|
2018
|
+
}
|
|
2019
|
+
return (await this.readEntityFileResolvingRename(filePath, name))?.content ?? "";
|
|
1990
2020
|
}
|
|
1991
2021
|
/**
|
|
1992
2022
|
* True when `entities/` is a real directory inside this memory root.
|
|
@@ -2033,6 +2063,15 @@ var EntityStore = class {
|
|
|
2033
2063
|
* Symlinks, FIFOs, and devices are skipped before any read. The entities
|
|
2034
2064
|
* root is refused separately, before the directory is listed.
|
|
2035
2065
|
*/
|
|
2066
|
+
async isMissingEntry(file) {
|
|
2067
|
+
try {
|
|
2068
|
+
await lstat2(path5.join(this.deps.entitiesDir, file));
|
|
2069
|
+
return false;
|
|
2070
|
+
} catch (err) {
|
|
2071
|
+
if (isErrnoCode(err, "ENOENT")) return true;
|
|
2072
|
+
throw err;
|
|
2073
|
+
}
|
|
2074
|
+
}
|
|
2036
2075
|
async isContainedRegularEntityFile(file) {
|
|
2037
2076
|
const filePath = path5.join(this.deps.entitiesDir, file);
|
|
2038
2077
|
let entryStat;
|
|
@@ -2086,23 +2125,40 @@ var EntityStore = class {
|
|
|
2086
2125
|
const names = [];
|
|
2087
2126
|
const batchSize = 100;
|
|
2088
2127
|
for (let i = 0; i < mdFiles.length; i += batchSize) {
|
|
2128
|
+
const historicalIds = this.deps.currentHistoricalIds();
|
|
2129
|
+
const snapshotIds = new Set(mdFiles.map((file) => file.slice(0, -3)));
|
|
2130
|
+
const journalComplete = this.deps.entityCanonicalMigrationComplete();
|
|
2131
|
+
const resolveCanonical = (entityId) => {
|
|
2132
|
+
const canonical = resolveHistoricalEntityCanonicalId(entityId, historicalIds);
|
|
2133
|
+
if (canonical === entityId) return entityId;
|
|
2134
|
+
if (journalComplete) return entityId;
|
|
2135
|
+
if (snapshotIds.has(canonical)) return entityId;
|
|
2136
|
+
return canonical;
|
|
2137
|
+
};
|
|
2089
2138
|
const resolved = await Promise.all(mdFiles.slice(i, i + batchSize).map(async (file) => {
|
|
2139
|
+
const entityId = file.slice(0, -3);
|
|
2090
2140
|
try {
|
|
2091
|
-
if (
|
|
2141
|
+
if (await this.isIndexableEntityMarkdown(file)) {
|
|
2142
|
+
return resolveCanonical(entityId);
|
|
2143
|
+
}
|
|
2092
2144
|
} catch (err) {
|
|
2093
|
-
if (err instanceof SecureStoreLockedError) throw err;
|
|
2094
|
-
|
|
2145
|
+
if (err instanceof SecureStoreLockedError || err instanceof SecureStoreDecryptError) throw err;
|
|
2146
|
+
}
|
|
2147
|
+
try {
|
|
2148
|
+
if (await this.isMissingEntry(file)) {
|
|
2149
|
+
const canonical = resolveHistoricalEntityCanonicalId(entityId, this.deps.currentHistoricalIds());
|
|
2150
|
+
if (canonical !== entityId) return canonical;
|
|
2151
|
+
}
|
|
2152
|
+
} catch (err) {
|
|
2153
|
+
if (err instanceof SecureStoreLockedError || err instanceof SecureStoreDecryptError) throw err;
|
|
2095
2154
|
}
|
|
2096
|
-
return
|
|
2155
|
+
return null;
|
|
2097
2156
|
}));
|
|
2098
|
-
|
|
2099
|
-
if (name) names.push(name);
|
|
2100
|
-
}
|
|
2157
|
+
names.push(...resolved.filter((name) => name !== null));
|
|
2101
2158
|
}
|
|
2102
|
-
names.sort();
|
|
2103
|
-
return names;
|
|
2159
|
+
return [...new Set(names)].sort();
|
|
2104
2160
|
} catch (err) {
|
|
2105
|
-
if (err instanceof SecureStoreLockedError) throw err;
|
|
2161
|
+
if (err instanceof SecureStoreLockedError || err instanceof SecureStoreDecryptError) throw err;
|
|
2106
2162
|
return [];
|
|
2107
2163
|
}
|
|
2108
2164
|
}
|
|
@@ -2190,9 +2246,16 @@ var EntityStore = class {
|
|
|
2190
2246
|
const cached = getCachedEntities(this.deps.baseDir, currentVersion, cacheKey);
|
|
2191
2247
|
if (cached) return cached;
|
|
2192
2248
|
try {
|
|
2193
|
-
|
|
2249
|
+
if (!await this.isTrustedEntitiesRoot()) return [];
|
|
2250
|
+
const listed = await readdir2(this.deps.entitiesDir);
|
|
2251
|
+
const { kept: entries, ignored } = withoutMacOsReplicationJunk(listed, (name) => name);
|
|
2252
|
+
warnIgnoredMacOsReplicationJunk(this.deps.entitiesDir, ignored, (message) => {
|
|
2253
|
+
log.warn(`entity load ${message}`);
|
|
2254
|
+
});
|
|
2194
2255
|
const mdFiles = entries.filter((e) => e.endsWith(".md"));
|
|
2195
2256
|
if (mdFiles.length === 0) return [];
|
|
2257
|
+
const historicalIds = this.deps.currentHistoricalIds();
|
|
2258
|
+
const seen = /* @__PURE__ */ new Map();
|
|
2196
2259
|
const BATCH_SIZE = 100;
|
|
2197
2260
|
const entities = [];
|
|
2198
2261
|
for (let i = 0; i < mdFiles.length; i += BATCH_SIZE) {
|
|
@@ -2200,19 +2263,34 @@ var EntityStore = class {
|
|
|
2200
2263
|
const batch = mdFiles.slice(i, i + BATCH_SIZE);
|
|
2201
2264
|
const results = await Promise.all(
|
|
2202
2265
|
batch.map(async (entry) => {
|
|
2266
|
+
const entityId = entry.slice(0, -".md".length);
|
|
2267
|
+
const entryPath = path5.join(this.deps.entitiesDir, entry);
|
|
2203
2268
|
try {
|
|
2204
|
-
if (!await this.isContainedRegularEntityFile(entry))
|
|
2205
|
-
|
|
2269
|
+
if (!await this.isContainedRegularEntityFile(entry)) {
|
|
2270
|
+
if (await this.isMissingEntry(entry)) {
|
|
2271
|
+
return await this.readEntityFileResolvingRename(entryPath, entityId);
|
|
2272
|
+
}
|
|
2273
|
+
return null;
|
|
2274
|
+
}
|
|
2275
|
+
return await this.readEntityFileResolvingRename(entryPath, entityId);
|
|
2206
2276
|
} catch (err) {
|
|
2207
|
-
if (err instanceof SecureStoreLockedError) throw err;
|
|
2208
|
-
|
|
2277
|
+
if (err instanceof SecureStoreLockedError || err instanceof SecureStoreDecryptError) throw err;
|
|
2278
|
+
log.warn(`entity read isolated failure for ${entry}: ${err instanceof Error ? err.message : String(err)}`);
|
|
2209
2279
|
return null;
|
|
2210
2280
|
}
|
|
2211
2281
|
})
|
|
2212
2282
|
);
|
|
2213
|
-
for (const
|
|
2214
|
-
if (
|
|
2215
|
-
const
|
|
2283
|
+
for (const result of results) {
|
|
2284
|
+
if (result === null) continue;
|
|
2285
|
+
const canonical = resolveHistoricalEntityCanonicalId(result.id, historicalIds);
|
|
2286
|
+
let contents = seen.get(canonical);
|
|
2287
|
+
if (contents?.has(result.content)) continue;
|
|
2288
|
+
if (!contents) {
|
|
2289
|
+
contents = /* @__PURE__ */ new Set();
|
|
2290
|
+
seen.set(canonical, contents);
|
|
2291
|
+
}
|
|
2292
|
+
contents.add(result.content);
|
|
2293
|
+
const entity = parseEntityFile(result.content, this.deps.entitySchemas);
|
|
2216
2294
|
if (!entity.name.trim() || !entity.type.trim()) continue;
|
|
2217
2295
|
entities.push(entity);
|
|
2218
2296
|
}
|
|
@@ -2679,859 +2757,8 @@ var IdentityContinuityStore = class {
|
|
|
2679
2757
|
}
|
|
2680
2758
|
};
|
|
2681
2759
|
|
|
2682
|
-
// src/storage/entity-canonical-id-migration.ts
|
|
2683
|
-
import { createHash, randomUUID } from "crypto";
|
|
2684
|
-
import {
|
|
2685
|
-
access,
|
|
2686
|
-
lstat as lstat3,
|
|
2687
|
-
readFile,
|
|
2688
|
-
readdir as readdir4,
|
|
2689
|
-
realpath as realpath3,
|
|
2690
|
-
rename,
|
|
2691
|
-
stat as statFile,
|
|
2692
|
-
unlink as unlink2,
|
|
2693
|
-
writeFile
|
|
2694
|
-
} from "fs/promises";
|
|
2695
|
-
import path7 from "path";
|
|
2696
|
-
import { z } from "zod";
|
|
2697
|
-
var ENTITY_CANONICAL_ID_MIGRATION_VERSION = 1;
|
|
2698
|
-
var ENTITY_CANONICAL_ID_MIGRATION_LOCK_STALE_MS = 6e4;
|
|
2699
|
-
var ENTITY_CANONICAL_ID_MIGRATION_LOCK_MAX_WAIT_MS = 3e5;
|
|
2700
|
-
var TOMBSTONE_LOCK_STALE_MS = 3e4;
|
|
2701
|
-
var TOMBSTONE_LOCK_MAX_WAIT_MS = 5e3;
|
|
2702
|
-
var MEMORY_REWRITE_MAX_PASSES = 3;
|
|
2703
|
-
var ENTITY_MAPPING_RESCAN_MAX_PASSES = 3;
|
|
2704
|
-
var EntityCanonicalIdMigrationStateSchema = z.object({
|
|
2705
|
-
version: z.literal(ENTITY_CANONICAL_ID_MIGRATION_VERSION),
|
|
2706
|
-
complete: z.boolean(),
|
|
2707
|
-
mappings: z.record(z.string().min(1)),
|
|
2708
|
-
/**
|
|
2709
|
-
* Pairs the migration refused to resolve, PARKED rather than dropped.
|
|
2710
|
-
* Deleting the record would strand the collision: once an operator removes
|
|
2711
|
-
* the legacy file, no later scan can rediscover the mapping, so references
|
|
2712
|
-
* still naming the legacy id would never be rewritten. Optional so a journal
|
|
2713
|
-
* written by an older build still parses.
|
|
2714
|
-
*/
|
|
2715
|
-
blocked: z.record(z.string().min(1)).optional()
|
|
2716
|
-
});
|
|
2717
|
-
async function fingerprintPath(filePath) {
|
|
2718
|
-
let fileStat;
|
|
2719
|
-
try {
|
|
2720
|
-
fileStat = await lstat3(filePath);
|
|
2721
|
-
} catch (error) {
|
|
2722
|
-
if (!isErrnoCode(error, "ENOENT")) throw error;
|
|
2723
|
-
}
|
|
2724
|
-
return fileStat ? `${fileStat.dev}:${fileStat.ino}:${fileStat.mtimeMs}:${fileStat.ctimeMs}:${fileStat.size}` : "missing";
|
|
2725
|
-
}
|
|
2726
|
-
async function fingerprintEntityEntries(entitiesDir) {
|
|
2727
|
-
let names;
|
|
2728
|
-
try {
|
|
2729
|
-
names = (await readdir4(entitiesDir)).filter((name) => path7.extname(name) === ".md" && !isMacOsReplicationJunkBasename(name)).sort();
|
|
2730
|
-
} catch (error) {
|
|
2731
|
-
if (isErrnoCode(error, "ENOENT")) return "missing";
|
|
2732
|
-
throw error;
|
|
2733
|
-
}
|
|
2734
|
-
const hash = createHash("sha256");
|
|
2735
|
-
for (const name of names) {
|
|
2736
|
-
hash.update(`${name.length}:${name}:`);
|
|
2737
|
-
try {
|
|
2738
|
-
const entry = await lstat3(path7.join(entitiesDir, name), { bigint: true });
|
|
2739
|
-
hash.update(`${entry.dev}:${entry.ino}:${entry.size}:${entry.mtimeNs}:${entry.ctimeNs}`);
|
|
2740
|
-
} catch (error) {
|
|
2741
|
-
if (!isErrnoCode(error, "ENOENT")) throw error;
|
|
2742
|
-
hash.update("missing");
|
|
2743
|
-
}
|
|
2744
|
-
hash.update("\n");
|
|
2745
|
-
}
|
|
2746
|
-
return hash.digest("hex");
|
|
2747
|
-
}
|
|
2748
|
-
async function getFingerprint(baseDir, entitiesDir, getEntityMutationVersion) {
|
|
2749
|
-
const [
|
|
2750
|
-
entityDirectoryFingerprint,
|
|
2751
|
-
entityEntriesFingerprint,
|
|
2752
|
-
aliasFingerprint,
|
|
2753
|
-
reconcileFingerprint,
|
|
2754
|
-
consumingFingerprint
|
|
2755
|
-
] = await Promise.all([
|
|
2756
|
-
fingerprintPath(entitiesDir),
|
|
2757
|
-
fingerprintEntityEntries(entitiesDir),
|
|
2758
|
-
fingerprintPath(path7.join(baseDir, "config", "aliases.json")),
|
|
2759
|
-
fingerprintPath(path7.join(baseDir, "state", ENTITY_CANONICAL_ID_RECONCILE_MARKER)),
|
|
2760
|
-
fingerprintPath(path7.join(baseDir, "state", ENTITY_CANONICAL_ID_RECONCILE_CONSUMING_MARKER))
|
|
2761
|
-
]);
|
|
2762
|
-
return [
|
|
2763
|
-
entityDirectoryFingerprint,
|
|
2764
|
-
entityEntriesFingerprint,
|
|
2765
|
-
aliasFingerprint,
|
|
2766
|
-
reconcileFingerprint,
|
|
2767
|
-
consumingFingerprint,
|
|
2768
|
-
getEntityMutationVersion()
|
|
2769
|
-
].join(":");
|
|
2770
|
-
}
|
|
2771
|
-
async function validateRoots(baseDir, entitiesDir, stateDir, archiveDir) {
|
|
2772
|
-
let baseStat;
|
|
2773
|
-
try {
|
|
2774
|
-
baseStat = await lstat3(baseDir);
|
|
2775
|
-
} catch (error) {
|
|
2776
|
-
if (isErrnoCode(error, "ENOENT")) return;
|
|
2777
|
-
throw error;
|
|
2778
|
-
}
|
|
2779
|
-
if (baseStat.isSymbolicLink() || !baseStat.isDirectory()) {
|
|
2780
|
-
throw new Error(`Refusing entity canonical-id migration through unsafe memory root: ${baseDir}.`);
|
|
2781
|
-
}
|
|
2782
|
-
const memoryRoot = await realpath3(baseDir);
|
|
2783
|
-
const roots = [
|
|
2784
|
-
entitiesDir,
|
|
2785
|
-
stateDir,
|
|
2786
|
-
...RECALL_FALLBACK_DIRS.map((directory) => path7.join(baseDir, directory)),
|
|
2787
|
-
path7.join(baseDir, "cold"),
|
|
2788
|
-
archiveDir
|
|
2789
|
-
];
|
|
2790
|
-
for (const root of roots) {
|
|
2791
|
-
let rootStat;
|
|
2792
|
-
try {
|
|
2793
|
-
rootStat = await lstat3(root);
|
|
2794
|
-
} catch (error) {
|
|
2795
|
-
if (isErrnoCode(error, "ENOENT")) continue;
|
|
2796
|
-
throw error;
|
|
2797
|
-
}
|
|
2798
|
-
if (rootStat.isSymbolicLink() || !rootStat.isDirectory()) {
|
|
2799
|
-
throw new Error(`Refusing entity canonical-id migration through unsafe memory root: ${root}.`);
|
|
2800
|
-
}
|
|
2801
|
-
assertPathInsideRoot(memoryRoot, await realpath3(root), root);
|
|
2802
|
-
}
|
|
2803
|
-
}
|
|
2804
|
-
function statePath(deps) {
|
|
2805
|
-
return path7.join(deps.stateDir, ENTITY_CANONICAL_ID_MIGRATION_FILE);
|
|
2806
|
-
}
|
|
2807
|
-
async function assertSafeMigrationStateFile(deps) {
|
|
2808
|
-
const migrationStatePath = statePath(deps);
|
|
2809
|
-
let fileStat;
|
|
2810
|
-
try {
|
|
2811
|
-
fileStat = await lstat3(migrationStatePath);
|
|
2812
|
-
} catch (error) {
|
|
2813
|
-
if (isErrnoCode(error, "ENOENT")) return;
|
|
2814
|
-
throw error;
|
|
2815
|
-
}
|
|
2816
|
-
if (fileStat.isSymbolicLink() || !fileStat.isFile()) {
|
|
2817
|
-
throw new Error(
|
|
2818
|
-
`Refusing entity canonical-id migration through unsafe migration state file: ${migrationStatePath}.`
|
|
2819
|
-
);
|
|
2820
|
-
}
|
|
2821
|
-
const [stateRoot, stateFile] = await Promise.all([
|
|
2822
|
-
realpath3(deps.stateDir),
|
|
2823
|
-
realpath3(migrationStatePath)
|
|
2824
|
-
]);
|
|
2825
|
-
assertPathInsideRoot(stateRoot, stateFile, migrationStatePath);
|
|
2826
|
-
}
|
|
2827
|
-
async function assertSafeTombstoneFile(deps, tombstonePath) {
|
|
2828
|
-
let fileStat;
|
|
2829
|
-
try {
|
|
2830
|
-
fileStat = await lstat3(tombstonePath);
|
|
2831
|
-
} catch (error) {
|
|
2832
|
-
if (isErrnoCode(error, "ENOENT")) return false;
|
|
2833
|
-
throw error;
|
|
2834
|
-
}
|
|
2835
|
-
if (fileStat.isSymbolicLink() || !fileStat.isFile()) {
|
|
2836
|
-
throw new Error(
|
|
2837
|
-
`Refusing entity canonical-id migration through unsafe tombstone ledger: ${tombstonePath}.`
|
|
2838
|
-
);
|
|
2839
|
-
}
|
|
2840
|
-
const [stateRoot, tombstoneFile] = await Promise.all([
|
|
2841
|
-
realpath3(deps.stateDir),
|
|
2842
|
-
realpath3(tombstonePath)
|
|
2843
|
-
]);
|
|
2844
|
-
assertPathInsideRoot(stateRoot, tombstoneFile, tombstonePath);
|
|
2845
|
-
return true;
|
|
2846
|
-
}
|
|
2847
|
-
function lockPath(deps) {
|
|
2848
|
-
return path7.join(deps.stateDir, "entity-canonical-id-migration.lock");
|
|
2849
|
-
}
|
|
2850
|
-
async function readState(deps) {
|
|
2851
|
-
await assertSafeMigrationStateFile(deps);
|
|
2852
|
-
let raw;
|
|
2853
|
-
try {
|
|
2854
|
-
raw = await readFile(statePath(deps), "utf-8");
|
|
2855
|
-
} catch (error) {
|
|
2856
|
-
if (isErrnoCode(error, "ENOENT")) return null;
|
|
2857
|
-
throw error;
|
|
2858
|
-
}
|
|
2859
|
-
let parsed;
|
|
2860
|
-
try {
|
|
2861
|
-
parsed = JSON.parse(raw);
|
|
2862
|
-
} catch {
|
|
2863
|
-
throw new Error("Invalid entity canonical-id migration state.");
|
|
2864
|
-
}
|
|
2865
|
-
const result = EntityCanonicalIdMigrationStateSchema.safeParse(parsed);
|
|
2866
|
-
if (!result.success) throw new Error("Invalid entity canonical-id migration state.");
|
|
2867
|
-
for (const mappings of [result.data.mappings, result.data.blocked ?? {}]) {
|
|
2868
|
-
for (const [legacyId, canonicalId] of Object.entries(mappings)) {
|
|
2869
|
-
assertSafeEntityId(legacyId);
|
|
2870
|
-
assertSafeEntityId(canonicalId);
|
|
2871
|
-
}
|
|
2872
|
-
}
|
|
2873
|
-
return result.data;
|
|
2874
|
-
}
|
|
2875
|
-
async function writeState(deps, state) {
|
|
2876
|
-
const destination = statePath(deps);
|
|
2877
|
-
const temporary = `${destination}.${process.pid}.${randomUUID()}.tmp`;
|
|
2878
|
-
try {
|
|
2879
|
-
await writeFile(temporary, `${JSON.stringify(state, null, 2)}
|
|
2880
|
-
`, "utf-8");
|
|
2881
|
-
await rename(temporary, destination);
|
|
2882
|
-
} finally {
|
|
2883
|
-
await unlink2(temporary).catch(() => void 0);
|
|
2884
|
-
}
|
|
2885
|
-
}
|
|
2886
|
-
async function publishState(deps, state) {
|
|
2887
|
-
await withEntityCanonicalMutationLock(deps.stateDir, async () => {
|
|
2888
|
-
await writeState(deps, state);
|
|
2889
|
-
});
|
|
2890
|
-
}
|
|
2891
|
-
async function fileExists(filePath) {
|
|
2892
|
-
try {
|
|
2893
|
-
await access(filePath);
|
|
2894
|
-
return true;
|
|
2895
|
-
} catch (error) {
|
|
2896
|
-
if (isErrnoCode(error, "ENOENT")) return false;
|
|
2897
|
-
throw error;
|
|
2898
|
-
}
|
|
2899
|
-
}
|
|
2900
|
-
async function sameFileIdentity(leftPath, rightPath) {
|
|
2901
|
-
try {
|
|
2902
|
-
const [left, right] = await Promise.all([statFile(leftPath), statFile(rightPath)]);
|
|
2903
|
-
return left.dev === right.dev && left.ino === right.ino;
|
|
2904
|
-
} catch (error) {
|
|
2905
|
-
if (isErrnoCode(error, "ENOENT")) return false;
|
|
2906
|
-
throw error;
|
|
2907
|
-
}
|
|
2908
|
-
}
|
|
2909
|
-
async function assertNotSymlink(filePath, label) {
|
|
2910
|
-
let stat4;
|
|
2911
|
-
try {
|
|
2912
|
-
stat4 = await lstat3(filePath);
|
|
2913
|
-
} catch (error) {
|
|
2914
|
-
if (isErrnoCode(error, "ENOENT")) return;
|
|
2915
|
-
throw error;
|
|
2916
|
-
}
|
|
2917
|
-
if (stat4.isSymbolicLink()) {
|
|
2918
|
-
throw new Error(`Refusing entity canonical-id migration through symlink: ${label}.`);
|
|
2919
|
-
}
|
|
2920
|
-
}
|
|
2921
|
-
async function assertNotMemorySymlink(filePath) {
|
|
2922
|
-
let stat4;
|
|
2923
|
-
try {
|
|
2924
|
-
stat4 = await lstat3(filePath);
|
|
2925
|
-
} catch (error) {
|
|
2926
|
-
if (isErrnoCode(error, "ENOENT")) return;
|
|
2927
|
-
throw error;
|
|
2928
|
-
}
|
|
2929
|
-
if (stat4.isSymbolicLink()) {
|
|
2930
|
-
throw new Error(`Refusing entity canonical-id migration through symlinked memory: ${filePath}.`);
|
|
2931
|
-
}
|
|
2932
|
-
}
|
|
2933
|
-
async function assertEntityContentUnchanged(deps, filePath, expectedContent, legacyId) {
|
|
2934
|
-
const latestContent = await deps.readStorageSecureFile(filePath);
|
|
2935
|
-
if (latestContent !== expectedContent) {
|
|
2936
|
-
throw new Error(`Legacy entity id ${legacyId} changed while migration was running; retry migration.`);
|
|
2937
|
-
}
|
|
2938
|
-
}
|
|
2939
|
-
async function readSafeEntityEntries(entitiesDir) {
|
|
2940
|
-
const rootStat = await lstat3(entitiesDir);
|
|
2941
|
-
if (rootStat.isSymbolicLink() || !rootStat.isDirectory()) {
|
|
2942
|
-
throw new Error("Refusing entity canonical-id migration through a symlinked or non-directory entities root.");
|
|
2943
|
-
}
|
|
2944
|
-
const entries = await readdir4(entitiesDir);
|
|
2945
|
-
for (const entry of entries) {
|
|
2946
|
-
await assertNotSymlink(path7.join(entitiesDir, entry), entry);
|
|
2947
|
-
}
|
|
2948
|
-
return entries;
|
|
2949
|
-
}
|
|
2950
|
-
async function discoverMappings(deps, knownMappings = {}, blocked = /* @__PURE__ */ new Map(), scanNotes) {
|
|
2951
|
-
const mappings = {};
|
|
2952
|
-
const canonicalOwners = /* @__PURE__ */ new Map();
|
|
2953
|
-
blocked.clear();
|
|
2954
|
-
const entityEntries = await readSafeEntityEntries(deps.entitiesDir);
|
|
2955
|
-
for (const entry of entityEntries) {
|
|
2956
|
-
if (isMacOsReplicationJunkBasename(entry)) {
|
|
2957
|
-
scanNotes?.junk.add(entry);
|
|
2958
|
-
continue;
|
|
2959
|
-
}
|
|
2960
|
-
if (!entry.endsWith(".md")) continue;
|
|
2961
|
-
const legacyId = entry.slice(0, -".md".length);
|
|
2962
|
-
assertSafeEntityId(legacyId);
|
|
2963
|
-
const legacyPath = deps.resolveEntityFilePath(legacyId);
|
|
2964
|
-
if (legacyPath === null) continue;
|
|
2965
|
-
const entityContent = await deps.readStorageSecureFile(legacyPath);
|
|
2966
|
-
if (isMalformedEntityRecord(entityContent)) {
|
|
2967
|
-
scanNotes?.malformed.add(entry);
|
|
2968
|
-
continue;
|
|
2969
|
-
}
|
|
2970
|
-
const entity = deps.parseEntityFile(entityContent);
|
|
2971
|
-
if (!entity.name.trim() || !entity.type.trim()) {
|
|
2972
|
-
scanNotes?.malformed.add(entry);
|
|
2973
|
-
continue;
|
|
2974
|
-
}
|
|
2975
|
-
const canonicalId = deps.normalizeEntityName(entity.name, entity.type);
|
|
2976
|
-
assertSafeEntityId(canonicalId);
|
|
2977
|
-
if (legacyId === canonicalId) continue;
|
|
2978
|
-
const canonicalPath = deps.resolveEntityFilePath(canonicalId);
|
|
2979
|
-
if (canonicalPath === null) continue;
|
|
2980
|
-
const canonicalExists = await fileExists(canonicalPath);
|
|
2981
|
-
if (canonicalExists && await sameFileIdentity(legacyPath, canonicalPath) && knownMappings[legacyId] === canonicalId) continue;
|
|
2982
|
-
if (canonicalExists) {
|
|
2983
|
-
const canonicalContent2 = await deps.readStorageSecureFile(canonicalPath);
|
|
2984
|
-
if (entityContent !== canonicalContent2) {
|
|
2985
|
-
blocked.set(legacyId, canonicalId);
|
|
2986
|
-
continue;
|
|
2987
|
-
}
|
|
2988
|
-
}
|
|
2989
|
-
canonicalOwners.set(canonicalId, [...canonicalOwners.get(canonicalId) ?? [], legacyId]);
|
|
2990
|
-
mappings[legacyId] = canonicalId;
|
|
2991
|
-
}
|
|
2992
|
-
for (const [canonicalId, claimants] of canonicalOwners) {
|
|
2993
|
-
if (claimants.length < 2) continue;
|
|
2994
|
-
for (const legacyId of claimants) {
|
|
2995
|
-
blocked.set(legacyId, canonicalId);
|
|
2996
|
-
delete mappings[legacyId];
|
|
2997
|
-
}
|
|
2998
|
-
}
|
|
2999
|
-
return mappings;
|
|
3000
|
-
}
|
|
3001
|
-
async function rewriteReferences(deps, mappings, refreshLock) {
|
|
3002
|
-
let rewroteColdMemory = false;
|
|
3003
|
-
for (let pass = 0; pass < MEMORY_REWRITE_MAX_PASSES; pass += 1) {
|
|
3004
|
-
deps.invalidateAllMemoriesCache();
|
|
3005
|
-
deps.invalidateColdMemoriesCache();
|
|
3006
|
-
const [hotMemories, coldMemories, archivedMemories] = await Promise.all([
|
|
3007
|
-
deps.readAllMemories(),
|
|
3008
|
-
deps.readAllColdMemories(),
|
|
3009
|
-
deps.readArchivedMemories()
|
|
3010
|
-
]);
|
|
3011
|
-
const seenPaths = /* @__PURE__ */ new Set();
|
|
3012
|
-
let rewroteAny = false;
|
|
3013
|
-
for (const memory of [...hotMemories, ...coldMemories, ...archivedMemories]) {
|
|
3014
|
-
const memoryPath = path7.resolve(memory.path);
|
|
3015
|
-
if (seenPaths.has(memoryPath)) continue;
|
|
3016
|
-
seenPaths.add(memoryPath);
|
|
3017
|
-
const previousEntityRef = memory.frontmatter.entityRef;
|
|
3018
|
-
const canonicalId = previousEntityRef ? mappings[previousEntityRef] : void 0;
|
|
3019
|
-
if (!previousEntityRef || !canonicalId) continue;
|
|
3020
|
-
await assertNotMemorySymlink(memory.path);
|
|
3021
|
-
const observedMemoryFingerprint = await fingerprintPath(memory.path);
|
|
3022
|
-
if (observedMemoryFingerprint === "missing") continue;
|
|
3023
|
-
if (!await refreshLock()) throw new Error("Lost entity canonical-id migration lock.");
|
|
3024
|
-
const latestMemory = await deps.readMemoryByPath(memory.path);
|
|
3025
|
-
if (!latestMemory) continue;
|
|
3026
|
-
const latestMemoryFingerprint = await fingerprintPath(latestMemory.path);
|
|
3027
|
-
if (latestMemoryFingerprint !== observedMemoryFingerprint) continue;
|
|
3028
|
-
const latestPreviousEntityRef = latestMemory.frontmatter.entityRef;
|
|
3029
|
-
const latestCanonicalId = latestPreviousEntityRef ? mappings[latestPreviousEntityRef] : void 0;
|
|
3030
|
-
if (!latestPreviousEntityRef || !latestCanonicalId) continue;
|
|
3031
|
-
const memoryEncrypted = await deps.isEncryptedStorageFile(latestMemory.path);
|
|
3032
|
-
if (await fingerprintPath(latestMemory.path) !== latestMemoryFingerprint) continue;
|
|
3033
|
-
await deps.snapshotBeforeWrite(latestMemory.path, "write");
|
|
3034
|
-
if (await fingerprintPath(latestMemory.path) !== latestMemoryFingerprint) continue;
|
|
3035
|
-
await deps.writeStorageSecureFile(
|
|
3036
|
-
latestMemory.path,
|
|
3037
|
-
deps.serializeMemoryWithEntityRef(latestMemory, latestCanonicalId),
|
|
3038
|
-
memoryEncrypted
|
|
3039
|
-
);
|
|
3040
|
-
await deps.rewriteProjectedMemoryEntityReference(
|
|
3041
|
-
latestMemory.frontmatter.id,
|
|
3042
|
-
latestPreviousEntityRef,
|
|
3043
|
-
latestCanonicalId
|
|
3044
|
-
);
|
|
3045
|
-
rewroteAny = true;
|
|
3046
|
-
rewroteColdMemory ||= latestMemory.path.includes(`${path7.sep}cold${path7.sep}`);
|
|
3047
|
-
}
|
|
3048
|
-
if (!rewroteAny) return { rewroteColdMemory };
|
|
3049
|
-
}
|
|
3050
|
-
throw new Error("Memory references changed while entity canonical-id migration was running; retry migration.");
|
|
3051
|
-
}
|
|
3052
|
-
function rewriteTombstoneLine(line, mappings, normalizedMappings) {
|
|
3053
|
-
let parsed;
|
|
3054
|
-
try {
|
|
3055
|
-
parsed = JSON.parse(line);
|
|
3056
|
-
} catch {
|
|
3057
|
-
return line;
|
|
3058
|
-
}
|
|
3059
|
-
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return line;
|
|
3060
|
-
const tombstone = parsed;
|
|
3061
|
-
let changed = false;
|
|
3062
|
-
if (typeof tombstone.entityRef === "string") {
|
|
3063
|
-
const canonicalId = mappings[tombstone.entityRef];
|
|
3064
|
-
if (canonicalId) {
|
|
3065
|
-
tombstone.entityRef = canonicalId;
|
|
3066
|
-
changed = true;
|
|
3067
|
-
}
|
|
3068
|
-
}
|
|
3069
|
-
if (typeof tombstone.supersessionKey === "string") {
|
|
3070
|
-
const separator = tombstone.supersessionKey.indexOf("::");
|
|
3071
|
-
if (separator < 0) return changed ? JSON.stringify(tombstone) : line;
|
|
3072
|
-
const normalizedLegacyId = normalizeSupersessionKey(tombstone.supersessionKey.slice(0, separator));
|
|
3073
|
-
const canonicalId = normalizedMappings.get(normalizedLegacyId);
|
|
3074
|
-
if (canonicalId) {
|
|
3075
|
-
const canonicalKey = computeSupersessionKey(canonicalId, tombstone.supersessionKey.slice(separator + 2));
|
|
3076
|
-
if (canonicalKey) {
|
|
3077
|
-
tombstone.supersessionKey = canonicalKey;
|
|
3078
|
-
changed = true;
|
|
3079
|
-
}
|
|
3080
|
-
}
|
|
3081
|
-
}
|
|
3082
|
-
return changed ? JSON.stringify(tombstone) : line;
|
|
3083
|
-
}
|
|
3084
|
-
async function rewriteTombstoneReferences(deps, mappings, refreshLock) {
|
|
3085
|
-
const tombstonePath = path7.join(deps.stateDir, "tombstones.jsonl");
|
|
3086
|
-
const normalizedMappings = /* @__PURE__ */ new Map();
|
|
3087
|
-
for (const [legacyId, canonicalId] of Object.entries(mappings)) {
|
|
3088
|
-
const normalizedLegacyId = normalizeSupersessionKey(legacyId);
|
|
3089
|
-
if (normalizedLegacyId && !normalizedMappings.has(normalizedLegacyId)) {
|
|
3090
|
-
normalizedMappings.set(normalizedLegacyId, canonicalId);
|
|
3091
|
-
}
|
|
3092
|
-
}
|
|
3093
|
-
await withHeldFileLock(
|
|
3094
|
-
path7.join(deps.stateDir, "tombstones.lock"),
|
|
3095
|
-
{
|
|
3096
|
-
staleMs: TOMBSTONE_LOCK_STALE_MS,
|
|
3097
|
-
maxWaitMs: TOMBSTONE_LOCK_MAX_WAIT_MS
|
|
3098
|
-
},
|
|
3099
|
-
async (acquired, tombstoneLock) => {
|
|
3100
|
-
if (!acquired) throw new Error("Timed out waiting for active tombstone migration.");
|
|
3101
|
-
if (!await assertSafeTombstoneFile(deps, tombstonePath)) return;
|
|
3102
|
-
const tombstoneEncrypted = await deps.isEncryptedStorageFile(tombstonePath);
|
|
3103
|
-
const original = await deps.readStorageSecureFile(tombstonePath);
|
|
3104
|
-
let changed = false;
|
|
3105
|
-
const rewritten = original.split("\n").map((line) => {
|
|
3106
|
-
const next = rewriteTombstoneLine(line, mappings, normalizedMappings);
|
|
3107
|
-
changed ||= next !== line;
|
|
3108
|
-
return next;
|
|
3109
|
-
}).join("\n");
|
|
3110
|
-
if (!changed) return;
|
|
3111
|
-
if (!await refreshLock()) throw new Error("Lost entity canonical-id migration lock.");
|
|
3112
|
-
if (!await tombstoneLock.refresh()) throw new Error("Lost tombstone migration lock.");
|
|
3113
|
-
await deps.snapshotBeforeWrite(tombstonePath, "write");
|
|
3114
|
-
await deps.writeStorageSecureFile(tombstonePath, rewritten, tombstoneEncrypted);
|
|
3115
|
-
}
|
|
3116
|
-
);
|
|
3117
|
-
}
|
|
3118
|
-
async function rewriteRelationshipTargets(deps, mappings, refreshLock) {
|
|
3119
|
-
let rewritten = false;
|
|
3120
|
-
const entries = await readSafeEntityEntries(deps.entitiesDir);
|
|
3121
|
-
for (const entry of entries) {
|
|
3122
|
-
if (!entry.endsWith(".md") || isMacOsReplicationJunkBasename(entry)) continue;
|
|
3123
|
-
const entityPath = deps.resolveEntityFilePath(entry.slice(0, -".md".length));
|
|
3124
|
-
if (entityPath === null) continue;
|
|
3125
|
-
const observedEntityFingerprint = await fingerprintPath(entityPath);
|
|
3126
|
-
if (observedEntityFingerprint === "missing") continue;
|
|
3127
|
-
const entityRaw = await deps.readStorageSecureFile(entityPath);
|
|
3128
|
-
if (isMalformedEntityRecord(entityRaw)) continue;
|
|
3129
|
-
const entity = deps.parseEntityFile(entityRaw);
|
|
3130
|
-
const relationships = entity.relationships.map((relationship) => {
|
|
3131
|
-
const target = mappings[relationship.target];
|
|
3132
|
-
return target ? { ...relationship, target } : relationship;
|
|
3133
|
-
});
|
|
3134
|
-
if (relationships.every((relationship, index) => relationship === entity.relationships[index])) continue;
|
|
3135
|
-
const rewroteEntity = await withEntityCanonicalMutationLock(
|
|
3136
|
-
deps.stateDir,
|
|
3137
|
-
async (refreshEntityLock) => {
|
|
3138
|
-
if (!await refreshLock()) throw new Error("Lost entity canonical-id migration lock.");
|
|
3139
|
-
const latestRaw = await deps.readStorageSecureFile(entityPath);
|
|
3140
|
-
if (isMalformedEntityRecord(latestRaw)) return false;
|
|
3141
|
-
const latestEntity = deps.parseEntityFile(latestRaw);
|
|
3142
|
-
if (await fingerprintPath(entityPath) !== observedEntityFingerprint) return false;
|
|
3143
|
-
const latestRelationships = latestEntity.relationships.map((relationship) => {
|
|
3144
|
-
const target = mappings[relationship.target];
|
|
3145
|
-
return target ? { ...relationship, target } : relationship;
|
|
3146
|
-
});
|
|
3147
|
-
if (latestRelationships.every((relationship, index) => relationship === latestEntity.relationships[index])) {
|
|
3148
|
-
return false;
|
|
3149
|
-
}
|
|
3150
|
-
const entityEncrypted = await deps.isEncryptedStorageFile(entityPath);
|
|
3151
|
-
if (!await refreshEntityLock()) throw new Error("Lost entity mutation lock.");
|
|
3152
|
-
if (await fingerprintPath(entityPath) !== observedEntityFingerprint) return false;
|
|
3153
|
-
await deps.snapshotBeforeWrite(entityPath, "write");
|
|
3154
|
-
if (await fingerprintPath(entityPath) !== observedEntityFingerprint) return false;
|
|
3155
|
-
await deps.writeStorageSecureFile(
|
|
3156
|
-
entityPath,
|
|
3157
|
-
deps.serializeEntityFile({ ...latestEntity, relationships: latestRelationships }),
|
|
3158
|
-
entityEncrypted
|
|
3159
|
-
);
|
|
3160
|
-
return true;
|
|
3161
|
-
}
|
|
3162
|
-
);
|
|
3163
|
-
rewritten ||= rewroteEntity;
|
|
3164
|
-
}
|
|
3165
|
-
return rewritten;
|
|
3166
|
-
}
|
|
3167
|
-
async function rewriteKnownReferences(deps, mappings, refreshLock) {
|
|
3168
|
-
await rewriteRelationshipTargets(deps, mappings, refreshLock);
|
|
3169
|
-
let rewroteColdMemory = (await rewriteReferences(deps, mappings, refreshLock)).rewroteColdMemory;
|
|
3170
|
-
await rewriteTombstoneReferences(deps, mappings, refreshLock);
|
|
3171
|
-
await deps.rewriteProjectedEntityReferences(mappings);
|
|
3172
|
-
const finalMemoryPass = await rewriteReferences(deps, mappings, refreshLock);
|
|
3173
|
-
rewroteColdMemory ||= finalMemoryPass.rewroteColdMemory;
|
|
3174
|
-
return rewroteColdMemory;
|
|
3175
|
-
}
|
|
3176
|
-
function wouldCreateMappingCycle(mappings, legacyId, canonicalId) {
|
|
3177
|
-
let current = canonicalId;
|
|
3178
|
-
const seen = /* @__PURE__ */ new Set();
|
|
3179
|
-
while (true) {
|
|
3180
|
-
if (current === legacyId) return true;
|
|
3181
|
-
if (seen.has(current)) return false;
|
|
3182
|
-
seen.add(current);
|
|
3183
|
-
const next = mappings[current];
|
|
3184
|
-
if (!next || next === current) return false;
|
|
3185
|
-
current = next;
|
|
3186
|
-
}
|
|
3187
|
-
}
|
|
3188
|
-
function rejectMappingCycles(existing, discovered) {
|
|
3189
|
-
const accepted = {};
|
|
3190
|
-
const merged = { ...existing };
|
|
3191
|
-
for (const [legacyId, canonicalId] of Object.entries(discovered)) {
|
|
3192
|
-
if (merged[legacyId] === void 0 && wouldCreateMappingCycle(merged, legacyId, canonicalId)) continue;
|
|
3193
|
-
accepted[legacyId] = canonicalId;
|
|
3194
|
-
merged[legacyId] = canonicalId;
|
|
3195
|
-
}
|
|
3196
|
-
return accepted;
|
|
3197
|
-
}
|
|
3198
|
-
function mergeDiscoveredMappings(existing, discovered) {
|
|
3199
|
-
const merged = { ...existing };
|
|
3200
|
-
const canonicalOwners = /* @__PURE__ */ new Map();
|
|
3201
|
-
for (const [legacyId, canonicalId] of Object.entries(discovered)) {
|
|
3202
|
-
const previousMapping = merged[legacyId];
|
|
3203
|
-
if (previousMapping !== void 0 && previousMapping !== canonicalId) {
|
|
3204
|
-
continue;
|
|
3205
|
-
}
|
|
3206
|
-
if (previousMapping === void 0 && wouldCreateMappingCycle(merged, legacyId, canonicalId)) continue;
|
|
3207
|
-
const previousOwner = canonicalOwners.get(canonicalId);
|
|
3208
|
-
if (previousOwner !== void 0 && previousOwner !== legacyId) {
|
|
3209
|
-
throw new Error(
|
|
3210
|
-
`Cannot migrate legacy entity ids ${previousOwner} and ${legacyId}: both normalize to ${canonicalId}.`
|
|
3211
|
-
);
|
|
3212
|
-
}
|
|
3213
|
-
merged[legacyId] = canonicalId;
|
|
3214
|
-
canonicalOwners.set(canonicalId, legacyId);
|
|
3215
|
-
}
|
|
3216
|
-
return merged;
|
|
3217
|
-
}
|
|
3218
|
-
function collapseMappings(mappings) {
|
|
3219
|
-
const collapsed = {};
|
|
3220
|
-
for (const legacyId of Object.keys(mappings)) {
|
|
3221
|
-
let current = legacyId;
|
|
3222
|
-
const seen = /* @__PURE__ */ new Set();
|
|
3223
|
-
while (true) {
|
|
3224
|
-
const next = mappings[current];
|
|
3225
|
-
if (!next || next === current) break;
|
|
3226
|
-
if (seen.has(current)) {
|
|
3227
|
-
throw new Error(`Entity canonical-id migration mapping cycle includes ${legacyId}.`);
|
|
3228
|
-
}
|
|
3229
|
-
seen.add(current);
|
|
3230
|
-
current = next;
|
|
3231
|
-
}
|
|
3232
|
-
if (current !== legacyId) collapsed[legacyId] = current;
|
|
3233
|
-
}
|
|
3234
|
-
return collapsed;
|
|
3235
|
-
}
|
|
3236
|
-
async function migrateEntityFilePair(deps, legacyId, canonicalId, refreshMigrationLock) {
|
|
3237
|
-
return withEntityCanonicalMutationLock(deps.stateDir, async (refreshEntityLock) => {
|
|
3238
|
-
assertSafeEntityId(legacyId);
|
|
3239
|
-
assertSafeEntityId(canonicalId);
|
|
3240
|
-
const legacyPath = deps.resolveEntityFilePath(legacyId);
|
|
3241
|
-
const canonicalPath = deps.resolveEntityFilePath(canonicalId);
|
|
3242
|
-
if (legacyPath === null || canonicalPath === null) {
|
|
3243
|
-
throw new Error("Invalid entity canonical-id migration path.");
|
|
3244
|
-
}
|
|
3245
|
-
await assertNotSymlink(legacyPath, legacyId);
|
|
3246
|
-
await assertNotSymlink(canonicalPath, canonicalId);
|
|
3247
|
-
const legacyExists = await fileExists(legacyPath);
|
|
3248
|
-
const canonicalExists = await fileExists(canonicalPath);
|
|
3249
|
-
if (!legacyExists && !canonicalExists) return { deferred: true, progressed: false };
|
|
3250
|
-
if (legacyExists && canonicalExists) {
|
|
3251
|
-
if (await sameFileIdentity(legacyPath, canonicalPath)) return { deferred: false, progressed: false };
|
|
3252
|
-
const [legacyContent, canonicalContent2, legacyEncrypted, canonicalEncrypted] = await Promise.all([
|
|
3253
|
-
deps.readStorageSecureFile(legacyPath),
|
|
3254
|
-
deps.readStorageSecureFile(canonicalPath),
|
|
3255
|
-
deps.isEncryptedStorageFile(legacyPath),
|
|
3256
|
-
deps.isEncryptedStorageFile(canonicalPath)
|
|
3257
|
-
]);
|
|
3258
|
-
if (legacyContent !== canonicalContent2) {
|
|
3259
|
-
return { deferred: false, progressed: false, blocked: true };
|
|
3260
|
-
}
|
|
3261
|
-
if (legacyEncrypted && !canonicalEncrypted) {
|
|
3262
|
-
if (!await refreshMigrationLock() || !await refreshEntityLock()) {
|
|
3263
|
-
throw new Error("Lost entity canonical-id migration lock.");
|
|
3264
|
-
}
|
|
3265
|
-
await deps.snapshotBeforeWrite(canonicalPath, "write");
|
|
3266
|
-
await deps.writeStorageSecureFile(canonicalPath, legacyContent, true);
|
|
3267
|
-
if (await deps.readStorageSecureFile(canonicalPath) !== legacyContent) {
|
|
3268
|
-
throw new Error(`Cannot verify migrated entity id ${canonicalId}.`);
|
|
3269
|
-
}
|
|
3270
|
-
}
|
|
3271
|
-
if (!await refreshMigrationLock() || !await refreshEntityLock()) {
|
|
3272
|
-
throw new Error("Lost entity canonical-id migration lock.");
|
|
3273
|
-
}
|
|
3274
|
-
await deps.snapshotBeforeWrite(legacyPath, "write");
|
|
3275
|
-
await assertNotSymlink(legacyPath, legacyId);
|
|
3276
|
-
await assertEntityContentUnchanged(deps, legacyPath, legacyContent, legacyId);
|
|
3277
|
-
await unlink2(legacyPath);
|
|
3278
|
-
return { deferred: false, progressed: true };
|
|
3279
|
-
}
|
|
3280
|
-
if (!legacyExists) return { deferred: false, progressed: false };
|
|
3281
|
-
if (!await refreshMigrationLock() || !await refreshEntityLock()) {
|
|
3282
|
-
throw new Error("Lost entity canonical-id migration lock.");
|
|
3283
|
-
}
|
|
3284
|
-
const entityEncrypted = await deps.isEncryptedStorageFile(legacyPath);
|
|
3285
|
-
const entityContent = await deps.readStorageSecureFile(legacyPath);
|
|
3286
|
-
await assertNotSymlink(legacyPath, legacyId);
|
|
3287
|
-
await assertEntityContentUnchanged(deps, legacyPath, entityContent, legacyId);
|
|
3288
|
-
if (isMacOsReplicationJunkBasename(path7.basename(legacyPath)) || isMalformedEntityRecord(entityContent)) {
|
|
3289
|
-
return { deferred: false, progressed: false };
|
|
3290
|
-
}
|
|
3291
|
-
let canonicalFingerprintAfterWrite = null;
|
|
3292
|
-
try {
|
|
3293
|
-
await deps.writeStorageSecureFile(canonicalPath, entityContent, entityEncrypted);
|
|
3294
|
-
canonicalFingerprintAfterWrite = await fingerprintPath(canonicalPath);
|
|
3295
|
-
if (await deps.readStorageSecureFile(canonicalPath) !== entityContent) {
|
|
3296
|
-
throw new Error(`Cannot verify migrated entity id ${canonicalId}.`);
|
|
3297
|
-
}
|
|
3298
|
-
if (!await refreshMigrationLock() || !await refreshEntityLock()) {
|
|
3299
|
-
throw new Error("Lost entity canonical-id migration lock.");
|
|
3300
|
-
}
|
|
3301
|
-
await deps.snapshotBeforeWrite(legacyPath, "write");
|
|
3302
|
-
await assertNotSymlink(legacyPath, legacyId);
|
|
3303
|
-
await assertEntityContentUnchanged(deps, legacyPath, entityContent, legacyId);
|
|
3304
|
-
await unlink2(legacyPath);
|
|
3305
|
-
} catch (error) {
|
|
3306
|
-
if (!canonicalExists && canonicalFingerprintAfterWrite !== null) {
|
|
3307
|
-
try {
|
|
3308
|
-
if (await fingerprintPath(canonicalPath) === canonicalFingerprintAfterWrite) {
|
|
3309
|
-
await assertNotSymlink(canonicalPath, canonicalId);
|
|
3310
|
-
await unlink2(canonicalPath);
|
|
3311
|
-
}
|
|
3312
|
-
} catch {
|
|
3313
|
-
}
|
|
3314
|
-
}
|
|
3315
|
-
throw error;
|
|
3316
|
-
}
|
|
3317
|
-
return { deferred: false, progressed: true };
|
|
3318
|
-
});
|
|
3319
|
-
}
|
|
3320
|
-
async function migrateLegacyEntityCanonicalIds(deps) {
|
|
3321
|
-
return withHeldFileLock(
|
|
3322
|
-
lockPath(deps),
|
|
3323
|
-
{
|
|
3324
|
-
staleMs: ENTITY_CANONICAL_ID_MIGRATION_LOCK_STALE_MS,
|
|
3325
|
-
maxWaitMs: ENTITY_CANONICAL_ID_MIGRATION_LOCK_MAX_WAIT_MS
|
|
3326
|
-
},
|
|
3327
|
-
async (acquired, lock) => {
|
|
3328
|
-
if (!acquired) throw new Error("Timed out waiting for active entity canonical-id migration.");
|
|
3329
|
-
await deps.validateMemoryScanRoots?.();
|
|
3330
|
-
await readSafeEntityEntries(deps.entitiesDir);
|
|
3331
|
-
const reconcileMarkerPath = path7.join(deps.stateDir, ENTITY_CANONICAL_ID_RECONCILE_MARKER);
|
|
3332
|
-
const consumingMarkerPath = path7.join(deps.stateDir, ENTITY_CANONICAL_ID_RECONCILE_CONSUMING_MARKER);
|
|
3333
|
-
let reconcileRequested = await fileExists(consumingMarkerPath);
|
|
3334
|
-
if (await fileExists(reconcileMarkerPath)) {
|
|
3335
|
-
try {
|
|
3336
|
-
await rename(reconcileMarkerPath, consumingMarkerPath);
|
|
3337
|
-
reconcileRequested = true;
|
|
3338
|
-
} catch (error) {
|
|
3339
|
-
if (!isErrnoCode(error, "ENOENT")) throw error;
|
|
3340
|
-
}
|
|
3341
|
-
}
|
|
3342
|
-
let state = await readState(deps);
|
|
3343
|
-
if (!state) {
|
|
3344
|
-
state = {
|
|
3345
|
-
version: ENTITY_CANONICAL_ID_MIGRATION_VERSION,
|
|
3346
|
-
complete: false,
|
|
3347
|
-
mappings: {}
|
|
3348
|
-
};
|
|
3349
|
-
}
|
|
3350
|
-
const blocked = /* @__PURE__ */ new Map();
|
|
3351
|
-
const scanNotes = { junk: /* @__PURE__ */ new Set(), malformed: /* @__PURE__ */ new Set() };
|
|
3352
|
-
const staleParked = /* @__PURE__ */ new Map();
|
|
3353
|
-
const finish = async () => {
|
|
3354
|
-
if (blocked.size > 0) {
|
|
3355
|
-
const pairs = [...blocked].map(([legacyId, canonicalId]) => `${legacyId} -> ${canonicalId}`).join(", ");
|
|
3356
|
-
log.warn(
|
|
3357
|
-
`entity canonical-id migration skipped ${blocked.size} unresolvable pair(s): ${pairs}. Both files were kept and the legacy id still resolves; merge or delete one side to migrate it.`
|
|
3358
|
-
);
|
|
3359
|
-
}
|
|
3360
|
-
if (staleParked.size > 0) {
|
|
3361
|
-
const pairs = [...staleParked].map(([legacyId, canonicalId]) => `${legacyId} -> ${canonicalId}`).join(", ");
|
|
3362
|
-
log.warn(
|
|
3363
|
-
`entity canonical-id migration dropped ${staleParked.size} mapping(s) whose entity files are gone: ${pairs}. The stale journal entries were removed; references to those legacy ids do not resolve either way.`
|
|
3364
|
-
);
|
|
3365
|
-
}
|
|
3366
|
-
warnIgnoredMacOsReplicationJunk(deps.entitiesDir, scanNotes.junk.size, (message) => {
|
|
3367
|
-
log.warn(`entity canonical-id migration ${message}`);
|
|
3368
|
-
});
|
|
3369
|
-
if (scanNotes.malformed.size > 0) {
|
|
3370
|
-
const names = [...scanNotes.malformed].sort().join(", ");
|
|
3371
|
-
log.warn(
|
|
3372
|
-
`entity canonical-id migration skipped ${scanNotes.malformed.size} malformed entity file(s): ${names}. Each file was left in place; startup continues. Fix or remove the file to migrate it.`
|
|
3373
|
-
);
|
|
3374
|
-
}
|
|
3375
|
-
if (reconcileRequested) {
|
|
3376
|
-
await unlink2(consumingMarkerPath).catch((error) => {
|
|
3377
|
-
if (!isErrnoCode(error, "ENOENT")) throw error;
|
|
3378
|
-
});
|
|
3379
|
-
}
|
|
3380
|
-
const completionFingerprint = await deps.readMigrationFingerprint?.();
|
|
3381
|
-
if (await fileExists(reconcileMarkerPath)) return void 0;
|
|
3382
|
-
return completionFingerprint;
|
|
3383
|
-
};
|
|
3384
|
-
const pruneBlocked = async () => {
|
|
3385
|
-
const current = state;
|
|
3386
|
-
if (!current) return false;
|
|
3387
|
-
let revived = false;
|
|
3388
|
-
const parked = { ...current.blocked ?? {} };
|
|
3389
|
-
const active = {};
|
|
3390
|
-
for (const [legacyId, canonicalId] of Object.entries(current.mappings)) {
|
|
3391
|
-
if (!blocked.has(legacyId)) active[legacyId] = canonicalId;
|
|
3392
|
-
}
|
|
3393
|
-
for (const [legacyId, canonicalId] of blocked) parked[legacyId] = canonicalId;
|
|
3394
|
-
for (const [legacyId, canonicalId] of Object.entries(parked)) {
|
|
3395
|
-
if (blocked.has(legacyId)) continue;
|
|
3396
|
-
delete parked[legacyId];
|
|
3397
|
-
if (active[legacyId] !== void 0) continue;
|
|
3398
|
-
const legacyPath = deps.resolveEntityFilePath(legacyId);
|
|
3399
|
-
if (legacyPath !== null && await fileExists(legacyPath)) continue;
|
|
3400
|
-
let target = canonicalId;
|
|
3401
|
-
const seenTargets = /* @__PURE__ */ new Set();
|
|
3402
|
-
while (active[target] !== void 0 && !seenTargets.has(target)) {
|
|
3403
|
-
seenTargets.add(target);
|
|
3404
|
-
target = active[target];
|
|
3405
|
-
}
|
|
3406
|
-
const targetPath = deps.resolveEntityFilePath(target);
|
|
3407
|
-
if (targetPath === null || !await fileExists(targetPath)) {
|
|
3408
|
-
staleParked.set(legacyId, canonicalId);
|
|
3409
|
-
continue;
|
|
3410
|
-
}
|
|
3411
|
-
active[legacyId] = target;
|
|
3412
|
-
revived = true;
|
|
3413
|
-
}
|
|
3414
|
-
const collapsed = collapseMappings(active);
|
|
3415
|
-
for (const [legacyId, canonicalId] of Object.entries(parked)) {
|
|
3416
|
-
const moved = collapsed[canonicalId];
|
|
3417
|
-
if (moved !== void 0 && moved !== legacyId) parked[legacyId] = moved;
|
|
3418
|
-
}
|
|
3419
|
-
const same = (a, b) => Object.keys(a).length === Object.keys(b).length && Object.entries(a).every(([key, value]) => b[key] === value);
|
|
3420
|
-
if (same(collapsed, current.mappings) && same(parked, current.blocked ?? {})) return revived;
|
|
3421
|
-
state = { ...current, mappings: collapsed, blocked: parked };
|
|
3422
|
-
await publishState(deps, state);
|
|
3423
|
-
return revived;
|
|
3424
|
-
};
|
|
3425
|
-
const previousMappings = state.mappings;
|
|
3426
|
-
const collapsedMappings = collapseMappings(previousMappings);
|
|
3427
|
-
const mappingsChanged = Object.keys(collapsedMappings).length !== Object.keys(previousMappings).length || Object.entries(collapsedMappings).some(
|
|
3428
|
-
([legacyId, canonicalId]) => previousMappings[legacyId] !== canonicalId
|
|
3429
|
-
);
|
|
3430
|
-
state = { ...state, mappings: collapsedMappings };
|
|
3431
|
-
for (let migrationPass = 0; migrationPass < ENTITY_MAPPING_RESCAN_MAX_PASSES; migrationPass += 1) {
|
|
3432
|
-
if (!await lock.refresh()) throw new Error("Lost entity canonical-id migration lock.");
|
|
3433
|
-
const discoveredBefore = rejectMappingCycles(
|
|
3434
|
-
state.mappings,
|
|
3435
|
-
await discoverMappings(deps, state.mappings, blocked, scanNotes)
|
|
3436
|
-
);
|
|
3437
|
-
const revivedBefore = await pruneBlocked();
|
|
3438
|
-
const mergedBefore = collapseMappings(mergeDiscoveredMappings(state.mappings, discoveredBefore));
|
|
3439
|
-
if (state.complete && Object.keys(discoveredBefore).length === 0 && !mappingsChanged && !revivedBefore) {
|
|
3440
|
-
if (reconcileRequested && Object.keys(state.mappings).length > 0) {
|
|
3441
|
-
const rewroteColdMemory2 = await rewriteKnownReferences(
|
|
3442
|
-
deps,
|
|
3443
|
-
state.mappings,
|
|
3444
|
-
() => lock.refresh()
|
|
3445
|
-
);
|
|
3446
|
-
deps.invalidateKnowledgeIndexCache();
|
|
3447
|
-
deps.invalidateAllMemoriesCache();
|
|
3448
|
-
if (rewroteColdMemory2) deps.invalidateColdMemoriesCache();
|
|
3449
|
-
deps.bumpMemoryStatusVersion();
|
|
3450
|
-
}
|
|
3451
|
-
return finish();
|
|
3452
|
-
}
|
|
3453
|
-
if (state.complete || Object.keys(discoveredBefore).length > 0 || Object.keys(mergedBefore).length !== Object.keys(state.mappings).length) {
|
|
3454
|
-
state = { ...state, complete: false, mappings: mergedBefore };
|
|
3455
|
-
await publishState(deps, state);
|
|
3456
|
-
}
|
|
3457
|
-
if (Object.keys(state.mappings).length === 0) {
|
|
3458
|
-
if (!await lock.refresh()) throw new Error("Lost entity canonical-id migration lock.");
|
|
3459
|
-
const discoveredAfter2 = rejectMappingCycles(
|
|
3460
|
-
state.mappings,
|
|
3461
|
-
await discoverMappings(deps, state.mappings, blocked, scanNotes)
|
|
3462
|
-
);
|
|
3463
|
-
const revivedInRescan = await pruneBlocked();
|
|
3464
|
-
if (Object.keys(discoveredAfter2).length === 0 && !revivedInRescan) {
|
|
3465
|
-
await publishState(deps, { ...state, complete: true });
|
|
3466
|
-
return finish();
|
|
3467
|
-
}
|
|
3468
|
-
state = {
|
|
3469
|
-
...state,
|
|
3470
|
-
complete: false,
|
|
3471
|
-
mappings: collapseMappings(mergeDiscoveredMappings(state.mappings, discoveredAfter2))
|
|
3472
|
-
};
|
|
3473
|
-
await publishState(deps, state);
|
|
3474
|
-
continue;
|
|
3475
|
-
}
|
|
3476
|
-
let pendingMappings = Object.entries(state.mappings);
|
|
3477
|
-
while (pendingMappings.length > 0) {
|
|
3478
|
-
const deferredMappings = [];
|
|
3479
|
-
let progressed = false;
|
|
3480
|
-
for (const [legacyId, canonicalId] of pendingMappings) {
|
|
3481
|
-
const result = await migrateEntityFilePair(
|
|
3482
|
-
deps,
|
|
3483
|
-
legacyId,
|
|
3484
|
-
canonicalId,
|
|
3485
|
-
() => lock.refresh()
|
|
3486
|
-
);
|
|
3487
|
-
if (result.blocked) blocked.set(legacyId, canonicalId);
|
|
3488
|
-
else if (result.deferred) deferredMappings.push([legacyId, canonicalId]);
|
|
3489
|
-
progressed ||= result.progressed;
|
|
3490
|
-
}
|
|
3491
|
-
if (deferredMappings.length === 0) break;
|
|
3492
|
-
if (!progressed) {
|
|
3493
|
-
for (const [legacyId, canonicalId] of deferredMappings) {
|
|
3494
|
-
blocked.set(legacyId, canonicalId);
|
|
3495
|
-
staleParked.set(legacyId, canonicalId);
|
|
3496
|
-
}
|
|
3497
|
-
break;
|
|
3498
|
-
}
|
|
3499
|
-
pendingMappings = deferredMappings;
|
|
3500
|
-
}
|
|
3501
|
-
await pruneBlocked();
|
|
3502
|
-
const rewroteColdMemory = await rewriteKnownReferences(
|
|
3503
|
-
deps,
|
|
3504
|
-
state.mappings,
|
|
3505
|
-
() => lock.refresh()
|
|
3506
|
-
);
|
|
3507
|
-
deps.invalidateKnowledgeIndexCache();
|
|
3508
|
-
deps.invalidateAllMemoriesCache();
|
|
3509
|
-
if (rewroteColdMemory) deps.invalidateColdMemoriesCache();
|
|
3510
|
-
deps.bumpMemoryStatusVersion();
|
|
3511
|
-
if (!await lock.refresh()) throw new Error("Lost entity canonical-id migration lock.");
|
|
3512
|
-
const discoveredAfter = rejectMappingCycles(
|
|
3513
|
-
state.mappings,
|
|
3514
|
-
await discoverMappings(deps, state.mappings, blocked, scanNotes)
|
|
3515
|
-
);
|
|
3516
|
-
const revivedAfterRewrite = await pruneBlocked();
|
|
3517
|
-
if (Object.keys(discoveredAfter).length === 0 && !revivedAfterRewrite) {
|
|
3518
|
-
await publishState(deps, { ...state, complete: true });
|
|
3519
|
-
return finish();
|
|
3520
|
-
}
|
|
3521
|
-
state = {
|
|
3522
|
-
...state,
|
|
3523
|
-
complete: false,
|
|
3524
|
-
mappings: collapseMappings(mergeDiscoveredMappings(state.mappings, discoveredAfter))
|
|
3525
|
-
};
|
|
3526
|
-
await publishState(deps, state);
|
|
3527
|
-
}
|
|
3528
|
-
throw new Error("Entity canonical-id migration mappings changed while migration was running; retry migration.");
|
|
3529
|
-
}
|
|
3530
|
-
);
|
|
3531
|
-
}
|
|
3532
|
-
|
|
3533
2760
|
// src/storage/entity-ref-repair.ts
|
|
3534
|
-
import { unlink as
|
|
2761
|
+
import { unlink as unlink2 } from "fs/promises";
|
|
3535
2762
|
var EntityRefRepair = class {
|
|
3536
2763
|
constructor(deps) {
|
|
3537
2764
|
this.deps = deps;
|
|
@@ -3593,7 +2820,7 @@ ${body}
|
|
|
3593
2820
|
if (opts.onFailRestore) {
|
|
3594
2821
|
await this.restore(opts.onFailRestore);
|
|
3595
2822
|
} else if (opts.onFailRemove) {
|
|
3596
|
-
await
|
|
2823
|
+
await unlink2(opts.onFailRemove).catch(() => void 0);
|
|
3597
2824
|
this.deps.invalidateAllMemoriesCache();
|
|
3598
2825
|
}
|
|
3599
2826
|
throw err;
|
|
@@ -3679,6 +2906,33 @@ var EntityCanonicalIdMigrationRunner = class {
|
|
|
3679
2906
|
directoriesInitialized = false;
|
|
3680
2907
|
migrationComplete = false;
|
|
3681
2908
|
completedFingerprint = null;
|
|
2909
|
+
/**
|
|
2910
|
+
* First half of deferred startup: when waiting, ensure the migration runs;
|
|
2911
|
+
* when deferring, pre-read the entity entries the store serves instead and
|
|
2912
|
+
* let the migration start later (finishBegin detaches it).
|
|
2913
|
+
*/
|
|
2914
|
+
async begin(wait, entitiesDir) {
|
|
2915
|
+
if (wait) {
|
|
2916
|
+
await this.ensure();
|
|
2917
|
+
return;
|
|
2918
|
+
}
|
|
2919
|
+
const { readSafeEntityEntries } = await import("./entity-canonical-id-migration-GD5MPFUF.js");
|
|
2920
|
+
await readSafeEntityEntries(entitiesDir);
|
|
2921
|
+
}
|
|
2922
|
+
/**
|
|
2923
|
+
* Second half: return the directory-initialized barrier when waiting, or
|
|
2924
|
+
* detach it with a warning when the caller deferred the migration.
|
|
2925
|
+
*/
|
|
2926
|
+
finishBegin(wait) {
|
|
2927
|
+
const barrier = this.markDirectoriesInitialized();
|
|
2928
|
+
if (wait) return barrier;
|
|
2929
|
+
const describeDeferredFailure = (failure) => failure instanceof Error ? failure.message : failure;
|
|
2930
|
+
void barrier.catch(describeDeferredFailureAndWarn);
|
|
2931
|
+
function describeDeferredFailureAndWarn(failure) {
|
|
2932
|
+
console.warn(`entity canonical-id migration deferred at startup failed: ${describeDeferredFailure(failure)}`);
|
|
2933
|
+
}
|
|
2934
|
+
return Promise.resolve();
|
|
2935
|
+
}
|
|
3682
2936
|
async markDirectoriesInitialized() {
|
|
3683
2937
|
this.directoriesInitialized = true;
|
|
3684
2938
|
await this.ensure();
|
|
@@ -3698,6 +2952,9 @@ var EntityCanonicalIdMigrationRunner = class {
|
|
|
3698
2952
|
if (!this.directoriesInitialized) return Promise.resolve();
|
|
3699
2953
|
return this.ensure();
|
|
3700
2954
|
}
|
|
2955
|
+
async drain() {
|
|
2956
|
+
while (this.inFlight) await this.inFlight.catch(() => void 0);
|
|
2957
|
+
}
|
|
3701
2958
|
async runOrReuse() {
|
|
3702
2959
|
let fingerprintAtStart = await this.readFingerprint();
|
|
3703
2960
|
if (this.migrationComplete && fingerprintAtStart === this.completedFingerprint) return;
|
|
@@ -3754,7 +3011,7 @@ import {
|
|
|
3754
3011
|
readFileSync,
|
|
3755
3012
|
realpathSync
|
|
3756
3013
|
} from "fs";
|
|
3757
|
-
import
|
|
3014
|
+
import path7 from "path";
|
|
3758
3015
|
function resolveSafeAliasRoots(baseDir, configDir) {
|
|
3759
3016
|
let baseStat;
|
|
3760
3017
|
try {
|
|
@@ -3781,8 +3038,8 @@ function resolveSafeAliasRoots(baseDir, configDir) {
|
|
|
3781
3038
|
return memoryRoot;
|
|
3782
3039
|
}
|
|
3783
3040
|
function readEntityAliasConfigSync(baseDir) {
|
|
3784
|
-
const configDir =
|
|
3785
|
-
const aliasPath =
|
|
3041
|
+
const configDir = path7.join(baseDir, "config");
|
|
3042
|
+
const aliasPath = path7.join(configDir, "aliases.json");
|
|
3786
3043
|
let memoryRoot = resolveSafeAliasRoots(baseDir, configDir);
|
|
3787
3044
|
if (memoryRoot === void 0) return void 0;
|
|
3788
3045
|
let aliasPreflight;
|
|
@@ -3843,7 +3100,7 @@ function decodeYamlScalar(value) {
|
|
|
3843
3100
|
}
|
|
3844
3101
|
|
|
3845
3102
|
// src/orchestration/qmd-result-resolver.ts
|
|
3846
|
-
import
|
|
3103
|
+
import path8 from "path";
|
|
3847
3104
|
var INTERNAL_QMD_ROOTS = /* @__PURE__ */ new Set([
|
|
3848
3105
|
...ALL_CATEGORY_DIRS,
|
|
3849
3106
|
"activity",
|
|
@@ -3865,7 +3122,7 @@ var INTERNAL_QMD_ROOTS = /* @__PURE__ */ new Set([
|
|
|
3865
3122
|
]);
|
|
3866
3123
|
var PRIVATE_RESULT_RESOLUTION_CONCURRENCY = 16;
|
|
3867
3124
|
function qmdCollectionPathParts(resultPath) {
|
|
3868
|
-
if (!resultPath ||
|
|
3125
|
+
if (!resultPath || path8.isAbsolute(resultPath)) return null;
|
|
3869
3126
|
if (resultPath.trim().startsWith("qmd://")) {
|
|
3870
3127
|
try {
|
|
3871
3128
|
const parsed = new URL(resultPath.trim());
|
|
@@ -3890,9 +3147,9 @@ function qmdCollectionPathParts(resultPath) {
|
|
|
3890
3147
|
}
|
|
3891
3148
|
function qmdResultPathCandidates(storageDir, resultPath) {
|
|
3892
3149
|
const candidates = /* @__PURE__ */ new Set();
|
|
3893
|
-
const storageRoot =
|
|
3150
|
+
const storageRoot = path8.resolve(storageDir);
|
|
3894
3151
|
const addCandidate = (candidate) => {
|
|
3895
|
-
const resolved =
|
|
3152
|
+
const resolved = path8.resolve(candidate);
|
|
3896
3153
|
if (isPathInsideStorageRoot(storageRoot, resolved)) {
|
|
3897
3154
|
candidates.add(resolved);
|
|
3898
3155
|
}
|
|
@@ -3900,18 +3157,18 @@ function qmdResultPathCandidates(storageDir, resultPath) {
|
|
|
3900
3157
|
const addRelativeCandidates = (relativePath) => {
|
|
3901
3158
|
const normalized = relativePath.replace(/\\/g, "/").replace(/^\/+/, "");
|
|
3902
3159
|
if (!normalized) return;
|
|
3903
|
-
addCandidate(
|
|
3160
|
+
addCandidate(path8.join(storageRoot, normalized));
|
|
3904
3161
|
if (/^\d{4}-\d{2}-\d{2}\//.test(normalized)) {
|
|
3905
|
-
addCandidate(
|
|
3162
|
+
addCandidate(path8.join(storageRoot, "facts", normalized));
|
|
3906
3163
|
}
|
|
3907
3164
|
};
|
|
3908
|
-
if (
|
|
3165
|
+
if (path8.isAbsolute(resultPath)) {
|
|
3909
3166
|
addCandidate(resultPath);
|
|
3910
|
-
const relative2 =
|
|
3911
|
-
if (relative2 && !relative2.startsWith("..") && !
|
|
3912
|
-
const normalized = relative2.split(
|
|
3167
|
+
const relative2 = path8.relative(storageRoot, path8.resolve(resultPath));
|
|
3168
|
+
if (relative2 && !relative2.startsWith("..") && !path8.isAbsolute(relative2)) {
|
|
3169
|
+
const normalized = relative2.split(path8.sep).join("/");
|
|
3913
3170
|
if (/^\d{4}-\d{2}-\d{2}\//.test(normalized)) {
|
|
3914
|
-
addCandidate(
|
|
3171
|
+
addCandidate(path8.join(storageRoot, "facts", normalized));
|
|
3915
3172
|
}
|
|
3916
3173
|
}
|
|
3917
3174
|
} else {
|
|
@@ -3947,7 +3204,7 @@ var QmdResultResolver = class {
|
|
|
3947
3204
|
const seenStorageDirs = /* @__PURE__ */ new Set();
|
|
3948
3205
|
const addStorage = (storage) => {
|
|
3949
3206
|
const storageDir = storageDirOrNull(storage);
|
|
3950
|
-
const storageKey = storageDir ?
|
|
3207
|
+
const storageKey = storageDir ? path8.resolve(storageDir) : `storage-without-dir-${storages.length}`;
|
|
3951
3208
|
if (seenStorageDirs.has(storageKey)) return;
|
|
3952
3209
|
seenStorageDirs.add(storageKey);
|
|
3953
3210
|
storages.push(storage);
|
|
@@ -3977,7 +3234,7 @@ var QmdResultResolver = class {
|
|
|
3977
3234
|
continue;
|
|
3978
3235
|
}
|
|
3979
3236
|
try {
|
|
3980
|
-
const coldRoot =
|
|
3237
|
+
const coldRoot = path8.join(storageDir, "cold");
|
|
3981
3238
|
for (const candidate of qmdResultPathCandidates(coldRoot, parts.relativePath)) {
|
|
3982
3239
|
const memory = await storage.readMemoryByPath(candidate);
|
|
3983
3240
|
if (memory) return memory;
|
|
@@ -4027,9 +3284,9 @@ var QmdResultResolver = class {
|
|
|
4027
3284
|
error: err.message
|
|
4028
3285
|
});
|
|
4029
3286
|
}
|
|
4030
|
-
if (!
|
|
3287
|
+
if (!path8.isAbsolute(fallbackResultPath)) return null;
|
|
4031
3288
|
}
|
|
4032
|
-
if (
|
|
3289
|
+
if (path8.isAbsolute(fallbackResultPath)) {
|
|
4033
3290
|
if (!fallbackStorageDir) {
|
|
4034
3291
|
return await fallbackStorage.readMemoryByPath(fallbackResultPath);
|
|
4035
3292
|
}
|
|
@@ -4086,17 +3343,17 @@ var QmdResultResolver = class {
|
|
|
4086
3343
|
if (!memory && parts && !collectionIsKnownInternal && !collectionIsConfigured) {
|
|
4087
3344
|
memory = await this.readQmdResultMemory(parts.relativePath, fallbackStorage, namespaces, result.namespace);
|
|
4088
3345
|
}
|
|
4089
|
-
const absoluteInsideMemoryRoot =
|
|
3346
|
+
const absoluteInsideMemoryRoot = path8.isAbsolute(result.path) && isPathInsideStorageRoot(path8.resolve(config.memoryDir), path8.resolve(result.path));
|
|
4090
3347
|
const hasExplicitQmdCollection = result.path.trim().startsWith("qmd://");
|
|
4091
3348
|
const unresolvedInternalPath = !memory && (absoluteInsideMemoryRoot || collectionIsKnownInternal && (!preserveUnresolved || hasExplicitQmdCollection) || hasExplicitQmdCollection && collectionIsConfigured);
|
|
4092
|
-
const unresolvedExternalCollection = !memory && (parts !== null && !collectionIsKnownInternal && !collectionIsConfigured ||
|
|
3349
|
+
const unresolvedExternalCollection = !memory && (parts !== null && !collectionIsKnownInternal && !collectionIsConfigured || path8.isAbsolute(result.path) && !isPathInsideStorageRoot(path8.resolve(config.memoryDir), path8.resolve(result.path)));
|
|
4093
3350
|
return memory !== null && !isSupportPassportPrivateMemory(memory) || !memory && !unresolvedInternalPath && (preserveUnresolved || unresolvedExternalCollection);
|
|
4094
3351
|
}
|
|
4095
3352
|
async resolveColdQmdResultForRecall(result, fallbackStorage, recallNamespaces = []) {
|
|
4096
3353
|
const memory = await this.readQmdResultMemory(result.path, fallbackStorage, recallNamespaces, result.namespace);
|
|
4097
3354
|
if (!memory) return null;
|
|
4098
3355
|
let ownerNamespace = null;
|
|
4099
|
-
if (
|
|
3356
|
+
if (path8.isAbsolute(memory.path)) {
|
|
4100
3357
|
const ownerStorage = await this.storageForAbsoluteQmdResultPath(memory.path, fallbackStorage, recallNamespaces);
|
|
4101
3358
|
ownerNamespace = ownerStorage?.namespace ?? null;
|
|
4102
3359
|
if (!ownerNamespace && resolveNamespaceCapabilities(this.getConfig()).namespaces) return null;
|
|
@@ -4117,17 +3374,17 @@ var QmdResultResolver = class {
|
|
|
4117
3374
|
};
|
|
4118
3375
|
}
|
|
4119
3376
|
async storageForAbsoluteQmdResultPath(resultPath, fallbackStorage, recallNamespaces = []) {
|
|
4120
|
-
const resolvedPath =
|
|
3377
|
+
const resolvedPath = path8.resolve(resultPath);
|
|
4121
3378
|
const config = this.getConfig();
|
|
4122
|
-
const memoryRoot =
|
|
4123
|
-
const namespacesRoot =
|
|
3379
|
+
const memoryRoot = path8.resolve(config.memoryDir);
|
|
3380
|
+
const namespacesRoot = path8.join(memoryRoot, "namespaces");
|
|
4124
3381
|
const fallbackStorageDir = storageDirOrNull(fallbackStorage);
|
|
4125
3382
|
const matches = [];
|
|
4126
3383
|
const seenDirs = /* @__PURE__ */ new Set();
|
|
4127
3384
|
const maybeAddStorage = (storage, namespace) => {
|
|
4128
3385
|
const storageDir = storageDirOrNull(storage);
|
|
4129
3386
|
if (!storageDir) return;
|
|
4130
|
-
const candidateRoot =
|
|
3387
|
+
const candidateRoot = path8.resolve(storageDir);
|
|
4131
3388
|
if (seenDirs.has(candidateRoot)) return;
|
|
4132
3389
|
if (!isPathInsideStorageRoot(candidateRoot, resolvedPath)) return;
|
|
4133
3390
|
if (candidateRoot === memoryRoot && isPathInsideStorageRoot(namespacesRoot, resolvedPath)) {
|
|
@@ -4145,7 +3402,7 @@ var QmdResultResolver = class {
|
|
|
4145
3402
|
candidateNamespaces.add(ns);
|
|
4146
3403
|
}
|
|
4147
3404
|
if (isPathInsideStorageRoot(namespacesRoot, resolvedPath)) {
|
|
4148
|
-
const relativeToNamespaces =
|
|
3405
|
+
const relativeToNamespaces = path8.relative(namespacesRoot, resolvedPath);
|
|
4149
3406
|
const [namespaceSegment] = relativeToNamespaces.split(/[\\/]/);
|
|
4150
3407
|
if (namespaceSegment) {
|
|
4151
3408
|
candidateNamespaces.add(namespaceIdentityFromToken(namespaceSegment) ?? namespaceSegment);
|
|
@@ -4702,7 +3959,7 @@ function collectSpeakers(tagged) {
|
|
|
4702
3959
|
}
|
|
4703
3960
|
|
|
4704
3961
|
// src/wearables/fusion/fuse.ts
|
|
4705
|
-
import { createHash
|
|
3962
|
+
import { createHash } from "crypto";
|
|
4706
3963
|
var FUSION_ID_PREFIX = "fusion";
|
|
4707
3964
|
var FUSION_ALGO_VERSION = "2026-07-12-1";
|
|
4708
3965
|
function canonicalInputsKey(date, inputs) {
|
|
@@ -4731,7 +3988,7 @@ function canonicalInputsKey(date, inputs) {
|
|
|
4731
3988
|
])
|
|
4732
3989
|
])
|
|
4733
3990
|
];
|
|
4734
|
-
return
|
|
3991
|
+
return createHash("sha256").update(JSON.stringify(record), "utf-8").digest("hex");
|
|
4735
3992
|
}
|
|
4736
3993
|
function configFingerprint(options, sources) {
|
|
4737
3994
|
const proximityGapMs = options.proximityGapMs ?? DEFAULT_PROXIMITY_GAP_MS;
|
|
@@ -4746,7 +4003,7 @@ function canonicalDayKey(date, inputs, options, algoVersion = FUSION_ALGO_VERSIO
|
|
|
4746
4003
|
options,
|
|
4747
4004
|
inputs.map((conv) => conv.source)
|
|
4748
4005
|
);
|
|
4749
|
-
return
|
|
4006
|
+
return createHash("sha256").update(inputsKey).update("\n").update(fingerprint).update("\n").update(algoVersion).digest("hex");
|
|
4750
4007
|
}
|
|
4751
4008
|
function buildProvenance(cluster, proximityGapMs, windowToleranceMs) {
|
|
4752
4009
|
return {
|
|
@@ -4806,11 +4063,11 @@ function fuseDay(date, inputs, options = {}) {
|
|
|
4806
4063
|
}
|
|
4807
4064
|
|
|
4808
4065
|
// src/wearables/fusion/store.ts
|
|
4809
|
-
import { createHash as
|
|
4810
|
-
import * as
|
|
4066
|
+
import { createHash as createHash2 } from "crypto";
|
|
4067
|
+
import * as path9 from "path";
|
|
4811
4068
|
var FUSION_KIND = "wearable-fusion";
|
|
4812
4069
|
function hashFusionBody(conversations) {
|
|
4813
|
-
return
|
|
4070
|
+
return createHash2("sha256").update(JSON.stringify(conversations), "utf-8").digest("hex");
|
|
4814
4071
|
}
|
|
4815
4072
|
function composeFusionDayMeta(date, conversations, sources, contentHash, fusedAt) {
|
|
4816
4073
|
return {
|
|
@@ -4994,7 +4251,7 @@ var FusionArtifactStore = class {
|
|
|
4994
4251
|
`invalid wearable fusion date '${String(date)}' \u2014 expected YYYY-MM-DD`
|
|
4995
4252
|
);
|
|
4996
4253
|
}
|
|
4997
|
-
return
|
|
4254
|
+
return path9.join(this.wearablesDir, FUSION_DIR_NAME, `${date}.md`);
|
|
4998
4255
|
}
|
|
4999
4256
|
async writeFusedDay(date, serialized) {
|
|
5000
4257
|
const filePath = this.fusedDayPath(date);
|
|
@@ -5031,7 +4288,7 @@ var FusionArtifactStore = class {
|
|
|
5031
4288
|
}
|
|
5032
4289
|
/** List dates with stored fused artifacts, newest first. */
|
|
5033
4290
|
async listFusedDays() {
|
|
5034
|
-
const fusionDir =
|
|
4291
|
+
const fusionDir = path9.join(this.wearablesDir, FUSION_DIR_NAME);
|
|
5035
4292
|
await this.assertPathContained(fusionDir);
|
|
5036
4293
|
let entries;
|
|
5037
4294
|
try {
|
|
@@ -5075,10 +4332,10 @@ var FusionArtifactStore = class {
|
|
|
5075
4332
|
try {
|
|
5076
4333
|
rootReal = await this.io.realpath(this.memoryDir);
|
|
5077
4334
|
} catch {
|
|
5078
|
-
rootReal =
|
|
4335
|
+
rootReal = path9.resolve(this.memoryDir);
|
|
5079
4336
|
}
|
|
5080
4337
|
await this.assertNoEscape(rootReal, this.wearablesDir);
|
|
5081
|
-
await this.assertNoEscape(rootReal,
|
|
4338
|
+
await this.assertNoEscape(rootReal, path9.dirname(targetPath));
|
|
5082
4339
|
await this.assertNoEscape(rootReal, targetPath);
|
|
5083
4340
|
await this.assertFusionDirNotSymlinked();
|
|
5084
4341
|
}
|
|
@@ -5092,7 +4349,7 @@ var FusionArtifactStore = class {
|
|
|
5092
4349
|
* (a fresh write creates a real directory lexically under the root).
|
|
5093
4350
|
*/
|
|
5094
4351
|
async assertFusionDirNotSymlinked() {
|
|
5095
|
-
const fusionDir =
|
|
4352
|
+
const fusionDir = path9.join(this.wearablesDir, FUSION_DIR_NAME);
|
|
5096
4353
|
let stat4;
|
|
5097
4354
|
try {
|
|
5098
4355
|
stat4 = await this.io.lstat(fusionDir);
|
|
@@ -5227,8 +4484,8 @@ function reconstructFusionInputs(date, dayTranscripts) {
|
|
|
5227
4484
|
}
|
|
5228
4485
|
|
|
5229
4486
|
// src/meetings/store.ts
|
|
5230
|
-
import { createHash as
|
|
5231
|
-
import * as
|
|
4487
|
+
import { createHash as createHash3 } from "crypto";
|
|
4488
|
+
import * as path10 from "path";
|
|
5232
4489
|
var MEETINGS_DIR_NAME = "meetings";
|
|
5233
4490
|
var MEETING_KIND = "meeting";
|
|
5234
4491
|
var MEETING_FORMAT_VERSION = 1;
|
|
@@ -5258,7 +4515,7 @@ function canonicalContent(base, fused) {
|
|
|
5258
4515
|
});
|
|
5259
4516
|
}
|
|
5260
4517
|
function composeMeetingRecord(base, fused) {
|
|
5261
|
-
const contentHash =
|
|
4518
|
+
const contentHash = createHash3("sha256").update(canonicalContent(base, fused), "utf-8").digest("hex");
|
|
5262
4519
|
return {
|
|
5263
4520
|
...base,
|
|
5264
4521
|
...fused,
|
|
@@ -5397,7 +4654,7 @@ var MeetingRecordStore = class {
|
|
|
5397
4654
|
constructor(memoryDir, io) {
|
|
5398
4655
|
this.memoryDir = memoryDir;
|
|
5399
4656
|
this.io = io;
|
|
5400
|
-
this.meetingsDir =
|
|
4657
|
+
this.meetingsDir = path10.join(memoryDir, MEETINGS_DIR_NAME);
|
|
5401
4658
|
}
|
|
5402
4659
|
memoryDir;
|
|
5403
4660
|
io;
|
|
@@ -5413,7 +4670,7 @@ var MeetingRecordStore = class {
|
|
|
5413
4670
|
if (idDate !== date) {
|
|
5414
4671
|
throw new Error(`meeting id '${id}' does not belong to date '${date}'`);
|
|
5415
4672
|
}
|
|
5416
|
-
return
|
|
4673
|
+
return path10.join(this.meetingsDir, date, `${id}.md`);
|
|
5417
4674
|
}
|
|
5418
4675
|
/** Idempotently persist a record: skip the write when contentHash is unchanged. */
|
|
5419
4676
|
async saveMeetingRecord(record) {
|
|
@@ -5444,7 +4701,7 @@ var MeetingRecordStore = class {
|
|
|
5444
4701
|
if (!isValidTranscriptDate(date)) {
|
|
5445
4702
|
throw new Error(`invalid meeting date '${String(date)}' \u2014 expected YYYY-MM-DD`);
|
|
5446
4703
|
}
|
|
5447
|
-
const dayDir =
|
|
4704
|
+
const dayDir = path10.join(this.meetingsDir, date);
|
|
5448
4705
|
await this.assertPathContained(dayDir);
|
|
5449
4706
|
let entries;
|
|
5450
4707
|
try {
|
|
@@ -5512,10 +4769,10 @@ var MeetingRecordStore = class {
|
|
|
5512
4769
|
try {
|
|
5513
4770
|
rootReal = await this.io.realpath(this.memoryDir);
|
|
5514
4771
|
} catch {
|
|
5515
|
-
rootReal =
|
|
4772
|
+
rootReal = path10.resolve(this.memoryDir);
|
|
5516
4773
|
}
|
|
5517
4774
|
await this.assertNoEscape(rootReal, this.meetingsDir);
|
|
5518
|
-
await this.assertNoEscape(rootReal,
|
|
4775
|
+
await this.assertNoEscape(rootReal, path10.dirname(targetPath));
|
|
5519
4776
|
await this.assertNoEscape(rootReal, targetPath);
|
|
5520
4777
|
await this.assertNotSymlink(this.meetingsDir, "directory");
|
|
5521
4778
|
const dayDir = this.dayDirWithin(targetPath);
|
|
@@ -5525,11 +4782,11 @@ var MeetingRecordStore = class {
|
|
|
5525
4782
|
/** The `<meetings>/<date>` directory on the path to `targetPath`, or null when
|
|
5526
4783
|
* `targetPath` is the meetings root itself. */
|
|
5527
4784
|
dayDirWithin(targetPath) {
|
|
5528
|
-
const rel =
|
|
5529
|
-
if (rel === "" || rel.startsWith("..") ||
|
|
5530
|
-
const first = rel.split(
|
|
4785
|
+
const rel = path10.relative(this.meetingsDir, targetPath);
|
|
4786
|
+
if (rel === "" || rel.startsWith("..") || path10.isAbsolute(rel)) return null;
|
|
4787
|
+
const first = rel.split(path10.sep)[0];
|
|
5531
4788
|
if (first === void 0 || first.length === 0) return null;
|
|
5532
|
-
return
|
|
4789
|
+
return path10.join(this.meetingsDir, first);
|
|
5533
4790
|
}
|
|
5534
4791
|
async assertNotSymlink(target, kind) {
|
|
5535
4792
|
let stat4;
|
|
@@ -5540,7 +4797,7 @@ var MeetingRecordStore = class {
|
|
|
5540
4797
|
throw err;
|
|
5541
4798
|
}
|
|
5542
4799
|
if (stat4.isSymbolicLink) {
|
|
5543
|
-
const label =
|
|
4800
|
+
const label = path10.relative(this.memoryDir, target) || MEETINGS_DIR_NAME;
|
|
5544
4801
|
throw new Error(
|
|
5545
4802
|
`meetings ${kind} '${label}' is a symbolic link \u2014 refusing to follow it even when it resolves inside the memory dir (AGENTS.md pattern #3)`
|
|
5546
4803
|
);
|
|
@@ -5563,12 +4820,12 @@ var MeetingRecordStore = class {
|
|
|
5563
4820
|
var SORT_STR = (a, b) => a < b ? -1 : a > b ? 1 : 0;
|
|
5564
4821
|
|
|
5565
4822
|
// src/storage/supersession-audit.ts
|
|
5566
|
-
import { readdir as
|
|
5567
|
-
import
|
|
4823
|
+
import { readdir as readdir4 } from "fs/promises";
|
|
4824
|
+
import path11 from "path";
|
|
5568
4825
|
async function hasSupersessionAudit(lookup, oldMemoryId, newMemoryId, auditBody, structuredAttributes) {
|
|
5569
4826
|
let entries;
|
|
5570
4827
|
try {
|
|
5571
|
-
entries = await
|
|
4828
|
+
entries = await readdir4(lookup.correctionsDir, { withFileTypes: true });
|
|
5572
4829
|
} catch (error) {
|
|
5573
4830
|
if (isErrnoCode(error, "ENOENT")) return false;
|
|
5574
4831
|
throw error;
|
|
@@ -5576,7 +4833,7 @@ async function hasSupersessionAudit(lookup, oldMemoryId, newMemoryId, auditBody,
|
|
|
5576
4833
|
for (const entry of entries) {
|
|
5577
4834
|
if (isMacOsReplicationJunkBasename(entry.name)) continue;
|
|
5578
4835
|
if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
|
|
5579
|
-
const memory = await lookup.readMemoryByPath(
|
|
4836
|
+
const memory = await lookup.readMemoryByPath(path11.join(lookup.correctionsDir, entry.name));
|
|
5580
4837
|
if (memory?.frontmatter.category === "correction" && (memory.frontmatter.sourceMemoryId === oldMemoryId || memory.frontmatter.sourceMemoryId === void 0 && memory.frontmatter.lineage?.includes(oldMemoryId)) && memory.frontmatter.lineage?.includes(newMemoryId) && stripAttributesSuffix(memory.content) === auditBody && (structuredAttributes === void 0 || Object.entries(structuredAttributes).every(
|
|
5581
4838
|
([key, value]) => memory.frontmatter.structuredAttributes?.[key] === value
|
|
5582
4839
|
))) {
|
|
@@ -5666,7 +4923,7 @@ Reason: ${reason}`;
|
|
|
5666
4923
|
}
|
|
5667
4924
|
|
|
5668
4925
|
// src/storage/entity-timeline.ts
|
|
5669
|
-
import { createHash as
|
|
4926
|
+
import { createHash as createHash4 } from "crypto";
|
|
5670
4927
|
var ENTITY_TIMELINE_METADATA_MARKER = "remnic-meta-v1";
|
|
5671
4928
|
function parseEntityTimelineBullet(bullet, fallbackTimestamp) {
|
|
5672
4929
|
const trimmed = bullet.trim();
|
|
@@ -6108,7 +5365,7 @@ function fingerprintEntityStructuredFacts(entity) {
|
|
|
6108
5365
|
(left, right) => left.key.localeCompare(right.key) || left.title.localeCompare(right.title) || left.facts.join("\n").localeCompare(right.facts.join("\n"))
|
|
6109
5366
|
);
|
|
6110
5367
|
if (normalizedSections.length === 0) return void 0;
|
|
6111
|
-
return
|
|
5368
|
+
return createHash4("sha256").update(JSON.stringify(normalizedSections)).digest("hex");
|
|
6112
5369
|
}
|
|
6113
5370
|
function isEntitySynthesisStale(entity) {
|
|
6114
5371
|
const structuredFactCount = countEntityStructuredFacts(entity);
|
|
@@ -6665,17 +5922,17 @@ function inferEntityTypeFromContent(content) {
|
|
|
6665
5922
|
}
|
|
6666
5923
|
var KNOWN_ENTITY_FILENAME_PREFIXES = /* @__PURE__ */ new Set(["company", "other", "person", "place", "project", "tool", "topic"]);
|
|
6667
5924
|
function inferEntityTypeFromFilename(pathRel) {
|
|
6668
|
-
const basename =
|
|
5925
|
+
const basename = path12.basename(pathRel, ".md").toLowerCase();
|
|
6669
5926
|
const separator = basename.indexOf("-");
|
|
6670
5927
|
if (separator <= 0) return void 0;
|
|
6671
5928
|
const candidate = basename.slice(0, separator);
|
|
6672
5929
|
return KNOWN_ENTITY_FILENAME_PREFIXES.has(candidate) ? candidate : void 0;
|
|
6673
5930
|
}
|
|
6674
5931
|
function normalizeFrontmatterForPath(frontmatter, pathRel, content = "") {
|
|
6675
|
-
const normalizedPath = pathRel.split(
|
|
5932
|
+
const normalizedPath = pathRel.split(path12.sep).join("/");
|
|
6676
5933
|
let normalizedFrontmatter = frontmatter;
|
|
6677
5934
|
if (normalizedPath === "entities" || normalizedPath.startsWith("entities/") || normalizedPath.includes("/entities/")) {
|
|
6678
|
-
const basename =
|
|
5935
|
+
const basename = path12.basename(pathRel, ".md");
|
|
6679
5936
|
const inferredType = inferEntityTypeFromContent(content) || inferEntityTypeFromFilename(pathRel) || "entity";
|
|
6680
5937
|
const existingTags = Array.isArray(frontmatter.tags) ? frontmatter.tags : [];
|
|
6681
5938
|
normalizedFrontmatter = {
|
|
@@ -7148,9 +6405,9 @@ var StorageManager3 = class _StorageManager extends TombstoneBlockedCaptureIndex
|
|
|
7148
6405
|
this.entitySchemas = entitySchemas;
|
|
7149
6406
|
this.deletionRevisionStore = new DeletionRevisionStore({
|
|
7150
6407
|
baseDir,
|
|
7151
|
-
deletionRevisionMetadataPath:
|
|
7152
|
-
invalidationCommitMetadataPath:
|
|
7153
|
-
deletionRevisionLockPath:
|
|
6408
|
+
deletionRevisionMetadataPath: path12.join(baseDir, ".offline-sync", "deletion-revisions.v1.json"),
|
|
6409
|
+
invalidationCommitMetadataPath: path12.join(baseDir, ".offline-sync", "invalidation-commits.v1.json"),
|
|
6410
|
+
deletionRevisionLockPath: path12.join(baseDir, ".offline-sync", "deletion-revisions.v1.json.lock"),
|
|
7154
6411
|
assertManagedStoragePath: (filePath, method) => this.assertManagedStoragePath(filePath, method)
|
|
7155
6412
|
});
|
|
7156
6413
|
this.casRevisions = new CasRevisionHost(baseDir);
|
|
@@ -7336,8 +6593,8 @@ var StorageManager3 = class _StorageManager extends TombstoneBlockedCaptureIndex
|
|
|
7336
6593
|
}
|
|
7337
6594
|
/** Whether `filePath` resolves to `stateDir` itself or a path contained in it. */
|
|
7338
6595
|
isStateFilePath(filePath) {
|
|
7339
|
-
const rel =
|
|
7340
|
-
return rel === "" || !rel.startsWith("..") && !
|
|
6596
|
+
const rel = path12.relative(this.stateDir, path12.resolve(filePath));
|
|
6597
|
+
return rel === "" || !rel.startsWith("..") && !path12.isAbsolute(rel);
|
|
7341
6598
|
}
|
|
7342
6599
|
// ── Tombstone store (issue #1579) ───────────────────────────────────────
|
|
7343
6600
|
// Instance-scoped (rule 11) + namespace-scoped (rule 42) tombstone index.
|
|
@@ -7452,8 +6709,8 @@ var StorageManager3 = class _StorageManager extends TombstoneBlockedCaptureIndex
|
|
|
7452
6709
|
* /srv/cold/remnic), skipping the patch and stranding a stale hot entry.
|
|
7453
6710
|
*/
|
|
7454
6711
|
isColdOrArchiveTierPath(p) {
|
|
7455
|
-
const rel =
|
|
7456
|
-
return rel === "cold" || rel === "archive" || rel.startsWith(`cold${
|
|
6712
|
+
const rel = path12.relative(this.baseDir, p);
|
|
6713
|
+
return rel === "cold" || rel === "archive" || rel.startsWith(`cold${path12.sep}`) || rel.startsWith(`archive${path12.sep}`);
|
|
7457
6714
|
}
|
|
7458
6715
|
/**
|
|
7459
6716
|
* Mark the secure-store as required for this storage instance.
|
|
@@ -7540,7 +6797,7 @@ var StorageManager3 = class _StorageManager extends TombstoneBlockedCaptureIndex
|
|
|
7540
6797
|
void 0,
|
|
7541
6798
|
this.baseDir
|
|
7542
6799
|
);
|
|
7543
|
-
const rel =
|
|
6800
|
+
const rel = path12.relative(this.baseDir, filePath).split(path12.sep).join("/");
|
|
7544
6801
|
return `${rel}:${version.versionId}`;
|
|
7545
6802
|
} catch (err) {
|
|
7546
6803
|
log.warn(
|
|
@@ -7585,10 +6842,10 @@ var StorageManager3 = class _StorageManager extends TombstoneBlockedCaptureIndex
|
|
|
7585
6842
|
_StorageManager.okfConformanceByDir.set(memoryDir, enabled !== false);
|
|
7586
6843
|
}
|
|
7587
6844
|
okfConformanceEnabled() {
|
|
7588
|
-
for (let dir = this.baseDir; ; dir =
|
|
6845
|
+
for (let dir = this.baseDir; ; dir = path12.dirname(dir)) {
|
|
7589
6846
|
const registered = _StorageManager.okfConformanceByDir.get(dir);
|
|
7590
6847
|
if (registered !== void 0) return registered;
|
|
7591
|
-
if (dir ===
|
|
6848
|
+
if (dir === path12.dirname(dir)) return true;
|
|
7592
6849
|
}
|
|
7593
6850
|
}
|
|
7594
6851
|
/**
|
|
@@ -7615,10 +6872,7 @@ var StorageManager3 = class _StorageManager extends TombstoneBlockedCaptureIndex
|
|
|
7615
6872
|
/** EntityStore (storage.ts decomposition). Lazy; selfDeps live wiring. */
|
|
7616
6873
|
_entityStore;
|
|
7617
6874
|
get entityStore() {
|
|
7618
|
-
|
|
7619
|
-
this._entityStore = new EntityStore(selfDeps(this));
|
|
7620
|
-
}
|
|
7621
|
-
return this._entityStore;
|
|
6875
|
+
return this._entityStore ??= new EntityStore(selfDeps(this));
|
|
7622
6876
|
}
|
|
7623
6877
|
/** IdentityContinuityStore (storage.ts decomposition). Lazy; selfDeps live wiring. */
|
|
7624
6878
|
_identityContinuityStore;
|
|
@@ -7635,12 +6889,12 @@ var StorageManager3 = class _StorageManager extends TombstoneBlockedCaptureIndex
|
|
|
7635
6889
|
}
|
|
7636
6890
|
identityFilePath(workspaceDir, namespace) {
|
|
7637
6891
|
const rawNamespace = typeof namespace === "string" ? namespace.trim() : "";
|
|
7638
|
-
if (!rawNamespace) return
|
|
6892
|
+
if (!rawNamespace) return path12.join(workspaceDir, "IDENTITY.md");
|
|
7639
6893
|
const safeNamespace = rawNamespace.replace(/[^a-zA-Z0-9._-]/g, "-");
|
|
7640
|
-
return
|
|
6894
|
+
return path12.join(workspaceDir, `IDENTITY.${safeNamespace}.md`);
|
|
7641
6895
|
}
|
|
7642
6896
|
versionFilePath(kind) {
|
|
7643
|
-
return
|
|
6897
|
+
return path12.join(this.stateDir, `.${kind}-version.log`);
|
|
7644
6898
|
}
|
|
7645
6899
|
bumpSharedVersion(kind, fallbackMap) {
|
|
7646
6900
|
const filePath = this.versionFilePath(kind);
|
|
@@ -7747,7 +7001,7 @@ var StorageManager3 = class _StorageManager extends TombstoneBlockedCaptureIndex
|
|
|
7747
7001
|
// memories.
|
|
7748
7002
|
// -------------------------------------------------------------------------
|
|
7749
7003
|
get wearablesDir() {
|
|
7750
|
-
return
|
|
7004
|
+
return path12.join(this.baseDir, WEARABLES_DIR_NAME);
|
|
7751
7005
|
}
|
|
7752
7006
|
/**
|
|
7753
7007
|
* Resolve the on-disk path for a source/day transcript. Throws on
|
|
@@ -7763,7 +7017,7 @@ var StorageManager3 = class _StorageManager extends TombstoneBlockedCaptureIndex
|
|
|
7763
7017
|
if (!isValidTranscriptDate(date)) {
|
|
7764
7018
|
throw new Error(`invalid wearable transcript date '${String(date)}' \u2014 expected YYYY-MM-DD`);
|
|
7765
7019
|
}
|
|
7766
|
-
return
|
|
7020
|
+
return path12.join(this.wearablesDir, sourceId, `${date}.md`);
|
|
7767
7021
|
}
|
|
7768
7022
|
async writeWearableDayTranscript(sourceId, date, serialized) {
|
|
7769
7023
|
const targetPath = this.wearableTranscriptPath(sourceId, date);
|
|
@@ -7789,10 +7043,10 @@ var StorageManager3 = class _StorageManager extends TombstoneBlockedCaptureIndex
|
|
|
7789
7043
|
return this._fusionStore = new FusionArtifactStore(this.wearablesDir, this.baseDir, {
|
|
7790
7044
|
writeFile: (p, c) => this.writeStorageSecureFile(p, c),
|
|
7791
7045
|
readFile: (p) => readMaybeEncryptedFile(p, this._secureStoreKey, this.baseDir),
|
|
7792
|
-
readDir: (d) =>
|
|
7793
|
-
deleteFile: (p) =>
|
|
7794
|
-
realpath: (p) =>
|
|
7795
|
-
lstat: (p) =>
|
|
7046
|
+
readDir: (d) => readdir5(d),
|
|
7047
|
+
deleteFile: (p) => unlink3(p),
|
|
7048
|
+
realpath: (p) => realpath3(p),
|
|
7049
|
+
lstat: (p) => lstat3(p).then((st) => ({ isSymbolicLink: st.isSymbolicLink() }))
|
|
7796
7050
|
});
|
|
7797
7051
|
}
|
|
7798
7052
|
_meetingRecordStore;
|
|
@@ -7807,10 +7061,10 @@ var StorageManager3 = class _StorageManager extends TombstoneBlockedCaptureIndex
|
|
|
7807
7061
|
return this._meetingRecordStore = new MeetingRecordStore(this.baseDir, {
|
|
7808
7062
|
writeFile: (p, c) => this.writeStorageSecureFile(p, c),
|
|
7809
7063
|
readFile: (p) => readMaybeEncryptedFile(p, this._secureStoreKey, this.baseDir),
|
|
7810
|
-
readDir: (d) =>
|
|
7811
|
-
deleteFile: (p) =>
|
|
7812
|
-
realpath: (p) =>
|
|
7813
|
-
lstat: (p) =>
|
|
7064
|
+
readDir: (d) => readdir5(d),
|
|
7065
|
+
deleteFile: (p) => unlink3(p),
|
|
7066
|
+
realpath: (p) => realpath3(p),
|
|
7067
|
+
lstat: (p) => lstat3(p).then((st) => ({ isSymbolicLink: st.isSymbolicLink() }))
|
|
7814
7068
|
});
|
|
7815
7069
|
}
|
|
7816
7070
|
/**
|
|
@@ -7877,25 +7131,25 @@ var StorageManager3 = class _StorageManager extends TombstoneBlockedCaptureIndex
|
|
|
7877
7131
|
});
|
|
7878
7132
|
}
|
|
7879
7133
|
get factsDir() {
|
|
7880
|
-
return
|
|
7134
|
+
return path12.join(this.baseDir, "facts");
|
|
7881
7135
|
}
|
|
7882
7136
|
get correctionsDir() {
|
|
7883
|
-
return
|
|
7137
|
+
return path12.join(this.baseDir, "corrections");
|
|
7884
7138
|
}
|
|
7885
7139
|
get proceduresDir() {
|
|
7886
|
-
return
|
|
7140
|
+
return path12.join(this.baseDir, "procedures");
|
|
7887
7141
|
}
|
|
7888
7142
|
get reasoningTracesDir() {
|
|
7889
|
-
return
|
|
7143
|
+
return path12.join(this.baseDir, "reasoning-traces");
|
|
7890
7144
|
}
|
|
7891
7145
|
get entitiesDir() {
|
|
7892
|
-
return
|
|
7146
|
+
return path12.join(this.baseDir, "entities");
|
|
7893
7147
|
}
|
|
7894
7148
|
resolveEntityFilePath(name) {
|
|
7895
7149
|
if (typeof name !== "string") return null;
|
|
7896
|
-
const filePath =
|
|
7897
|
-
const relative2 =
|
|
7898
|
-
if (relative2 === "" || relative2.startsWith("..") ||
|
|
7150
|
+
const filePath = path12.resolve(this.entitiesDir, `${name}.md`);
|
|
7151
|
+
const relative2 = path12.relative(this.entitiesDir, filePath);
|
|
7152
|
+
if (relative2 === "" || relative2.startsWith("..") || path12.isAbsolute(relative2)) {
|
|
7899
7153
|
return null;
|
|
7900
7154
|
}
|
|
7901
7155
|
return filePath;
|
|
@@ -7906,7 +7160,7 @@ var StorageManager3 = class _StorageManager extends TombstoneBlockedCaptureIndex
|
|
|
7906
7160
|
async readDependencyPropagationQueueFile(filePath) {
|
|
7907
7161
|
const target = await resolveSafeStoragePath(
|
|
7908
7162
|
this.baseDir,
|
|
7909
|
-
|
|
7163
|
+
path12.relative(
|
|
7910
7164
|
this.baseDir,
|
|
7911
7165
|
this.assertManagedStoragePath(filePath, "storage.readDependencyPropagationQueueFile")
|
|
7912
7166
|
)
|
|
@@ -7916,7 +7170,7 @@ var StorageManager3 = class _StorageManager extends TombstoneBlockedCaptureIndex
|
|
|
7916
7170
|
async writeDependencyPropagationQueueFile(filePath, content) {
|
|
7917
7171
|
const target = await resolveSafeStoragePath(
|
|
7918
7172
|
this.baseDir,
|
|
7919
|
-
|
|
7173
|
+
path12.relative(
|
|
7920
7174
|
this.baseDir,
|
|
7921
7175
|
this.assertManagedStoragePath(filePath, "storage.writeDependencyPropagationQueueFile")
|
|
7922
7176
|
)
|
|
@@ -7931,10 +7185,10 @@ var StorageManager3 = class _StorageManager extends TombstoneBlockedCaptureIndex
|
|
|
7931
7185
|
});
|
|
7932
7186
|
}
|
|
7933
7187
|
assertManagedStoragePath(filePath, method) {
|
|
7934
|
-
const resolved =
|
|
7935
|
-
const base =
|
|
7936
|
-
const rel =
|
|
7937
|
-
if (rel === "" || rel === ".." || rel.startsWith(`..${
|
|
7188
|
+
const resolved = path12.resolve(filePath);
|
|
7189
|
+
const base = path12.resolve(this.baseDir);
|
|
7190
|
+
const rel = path12.relative(base, resolved);
|
|
7191
|
+
if (rel === "" || rel === ".." || rel.startsWith(`..${path12.sep}`) || path12.isAbsolute(rel)) {
|
|
7938
7192
|
throw new Error(`${method}: file path escapes memory dir`);
|
|
7939
7193
|
}
|
|
7940
7194
|
return resolved;
|
|
@@ -7971,7 +7225,7 @@ var StorageManager3 = class _StorageManager extends TombstoneBlockedCaptureIndex
|
|
|
7971
7225
|
async digestOfflineSyncFile(filePath) {
|
|
7972
7226
|
const target = this.assertManagedStoragePath(filePath, "storage.digestOfflineSyncFile");
|
|
7973
7227
|
const st = await stat3(target);
|
|
7974
|
-
const relPath =
|
|
7228
|
+
const relPath = path12.relative(this.baseDir, target).split(path12.sep).join("/");
|
|
7975
7229
|
const cache = await this.loadOfflineSyncDigestCache();
|
|
7976
7230
|
const cached = cache.get(relPath);
|
|
7977
7231
|
if (cached && cached.statBytes === st.size && cached.mtimeMs === st.mtimeMs && cached.ctimeMs === st.ctimeMs && !cached.encrypted) {
|
|
@@ -7985,11 +7239,11 @@ var StorageManager3 = class _StorageManager extends TombstoneBlockedCaptureIndex
|
|
|
7985
7239
|
if (encrypted) {
|
|
7986
7240
|
const content = await readMaybeEncryptedFileBuffer(target, this._secureStoreKey, this.baseDir);
|
|
7987
7241
|
digest = {
|
|
7988
|
-
sha256:
|
|
7242
|
+
sha256: createHash5("sha256").update(content).digest("hex"),
|
|
7989
7243
|
bytes: content.byteLength
|
|
7990
7244
|
};
|
|
7991
7245
|
} else {
|
|
7992
|
-
const hash =
|
|
7246
|
+
const hash = createHash5("sha256");
|
|
7993
7247
|
let bytes = 0;
|
|
7994
7248
|
for await (const rawChunk of createReadStream(target)) {
|
|
7995
7249
|
const chunk = Buffer.isBuffer(rawChunk) ? rawChunk : Buffer.from(rawChunk);
|
|
@@ -8017,7 +7271,7 @@ var StorageManager3 = class _StorageManager extends TombstoneBlockedCaptureIndex
|
|
|
8017
7271
|
async readOfflineSyncDigestCache() {
|
|
8018
7272
|
const cache = /* @__PURE__ */ new Map();
|
|
8019
7273
|
try {
|
|
8020
|
-
const raw = await
|
|
7274
|
+
const raw = await readFile(this.offlineSyncDigestCachePath, "utf-8");
|
|
8021
7275
|
return parseOfflineSyncDigestCache(raw);
|
|
8022
7276
|
} catch (err) {
|
|
8023
7277
|
if (!isErrnoCode(err, "ENOENT")) {
|
|
@@ -8056,8 +7310,8 @@ var StorageManager3 = class _StorageManager extends TombstoneBlockedCaptureIndex
|
|
|
8056
7310
|
const cache = this.offlineSyncDigestCache;
|
|
8057
7311
|
if (!cache) return;
|
|
8058
7312
|
const entries = [...cache.entries()].sort(([a], [b]) => a.localeCompare(b)).map(([entryPath, entry]) => ({ path: entryPath, ...entry }));
|
|
8059
|
-
await mkdir(
|
|
8060
|
-
await
|
|
7313
|
+
await mkdir(path12.dirname(this.offlineSyncDigestCachePath), { recursive: true });
|
|
7314
|
+
await writeFile(this.offlineSyncDigestCachePath, `${JSON.stringify({ version: 1, entries })}
|
|
8061
7315
|
`, "utf-8");
|
|
8062
7316
|
}).catch((err) => {
|
|
8063
7317
|
log.warn(
|
|
@@ -8157,7 +7411,7 @@ var StorageManager3 = class _StorageManager extends TombstoneBlockedCaptureIndex
|
|
|
8157
7411
|
}
|
|
8158
7412
|
async appendStorageSecureFileUnlocked(filePath, content) {
|
|
8159
7413
|
const writeKey = this.resolveWriteKey();
|
|
8160
|
-
await mkdir(
|
|
7414
|
+
await mkdir(path12.dirname(filePath), { recursive: true });
|
|
8161
7415
|
if (writeKey === null) {
|
|
8162
7416
|
try {
|
|
8163
7417
|
if (await this.isEncryptedFileHeader(filePath)) {
|
|
@@ -8183,13 +7437,13 @@ var StorageManager3 = class _StorageManager extends TombstoneBlockedCaptureIndex
|
|
|
8183
7437
|
this.notifyCatalogWriteForPath(filePath);
|
|
8184
7438
|
}
|
|
8185
7439
|
get stateDir() {
|
|
8186
|
-
return
|
|
7440
|
+
return path12.join(this.baseDir, "state");
|
|
8187
7441
|
}
|
|
8188
7442
|
get offlineSyncDigestCachePath() {
|
|
8189
|
-
return
|
|
7443
|
+
return path12.join(this.baseDir, ".offline-sync", "digest-cache.v1.json");
|
|
8190
7444
|
}
|
|
8191
7445
|
get entitySynthesisQueuePath() {
|
|
8192
|
-
return
|
|
7446
|
+
return path12.join(this.stateDir, "entity-synthesis-queue.json");
|
|
8193
7447
|
}
|
|
8194
7448
|
// ── Tombstone store access (issue #1579) ─────────────────────────────────
|
|
8195
7449
|
/**
|
|
@@ -8199,7 +7453,7 @@ var StorageManager3 = class _StorageManager extends TombstoneBlockedCaptureIndex
|
|
|
8199
7453
|
* helpers are injected into the store).
|
|
8200
7454
|
*/
|
|
8201
7455
|
get tombstonesPath() {
|
|
8202
|
-
return
|
|
7456
|
+
return path12.join(this.stateDir, "tombstones.jsonl");
|
|
8203
7457
|
}
|
|
8204
7458
|
/**
|
|
8205
7459
|
* Configure the tombstone invariant for this storage instance. Installed
|
|
@@ -8512,55 +7766,55 @@ var StorageManager3 = class _StorageManager extends TombstoneBlockedCaptureIndex
|
|
|
8512
7766
|
return legacyMatches.length > 0 ? [...new Set(legacyMatches.map((content) => ContentHashIndex.computeHash(content)))] : [persistedHash];
|
|
8513
7767
|
}
|
|
8514
7768
|
get questionsDir() {
|
|
8515
|
-
return
|
|
7769
|
+
return path12.join(this.baseDir, "questions");
|
|
8516
7770
|
}
|
|
8517
7771
|
get artifactsDir() {
|
|
8518
|
-
return
|
|
7772
|
+
return path12.join(this.baseDir, "artifacts");
|
|
8519
7773
|
}
|
|
8520
7774
|
get identityDir() {
|
|
8521
|
-
return
|
|
7775
|
+
return path12.join(this.baseDir, "identity");
|
|
8522
7776
|
}
|
|
8523
7777
|
get identityAnchorPath() {
|
|
8524
|
-
return
|
|
7778
|
+
return path12.join(this.identityDir, "identity-anchor.md");
|
|
8525
7779
|
}
|
|
8526
7780
|
get identityIncidentsDir() {
|
|
8527
|
-
return
|
|
7781
|
+
return path12.join(this.identityDir, "incidents");
|
|
8528
7782
|
}
|
|
8529
7783
|
get identityAuditsWeeklyDir() {
|
|
8530
|
-
return
|
|
7784
|
+
return path12.join(this.identityDir, "audits", "weekly");
|
|
8531
7785
|
}
|
|
8532
7786
|
get identityAuditsMonthlyDir() {
|
|
8533
|
-
return
|
|
7787
|
+
return path12.join(this.identityDir, "audits", "monthly");
|
|
8534
7788
|
}
|
|
8535
7789
|
get identityImprovementLoopsPath() {
|
|
8536
|
-
return
|
|
7790
|
+
return path12.join(this.identityDir, "improvement-loops.md");
|
|
8537
7791
|
}
|
|
8538
7792
|
get identityReflectionsPath() {
|
|
8539
|
-
return
|
|
7793
|
+
return path12.join(this.identityDir, "reflections.md");
|
|
8540
7794
|
}
|
|
8541
7795
|
get profilePath() {
|
|
8542
|
-
return
|
|
7796
|
+
return path12.join(this.baseDir, "profile.md");
|
|
8543
7797
|
}
|
|
8544
7798
|
get memoryActionsPath() {
|
|
8545
|
-
return
|
|
7799
|
+
return path12.join(this.stateDir, "memory-actions.jsonl");
|
|
8546
7800
|
}
|
|
8547
7801
|
get memoryLifecycleLedgerPath() {
|
|
8548
|
-
return
|
|
7802
|
+
return path12.join(this.stateDir, "memory-lifecycle-ledger.jsonl");
|
|
8549
7803
|
}
|
|
8550
7804
|
get compressionGuidelinesPath() {
|
|
8551
|
-
return
|
|
7805
|
+
return path12.join(this.stateDir, "compression-guidelines.md");
|
|
8552
7806
|
}
|
|
8553
7807
|
get compressionGuidelineDraftPath() {
|
|
8554
|
-
return
|
|
7808
|
+
return path12.join(this.stateDir, "compression-guidelines.draft.md");
|
|
8555
7809
|
}
|
|
8556
7810
|
get compressionGuidelineStatePath() {
|
|
8557
|
-
return
|
|
7811
|
+
return path12.join(this.stateDir, "compression-guideline-state.json");
|
|
8558
7812
|
}
|
|
8559
7813
|
get compressionGuidelineDraftStatePath() {
|
|
8560
|
-
return
|
|
7814
|
+
return path12.join(this.stateDir, "compression-guideline-draft-state.json");
|
|
8561
7815
|
}
|
|
8562
7816
|
get behaviorSignalsPath() {
|
|
8563
|
-
return
|
|
7817
|
+
return path12.join(this.stateDir, "behavior-signals.jsonl");
|
|
8564
7818
|
}
|
|
8565
7819
|
/**
|
|
8566
7820
|
* In-memory dedup key set for behavior-signals appends (issue #1909),
|
|
@@ -8592,7 +7846,7 @@ var StorageManager3 = class _StorageManager extends TombstoneBlockedCaptureIndex
|
|
|
8592
7846
|
* governance sweeps can treat it uniformly.
|
|
8593
7847
|
*/
|
|
8594
7848
|
get bufferSurpriseLedgerPath() {
|
|
8595
|
-
return
|
|
7849
|
+
return path12.join(this.stateDir, "buffer-surprise-ledger.jsonl");
|
|
8596
7850
|
}
|
|
8597
7851
|
/**
|
|
8598
7852
|
* Entity alias table loaded from THIS store's config/aliases.json.
|
|
@@ -8606,6 +7860,14 @@ var StorageManager3 = class _StorageManager extends TombstoneBlockedCaptureIndex
|
|
|
8606
7860
|
currentHistoricalIds() {
|
|
8607
7861
|
return this.historicalEntityCanonicalIds.get(this.stateDir);
|
|
8608
7862
|
}
|
|
7863
|
+
/** Journal completion for EntityStore's legacy-id retry gate (live view). */
|
|
7864
|
+
entityCanonicalMigrationComplete = memoizedJournalCompletion(this.historicalEntityCanonicalIds, () => this.stateDir);
|
|
7865
|
+
normalizeEntityName(raw, type) {
|
|
7866
|
+
return resolveHistoricalEntityCanonicalId(
|
|
7867
|
+
this.entityStore.normalizeEntityName(raw, type),
|
|
7868
|
+
this.currentHistoricalIds()
|
|
7869
|
+
);
|
|
7870
|
+
}
|
|
8609
7871
|
/** Post-persist repair subsystem (issue #2213) — storage/entity-ref-repair.ts. */
|
|
8610
7872
|
_entityRefRepair;
|
|
8611
7873
|
get entityRefRepair() {
|
|
@@ -8629,12 +7891,6 @@ var StorageManager3 = class _StorageManager extends TombstoneBlockedCaptureIndex
|
|
|
8629
7891
|
() => this.runLegacyEntityCanonicalIdMigration(),
|
|
8630
7892
|
() => getFingerprint(this.baseDir, this.entitiesDir, () => String(this.getEntityMutationVersion()))
|
|
8631
7893
|
);
|
|
8632
|
-
normalizeEntityName(raw, type) {
|
|
8633
|
-
return resolveHistoricalEntityCanonicalId(
|
|
8634
|
-
this.entityStore.normalizeEntityName(raw, type),
|
|
8635
|
-
this.currentHistoricalIds()
|
|
8636
|
-
);
|
|
8637
|
-
}
|
|
8638
7894
|
/**
|
|
8639
7895
|
* Read-only view of this store's user alias table, for call sites that
|
|
8640
7896
|
* normalize outside the manager (pass it to the free `normalizeEntityName`).
|
|
@@ -8653,7 +7909,7 @@ var StorageManager3 = class _StorageManager extends TombstoneBlockedCaptureIndex
|
|
|
8653
7909
|
this.loadAliasesSync();
|
|
8654
7910
|
}
|
|
8655
7911
|
loadAliasesSync() {
|
|
8656
|
-
const aliasPath =
|
|
7912
|
+
const aliasPath = path12.join(this.baseDir, "config", "aliases.json");
|
|
8657
7913
|
this.userAliases = {};
|
|
8658
7914
|
const raw = readEntityAliasConfigSync(this.baseDir);
|
|
8659
7915
|
if (raw === void 0) return;
|
|
@@ -8687,13 +7943,13 @@ var StorageManager3 = class _StorageManager extends TombstoneBlockedCaptureIndex
|
|
|
8687
7943
|
);
|
|
8688
7944
|
return completionFingerprint;
|
|
8689
7945
|
}
|
|
8690
|
-
async ensureDirectories() {
|
|
7946
|
+
async ensureDirectories(options = {}) {
|
|
8691
7947
|
await mkdir(this.baseDir, { recursive: true });
|
|
8692
7948
|
await validateRoots(this.baseDir, this.entitiesDir, this.stateDir, this.archiveDir);
|
|
8693
7949
|
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
8694
|
-
await mkdir(
|
|
8695
|
-
await mkdir(
|
|
8696
|
-
await mkdir(
|
|
7950
|
+
await mkdir(path12.join(this.factsDir, today), { recursive: true });
|
|
7951
|
+
await mkdir(path12.join(this.proceduresDir, today), { recursive: true });
|
|
7952
|
+
await mkdir(path12.join(this.reasoningTracesDir, today), { recursive: true });
|
|
8697
7953
|
await mkdir(this.correctionsDir, { recursive: true });
|
|
8698
7954
|
await mkdir(this.entitiesDir, { recursive: true });
|
|
8699
7955
|
await mkdir(this.stateDir, { recursive: true });
|
|
@@ -8703,13 +7959,14 @@ var StorageManager3 = class _StorageManager extends TombstoneBlockedCaptureIndex
|
|
|
8703
7959
|
await mkdir(this.identityIncidentsDir, { recursive: true });
|
|
8704
7960
|
await mkdir(this.identityAuditsWeeklyDir, { recursive: true });
|
|
8705
7961
|
await mkdir(this.identityAuditsMonthlyDir, { recursive: true });
|
|
8706
|
-
await mkdir(
|
|
8707
|
-
await this.entityCanonicalIdMigration.
|
|
7962
|
+
await mkdir(path12.join(this.baseDir, "config"), { recursive: true });
|
|
7963
|
+
await this.entityCanonicalIdMigration.begin(options.waitForEntityMigration !== false, this.entitiesDir);
|
|
8708
7964
|
if (this.hotMemoriesCacheEnabled && this.getMemoryCorpusVersion() === 0) {
|
|
8709
7965
|
this.bumpMemoryCorpusVersion();
|
|
8710
7966
|
}
|
|
8711
|
-
|
|
7967
|
+
return this.entityCanonicalIdMigration.finishBegin(options.waitForEntityMigration !== false);
|
|
8712
7968
|
}
|
|
7969
|
+
drainEntityCanonicalIdMigration = () => this.entityCanonicalIdMigration.drain();
|
|
8713
7970
|
/**
|
|
8714
7971
|
* Resolve the on-disk write path for a memory of the given category, creating
|
|
8715
7972
|
* the target directory. Category routing goes through the shared
|
|
@@ -8725,11 +7982,11 @@ var StorageManager3 = class _StorageManager extends TombstoneBlockedCaptureIndex
|
|
|
8725
7982
|
async resolveCategoryWritePath(category, id, today) {
|
|
8726
7983
|
if (category === "correction") {
|
|
8727
7984
|
await mkdir(this.correctionsDir, { recursive: true });
|
|
8728
|
-
return
|
|
7985
|
+
return path12.join(this.correctionsDir, `${id}.md`);
|
|
8729
7986
|
}
|
|
8730
|
-
const datedDir =
|
|
7987
|
+
const datedDir = path12.join(getCategoryDir(this.baseDir, category), today);
|
|
8731
7988
|
await mkdir(datedDir, { recursive: true });
|
|
8732
|
-
return
|
|
7989
|
+
return path12.join(datedDir, `${id}.md`);
|
|
8733
7990
|
}
|
|
8734
7991
|
async findExistingTombstoneBlockedMemory(content, category, sourceConnector) {
|
|
8735
7992
|
const identity = buildExplicitCaptureDedupKey(content, category, sourceConnector);
|
|
@@ -8900,7 +8157,7 @@ ${sanitized.text}
|
|
|
8900
8157
|
}
|
|
8901
8158
|
});
|
|
8902
8159
|
} catch (err) {
|
|
8903
|
-
await
|
|
8160
|
+
await unlink3(filePath).catch(() => void 0);
|
|
8904
8161
|
this.invalidateAllMemoriesCache();
|
|
8905
8162
|
await this.rebuildTombstoneBlockedCaptureAfterInvalidationForPath(filePath);
|
|
8906
8163
|
throw err;
|
|
@@ -9108,7 +8365,7 @@ ${sanitized.text}
|
|
|
9108
8365
|
await this.ensureDirectories();
|
|
9109
8366
|
const now = /* @__PURE__ */ new Date();
|
|
9110
8367
|
const day = now.toISOString().slice(0, 10);
|
|
9111
|
-
const dir =
|
|
8368
|
+
const dir = path12.join(this.artifactsDir, day);
|
|
9112
8369
|
await mkdir(dir, { recursive: true });
|
|
9113
8370
|
const id = `artifact-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`;
|
|
9114
8371
|
const fm = {
|
|
@@ -9135,7 +8392,7 @@ ${sanitized.text}
|
|
|
9135
8392
|
log.warn(`artifact content rejected for ${id}; violations=${sanitized.violations.join(", ")}`);
|
|
9136
8393
|
return "";
|
|
9137
8394
|
}
|
|
9138
|
-
const filePath =
|
|
8395
|
+
const filePath = path12.join(dir, `${id}.md`);
|
|
9139
8396
|
await this.writeStorageSecureFile(filePath, `${serializeFrontmatter(this.withOkfType(fm))}
|
|
9140
8397
|
|
|
9141
8398
|
${sanitized.text}
|
|
@@ -9429,7 +8686,7 @@ ${sanitized.text}
|
|
|
9429
8686
|
* per-process in-memory cache safe across process boundaries.
|
|
9430
8687
|
*/
|
|
9431
8688
|
invalidateColdMemoriesCache() {
|
|
9432
|
-
const coldRoot =
|
|
8689
|
+
const coldRoot = path12.join(this.baseDir, "cold");
|
|
9433
8690
|
_StorageManager.coldMemoriesCache.delete(coldRoot);
|
|
9434
8691
|
this.bumpColdWriteVersion();
|
|
9435
8692
|
invalidateAllForDir(this.baseDir);
|
|
@@ -9547,7 +8804,7 @@ ${sanitized.text}
|
|
|
9547
8804
|
const correctionPaths = [];
|
|
9548
8805
|
const factPaths = [];
|
|
9549
8806
|
for (const filePath of filePaths) {
|
|
9550
|
-
if (filePath === this.correctionsDir || filePath.startsWith(`${this.correctionsDir}${
|
|
8807
|
+
if (filePath === this.correctionsDir || filePath.startsWith(`${this.correctionsDir}${path12.sep}`)) {
|
|
9551
8808
|
correctionPaths.push(filePath);
|
|
9552
8809
|
} else {
|
|
9553
8810
|
factPaths.push(filePath);
|
|
@@ -9610,10 +8867,10 @@ ${sanitized.text}
|
|
|
9610
8867
|
const root = this.archiveDir;
|
|
9611
8868
|
const readDir = async (dir) => {
|
|
9612
8869
|
try {
|
|
9613
|
-
const entries = (await
|
|
8870
|
+
const entries = (await readdir5(dir, { withFileTypes: true })).filter((e) => !isMacOsReplicationJunkBasename(e.name));
|
|
9614
8871
|
for (const entry of entries) {
|
|
9615
8872
|
checkCorpusReadAbort(options);
|
|
9616
|
-
const fullPath =
|
|
8873
|
+
const fullPath = path12.join(dir, entry.name);
|
|
9617
8874
|
if (entry.isDirectory()) {
|
|
9618
8875
|
await readDir(fullPath);
|
|
9619
8876
|
} else if (entry.name.endsWith(".md")) {
|
|
@@ -9653,7 +8910,7 @@ ${sanitized.text}
|
|
|
9653
8910
|
return this.rememberMemorySnapshot(await this.memoryReadStore.readMemoryByPath(filePath));
|
|
9654
8911
|
}
|
|
9655
8912
|
resolveTierRootDir(tier) {
|
|
9656
|
-
return tier === "cold" ?
|
|
8913
|
+
return tier === "cold" ? path12.join(this.baseDir, "cold") : this.baseDir;
|
|
9657
8914
|
}
|
|
9658
8915
|
resolveMemoryDateDir(memory) {
|
|
9659
8916
|
const preferred = memory.frontmatter.created || memory.frontmatter.updated;
|
|
@@ -9668,13 +8925,13 @@ ${sanitized.text}
|
|
|
9668
8925
|
buildTierMemoryPath(memory, tier) {
|
|
9669
8926
|
const root = this.resolveTierRootDir(tier);
|
|
9670
8927
|
if (this.isArtifactMemory(memory)) {
|
|
9671
|
-
return
|
|
8928
|
+
return path12.join(root, "artifacts", this.resolveMemoryDateDir(memory), `${memory.frontmatter.id}.md`);
|
|
9672
8929
|
}
|
|
9673
8930
|
if (memory.frontmatter.category === "correction") {
|
|
9674
|
-
return
|
|
8931
|
+
return path12.join(root, "corrections", `${memory.frontmatter.id}.md`);
|
|
9675
8932
|
}
|
|
9676
8933
|
const dir = categoryDirName(memory.frontmatter.category);
|
|
9677
|
-
return
|
|
8934
|
+
return path12.join(root, dir, this.resolveMemoryDateDir(memory), `${memory.frontmatter.id}.md`);
|
|
9678
8935
|
}
|
|
9679
8936
|
async writeMemoryFileAtomic(targetPath, memory) {
|
|
9680
8937
|
assertNotOkfReservedBasename(targetPath);
|
|
@@ -9691,7 +8948,7 @@ ${memory.content}
|
|
|
9691
8948
|
{},
|
|
9692
8949
|
this.baseDir
|
|
9693
8950
|
);
|
|
9694
|
-
const priorDest = await
|
|
8951
|
+
const priorDest = await readFile(targetPath).catch(() => null);
|
|
9695
8952
|
await persist();
|
|
9696
8953
|
if (typeof rawRef === "string") {
|
|
9697
8954
|
const refBeforeRepair = frontmatter.entityRef;
|
|
@@ -9706,9 +8963,9 @@ ${memory.content}
|
|
|
9706
8963
|
});
|
|
9707
8964
|
} catch (err) {
|
|
9708
8965
|
if (priorDest === null) {
|
|
9709
|
-
await
|
|
8966
|
+
await unlink3(targetPath).catch(() => void 0);
|
|
9710
8967
|
} else {
|
|
9711
|
-
await
|
|
8968
|
+
await writeFile(targetPath, priorDest).catch(() => void 0);
|
|
9712
8969
|
}
|
|
9713
8970
|
this.invalidateAllMemoriesCache();
|
|
9714
8971
|
throw err;
|
|
@@ -9753,8 +9010,8 @@ ${memory.content}
|
|
|
9753
9010
|
memory.frontmatter.entityRef = current.frontmatter.entityRef;
|
|
9754
9011
|
}
|
|
9755
9012
|
durable = true;
|
|
9756
|
-
const sourcePath =
|
|
9757
|
-
const destPath =
|
|
9013
|
+
const sourcePath = path12.resolve(current.path);
|
|
9014
|
+
const destPath = path12.resolve(targetPath);
|
|
9758
9015
|
if (sourcePath !== destPath) {
|
|
9759
9016
|
await recordArchiveDelete2(this.baseDir, current.path, () => this.deleteManagedStorageFile(current.path));
|
|
9760
9017
|
this.invalidateAllMemoriesCache();
|
|
@@ -9778,8 +9035,8 @@ ${memory.content}
|
|
|
9778
9035
|
}
|
|
9779
9036
|
async migrateMemoryToTier(memory, targetTier) {
|
|
9780
9037
|
const targetPath = this.buildTierMemoryPath(memory, targetTier);
|
|
9781
|
-
const sourcePath =
|
|
9782
|
-
const destPath =
|
|
9038
|
+
const sourcePath = path12.resolve(memory.path);
|
|
9039
|
+
const destPath = path12.resolve(targetPath);
|
|
9783
9040
|
if (sourcePath === destPath) {
|
|
9784
9041
|
return { changed: false, targetPath };
|
|
9785
9042
|
}
|
|
@@ -9789,7 +9046,7 @@ ${memory.content}
|
|
|
9789
9046
|
return { changed, targetPath };
|
|
9790
9047
|
}
|
|
9791
9048
|
get archiveDir() {
|
|
9792
|
-
return
|
|
9049
|
+
return path12.join(this.baseDir, "archive");
|
|
9793
9050
|
}
|
|
9794
9051
|
/**
|
|
9795
9052
|
* Archive a memory by moving it from facts/ to archive/YYYY-MM-DD/.
|
|
@@ -9802,7 +9059,7 @@ ${memory.content}
|
|
|
9802
9059
|
try {
|
|
9803
9060
|
const now = lifecycle?.at ?? /* @__PURE__ */ new Date();
|
|
9804
9061
|
const today = now.toISOString().slice(0, 10);
|
|
9805
|
-
const destDir =
|
|
9062
|
+
const destDir = path12.join(this.archiveDir, today);
|
|
9806
9063
|
await mkdir(destDir, { recursive: true });
|
|
9807
9064
|
const refIdsAtWrite = this.currentHistoricalIds();
|
|
9808
9065
|
const updatedFm = canonicalizeEntityRefOption(
|
|
@@ -9818,7 +9075,7 @@ ${memory.content}
|
|
|
9818
9075
|
|
|
9819
9076
|
${current.content}
|
|
9820
9077
|
`;
|
|
9821
|
-
const destPath =
|
|
9078
|
+
const destPath = path12.join(destDir, path12.basename(current.path));
|
|
9822
9079
|
const priorDest = await this.readStorageSecureFile(destPath).catch(() => null);
|
|
9823
9080
|
await recordArchiveWrite(this.baseDir, destPath, () => this.writeStorageSecureFile(destPath, fileContent));
|
|
9824
9081
|
if (typeof current.frontmatter.entityRef === "string") {
|
|
@@ -9835,7 +9092,7 @@ ${current.content}
|
|
|
9835
9092
|
await recordArchiveDelete2(
|
|
9836
9093
|
this.baseDir,
|
|
9837
9094
|
destPath,
|
|
9838
|
-
() =>
|
|
9095
|
+
() => unlink3(destPath).then(
|
|
9839
9096
|
() => true,
|
|
9840
9097
|
() => false
|
|
9841
9098
|
)
|
|
@@ -10052,7 +9309,7 @@ ${memory.content}
|
|
|
10052
9309
|
`;
|
|
10053
9310
|
await this.writeTombstoneBlockedFrontmatter(memory, fileContent, updated, async () => {
|
|
10054
9311
|
this.invalidateAllMemoriesCache();
|
|
10055
|
-
if (memory.path.includes(`${
|
|
9312
|
+
if (memory.path.includes(`${path12.sep}cold${path12.sep}`)) {
|
|
10056
9313
|
this.invalidateColdMemoriesCache();
|
|
10057
9314
|
}
|
|
10058
9315
|
});
|
|
@@ -10064,7 +9321,7 @@ ${memory.content}
|
|
|
10064
9321
|
}
|
|
10065
9322
|
if (mentionReentry && !entityMentionEpoch.neutral(memory.frontmatter, updated)) entityMentionEpoch.bump(this.baseDir);
|
|
10066
9323
|
await this.patchHotMemoriesCache({ addedPath: memory.path });
|
|
10067
|
-
if (memory.path.includes(`${
|
|
9324
|
+
if (memory.path.includes(`${path12.sep}cold${path12.sep}`)) {
|
|
10068
9325
|
this.invalidateColdMemoriesCache();
|
|
10069
9326
|
}
|
|
10070
9327
|
try {
|
|
@@ -10145,7 +9402,7 @@ ${memory.content}
|
|
|
10145
9402
|
return deleted;
|
|
10146
9403
|
}
|
|
10147
9404
|
async loadBuffer() {
|
|
10148
|
-
const bufferPath =
|
|
9405
|
+
const bufferPath = path12.join(this.stateDir, "buffer.json");
|
|
10149
9406
|
try {
|
|
10150
9407
|
const raw = await this.readStorageSecureFile(bufferPath);
|
|
10151
9408
|
return JSON.parse(raw);
|
|
@@ -10157,11 +9414,11 @@ ${memory.content}
|
|
|
10157
9414
|
}
|
|
10158
9415
|
async saveBuffer(state) {
|
|
10159
9416
|
await this.ensureDirectories();
|
|
10160
|
-
const bufferPath =
|
|
9417
|
+
const bufferPath = path12.join(this.stateDir, "buffer.json");
|
|
10161
9418
|
await this.writeStorageSecureFile(bufferPath, JSON.stringify(state, null, 2));
|
|
10162
9419
|
}
|
|
10163
9420
|
async loadMeta() {
|
|
10164
|
-
const metaPath =
|
|
9421
|
+
const metaPath = path12.join(this.stateDir, "meta.json");
|
|
10165
9422
|
try {
|
|
10166
9423
|
const raw = await this.readStorageSecureFile(metaPath);
|
|
10167
9424
|
const parsed = JSON.parse(raw);
|
|
@@ -10194,7 +9451,7 @@ ${memory.content}
|
|
|
10194
9451
|
}
|
|
10195
9452
|
async saveMeta(state) {
|
|
10196
9453
|
await this.ensureDirectories();
|
|
10197
|
-
const metaPath =
|
|
9454
|
+
const metaPath = path12.join(this.stateDir, "meta.json");
|
|
10198
9455
|
await this.writeStorageSecureFile(metaPath, JSON.stringify(state, null, 2));
|
|
10199
9456
|
}
|
|
10200
9457
|
async appendMemoryActionEvents(events) {
|
|
@@ -10264,7 +9521,7 @@ ${memory.content}
|
|
|
10264
9521
|
},
|
|
10265
9522
|
(payload) => this.appendStorageSecureFile(target, payload),
|
|
10266
9523
|
async () => {
|
|
10267
|
-
await mkdir(
|
|
9524
|
+
await mkdir(path12.dirname(target), { recursive: true });
|
|
10268
9525
|
}
|
|
10269
9526
|
);
|
|
10270
9527
|
}
|
|
@@ -10362,7 +9619,7 @@ ${memory.content}
|
|
|
10362
9619
|
async appendReextractJobs(events) {
|
|
10363
9620
|
if (events.length === 0) return 0;
|
|
10364
9621
|
await this.ensureDirectories();
|
|
10365
|
-
const filePath =
|
|
9622
|
+
const filePath = path12.join(this.stateDir, "reextract-jobs.jsonl");
|
|
10366
9623
|
const lines = events.map((event) => JSON.stringify(event)).join("\n") + "\n";
|
|
10367
9624
|
try {
|
|
10368
9625
|
await this.appendStorageSecureFile(filePath, lines);
|
|
@@ -10375,7 +9632,7 @@ ${memory.content}
|
|
|
10375
9632
|
}
|
|
10376
9633
|
async readReextractJobs(limit = 200) {
|
|
10377
9634
|
const safeLimit = Number.isFinite(limit) ? Math.max(1, Math.min(1e3, Math.floor(limit))) : 200;
|
|
10378
|
-
const filePath =
|
|
9635
|
+
const filePath = path12.join(this.stateDir, "reextract-jobs.jsonl");
|
|
10379
9636
|
try {
|
|
10380
9637
|
const raw = await this.readStorageSecureFile(filePath);
|
|
10381
9638
|
const lines = raw.split("\n").filter((line) => line.trim().length > 0);
|
|
@@ -10531,7 +9788,7 @@ ${memory.content}
|
|
|
10531
9788
|
return false;
|
|
10532
9789
|
}
|
|
10533
9790
|
if (draftState.contentHash) {
|
|
10534
|
-
const contentHash =
|
|
9791
|
+
const contentHash = createHash5("sha256").update(draftContent).digest("hex");
|
|
10535
9792
|
if (contentHash !== draftState.contentHash) return false;
|
|
10536
9793
|
}
|
|
10537
9794
|
await this.writeCompressionGuidelines(draftContent);
|
|
@@ -10540,8 +9797,8 @@ ${memory.content}
|
|
|
10540
9797
|
activationState: "active"
|
|
10541
9798
|
});
|
|
10542
9799
|
await Promise.all([
|
|
10543
|
-
|
|
10544
|
-
|
|
9800
|
+
unlink3(this.compressionGuidelineDraftPath).catch(() => void 0),
|
|
9801
|
+
unlink3(this.compressionGuidelineDraftStatePath).catch(() => void 0)
|
|
10545
9802
|
]);
|
|
10546
9803
|
return true;
|
|
10547
9804
|
}
|
|
@@ -10610,7 +9867,7 @@ ${question}
|
|
|
10610
9867
|
|
|
10611
9868
|
**Context:** ${context}
|
|
10612
9869
|
`;
|
|
10613
|
-
const filePath =
|
|
9870
|
+
const filePath = path12.join(this.questionsDir, `${id}.md`);
|
|
10614
9871
|
await this.writeStorageSecureFile(filePath, content);
|
|
10615
9872
|
log.debug(`wrote question ${id} to ${filePath}`);
|
|
10616
9873
|
this.invalidateQuestionsCache();
|
|
@@ -10647,14 +9904,14 @@ ${question}
|
|
|
10647
9904
|
async readIdentity(workspaceDir, namespace) {
|
|
10648
9905
|
const identityPath = this.identityFilePath(workspaceDir, namespace);
|
|
10649
9906
|
try {
|
|
10650
|
-
return await
|
|
9907
|
+
return await readFile(identityPath, "utf-8");
|
|
10651
9908
|
} catch {
|
|
10652
9909
|
return "";
|
|
10653
9910
|
}
|
|
10654
9911
|
}
|
|
10655
9912
|
async writeIdentity(workspaceDir, content, namespace) {
|
|
10656
9913
|
const identityPath = this.identityFilePath(workspaceDir, namespace);
|
|
10657
|
-
await
|
|
9914
|
+
await writeFile(identityPath, content, "utf-8");
|
|
10658
9915
|
log.debug(`wrote consolidated IDENTITY.md (${content.length} chars)`);
|
|
10659
9916
|
}
|
|
10660
9917
|
/** Max size for IDENTITY.md before we stop appending reflections (15KB leaves room under 20KB gateway limit) */
|
|
@@ -10665,22 +9922,22 @@ ${question}
|
|
|
10665
9922
|
const identityPath = this.identityFilePath(workspaceDir, opts?.namespace);
|
|
10666
9923
|
let existing = "";
|
|
10667
9924
|
try {
|
|
10668
|
-
existing = await
|
|
9925
|
+
existing = await readFile(identityPath, "utf-8");
|
|
10669
9926
|
} catch {
|
|
10670
9927
|
}
|
|
10671
9928
|
const hygiene = opts?.hygiene;
|
|
10672
|
-
const rotateEnabled = hygiene?.enabled === true && hygiene.rotateEnabled === true && Array.isArray(hygiene.rotatePaths) && hygiene.rotatePaths.includes(
|
|
9929
|
+
const rotateEnabled = hygiene?.enabled === true && hygiene.rotateEnabled === true && Array.isArray(hygiene.rotatePaths) && hygiene.rotatePaths.includes(path12.basename(identityPath));
|
|
10673
9930
|
if (rotateEnabled) {
|
|
10674
9931
|
const maxBytes = hygiene.rotateMaxBytes;
|
|
10675
9932
|
if (existing.length > maxBytes) {
|
|
10676
|
-
const archiveDir =
|
|
9933
|
+
const archiveDir = path12.join(workspaceDir, hygiene.archiveDir);
|
|
10677
9934
|
const { newContent } = await rotateMarkdownFileToArchive({
|
|
10678
9935
|
filePath: identityPath,
|
|
10679
9936
|
archiveDir,
|
|
10680
9937
|
archivePrefix: "IDENTITY",
|
|
10681
9938
|
keepTailChars: hygiene.rotateKeepTailChars
|
|
10682
9939
|
});
|
|
10683
|
-
await
|
|
9940
|
+
await writeFile(identityPath, newContent, "utf-8");
|
|
10684
9941
|
existing = newContent;
|
|
10685
9942
|
log.info(`rotated IDENTITY.md to archive (size=${existing.length} chars, maxBytes=${maxBytes})`);
|
|
10686
9943
|
}
|
|
@@ -10713,7 +9970,7 @@ ${question}
|
|
|
10713
9970
|
|
|
10714
9971
|
${reflection}
|
|
10715
9972
|
`;
|
|
10716
|
-
await
|
|
9973
|
+
await writeFile(identityPath, existing + section, "utf-8");
|
|
10717
9974
|
log.debug(`appended reflection to ${identityPath}`);
|
|
10718
9975
|
}
|
|
10719
9976
|
async readIdentityReflections() {
|
|
@@ -10933,7 +10190,7 @@ ${reflection}
|
|
|
10933
10190
|
if (entries.length === 0) return 0;
|
|
10934
10191
|
const memories = await this.readAllMemories();
|
|
10935
10192
|
const memoryMap = new Map(memories.map((m) => [m.frontmatter.id, m]));
|
|
10936
|
-
const memoryPathMap = new Map(memories.map((m) => [
|
|
10193
|
+
const memoryPathMap = new Map(memories.map((m) => [path12.resolve(m.path), m]));
|
|
10937
10194
|
let updated = 0;
|
|
10938
10195
|
const prevVersion = this.getMemoryCorpusVersion();
|
|
10939
10196
|
let entityRefMoved = false;
|
|
@@ -10941,7 +10198,7 @@ ${reflection}
|
|
|
10941
10198
|
const warm = this.hotMemoriesCacheEnabled && getCachedMemories(this.baseDir, prevVersion, keyId, this.hotCacheTtlMs()) !== null;
|
|
10942
10199
|
const appliedPatches = /* @__PURE__ */ new Map();
|
|
10943
10200
|
for (const entry of entries) {
|
|
10944
|
-
const memory = entry.memoryPath ? memoryPathMap.get(
|
|
10201
|
+
const memory = entry.memoryPath ? memoryPathMap.get(path12.resolve(entry.memoryPath)) : memoryMap.get(entry.memoryId);
|
|
10945
10202
|
if (!memory) continue;
|
|
10946
10203
|
try {
|
|
10947
10204
|
const applied = await this.withTombstoneBlockedMemoryPathLock(memory.path, async (current) => {
|
|
@@ -10973,7 +10230,7 @@ ${current.content}
|
|
|
10973
10230
|
if (warm) {
|
|
10974
10231
|
updateCacheOnWrite(this.baseDir, { ...applied.current, frontmatter: applied.newFm }, keyId);
|
|
10975
10232
|
}
|
|
10976
|
-
appliedPatches.set(
|
|
10233
|
+
appliedPatches.set(path12.resolve(memory.path), {
|
|
10977
10234
|
accessCount: entry.newCount,
|
|
10978
10235
|
lastAccessed: entry.lastAccessed
|
|
10979
10236
|
});
|
|
@@ -10991,7 +10248,7 @@ ${current.content}
|
|
|
10991
10248
|
const cur = getCachedMemories(this.baseDir, prevVersion, keyId);
|
|
10992
10249
|
if (cur) {
|
|
10993
10250
|
const reapplied = cur.map((m) => {
|
|
10994
|
-
const patch = appliedPatches.get(
|
|
10251
|
+
const patch = appliedPatches.get(path12.resolve(m.path));
|
|
10995
10252
|
return patch ? {
|
|
10996
10253
|
...m,
|
|
10997
10254
|
frontmatter: { ...m.frontmatter, accessCount: patch.accessCount, lastAccessed: patch.lastAccessed }
|
|
@@ -11021,7 +10278,7 @@ ${current.content}
|
|
|
11021
10278
|
const pathsById = /* @__PURE__ */ new Map();
|
|
11022
10279
|
const filePathsById = /* @__PURE__ */ new Map();
|
|
11023
10280
|
for (const filePath of filePaths) {
|
|
11024
|
-
const memoryId =
|
|
10281
|
+
const memoryId = path12.basename(filePath, ".md");
|
|
11025
10282
|
if (!wantedIds.has(memoryId)) continue;
|
|
11026
10283
|
const paths = filePathsById.get(memoryId) ?? [];
|
|
11027
10284
|
paths.push(filePath);
|
|
@@ -11033,7 +10290,7 @@ ${current.content}
|
|
|
11033
10290
|
const preferredMatches = [];
|
|
11034
10291
|
for (const preferredPath of preferred) {
|
|
11035
10292
|
const directCandidates = new Set(qmdResultPathCandidates(this.baseDir, preferredPath));
|
|
11036
|
-
const directMatch = existingPaths.find((filePath) => directCandidates.has(
|
|
10293
|
+
const directMatch = existingPaths.find((filePath) => directCandidates.has(path12.resolve(filePath)));
|
|
11037
10294
|
if (directMatch) {
|
|
11038
10295
|
preferredMatches.push(directMatch);
|
|
11039
10296
|
continue;
|
|
@@ -11045,7 +10302,7 @@ ${current.content}
|
|
|
11045
10302
|
candidates.add(candidate);
|
|
11046
10303
|
}
|
|
11047
10304
|
}
|
|
11048
|
-
const match = existingPaths.find((filePath) => candidates.has(
|
|
10305
|
+
const match = existingPaths.find((filePath) => candidates.has(path12.resolve(filePath)));
|
|
11049
10306
|
if (match) preferredMatches.push(match);
|
|
11050
10307
|
}
|
|
11051
10308
|
if (preferredMatches.length > 0) {
|
|
@@ -11236,7 +10493,7 @@ ${sanitized.text}
|
|
|
11236
10493
|
}
|
|
11237
10494
|
if (!oldMemory) return false;
|
|
11238
10495
|
const requireActiveAtWrite = options.requireActive === true || inferMemoryStatus(oldMemory.frontmatter, toMemoryPathRel(this.baseDir, oldMemory.path)) === "active";
|
|
11239
|
-
const operationId =
|
|
10496
|
+
const operationId = createHash5("sha256").update(
|
|
11240
10497
|
JSON.stringify({
|
|
11241
10498
|
oldMemoryId,
|
|
11242
10499
|
newMemoryId,
|
|
@@ -11367,21 +10624,21 @@ ${current.content}
|
|
|
11367
10624
|
}
|
|
11368
10625
|
}
|
|
11369
10626
|
get summariesDir() {
|
|
11370
|
-
return
|
|
10627
|
+
return path12.join(this.baseDir, "summaries");
|
|
11371
10628
|
}
|
|
11372
10629
|
async writeSummary(summary) {
|
|
11373
10630
|
await mkdir(this.summariesDir, { recursive: true });
|
|
11374
|
-
const filePath =
|
|
10631
|
+
const filePath = path12.join(this.summariesDir, `${summary.id}.json`);
|
|
11375
10632
|
await this.writeStorageSecureFile(filePath, JSON.stringify(summary, null, 2));
|
|
11376
10633
|
log.debug(`wrote summary ${summary.id}`);
|
|
11377
10634
|
}
|
|
11378
10635
|
async readSummaries() {
|
|
11379
10636
|
try {
|
|
11380
|
-
const files = await
|
|
10637
|
+
const files = await readdir5(this.summariesDir);
|
|
11381
10638
|
const summaries = [];
|
|
11382
10639
|
for (const file of files) {
|
|
11383
10640
|
if (isMacOsReplicationJunkBasename(file) || !file.endsWith(".json")) continue;
|
|
11384
|
-
const filePath =
|
|
10641
|
+
const filePath = path12.join(this.summariesDir, file);
|
|
11385
10642
|
const raw = await this.readStorageSecureFile(filePath);
|
|
11386
10643
|
summaries.push(JSON.parse(raw));
|
|
11387
10644
|
}
|
|
@@ -11451,7 +10708,7 @@ ${current.content}
|
|
|
11451
10708
|
return archived;
|
|
11452
10709
|
}
|
|
11453
10710
|
async saveTopics(topics) {
|
|
11454
|
-
const metaPath =
|
|
10711
|
+
const metaPath = path12.join(this.stateDir, "topics.json");
|
|
11455
10712
|
await mkdir(this.stateDir, { recursive: true });
|
|
11456
10713
|
await this.writeStorageSecureFile(
|
|
11457
10714
|
metaPath,
|
|
@@ -11460,7 +10717,7 @@ ${current.content}
|
|
|
11460
10717
|
log.debug(`saved ${topics.length} topic scores`);
|
|
11461
10718
|
}
|
|
11462
10719
|
async loadTopics() {
|
|
11463
|
-
const metaPath =
|
|
10720
|
+
const metaPath = path12.join(this.stateDir, "topics.json");
|
|
11464
10721
|
try {
|
|
11465
10722
|
const raw = await this.readStorageSecureFile(metaPath);
|
|
11466
10723
|
return JSON.parse(raw);
|
|
@@ -11579,4 +10836,4 @@ export {
|
|
|
11579
10836
|
isValidBufferSurpriseEvent,
|
|
11580
10837
|
StorageManager3 as StorageManager
|
|
11581
10838
|
};
|
|
11582
|
-
//# sourceMappingURL=chunk-
|
|
10839
|
+
//# sourceMappingURL=chunk-TTIEXXL3.js.map
|