@remnic/core 10.0.14 → 10.0.16
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/abstraction-nodes.js +3 -2
- package/dist/access-admin-ops-surface.js +34 -32
- package/dist/access-authorization-probe.js +35 -33
- package/dist/access-boundary.js +34 -32
- package/dist/access-cli.js +90 -88
- package/dist/access-cli.js.map +1 -1
- package/dist/access-extraction-force-flush.js +34 -32
- package/dist/access-http-briefing.js +35 -33
- package/dist/access-http-query.js +36 -34
- package/dist/access-http.js +53 -51
- package/dist/access-identity-continuity-surface.js +34 -32
- package/dist/access-lcm-surface.js +34 -32
- package/dist/access-mcp.js +45 -43
- package/dist/access-namespace-preflight.js +34 -32
- package/dist/access-observe-write-category.js +4 -3
- package/dist/access-observe-write-surface.js +34 -32
- package/dist/access-offline-manifest.js +3 -2
- package/dist/access-operations-batch.js +37 -35
- package/dist/access-operations.js +44 -42
- package/dist/access-recall-concurrency.js +34 -32
- package/dist/access-recall-response.js +34 -32
- package/dist/access-recall-surface.js +34 -32
- package/dist/access-schema.js +3 -2
- package/dist/access-service.js +34 -32
- package/dist/access-surface-catalog.js +36 -34
- package/dist/access-surface-catalog.js.map +1 -1
- package/dist/active-recall.js +14 -12
- package/dist/active-recall.js.map +1 -1
- package/dist/briefing.js +10 -8
- package/dist/buffer.js +2 -2
- package/dist/calibration.d.ts.map +1 -1
- package/dist/calibration.js +6 -3
- package/dist/calibration.js.map +1 -1
- package/dist/causal-behavior.js +4 -3
- package/dist/causal-behavior.js.map +1 -1
- package/dist/causal-chain.js +4 -3
- package/dist/causal-consolidation.js +14 -12
- package/dist/causal-consolidation.js.map +1 -1
- package/dist/causal-retrieval.js +4 -3
- package/dist/causal-retrieval.js.map +1 -1
- package/dist/causal-trajectory.js +3 -2
- package/dist/{chunk-63B2IZYE.js → chunk-23ZQPP2G.js} +6 -1
- package/dist/chunk-23ZQPP2G.js.map +1 -0
- package/dist/{chunk-YFMBHQRG.js → chunk-2PTH4PRL.js} +2 -2
- package/dist/{chunk-TITG2NBS.js → chunk-2PYHLSXK.js} +2 -2
- package/dist/{chunk-B6O2YLUR.js → chunk-2Z5DIDQD.js} +6 -1
- package/dist/chunk-2Z5DIDQD.js.map +1 -0
- package/dist/{chunk-KH2LKDX7.js → chunk-33G67YZF.js} +2 -2
- package/dist/{chunk-SWIKABKI.js → chunk-3Q3XD3NO.js} +2 -2
- package/dist/{chunk-4KY5GSMB.js → chunk-4PDTVVSW.js} +2 -2
- package/dist/{chunk-HM7RHKS4.js → chunk-4RNBLLZR.js} +2 -2
- package/dist/{chunk-PAZ35RJ4.js → chunk-4SCZZ3U7.js} +240 -55
- package/dist/chunk-4SCZZ3U7.js.map +1 -0
- package/dist/{chunk-Y4NKEXQT.js → chunk-5ATSXCAG.js} +3 -3
- package/dist/{chunk-JDZFIR2S.js → chunk-5KGYTX5O.js} +2 -2
- package/dist/{chunk-J7JWFZHI.js → chunk-5MLGY6IY.js} +39 -39
- package/dist/{chunk-NW2E4CI2.js → chunk-5SMR542T.js} +2 -2
- package/dist/{chunk-S7LWX2PQ.js → chunk-655FVTCD.js} +2 -2
- package/dist/{chunk-4OSG5Y6M.js → chunk-6YEPGWUP.js} +2 -2
- package/dist/{chunk-W47S5TIH.js → chunk-7VQ6AI7H.js} +2 -2
- package/dist/{chunk-WLMZ2L5P.js → chunk-AZDTDWS2.js} +2 -2
- package/dist/{chunk-G7NYVKD6.js → chunk-B2NXOVZN.js} +2 -2
- package/dist/{chunk-N7KYEVLK.js → chunk-BK2BVLZW.js} +2 -2
- package/dist/{chunk-QJ622LTI.js → chunk-BQOGQULP.js} +30 -8
- package/dist/chunk-BQOGQULP.js.map +1 -0
- package/dist/{chunk-S2I7DL5Q.js → chunk-C2RW36YR.js} +2 -2
- package/dist/{chunk-P5NQN4JE.js → chunk-C6JMGAMO.js} +6 -2
- package/dist/chunk-C6JMGAMO.js.map +1 -0
- package/dist/{chunk-6LG7BWKW.js → chunk-CFZ4SXXH.js} +2 -2
- package/dist/{chunk-JQ7XU625.js → chunk-CQOIWJ5E.js} +6 -6
- package/dist/{chunk-FSIMZNBC.js → chunk-CXOYUANR.js} +2 -2
- package/dist/{chunk-BLVHDY2U.js → chunk-DOWACHYO.js} +5 -2
- package/dist/chunk-DOWACHYO.js.map +1 -0
- package/dist/{chunk-QOZJCSFO.js → chunk-DQR2LD3V.js} +2 -2
- package/dist/{chunk-MATDGSJ7.js → chunk-DUPHIZBY.js} +2 -2
- package/dist/{chunk-EBA5DA77.js → chunk-EOU6V4IN.js} +2 -2
- package/dist/{chunk-5WCJLQTM.js → chunk-F2772ATT.js} +2 -2
- package/dist/{chunk-46EST7JO.js → chunk-F2XNSIPP.js} +2 -2
- package/dist/{chunk-PZHQWFR3.js → chunk-G3UUAQOD.js} +2 -2
- package/dist/{chunk-YE36AJL7.js → chunk-GCVDFX66.js} +2 -2
- package/dist/{chunk-ZV65I6ME.js → chunk-GFWRXPF6.js} +29 -26
- package/dist/chunk-GFWRXPF6.js.map +1 -0
- package/dist/{chunk-T2YX56QI.js → chunk-GQJKVQJR.js} +2 -2
- package/dist/{chunk-I7S55EOB.js → chunk-GUY6L6LL.js} +2 -2
- package/dist/{chunk-L5DAHSEZ.js → chunk-GWVNGDJW.js} +2 -2
- package/dist/{chunk-N45NEBOD.js → chunk-GZXXPCWJ.js} +3 -3
- package/dist/{chunk-EPJDSQHF.js → chunk-H5IUN433.js} +2 -2
- package/dist/{chunk-EUAIYYYR.js → chunk-H6FREOYX.js} +7 -7
- package/dist/{chunk-Q4E24IRR.js → chunk-HDN7IVIO.js} +14 -11
- package/dist/chunk-HDN7IVIO.js.map +1 -0
- package/dist/{chunk-T3FMRLWQ.js → chunk-HFSPY26A.js} +2 -2
- package/dist/{chunk-GH7AOMJD.js → chunk-IJMDBYCO.js} +2 -2
- package/dist/{chunk-4IHBN6WU.js → chunk-JKMIGCK6.js} +2 -2
- package/dist/{chunk-ROBHL3GL.js → chunk-JWX2Q6HS.js} +2 -2
- package/dist/{chunk-DPR2WTN3.js → chunk-JZTEOBOR.js} +16 -16
- package/dist/{chunk-4O6WRBGE.js → chunk-KJXP6RUG.js} +5 -1
- package/dist/chunk-KJXP6RUG.js.map +1 -0
- package/dist/{chunk-JIHMUOOS.js → chunk-KLJVTZ3R.js} +3 -3
- package/dist/{chunk-FP4JYE66.js → chunk-KW4AJ7T3.js} +2 -2
- package/dist/{chunk-NIRQGDYC.js → chunk-L5VCT7LU.js} +5 -1
- package/dist/chunk-L5VCT7LU.js.map +1 -0
- package/dist/{chunk-QODKDRSP.js → chunk-L6AZOEXV.js} +4 -4
- package/dist/{chunk-CLWBFR7Q.js → chunk-LO76EF3Y.js} +1 -1
- package/dist/chunk-LO76EF3Y.js.map +1 -0
- package/dist/{chunk-LS2FHUML.js → chunk-LQ5SS4OP.js} +3 -3
- package/dist/{chunk-SIIRTDJ4.js → chunk-LWFWZTWX.js} +2 -2
- package/dist/{chunk-BMWN7B3Y.js → chunk-LXATZLSC.js} +3 -3
- package/dist/{chunk-O4SGYW7H.js → chunk-MAVYEZKM.js} +2 -2
- package/dist/{chunk-B665A6BO.js → chunk-MJIOGYKX.js} +2 -2
- package/dist/{chunk-RTKV5XHL.js → chunk-MO6N4QYY.js} +2 -2
- package/dist/{chunk-N4C7QKOG.js → chunk-MWWAQXZ6.js} +2 -2
- package/dist/{chunk-LCKVXX5F.js → chunk-MXV2MY6C.js} +2 -2
- package/dist/{chunk-FFOVKNQV.js → chunk-NAGMQXWV.js} +2 -2
- package/dist/{chunk-ZJVMUBYF.js → chunk-NHUX6GXA.js} +6 -6
- package/dist/{chunk-CB6ANA2I.js → chunk-NZCKG25S.js} +2 -2
- package/dist/{chunk-UMTCNEVQ.js → chunk-O2YPCFJT.js} +11 -11
- package/dist/{chunk-WSGPFRBH.js → chunk-OMERTLB7.js} +3 -3
- package/dist/{chunk-QX6JN3O4.js → chunk-PEF5LHQU.js} +6 -6
- package/dist/{chunk-JYZSRNR7.js → chunk-PIITB2YZ.js} +2 -2
- package/dist/chunk-PPUNC7UX.js +73 -0
- package/dist/chunk-PPUNC7UX.js.map +1 -0
- package/dist/{chunk-EQWEIIKQ.js → chunk-PQM3B54K.js} +6 -1
- package/dist/chunk-PQM3B54K.js.map +1 -0
- package/dist/{chunk-UQDG3YLN.js → chunk-PRU7OF3Y.js} +3 -3
- package/dist/{chunk-EU534WGS.js → chunk-PVHQSLNN.js} +7 -7
- package/dist/{chunk-TZNDKTX5.js → chunk-Q7DWEXG2.js} +37 -33
- package/dist/chunk-Q7DWEXG2.js.map +1 -0
- package/dist/{chunk-5VC7J76U.js → chunk-QPH52AZB.js} +2 -2
- package/dist/{chunk-XISROV24.js → chunk-QSEUUQUF.js} +2 -2
- package/dist/chunk-QUIRIG2P.js +31 -0
- package/dist/chunk-QUIRIG2P.js.map +1 -0
- package/dist/{chunk-FUFAXVBA.js → chunk-RI2KCQHP.js} +6 -2
- package/dist/chunk-RI2KCQHP.js.map +1 -0
- package/dist/{chunk-O2IPAX26.js → chunk-RTTPBBAN.js} +4 -4
- package/dist/{chunk-W5MCEVUS.js → chunk-RYYVMZBR.js} +2 -2
- package/dist/{chunk-ZSH2NRDV.js → chunk-TN4EA4X4.js} +2 -2
- package/dist/{chunk-SS3IS2JR.js → chunk-UGYUBENJ.js} +2 -2
- package/dist/{chunk-GELS5Z5Z.js → chunk-V3TXIXXY.js} +3 -3
- package/dist/{chunk-WVADKFWV.js → chunk-VNZMZPAC.js} +2 -2
- package/dist/{chunk-JPTPS4OB.js → chunk-VPXIKBPX.js} +2 -2
- package/dist/{chunk-OP6N4H6A.js → chunk-W3FVQBGF.js} +2 -2
- package/dist/{chunk-W3K3HITK.js → chunk-WLT6LTQP.js} +2 -2
- package/dist/{chunk-GMXWTJNU.js → chunk-XKRXN63M.js} +2 -2
- package/dist/{chunk-KR6ZKECI.js → chunk-XYGQSDTH.js} +3 -3
- package/dist/{chunk-22W2XWGH.js → chunk-YBO2WGCV.js} +2 -2
- package/dist/{chunk-P7TOIOT7.js → chunk-YR4COAEC.js} +2 -2
- package/dist/{chunk-6WHJ2EAB.js → chunk-Z64TS5V4.js} +2 -2
- package/dist/{chunk-NHLLKEKK.js → chunk-ZAJLJ35W.js} +2 -2
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +73 -71
- package/dist/coding/export-okf-codegraph.js +9 -7
- package/dist/coding/export-okf-codegraph.js.map +1 -1
- package/dist/coding/pre-action-gate.js +4 -3
- package/dist/commitment-ledger.js +3 -2
- package/dist/compounding/engine.js +11 -9
- package/dist/config.js +14 -12
- package/dist/connectors/codex-materialize-runner.js +10 -8
- package/dist/connectors/index.js +10 -8
- package/dist/consolidation-provenance-check.d.ts.map +1 -1
- package/dist/consolidation-provenance-check.js +2 -1
- package/dist/contradiction/index.js +3 -2
- package/dist/convergence-refresh.js +12 -10
- package/dist/corpus-watermark.js +12 -10
- package/dist/correction/correction-planner.d.ts.map +1 -1
- package/dist/cue-anchors.js +4 -3
- package/dist/deep-recall-http-glue.js +4 -3
- package/dist/{dreams-ledger-567VKVOU.js → dreams-ledger-UCHHRQ4R.js} +3 -2
- package/dist/entity-retrieval.js +10 -8
- package/dist/eval-trajectory-store.js +4 -3
- package/dist/eval-trajectory.js +4 -3
- package/dist/evals.js +3 -2
- package/dist/external-wiki-access.js +35 -33
- package/dist/extraction.js +14 -12
- package/dist/{first-start-migration-6A5BJPDW.js → first-start-migration-QVD22WWS.js} +6 -5
- package/dist/{first-start-migration-6A5BJPDW.js.map → first-start-migration-QVD22WWS.js.map} +1 -1
- package/dist/harmonic-construction.js +5 -4
- package/dist/harmonic-retrieval.js +14 -12
- package/dist/harmonic-source-lookup.js +3 -2
- package/dist/index.js +90 -88
- package/dist/json-store.d.ts.map +1 -1
- package/dist/json-store.js +2 -1
- package/dist/location/index.js +12 -10
- package/dist/maintenance/dreams-ledger.d.ts.map +1 -1
- package/dist/maintenance/memory-governance.d.ts.map +1 -1
- package/dist/maintenance/memory-governance.js +10 -8
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +10 -8
- package/dist/maintenance/rebuild-memory-projection-runner.js +12 -10
- package/dist/maintenance/rebuild-memory-projection.js +11 -9
- package/dist/memory-browse-operations.js +35 -33
- package/dist/namespaces/migrate.js +11 -9
- package/dist/namespaces/search.js +7 -6
- package/dist/namespaces/storage.d.ts.map +1 -1
- package/dist/namespaces/storage.js +10 -8
- package/dist/objective-state-writers.js +4 -3
- package/dist/objective-state.js +3 -2
- package/dist/offline-sync-snapshot-stream.js +3 -2
- package/dist/offline-sync.d.ts.map +1 -1
- package/dist/offline-sync.js +2 -1
- package/dist/operator-doctor-corpus.js +13 -11
- package/dist/operator-toolkit.js +25 -23
- package/dist/orchestration/extraction-run.d.ts +6 -20
- package/dist/orchestration/extraction-run.d.ts.map +1 -1
- package/dist/orchestration/maintenance.js +20 -18
- package/dist/orchestrator.js +90 -88
- package/dist/profiling.d.ts.map +1 -1
- package/dist/profiling.js +2 -1
- package/dist/recall-navigation-operations.js +35 -33
- package/dist/recall-navigation.js +34 -32
- package/dist/{resolution-7AY36LGJ.js → resolution-ZU5BIAJA.js} +4 -3
- package/dist/resume-bundles.js +19 -17
- package/dist/retrieval-agents.d.ts +1 -1
- package/dist/retrieval-agents.d.ts.map +1 -1
- package/dist/retrieval-agents.js +7 -1
- package/dist/search/document-scanner.d.ts.map +1 -1
- package/dist/search/document-scanner.js +2 -1
- package/dist/search/factory.js +6 -5
- package/dist/search/index.js +6 -5
- package/dist/search/lancedb-backend.js +3 -2
- package/dist/search/meilisearch-backend.js +3 -2
- package/dist/search/orama-backend.js +3 -2
- package/dist/semantic-consolidation.js +11 -9
- package/dist/semantic-rule-promotion.js +10 -8
- package/dist/semantic-rule-verifier.js +10 -8
- package/dist/source-agent-qualifier.js +12 -10
- package/dist/standup/build.js +10 -8
- package/dist/storage/entity-canonical-id-migration.d.ts.map +1 -1
- package/dist/storage/entity-store.d.ts +32 -1
- package/dist/storage/entity-store.d.ts.map +1 -1
- package/dist/storage/memory-read-store.d.ts.map +1 -1
- package/dist/storage/supersession-audit.d.ts.map +1 -1
- package/dist/storage.d.ts.map +1 -1
- package/dist/storage.js +9 -7
- package/dist/support-passport/index.js +37 -35
- package/dist/{tier-stats-RQM76XYY.js → tier-stats-C3IAMS4X.js} +6 -5
- package/dist/{tier-stats-RQM76XYY.js.map → tier-stats-C3IAMS4X.js.map} +1 -1
- package/dist/transcript.d.ts.map +1 -1
- package/dist/transcript.js +2 -1
- package/dist/transfer/export-okf.js +10 -8
- package/dist/trust-zones.js +3 -2
- package/dist/utility-learner.js +4 -3
- package/dist/utility-runtime.js +5 -4
- package/dist/utility-telemetry.js +3 -2
- package/dist/utils/macos-replication-junk.d.ts +32 -0
- package/dist/utils/macos-replication-junk.d.ts.map +1 -0
- package/dist/utils/malformed-entity-record.d.ts +24 -0
- package/dist/utils/malformed-entity-record.d.ts.map +1 -0
- package/dist/verified-recall.js +10 -8
- package/dist/who-knows-cli.js +11 -9
- package/dist/who-knows.js +10 -8
- package/dist/work-product-ledger.js +3 -2
- package/package.json +2 -2
- package/src/calibration.ts +3 -2
- package/src/cli.ts +2 -2
- package/src/consolidation-provenance-check.ts +2 -0
- package/src/correction/correction-planner.ts +3 -2
- package/src/json-store.ts +3 -0
- package/src/macos-replication-junk-scanners.test.ts +275 -0
- package/src/maintenance/dreams-ledger.ts +2 -0
- package/src/maintenance/memory-governance.ts +2 -0
- package/src/namespaces/storage.ts +2 -0
- package/src/offline-sync-macos-junk.test.ts +169 -0
- package/src/offline-sync.ts +7 -0
- package/src/orchestration/extraction-run.ts +6 -20
- package/src/profiling.ts +2 -1
- package/src/retrieval-agents.ts +29 -12
- package/src/search/document-scanner.ts +4 -0
- package/src/storage/entity-canonical-id-migration.ts +56 -13
- package/src/storage/entity-store.ts +173 -15
- package/src/storage/memory-read-store.ts +30 -5
- package/src/storage/supersession-audit.ts +2 -0
- package/src/storage.ts +3 -2
- package/src/transcript.ts +11 -10
- package/src/utils/macos-replication-junk.test.ts +46 -0
- package/src/utils/macos-replication-junk.ts +65 -0
- package/src/utils/malformed-entity-record.ts +101 -0
- package/dist/chunk-4O6WRBGE.js.map +0 -1
- package/dist/chunk-63B2IZYE.js.map +0 -1
- package/dist/chunk-B6O2YLUR.js.map +0 -1
- package/dist/chunk-BLVHDY2U.js.map +0 -1
- package/dist/chunk-CLWBFR7Q.js.map +0 -1
- package/dist/chunk-EQWEIIKQ.js.map +0 -1
- package/dist/chunk-FUFAXVBA.js.map +0 -1
- package/dist/chunk-NIRQGDYC.js.map +0 -1
- package/dist/chunk-P5NQN4JE.js.map +0 -1
- package/dist/chunk-PAZ35RJ4.js.map +0 -1
- package/dist/chunk-Q4E24IRR.js.map +0 -1
- package/dist/chunk-QJ622LTI.js.map +0 -1
- package/dist/chunk-TZNDKTX5.js.map +0 -1
- package/dist/chunk-ZV65I6ME.js.map +0 -1
- /package/dist/{chunk-YFMBHQRG.js.map → chunk-2PTH4PRL.js.map} +0 -0
- /package/dist/{chunk-TITG2NBS.js.map → chunk-2PYHLSXK.js.map} +0 -0
- /package/dist/{chunk-KH2LKDX7.js.map → chunk-33G67YZF.js.map} +0 -0
- /package/dist/{chunk-SWIKABKI.js.map → chunk-3Q3XD3NO.js.map} +0 -0
- /package/dist/{chunk-4KY5GSMB.js.map → chunk-4PDTVVSW.js.map} +0 -0
- /package/dist/{chunk-HM7RHKS4.js.map → chunk-4RNBLLZR.js.map} +0 -0
- /package/dist/{chunk-Y4NKEXQT.js.map → chunk-5ATSXCAG.js.map} +0 -0
- /package/dist/{chunk-JDZFIR2S.js.map → chunk-5KGYTX5O.js.map} +0 -0
- /package/dist/{chunk-J7JWFZHI.js.map → chunk-5MLGY6IY.js.map} +0 -0
- /package/dist/{chunk-NW2E4CI2.js.map → chunk-5SMR542T.js.map} +0 -0
- /package/dist/{chunk-S7LWX2PQ.js.map → chunk-655FVTCD.js.map} +0 -0
- /package/dist/{chunk-4OSG5Y6M.js.map → chunk-6YEPGWUP.js.map} +0 -0
- /package/dist/{chunk-W47S5TIH.js.map → chunk-7VQ6AI7H.js.map} +0 -0
- /package/dist/{chunk-WLMZ2L5P.js.map → chunk-AZDTDWS2.js.map} +0 -0
- /package/dist/{chunk-G7NYVKD6.js.map → chunk-B2NXOVZN.js.map} +0 -0
- /package/dist/{chunk-N7KYEVLK.js.map → chunk-BK2BVLZW.js.map} +0 -0
- /package/dist/{chunk-S2I7DL5Q.js.map → chunk-C2RW36YR.js.map} +0 -0
- /package/dist/{chunk-6LG7BWKW.js.map → chunk-CFZ4SXXH.js.map} +0 -0
- /package/dist/{chunk-JQ7XU625.js.map → chunk-CQOIWJ5E.js.map} +0 -0
- /package/dist/{chunk-FSIMZNBC.js.map → chunk-CXOYUANR.js.map} +0 -0
- /package/dist/{chunk-QOZJCSFO.js.map → chunk-DQR2LD3V.js.map} +0 -0
- /package/dist/{chunk-MATDGSJ7.js.map → chunk-DUPHIZBY.js.map} +0 -0
- /package/dist/{chunk-EBA5DA77.js.map → chunk-EOU6V4IN.js.map} +0 -0
- /package/dist/{chunk-5WCJLQTM.js.map → chunk-F2772ATT.js.map} +0 -0
- /package/dist/{chunk-46EST7JO.js.map → chunk-F2XNSIPP.js.map} +0 -0
- /package/dist/{chunk-PZHQWFR3.js.map → chunk-G3UUAQOD.js.map} +0 -0
- /package/dist/{chunk-YE36AJL7.js.map → chunk-GCVDFX66.js.map} +0 -0
- /package/dist/{chunk-T2YX56QI.js.map → chunk-GQJKVQJR.js.map} +0 -0
- /package/dist/{chunk-I7S55EOB.js.map → chunk-GUY6L6LL.js.map} +0 -0
- /package/dist/{chunk-L5DAHSEZ.js.map → chunk-GWVNGDJW.js.map} +0 -0
- /package/dist/{chunk-N45NEBOD.js.map → chunk-GZXXPCWJ.js.map} +0 -0
- /package/dist/{chunk-EPJDSQHF.js.map → chunk-H5IUN433.js.map} +0 -0
- /package/dist/{chunk-EUAIYYYR.js.map → chunk-H6FREOYX.js.map} +0 -0
- /package/dist/{chunk-T3FMRLWQ.js.map → chunk-HFSPY26A.js.map} +0 -0
- /package/dist/{chunk-GH7AOMJD.js.map → chunk-IJMDBYCO.js.map} +0 -0
- /package/dist/{chunk-4IHBN6WU.js.map → chunk-JKMIGCK6.js.map} +0 -0
- /package/dist/{chunk-ROBHL3GL.js.map → chunk-JWX2Q6HS.js.map} +0 -0
- /package/dist/{chunk-DPR2WTN3.js.map → chunk-JZTEOBOR.js.map} +0 -0
- /package/dist/{chunk-JIHMUOOS.js.map → chunk-KLJVTZ3R.js.map} +0 -0
- /package/dist/{chunk-FP4JYE66.js.map → chunk-KW4AJ7T3.js.map} +0 -0
- /package/dist/{chunk-QODKDRSP.js.map → chunk-L6AZOEXV.js.map} +0 -0
- /package/dist/{chunk-LS2FHUML.js.map → chunk-LQ5SS4OP.js.map} +0 -0
- /package/dist/{chunk-SIIRTDJ4.js.map → chunk-LWFWZTWX.js.map} +0 -0
- /package/dist/{chunk-BMWN7B3Y.js.map → chunk-LXATZLSC.js.map} +0 -0
- /package/dist/{chunk-O4SGYW7H.js.map → chunk-MAVYEZKM.js.map} +0 -0
- /package/dist/{chunk-B665A6BO.js.map → chunk-MJIOGYKX.js.map} +0 -0
- /package/dist/{chunk-RTKV5XHL.js.map → chunk-MO6N4QYY.js.map} +0 -0
- /package/dist/{chunk-N4C7QKOG.js.map → chunk-MWWAQXZ6.js.map} +0 -0
- /package/dist/{chunk-LCKVXX5F.js.map → chunk-MXV2MY6C.js.map} +0 -0
- /package/dist/{chunk-FFOVKNQV.js.map → chunk-NAGMQXWV.js.map} +0 -0
- /package/dist/{chunk-ZJVMUBYF.js.map → chunk-NHUX6GXA.js.map} +0 -0
- /package/dist/{chunk-CB6ANA2I.js.map → chunk-NZCKG25S.js.map} +0 -0
- /package/dist/{chunk-UMTCNEVQ.js.map → chunk-O2YPCFJT.js.map} +0 -0
- /package/dist/{chunk-WSGPFRBH.js.map → chunk-OMERTLB7.js.map} +0 -0
- /package/dist/{chunk-QX6JN3O4.js.map → chunk-PEF5LHQU.js.map} +0 -0
- /package/dist/{chunk-JYZSRNR7.js.map → chunk-PIITB2YZ.js.map} +0 -0
- /package/dist/{chunk-UQDG3YLN.js.map → chunk-PRU7OF3Y.js.map} +0 -0
- /package/dist/{chunk-EU534WGS.js.map → chunk-PVHQSLNN.js.map} +0 -0
- /package/dist/{chunk-5VC7J76U.js.map → chunk-QPH52AZB.js.map} +0 -0
- /package/dist/{chunk-XISROV24.js.map → chunk-QSEUUQUF.js.map} +0 -0
- /package/dist/{chunk-O2IPAX26.js.map → chunk-RTTPBBAN.js.map} +0 -0
- /package/dist/{chunk-W5MCEVUS.js.map → chunk-RYYVMZBR.js.map} +0 -0
- /package/dist/{chunk-ZSH2NRDV.js.map → chunk-TN4EA4X4.js.map} +0 -0
- /package/dist/{chunk-SS3IS2JR.js.map → chunk-UGYUBENJ.js.map} +0 -0
- /package/dist/{chunk-GELS5Z5Z.js.map → chunk-V3TXIXXY.js.map} +0 -0
- /package/dist/{chunk-WVADKFWV.js.map → chunk-VNZMZPAC.js.map} +0 -0
- /package/dist/{chunk-JPTPS4OB.js.map → chunk-VPXIKBPX.js.map} +0 -0
- /package/dist/{chunk-OP6N4H6A.js.map → chunk-W3FVQBGF.js.map} +0 -0
- /package/dist/{chunk-W3K3HITK.js.map → chunk-WLT6LTQP.js.map} +0 -0
- /package/dist/{chunk-GMXWTJNU.js.map → chunk-XKRXN63M.js.map} +0 -0
- /package/dist/{chunk-KR6ZKECI.js.map → chunk-XYGQSDTH.js.map} +0 -0
- /package/dist/{chunk-22W2XWGH.js.map → chunk-YBO2WGCV.js.map} +0 -0
- /package/dist/{chunk-P7TOIOT7.js.map → chunk-YR4COAEC.js.map} +0 -0
- /package/dist/{chunk-6WHJ2EAB.js.map → chunk-Z64TS5V4.js.map} +0 -0
- /package/dist/{chunk-NHLLKEKK.js.map → chunk-ZAJLJ35W.js.map} +0 -0
- /package/dist/{dreams-ledger-567VKVOU.js.map → dreams-ledger-UCHHRQ4R.js.map} +0 -0
- /package/dist/{resolution-7AY36LGJ.js.map → resolution-ZU5BIAJA.js.map} +0 -0
|
@@ -22,6 +22,11 @@ import { RECALL_FALLBACK_DIRS } from "../utils/category-dir.js";
|
|
|
22
22
|
import { assertPathInsideRoot } from "../utils/path-containment.js";
|
|
23
23
|
import { withEntityCanonicalMutationLock } from "./entity-canonical-id-lock.js";
|
|
24
24
|
import { assertSafeEntityId } from "./entity-id-safety.js";
|
|
25
|
+
import { isMalformedEntityRecord } from "../utils/malformed-entity-record.js";
|
|
26
|
+
import {
|
|
27
|
+
isMacOsReplicationJunkBasename,
|
|
28
|
+
warnIgnoredMacOsReplicationJunk,
|
|
29
|
+
} from "../utils/macos-replication-junk.js";
|
|
25
30
|
|
|
26
31
|
import {
|
|
27
32
|
ENTITY_CANONICAL_ID_MIGRATION_FILE,
|
|
@@ -100,7 +105,7 @@ async function fingerprintEntityEntries(entitiesDir: string): Promise<string> {
|
|
|
100
105
|
let names: string[];
|
|
101
106
|
try {
|
|
102
107
|
names = (await readdir(entitiesDir))
|
|
103
|
-
.filter((name) => path.extname(name) === ".md")
|
|
108
|
+
.filter((name) => path.extname(name) === ".md" && !isMacOsReplicationJunkBasename(name))
|
|
104
109
|
.sort();
|
|
105
110
|
} catch (error) {
|
|
106
111
|
if (isErrnoCode(error, "ENOENT")) return "missing";
|
|
@@ -386,10 +391,16 @@ async function readSafeEntityEntries(entitiesDir: string): Promise<string[]> {
|
|
|
386
391
|
*/
|
|
387
392
|
export type BlockedEntityPairs = Map<string, string>;
|
|
388
393
|
|
|
394
|
+
interface EntityScanNotes {
|
|
395
|
+
junk: Set<string>;
|
|
396
|
+
malformed: Set<string>;
|
|
397
|
+
}
|
|
398
|
+
|
|
389
399
|
async function discoverMappings(
|
|
390
400
|
deps: EntityCanonicalIdMigrationDependencies,
|
|
391
401
|
knownMappings: Readonly<Record<string, string>> = {},
|
|
392
402
|
blocked: BlockedEntityPairs = new Map(),
|
|
403
|
+
scanNotes?: EntityScanNotes,
|
|
393
404
|
): Promise<Record<string, string>> {
|
|
394
405
|
const mappings: Record<string, string> = {};
|
|
395
406
|
const canonicalOwners = new Map<string, string[]>();
|
|
@@ -401,21 +412,29 @@ async function discoverMappings(
|
|
|
401
412
|
blocked.clear();
|
|
402
413
|
const entityEntries = await readSafeEntityEntries(deps.entitiesDir);
|
|
403
414
|
for (const entry of entityEntries) {
|
|
415
|
+
// AppleDouble (`._*`) and `.DS_Store` are Finder metadata, not entity
|
|
416
|
+
// files. A real file that cannot be parsed is left in place: this scan
|
|
417
|
+
// runs during directory init, and aborting it took the daemon down.
|
|
418
|
+
// Skipping is the same outcome as the old throw (the file is not
|
|
419
|
+
// rewritten) without refusing to boot. Symlink checks above still run.
|
|
420
|
+
if (isMacOsReplicationJunkBasename(entry)) {
|
|
421
|
+
scanNotes?.junk.add(entry);
|
|
422
|
+
continue;
|
|
423
|
+
}
|
|
404
424
|
if (!entry.endsWith(".md")) continue;
|
|
405
425
|
const legacyId = entry.slice(0, -".md".length);
|
|
406
426
|
assertSafeEntityId(legacyId);
|
|
407
427
|
const legacyPath = deps.resolveEntityFilePath(legacyId);
|
|
408
428
|
if (legacyPath === null) continue;
|
|
409
429
|
const entityContent = await deps.readStorageSecureFile(legacyPath);
|
|
410
|
-
if (
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
) {
|
|
414
|
-
throw new Error(`Cannot migrate malformed entity file ${entry}: missing name heading or type.`);
|
|
430
|
+
if (isMalformedEntityRecord(entityContent)) {
|
|
431
|
+
scanNotes?.malformed.add(entry);
|
|
432
|
+
continue;
|
|
415
433
|
}
|
|
416
434
|
const entity = deps.parseEntityFile(entityContent);
|
|
417
435
|
if (!entity.name.trim() || !entity.type.trim()) {
|
|
418
|
-
|
|
436
|
+
scanNotes?.malformed.add(entry);
|
|
437
|
+
continue;
|
|
419
438
|
}
|
|
420
439
|
const canonicalId = deps.normalizeEntityName(entity.name, entity.type);
|
|
421
440
|
assertSafeEntityId(canonicalId);
|
|
@@ -596,12 +615,14 @@ async function rewriteRelationshipTargets(
|
|
|
596
615
|
let rewritten = false;
|
|
597
616
|
const entries = await readSafeEntityEntries(deps.entitiesDir);
|
|
598
617
|
for (const entry of entries) {
|
|
599
|
-
if (!entry.endsWith(".md")) continue;
|
|
618
|
+
if (!entry.endsWith(".md") || isMacOsReplicationJunkBasename(entry)) continue;
|
|
600
619
|
const entityPath = deps.resolveEntityFilePath(entry.slice(0, -".md".length));
|
|
601
620
|
if (entityPath === null) continue;
|
|
602
621
|
const observedEntityFingerprint = await fingerprintPath(entityPath);
|
|
603
622
|
if (observedEntityFingerprint === "missing") continue;
|
|
604
|
-
const
|
|
623
|
+
const entityRaw = await deps.readStorageSecureFile(entityPath);
|
|
624
|
+
if (isMalformedEntityRecord(entityRaw)) continue;
|
|
625
|
+
const entity = deps.parseEntityFile(entityRaw);
|
|
605
626
|
const relationships = entity.relationships.map((relationship) => {
|
|
606
627
|
const target = mappings[relationship.target];
|
|
607
628
|
return target ? { ...relationship, target } : relationship;
|
|
@@ -611,7 +632,9 @@ async function rewriteRelationshipTargets(
|
|
|
611
632
|
deps.stateDir,
|
|
612
633
|
async (refreshEntityLock) => {
|
|
613
634
|
if (!(await refreshLock())) throw new Error("Lost entity canonical-id migration lock.");
|
|
614
|
-
const
|
|
635
|
+
const latestRaw = await deps.readStorageSecureFile(entityPath);
|
|
636
|
+
if (isMalformedEntityRecord(latestRaw)) return false;
|
|
637
|
+
const latestEntity = deps.parseEntityFile(latestRaw);
|
|
615
638
|
if ((await fingerprintPath(entityPath)) !== observedEntityFingerprint) return false;
|
|
616
639
|
const latestRelationships = latestEntity.relationships.map((relationship) => {
|
|
617
640
|
const target = mappings[relationship.target];
|
|
@@ -794,6 +817,15 @@ async function migrateEntityFilePair(
|
|
|
794
817
|
const entityContent = await deps.readStorageSecureFile(legacyPath);
|
|
795
818
|
await assertNotSymlink(legacyPath, legacyId);
|
|
796
819
|
await assertEntityContentUnchanged(deps, legacyPath, entityContent, legacyId);
|
|
820
|
+
// A journal entry must not relocate Finder metadata or a record this scan
|
|
821
|
+
// would leave in place. readStorageSecureFile has already decrypted, so
|
|
822
|
+
// the check is on that plaintext. The mapping stays for a later repair.
|
|
823
|
+
if (
|
|
824
|
+
isMacOsReplicationJunkBasename(path.basename(legacyPath))
|
|
825
|
+
|| isMalformedEntityRecord(entityContent)
|
|
826
|
+
) {
|
|
827
|
+
return { deferred: false, progressed: false };
|
|
828
|
+
}
|
|
797
829
|
let canonicalFingerprintAfterWrite: string | null = null;
|
|
798
830
|
try {
|
|
799
831
|
await deps.writeStorageSecureFile(canonicalPath, entityContent, entityEncrypted);
|
|
@@ -864,6 +896,7 @@ export async function migrateLegacyEntityCanonicalIds(
|
|
|
864
896
|
};
|
|
865
897
|
}
|
|
866
898
|
const blocked: BlockedEntityPairs = new Map();
|
|
899
|
+
const scanNotes: EntityScanNotes = { junk: new Set(), malformed: new Set() };
|
|
867
900
|
// Parks for pairs whose files are GONE, tracked separately from
|
|
868
901
|
// collision parks: pruneBlocked drops these (the canonical file is gone
|
|
869
902
|
// too), and the rescan's blocked.clear() would otherwise silence them
|
|
@@ -886,6 +919,16 @@ export async function migrateLegacyEntityCanonicalIds(
|
|
|
886
919
|
+ "The stale journal entries were removed; references to those legacy ids do not resolve either way.",
|
|
887
920
|
);
|
|
888
921
|
}
|
|
922
|
+
warnIgnoredMacOsReplicationJunk(deps.entitiesDir, scanNotes.junk.size, (message) => {
|
|
923
|
+
log.warn(`entity canonical-id migration ${message}`);
|
|
924
|
+
});
|
|
925
|
+
if (scanNotes.malformed.size > 0) {
|
|
926
|
+
const names = [...scanNotes.malformed].sort().join(", ");
|
|
927
|
+
log.warn(
|
|
928
|
+
`entity canonical-id migration skipped ${scanNotes.malformed.size} malformed entity file(s): ${names}. `
|
|
929
|
+
+ "Each file was left in place; startup continues. Fix or remove the file to migrate it.",
|
|
930
|
+
);
|
|
931
|
+
}
|
|
889
932
|
// Every finish() path either just rewrote references (main/reconcile
|
|
890
933
|
// paths), has none to rewrite (empty mappings), or observed no marker
|
|
891
934
|
// (stable no-op) — so the CONSUMED generation is removed here. A fresh
|
|
@@ -997,7 +1040,7 @@ export async function migrateLegacyEntityCanonicalIds(
|
|
|
997
1040
|
if (!(await lock.refresh())) throw new Error("Lost entity canonical-id migration lock.");
|
|
998
1041
|
const discoveredBefore = rejectMappingCycles(
|
|
999
1042
|
state.mappings,
|
|
1000
|
-
await discoverMappings(deps, state.mappings, blocked),
|
|
1043
|
+
await discoverMappings(deps, state.mappings, blocked, scanNotes),
|
|
1001
1044
|
);
|
|
1002
1045
|
const revivedBefore = await pruneBlocked();
|
|
1003
1046
|
const mergedBefore = collapseMappings(mergeDiscoveredMappings(state.mappings, discoveredBefore));
|
|
@@ -1046,7 +1089,7 @@ export async function migrateLegacyEntityCanonicalIds(
|
|
|
1046
1089
|
if (!(await lock.refresh())) throw new Error("Lost entity canonical-id migration lock.");
|
|
1047
1090
|
const discoveredAfter = rejectMappingCycles(
|
|
1048
1091
|
state.mappings,
|
|
1049
|
-
await discoverMappings(deps, state.mappings, blocked),
|
|
1092
|
+
await discoverMappings(deps, state.mappings, blocked, scanNotes),
|
|
1050
1093
|
);
|
|
1051
1094
|
// Reconcile before declaring completion: this rescan can resolve a
|
|
1052
1095
|
// park (another writer removed the legacy file), and completing
|
|
@@ -1107,7 +1150,7 @@ export async function migrateLegacyEntityCanonicalIds(
|
|
|
1107
1150
|
if (!(await lock.refresh())) throw new Error("Lost entity canonical-id migration lock.");
|
|
1108
1151
|
const discoveredAfter = rejectMappingCycles(
|
|
1109
1152
|
state.mappings,
|
|
1110
|
-
await discoverMappings(deps, state.mappings, blocked),
|
|
1153
|
+
await discoverMappings(deps, state.mappings, blocked, scanNotes),
|
|
1111
1154
|
);
|
|
1112
1155
|
// A park resolved after the rewrite pass is promoted here, and a
|
|
1113
1156
|
// promotion still has to be APPLIED. Completing on `discoveredAfter`
|
|
@@ -10,12 +10,17 @@
|
|
|
10
10
|
* - fragmented-entity merge (consolidation)
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
import { readdir, unlink } from "node:fs/promises";
|
|
13
|
+
import { lstat, readdir, realpath, unlink } from "node:fs/promises";
|
|
14
14
|
import path from "node:path";
|
|
15
15
|
import { checkCorpusReadAbort, type CorpusReadOptions } from "../corpus-read-cancellation.js";
|
|
16
16
|
import { normalizeEntityStructuredSection, sortStructuredSectionsBySchema } from "../entity-schema.js";
|
|
17
17
|
import { withEntityCanonicalMutationLock } from "./entity-canonical-id-lock.js";
|
|
18
|
+
import { isMalformedEntityRecord } from "../utils/malformed-entity-record.js";
|
|
18
19
|
import { log } from "../logger.js";
|
|
20
|
+
import {
|
|
21
|
+
warnIgnoredMacOsReplicationJunk,
|
|
22
|
+
withoutMacOsReplicationJunk,
|
|
23
|
+
} from "../utils/macos-replication-junk.js";
|
|
19
24
|
import { getCachedEntities, setCachedEntities } from "../memory-cache.js";
|
|
20
25
|
import type { VersionTrigger } from "../page-versioning.js";
|
|
21
26
|
import { SecureStoreLockedError } from "../secure-store/secure-fs.js";
|
|
@@ -28,6 +33,7 @@ import type {
|
|
|
28
33
|
ScoredEntity,
|
|
29
34
|
} from "../types.js";
|
|
30
35
|
import { isErrnoCode } from "../utils/errno.js";
|
|
36
|
+
import { pathIsInside } from "../utils/path-containment.js";
|
|
31
37
|
import {
|
|
32
38
|
reconcileIfJournalMovedSync,
|
|
33
39
|
requestEntityCanonicalIdReconcileSync,
|
|
@@ -79,6 +85,9 @@ export interface EntityStoreDeps {
|
|
|
79
85
|
}
|
|
80
86
|
|
|
81
87
|
export class EntityStore {
|
|
88
|
+
/** Filename → file identity of the last indexable check. Unchanged files are not reread. */
|
|
89
|
+
private readonly entityIndexableCache = new Map<string, { identity: string; ok: boolean }>();
|
|
90
|
+
|
|
82
91
|
constructor(
|
|
83
92
|
private readonly deps: EntityStoreDeps,
|
|
84
93
|
) {}
|
|
@@ -378,15 +387,127 @@ export class EntityStore {
|
|
|
378
387
|
}
|
|
379
388
|
}
|
|
380
389
|
|
|
381
|
-
/**
|
|
390
|
+
/**
|
|
391
|
+
* True when `entities/` is a real directory inside this memory root.
|
|
392
|
+
* `realpath` on a symlinked root would treat the link target as trusted,
|
|
393
|
+
* so the check uses `lstat` first and refuses the scan when the root
|
|
394
|
+
* itself is a symlink.
|
|
395
|
+
*/
|
|
396
|
+
private async isTrustedEntitiesRoot(): Promise<boolean> {
|
|
397
|
+
let rootStat;
|
|
398
|
+
try {
|
|
399
|
+
rootStat = await lstat(this.deps.entitiesDir);
|
|
400
|
+
} catch (err) {
|
|
401
|
+
if (isErrnoCode(err, "ENOENT")) return false;
|
|
402
|
+
throw err;
|
|
403
|
+
}
|
|
404
|
+
if (rootStat.isSymbolicLink() || !rootStat.isDirectory()) return false;
|
|
405
|
+
let memoryRoot: string;
|
|
406
|
+
let entitiesReal: string;
|
|
407
|
+
try {
|
|
408
|
+
memoryRoot = await realpath(this.deps.baseDir);
|
|
409
|
+
entitiesReal = await realpath(this.deps.entitiesDir);
|
|
410
|
+
} catch (err) {
|
|
411
|
+
if (isErrnoCode(err, "ENOENT")) return false;
|
|
412
|
+
throw err;
|
|
413
|
+
}
|
|
414
|
+
return pathIsInside(memoryRoot, entitiesReal);
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
/**
|
|
418
|
+
* Entity directory listing with macOS replication junk removed.
|
|
419
|
+
* One summary warning per directory and count, shared with migration.
|
|
420
|
+
* A symlinked entities root yields an empty list and is not read.
|
|
421
|
+
*/
|
|
422
|
+
private async readEntityDirectoryNames(): Promise<string[]> {
|
|
423
|
+
if (!(await this.isTrustedEntitiesRoot())) return [];
|
|
424
|
+
const entries = await readdir(this.deps.entitiesDir);
|
|
425
|
+
const { kept, ignored } = withoutMacOsReplicationJunk(entries, (name) => name);
|
|
426
|
+
warnIgnoredMacOsReplicationJunk(this.deps.entitiesDir, ignored, (message) => {
|
|
427
|
+
log.warn(`entity load ${message}`);
|
|
428
|
+
});
|
|
429
|
+
return kept;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
/**
|
|
433
|
+
* A directory entry is readable only when it is a regular file.
|
|
434
|
+
* Symlinks, FIFOs, and devices are skipped before any read. The entities
|
|
435
|
+
* root is refused separately, before the directory is listed.
|
|
436
|
+
*/
|
|
437
|
+
private async isContainedRegularEntityFile(file: string): Promise<boolean> {
|
|
438
|
+
const filePath = path.join(this.deps.entitiesDir, file);
|
|
439
|
+
let entryStat;
|
|
440
|
+
try {
|
|
441
|
+
entryStat = await lstat(filePath);
|
|
442
|
+
} catch (err) {
|
|
443
|
+
if (isErrnoCode(err, "ENOENT")) return false;
|
|
444
|
+
throw err;
|
|
445
|
+
}
|
|
446
|
+
return !entryStat.isSymbolicLink() && entryStat.isFile();
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
/**
|
|
450
|
+
* Malformed entity files stay on disk (startup must not relocate them)
|
|
451
|
+
* and stay out of merge, so a fragment merge cannot delete them.
|
|
452
|
+
* Unchanged files reuse the previous result so a name listing does not
|
|
453
|
+
* reread the whole directory on every extraction write.
|
|
454
|
+
*/
|
|
455
|
+
private async isIndexableEntityMarkdown(file: string): Promise<boolean> {
|
|
456
|
+
const filePath = path.join(this.deps.entitiesDir, file);
|
|
457
|
+
let entryStat;
|
|
458
|
+
try {
|
|
459
|
+
entryStat = await lstat(filePath);
|
|
460
|
+
} catch (err) {
|
|
461
|
+
if (isErrnoCode(err, "ENOENT")) return false;
|
|
462
|
+
throw err;
|
|
463
|
+
}
|
|
464
|
+
if (entryStat.isSymbolicLink() || !entryStat.isFile()) return false;
|
|
465
|
+
const identity = `${entryStat.dev}:${entryStat.ino}:${entryStat.mtimeMs}:${entryStat.size}`;
|
|
466
|
+
const cached = this.entityIndexableCache.get(file);
|
|
467
|
+
if (cached?.identity === identity) return cached.ok;
|
|
468
|
+
try {
|
|
469
|
+
const content = await this.deps.readStorageSecureFile(filePath);
|
|
470
|
+
// Missing `**Type:**` still parses (type defaults to "other"). Only an
|
|
471
|
+
// empty name, including a tab heading, stays out of the name list.
|
|
472
|
+
const parsed = parseEntityFile(content, this.deps.entitySchemas);
|
|
473
|
+
const ok = parsed.name.trim().length > 0 && parsed.type.trim().length > 0;
|
|
474
|
+
this.entityIndexableCache.set(file, { identity, ok });
|
|
475
|
+
return ok;
|
|
476
|
+
} catch (err) {
|
|
477
|
+
if (err instanceof SecureStoreLockedError) throw err;
|
|
478
|
+
if (!isErrnoCode(err, "ENOENT")) throw err;
|
|
479
|
+
return false;
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
/**
|
|
484
|
+
* Sorted entity filenames (without .md). Malformed records stay on disk
|
|
485
|
+
* and are omitted, so extraction, matching, and entity list cannot reuse them.
|
|
486
|
+
*/
|
|
382
487
|
async listEntityNames(): Promise<string[]> {
|
|
383
488
|
try {
|
|
384
|
-
const entries = await
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
489
|
+
const entries = await this.readEntityDirectoryNames();
|
|
490
|
+
const mdFiles = entries.filter((e) => e.endsWith(".md"));
|
|
491
|
+
const names: string[] = [];
|
|
492
|
+
const batchSize = 100;
|
|
493
|
+
for (let i = 0; i < mdFiles.length; i += batchSize) {
|
|
494
|
+
const resolved = await Promise.all(mdFiles.slice(i, i + batchSize).map(async (file) => {
|
|
495
|
+
try {
|
|
496
|
+
if (!(await this.isIndexableEntityMarkdown(file))) return null;
|
|
497
|
+
} catch (err) {
|
|
498
|
+
if (err instanceof SecureStoreLockedError) throw err;
|
|
499
|
+
return null;
|
|
500
|
+
}
|
|
501
|
+
return file.slice(0, -3);
|
|
502
|
+
}));
|
|
503
|
+
for (const name of resolved) {
|
|
504
|
+
if (name) names.push(name);
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
names.sort();
|
|
508
|
+
return names;
|
|
509
|
+
} catch (err) {
|
|
510
|
+
if (err instanceof SecureStoreLockedError) throw err;
|
|
390
511
|
return [];
|
|
391
512
|
}
|
|
392
513
|
}
|
|
@@ -404,8 +525,10 @@ export class EntityStore {
|
|
|
404
525
|
// completed migration's reference scan.
|
|
405
526
|
const wrote = await withEntityCanonicalMutationLock(stateDir, async () => {
|
|
406
527
|
const raw = await this.readEntity(entityName);
|
|
407
|
-
if (!raw) return false;
|
|
408
|
-
const
|
|
528
|
+
if (!raw || isMalformedEntityRecord(raw)) return false;
|
|
529
|
+
const parsed = parseEntityFile(raw, this.deps.entitySchemas);
|
|
530
|
+
if (!parsed.name.trim() || !parsed.type.trim()) return false;
|
|
531
|
+
const serialized = serializeEntityFile(parsed, this.deps.entitySchemas, this.deps.okfConformanceEnabled());
|
|
409
532
|
if (raw.trimEnd() === serialized.trimEnd()) return false;
|
|
410
533
|
const filePath = this.deps.resolveEntityFilePath(entityName);
|
|
411
534
|
if (filePath === null) return false;
|
|
@@ -513,7 +636,7 @@ export class EntityStore {
|
|
|
513
636
|
if (cached) return cached;
|
|
514
637
|
|
|
515
638
|
try {
|
|
516
|
-
const entries = await
|
|
639
|
+
const entries = await this.readEntityDirectoryNames();
|
|
517
640
|
const mdFiles = entries.filter((e) => e.endsWith(".md"));
|
|
518
641
|
if (mdFiles.length === 0) return [];
|
|
519
642
|
|
|
@@ -530,6 +653,7 @@ export class EntityStore {
|
|
|
530
653
|
const results = await Promise.all(
|
|
531
654
|
batch.map(async (entry) => {
|
|
532
655
|
try {
|
|
656
|
+
if (!(await this.isContainedRegularEntityFile(entry))) return null;
|
|
533
657
|
return await this.deps.readStorageSecureFile(path.join(this.deps.entitiesDir, entry));
|
|
534
658
|
} catch (err) {
|
|
535
659
|
if (err instanceof SecureStoreLockedError) throw err;
|
|
@@ -539,7 +663,10 @@ export class EntityStore {
|
|
|
539
663
|
}),
|
|
540
664
|
);
|
|
541
665
|
for (const content of results) {
|
|
542
|
-
if (content
|
|
666
|
+
if (content === null) continue;
|
|
667
|
+
const entity = parseEntityFile(content, this.deps.entitySchemas);
|
|
668
|
+
if (!entity.name.trim() || !entity.type.trim()) continue;
|
|
669
|
+
entities.push(entity);
|
|
543
670
|
}
|
|
544
671
|
}
|
|
545
672
|
// A signal that fired during the last batch's await would otherwise publish
|
|
@@ -642,8 +769,13 @@ export class EntityStore {
|
|
|
642
769
|
private async mergeFragmentedEntitiesUnlocked(): Promise<number> {
|
|
643
770
|
let merged = 0;
|
|
644
771
|
try {
|
|
645
|
-
const entries = await
|
|
646
|
-
const mdFiles =
|
|
772
|
+
const entries = await this.readEntityDirectoryNames();
|
|
773
|
+
const mdFiles: string[] = [];
|
|
774
|
+
for (const file of entries) {
|
|
775
|
+
if (!file.endsWith(".md")) continue;
|
|
776
|
+
if (!(await this.isIndexableEntityMarkdown(file))) continue;
|
|
777
|
+
mdFiles.push(file);
|
|
778
|
+
}
|
|
647
779
|
|
|
648
780
|
// Group files by their canonical name
|
|
649
781
|
const groups = new Map<string, string[]>();
|
|
@@ -660,9 +792,31 @@ export class EntityStore {
|
|
|
660
792
|
groups.get(canonical)!.push(file);
|
|
661
793
|
}
|
|
662
794
|
|
|
795
|
+
// A malformed or otherwise non-indexable file is absent from `files`.
|
|
796
|
+
// Writing the canonical path anyway would replace that file, then
|
|
797
|
+
// delete the fragments that still hold the only readable copy.
|
|
798
|
+
const canonicalDestinationOccupied = async (
|
|
799
|
+
canonicalName: string,
|
|
800
|
+
members: readonly string[],
|
|
801
|
+
): Promise<boolean> => {
|
|
802
|
+
if (members.includes(canonicalName)) return false;
|
|
803
|
+
try {
|
|
804
|
+
await lstat(path.join(this.deps.entitiesDir, canonicalName));
|
|
805
|
+
return true;
|
|
806
|
+
} catch (err) {
|
|
807
|
+
if (isErrnoCode(err, "ENOENT")) return false;
|
|
808
|
+
throw err;
|
|
809
|
+
}
|
|
810
|
+
};
|
|
811
|
+
|
|
663
812
|
// Merge groups with more than one file
|
|
664
813
|
for (const [canonical, files] of groups) {
|
|
665
814
|
if (files.length <= 1) continue;
|
|
815
|
+
const canonicalName = `${canonical}.md`;
|
|
816
|
+
if (await canonicalDestinationOccupied(canonicalName, files)) {
|
|
817
|
+
log.warn(`skipped entity merge into occupied ${canonicalName}`);
|
|
818
|
+
continue;
|
|
819
|
+
}
|
|
666
820
|
|
|
667
821
|
// Parse all files and merge into a single EntityFile
|
|
668
822
|
const mergedEntity: EntityFile = {
|
|
@@ -901,7 +1055,11 @@ export class EntityStore {
|
|
|
901
1055
|
mergedEntity.created = mergedEntity.created || mergedEntity.updated || new Date().toISOString();
|
|
902
1056
|
mergedEntity.updated = mergedEntity.updated || new Date().toISOString();
|
|
903
1057
|
|
|
904
|
-
const canonicalPath = path.join(this.deps.entitiesDir,
|
|
1058
|
+
const canonicalPath = path.join(this.deps.entitiesDir, canonicalName);
|
|
1059
|
+
if (await canonicalDestinationOccupied(canonicalName, files)) {
|
|
1060
|
+
log.warn(`skipped entity merge into occupied ${canonicalName}`);
|
|
1061
|
+
continue;
|
|
1062
|
+
}
|
|
905
1063
|
await this.deps.writeStorageSecureFile(canonicalPath, serializeEntityFile(mergedEntity, this.deps.entitySchemas, this.deps.okfConformanceEnabled()));
|
|
906
1064
|
this.deps.bumpEntityMutationVersion();
|
|
907
1065
|
|
|
@@ -17,6 +17,8 @@ import { SecureStoreLockedError, readMaybeEncryptedFile } from "../secure-store/
|
|
|
17
17
|
import { type BufferSurpriseEvent, type CompressionGuidelineOptimizerState, type MemoryFile, type PluginConfig, confidenceTier } from "../types.js";
|
|
18
18
|
import { RECALL_FALLBACK_DIRS } from "../utils/category-dir.js";
|
|
19
19
|
import { isErrnoCode } from "../utils/errno.js";
|
|
20
|
+
import { isPopulatedUnnamedEntityRecord } from "../utils/malformed-entity-record.js";
|
|
21
|
+
import { isMacOsReplicationJunkBasename } from "../utils/macos-replication-junk.js";
|
|
20
22
|
import { assertPathInsideRoot } from "../utils/path-containment.js";
|
|
21
23
|
import { isAbortError } from "../abort-error.js";
|
|
22
24
|
import { checkCorpusReadAbort, type CorpusReadOptions } from "../corpus-read-cancellation.js";
|
|
@@ -97,6 +99,18 @@ function isPropagatableReadError(err: unknown): boolean {
|
|
|
97
99
|
return typeof code === "string" && code !== "ENOENT";
|
|
98
100
|
}
|
|
99
101
|
|
|
102
|
+
/**
|
|
103
|
+
* Markdown under this store's `entities/` directory. The first relative
|
|
104
|
+
* segment must be `entities`; a memory root whose absolute path contains
|
|
105
|
+
* that name is not an entity store.
|
|
106
|
+
*/
|
|
107
|
+
function isStoreEntityMarkdown(baseDir: string, filePath: string): boolean {
|
|
108
|
+
if (!filePath.endsWith(".md")) return false;
|
|
109
|
+
const relative = path.relative(baseDir, filePath);
|
|
110
|
+
if (relative.length === 0 || relative.startsWith("..") || path.isAbsolute(relative)) return false;
|
|
111
|
+
return relative.split(path.sep)[0] === "entities";
|
|
112
|
+
}
|
|
113
|
+
|
|
100
114
|
export class MemoryReadStore {
|
|
101
115
|
constructor(
|
|
102
116
|
private readonly deps: MemoryReadStoreDeps,
|
|
@@ -117,7 +131,7 @@ export class MemoryReadStore {
|
|
|
117
131
|
try {
|
|
118
132
|
const entries = await readdir(this.deps.wearablesDir, { withFileTypes: true });
|
|
119
133
|
sources = entries
|
|
120
|
-
.filter((entry) => entry.isDirectory())
|
|
134
|
+
.filter((entry) => entry.isDirectory() && !isMacOsReplicationJunkBasename(entry.name))
|
|
121
135
|
.map((entry) => entry.name);
|
|
122
136
|
} catch (err) {
|
|
123
137
|
if ((err as NodeJS.ErrnoException).code === "ENOENT") return [];
|
|
@@ -134,7 +148,7 @@ export class MemoryReadStore {
|
|
|
134
148
|
throw err;
|
|
135
149
|
}
|
|
136
150
|
for (const entry of entries) {
|
|
137
|
-
if (!entry.endsWith(".md")) continue;
|
|
151
|
+
if (isMacOsReplicationJunkBasename(entry) || !entry.endsWith(".md")) continue;
|
|
138
152
|
const date = entry.slice(0, -3);
|
|
139
153
|
if (!isValidTranscriptDate(date)) continue;
|
|
140
154
|
days.push({ source, date });
|
|
@@ -170,6 +184,7 @@ export class MemoryReadStore {
|
|
|
170
184
|
// in-flight dedup, so every abandoned recall used to start another
|
|
171
185
|
// full walk of it (issue #2307).
|
|
172
186
|
checkCorpusReadAbort(options);
|
|
187
|
+
if (isMacOsReplicationJunkBasename(entry.name)) continue;
|
|
173
188
|
const fullPath = path.join(dir, entry.name);
|
|
174
189
|
if (entry.isDirectory()) {
|
|
175
190
|
await readDir(fullPath);
|
|
@@ -287,6 +302,7 @@ export class MemoryReadStore {
|
|
|
287
302
|
checkCorpusReadAbort(options);
|
|
288
303
|
// Never follow symlinked entries out of the store.
|
|
289
304
|
if (entry.isSymbolicLink()) continue;
|
|
305
|
+
if (isMacOsReplicationJunkBasename(entry.name)) continue;
|
|
290
306
|
const fullPath = path.join(dir, entry.name);
|
|
291
307
|
if (entry.isDirectory()) {
|
|
292
308
|
subdirs.push(fullPath);
|
|
@@ -500,6 +516,7 @@ export class MemoryReadStore {
|
|
|
500
516
|
const entries = await readdir(dir, { withFileTypes: true });
|
|
501
517
|
const subdirs: string[] = [];
|
|
502
518
|
for (const entry of entries) {
|
|
519
|
+
if (isMacOsReplicationJunkBasename(entry.name)) continue;
|
|
503
520
|
const fullPath = path.join(dir, entry.name);
|
|
504
521
|
if (entry.isDirectory()) {
|
|
505
522
|
subdirs.push(fullPath);
|
|
@@ -536,6 +553,15 @@ export class MemoryReadStore {
|
|
|
536
553
|
async readMemoryByPath(filePath: string): Promise<MemoryFile | null> {
|
|
537
554
|
try {
|
|
538
555
|
const raw = await readMaybeEncryptedFile(filePath, this.deps._secureStoreKey, this.deps.baseDir);
|
|
556
|
+
// Entity bodies with text but no name heading stay out of recall,
|
|
557
|
+
// including contextual QMD hits. An empty body still resolves through
|
|
558
|
+
// frontmatter and the canonical filename. A missing type line is still
|
|
559
|
+
// an entity. QMD query behavior is unchanged. Classification is
|
|
560
|
+
// relative to this store root: an absolute path that merely contains
|
|
561
|
+
// an `entities` segment is still an ordinary fact.
|
|
562
|
+
if (isStoreEntityMarkdown(this.deps.baseDir, filePath) && isPopulatedUnnamedEntityRecord(raw)) {
|
|
563
|
+
return null;
|
|
564
|
+
}
|
|
539
565
|
// Note: the outer catch intentionally swallows most errors (ENOENT etc.)
|
|
540
566
|
// but SecureStoreLockedError must propagate — see re-throw below.
|
|
541
567
|
const parsed = parseFrontmatter(raw);
|
|
@@ -555,8 +581,7 @@ export class MemoryReadStore {
|
|
|
555
581
|
// YAML frontmatter. Build a synthetic MemoryFile so entity files returned by
|
|
556
582
|
// the direct retrieval agent participate in boostSearchResults and last-recall
|
|
557
583
|
// tracking rather than being silently dropped.
|
|
558
|
-
|
|
559
|
-
if (normalizedPath.includes("/entities/") && filePath.endsWith(".md")) {
|
|
584
|
+
if (isStoreEntityMarkdown(this.deps.baseDir, filePath)) {
|
|
560
585
|
const entity = parseEntityFile(raw, this.deps.entitySchemas);
|
|
561
586
|
if (!entity.name) return null;
|
|
562
587
|
const nameWithoutExt = path.basename(filePath, ".md");
|
|
@@ -859,7 +884,7 @@ export class MemoryReadStore {
|
|
|
859
884
|
const files = await readdir(this.deps.questionsDir);
|
|
860
885
|
const questions = [];
|
|
861
886
|
for (const file of files) {
|
|
862
|
-
if (!file.endsWith(".md")) continue;
|
|
887
|
+
if (isMacOsReplicationJunkBasename(file) || !file.endsWith(".md")) continue;
|
|
863
888
|
const filePath = path.join(this.deps.questionsDir, file);
|
|
864
889
|
const raw = await readMaybeEncryptedFile(filePath, this.deps._secureStoreKey, this.deps.baseDir);
|
|
865
890
|
const parsed = this.deps.parseQuestionFile(raw, filePath);
|
|
@@ -5,6 +5,7 @@ import path from "node:path";
|
|
|
5
5
|
import { stripAttributesSuffix } from "../structured-attributes.js";
|
|
6
6
|
import type { MemoryFile } from "../types.js";
|
|
7
7
|
import { isErrnoCode } from "../utils/errno.js";
|
|
8
|
+
import { isMacOsReplicationJunkBasename } from "../utils/macos-replication-junk.js";
|
|
8
9
|
|
|
9
10
|
export interface SupersessionAuditLookup {
|
|
10
11
|
correctionsDir: string;
|
|
@@ -27,6 +28,7 @@ export async function hasSupersessionAudit(
|
|
|
27
28
|
}
|
|
28
29
|
|
|
29
30
|
for (const entry of entries) {
|
|
31
|
+
if (isMacOsReplicationJunkBasename(entry.name)) continue;
|
|
30
32
|
if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
|
|
31
33
|
const memory = await lookup.readMemoryByPath(path.join(lookup.correctionsDir, entry.name));
|
|
32
34
|
if (
|
package/src/storage.ts
CHANGED
|
@@ -65,6 +65,7 @@ import { readEntityAliasConfigSync } from "./storage/entity-alias-config.js";
|
|
|
65
65
|
import { assertSafeEntityId } from "./storage/entity-id-safety.js";
|
|
66
66
|
export { normalizeEntityName } from "./entity-id-normalization.js";
|
|
67
67
|
import { isErrnoCode } from "./utils/errno.js";
|
|
68
|
+
import { isMacOsReplicationJunkBasename } from "./utils/macos-replication-junk.js";
|
|
68
69
|
import { getCategoryDir, categoryDirName } from "./utils/category-dir.js";
|
|
69
70
|
import { decodeYamlScalar } from "./utils/yaml-scalar.js";
|
|
70
71
|
import { qmdCollectionPathParts, qmdResultPathCandidates } from "./orchestration/qmd-result-resolver.js";
|
|
@@ -4882,7 +4883,7 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
4882
4883
|
|
|
4883
4884
|
const readDir = async (dir: string) => {
|
|
4884
4885
|
try {
|
|
4885
|
-
const entries = await readdir(dir, { withFileTypes: true });
|
|
4886
|
+
const entries = (await readdir(dir, { withFileTypes: true })).filter((e) => !isMacOsReplicationJunkBasename(e.name));
|
|
4886
4887
|
for (const entry of entries) {
|
|
4887
4888
|
checkCorpusReadAbort(options);
|
|
4888
4889
|
const fullPath = path.join(dir, entry.name);
|
|
@@ -7133,7 +7134,7 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
7133
7134
|
const summaries: MemorySummary[] = [];
|
|
7134
7135
|
|
|
7135
7136
|
for (const file of files) {
|
|
7136
|
-
if (!file.endsWith(".json")) continue;
|
|
7137
|
+
if (isMacOsReplicationJunkBasename(file) || !file.endsWith(".json")) continue;
|
|
7137
7138
|
const filePath = path.join(this.summariesDir, file);
|
|
7138
7139
|
const raw = await this.readStorageSecureFile(filePath);
|
|
7139
7140
|
summaries.push(JSON.parse(raw) as MemorySummary);
|