@remnic/core 9.45.3 → 9.45.5
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/abort-error.d.ts +2 -1
- package/dist/abort-error.js +3 -1
- package/dist/access-admin-ops-surface.d.ts +14 -10
- package/dist/access-admin-ops-surface.js +84 -75
- package/dist/access-audit.js +2 -2
- package/dist/access-authorization-probe.d.ts +14 -10
- package/dist/access-authorization-probe.js +85 -76
- package/dist/access-boundary.d.ts +15 -11
- package/dist/access-boundary.js +84 -75
- package/dist/access-citation-namespace.js +2 -2
- package/dist/access-cli.js +191 -177
- package/dist/access-cli.js.map +1 -1
- package/dist/access-coding-context-resolution.d.ts +16 -0
- package/dist/access-coding-context-resolution.js +13 -0
- package/dist/access-coding-context-resolution.js.map +1 -0
- package/dist/access-extraction-force-flush.d.ts +14 -10
- package/dist/access-extraction-force-flush.js +84 -75
- package/dist/access-health-types.d.ts +2 -1
- package/dist/access-http-lcm-compaction.d.ts +16 -12
- package/dist/access-http-lcm-compaction.js +3 -3
- package/dist/access-http-lifecycle-flush.d.ts +14 -10
- package/dist/access-http-lifecycle-flush.js +2 -2
- package/dist/access-http-offline-stream.d.ts +123 -0
- package/dist/access-http-offline-stream.js +10 -0
- package/dist/access-http-offline-stream.js.map +1 -0
- package/dist/access-http-query.js +84 -75
- package/dist/access-http.d.ts +15 -11
- package/dist/access-http.js +104 -90
- package/dist/access-identity-continuity-surface.d.ts +9 -8
- package/dist/access-identity-continuity-surface.js +84 -75
- package/dist/access-lcm-surface.d.ts +14 -10
- package/dist/access-lcm-surface.js +84 -75
- package/dist/access-mcp-output-schemas.js +1 -1
- package/dist/access-mcp.d.ts +14 -10
- package/dist/access-mcp.js +95 -82
- package/dist/access-memory-search-fanout.d.ts +3 -2
- package/dist/{access-namespace-preflight-5yZ4g6F8.d.ts → access-namespace-preflight-CWUDwB4M.d.ts} +1 -1
- package/dist/access-namespace-preflight.d.ts +4 -3
- package/dist/access-namespace-preflight.js +84 -75
- package/dist/access-observe-helpers.d.ts +1 -0
- package/dist/access-observe-helpers.js +1 -1
- package/dist/access-observe-write-surface.d.ts +16 -10
- package/dist/access-observe-write-surface.js +84 -75
- package/dist/access-offline-manifest.d.ts +104 -0
- package/dist/access-offline-manifest.js +45 -0
- package/dist/access-offline-manifest.js.map +1 -0
- package/dist/access-operations-batch.js +86 -77
- package/dist/access-operations.d.ts +18 -14
- package/dist/access-operations.js +91 -79
- package/dist/access-recall-concurrency.d.ts +16 -26
- package/dist/access-recall-concurrency.js +86 -76
- package/dist/access-recall-response.d.ts +18 -14
- package/dist/access-recall-response.js +84 -75
- package/dist/access-recall-surface.d.ts +29 -24
- package/dist/access-recall-surface.js +84 -75
- package/dist/access-schema.d.ts +84 -84
- package/dist/access-schema.js +3 -3
- package/dist/{access-service-CiJRsgAB.d.ts → access-service-CNN89xyn.d.ts} +25 -16
- package/dist/access-service-helpers.d.ts +14 -10
- package/dist/access-service.d.ts +14 -10
- package/dist/access-service.js +84 -75
- package/dist/access-surface-catalog.d.ts +14 -10
- package/dist/access-surface-catalog.js +4 -0
- package/dist/access-surface-catalog.js.map +1 -1
- package/dist/access-wearables-meetings-surface.d.ts +4 -3
- package/dist/action-confidence.d.ts +2 -1
- package/dist/active-memory-bridge.d.ts +2 -1
- package/dist/active-recall.d.ts +2 -1
- package/dist/active-recall.js +10 -8
- package/dist/active-recall.js.map +1 -1
- package/dist/adapters/index.js +4 -4
- package/dist/adapters/registry.js +2 -2
- package/dist/{auto-sync-5OE5QOZB.js → auto-sync-UPTUVE4X.js} +6 -6
- package/dist/behavior-learner.d.ts +2 -1
- package/dist/behavior-learner.js +1 -1
- package/dist/behavior-signals.d.ts +2 -1
- package/dist/bootstrap.d.ts +9 -8
- package/dist/briefing.d.ts +3 -2
- package/dist/briefing.js +24 -22
- package/dist/buffer-surprise-report.d.ts +2 -1
- package/dist/buffer-turn-helpers.d.ts +2 -1
- package/dist/buffer.d.ts +3 -2
- package/dist/buffer.js +12 -11
- package/dist/bulk-import/index.d.ts +4 -3
- package/dist/calibration.d.ts +2 -1
- package/dist/capabilities.d.ts +2 -1
- package/dist/{capsule-merge-IDWJPCWK.js → capsule-merge-Q6AR3XL7.js} +67 -54
- package/dist/capsule-merge-Q6AR3XL7.js.map +1 -0
- package/dist/{catalog-scBmy0sO.d.ts → catalog-bctMURhN.d.ts} +1 -1
- package/dist/causal-behavior.d.ts +2 -1
- package/dist/causal-behavior.js +2 -2
- package/dist/causal-chain.js +2 -2
- package/dist/causal-consolidation.d.ts +2 -1
- package/dist/causal-consolidation.js +28 -26
- package/dist/causal-consolidation.js.map +1 -1
- package/dist/causal-retrieval.js +2 -2
- package/dist/causal-trajectory-graph.d.ts +2 -1
- package/dist/causal-trajectory.js +1 -1
- package/dist/{chunk-E5UK4VPE.js → chunk-2FSTB6BJ.js} +5 -5
- package/dist/{chunk-5ZE7QHTK.js → chunk-2X2T2UVE.js} +5 -5
- package/dist/{chunk-P4DRWEYC.js → chunk-3COYXTGM.js} +2 -2
- package/dist/{chunk-5IVLTFOV.js → chunk-44N6ESJ4.js} +2 -2
- package/dist/{chunk-DL7ZD3JH.js → chunk-4FBVAGV3.js} +14 -9
- package/dist/chunk-4FBVAGV3.js.map +1 -0
- package/dist/{chunk-WOCNN776.js → chunk-4POAMKV6.js} +100 -41
- package/dist/chunk-4POAMKV6.js.map +1 -0
- package/dist/{chunk-HO3QBJEY.js → chunk-5546W5SI.js} +2 -2
- package/dist/{chunk-AAIUERNB.js → chunk-5QJQHBLE.js} +6 -6
- package/dist/{chunk-6CZPDBJS.js → chunk-5U7ID3EZ.js} +3 -3
- package/dist/{chunk-RN7DY3FC.js → chunk-6ISC4AVB.js} +31 -12
- package/dist/chunk-6ISC4AVB.js.map +1 -0
- package/dist/chunk-773TRRGT.js +36 -0
- package/dist/chunk-773TRRGT.js.map +1 -0
- package/dist/chunk-7T4TOGMS.js +242 -0
- package/dist/chunk-7T4TOGMS.js.map +1 -0
- package/dist/{chunk-DLVPUX7U.js → chunk-7YKVM5H3.js} +8 -6
- package/dist/chunk-7YKVM5H3.js.map +1 -0
- package/dist/chunk-7YQ6ESEA.js +322 -0
- package/dist/chunk-7YQ6ESEA.js.map +1 -0
- package/dist/{chunk-DNWXFTLD.js → chunk-A4IJCD2Z.js} +2 -2
- package/dist/{chunk-3CE77VAP.js → chunk-A4JMGKCD.js} +87 -74
- package/dist/chunk-A4JMGKCD.js.map +1 -0
- package/dist/chunk-A5KNZSNA.js +26 -0
- package/dist/chunk-A5KNZSNA.js.map +1 -0
- package/dist/{chunk-PKNLM44P.js → chunk-AC5OWJLV.js} +9 -9
- package/dist/{chunk-LZ4LDKHZ.js → chunk-AMAUBUKY.js} +6 -6
- package/dist/{chunk-CUM2BBPN.js → chunk-AUMWZSE7.js} +19 -10
- package/dist/chunk-AUMWZSE7.js.map +1 -0
- package/dist/{chunk-BUE5E2HL.js → chunk-BGLY7EEM.js} +5 -314
- package/dist/chunk-BGLY7EEM.js.map +1 -0
- package/dist/chunk-BIPBQQFI.js +44 -0
- package/dist/chunk-BIPBQQFI.js.map +1 -0
- package/dist/{chunk-S5SLVSVY.js → chunk-BQIFZ2MP.js} +5 -5
- package/dist/chunk-BTTPKDIL.js +34 -0
- package/dist/{chunk-PVGDJXVK.js.map → chunk-BTTPKDIL.js.map} +1 -1
- package/dist/chunk-CK5KOVHW.js +69 -0
- package/dist/chunk-CK5KOVHW.js.map +1 -0
- package/dist/{chunk-Q6IP2ARR.js → chunk-CSOYVTRX.js} +2 -2
- package/dist/{chunk-XOQSEF7X.js → chunk-CVILPI77.js} +6 -6
- package/dist/{chunk-VWAXN2BN.js → chunk-CX4ZUMC6.js} +91 -83
- package/dist/chunk-CX4ZUMC6.js.map +1 -0
- package/dist/{chunk-NVRYW264.js → chunk-DAJPRXBR.js} +16 -13
- package/dist/chunk-DAJPRXBR.js.map +1 -0
- package/dist/{chunk-J7VGGECD.js → chunk-DZPFMQZ7.js} +1 -1
- package/dist/chunk-DZPFMQZ7.js.map +1 -0
- package/dist/{chunk-4LMA77JH.js → chunk-E5XQIWAL.js} +3 -3
- package/dist/{chunk-WUNIWKY4.js → chunk-ELIL2A37.js} +6 -6
- package/dist/{chunk-OQ5PRDDS.js → chunk-ERZ2R42X.js} +6 -6
- package/dist/{chunk-U7GW7NE7.js → chunk-FIK3CQNA.js} +10 -10
- package/dist/{chunk-D3J5SLQK.js → chunk-FR27HBBA.js} +81 -20
- package/dist/chunk-FR27HBBA.js.map +1 -0
- package/dist/{chunk-E6PNLPGJ.js → chunk-FUCYDRE5.js} +838 -480
- package/dist/chunk-FUCYDRE5.js.map +1 -0
- package/dist/{chunk-HZFHQ4AQ.js → chunk-G7A5HLUS.js} +23 -17
- package/dist/chunk-G7A5HLUS.js.map +1 -0
- package/dist/{chunk-33PLLLL7.js → chunk-GFCVUY6G.js} +6 -6
- package/dist/{chunk-HREE4JHI.js → chunk-GODSPTOT.js} +477 -278
- package/dist/chunk-GODSPTOT.js.map +1 -0
- package/dist/{chunk-S2NCTZGJ.js → chunk-GRUYA45P.js} +15 -15
- package/dist/chunk-GRUYA45P.js.map +1 -0
- package/dist/{chunk-VUPTKTDV.js → chunk-GUAL4PQH.js} +3 -3
- package/dist/{chunk-CINZGPSJ.js → chunk-GUMZC2BO.js} +2 -2
- package/dist/{chunk-H24WNPA2.js → chunk-GWFSVJ4P.js} +3 -3
- package/dist/{chunk-7XC2HX75.js → chunk-GYPQL6XN.js} +157 -16
- package/dist/chunk-GYPQL6XN.js.map +1 -0
- package/dist/{chunk-TSH56VPU.js → chunk-HAYSYUAB.js} +2 -2
- package/dist/{chunk-PDLBLTOK.js → chunk-HC3PBX23.js} +9 -9
- package/dist/{chunk-TDHTVMPG.js → chunk-HFPASSFV.js} +7 -2
- package/dist/chunk-HFPASSFV.js.map +1 -0
- package/dist/chunk-J2WC5LF4.js +395 -0
- package/dist/chunk-J2WC5LF4.js.map +1 -0
- package/dist/{chunk-KXB4VXHY.js → chunk-JIYDRBVZ.js} +2 -2
- package/dist/chunk-JV3C2MNQ.js +74 -0
- package/dist/chunk-JV3C2MNQ.js.map +1 -0
- package/dist/{chunk-HLPD7B7P.js → chunk-JZH4LWHB.js} +2 -2
- package/dist/{chunk-AV5ZEH4M.js → chunk-KVJRXN2E.js} +2 -2
- package/dist/{chunk-WFTIGIIS.js → chunk-L6CQ7WIW.js} +5 -5
- package/dist/{chunk-227UFSEQ.js → chunk-LEPOP46W.js} +4 -4
- package/dist/{chunk-EJUEXZHX.js → chunk-LLJMAULE.js} +2 -2
- package/dist/{chunk-N5Z4EVOR.js → chunk-LNEWDF2A.js} +36 -11
- package/dist/chunk-LNEWDF2A.js.map +1 -0
- package/dist/{chunk-QN25OCUF.js → chunk-LPYDOLSM.js} +5 -5
- package/dist/{chunk-AS7YMSL6.js → chunk-M23RF3LJ.js} +4 -4
- package/dist/{chunk-OAEQLRCY.js → chunk-MO4HSXHZ.js} +5 -5
- package/dist/{chunk-ECK75GDJ.js → chunk-N3LL5NEU.js} +43 -24
- package/dist/chunk-N3LL5NEU.js.map +1 -0
- package/dist/chunk-NEF7LR5J.js +29 -0
- package/dist/chunk-NEF7LR5J.js.map +1 -0
- package/dist/{chunk-3F2LKUMU.js → chunk-NIS256NW.js} +2 -2
- package/dist/{chunk-YIAA2X3D.js → chunk-NK5RGJ65.js} +3 -3
- package/dist/chunk-NLDVVWCL.js +84 -0
- package/dist/chunk-NLDVVWCL.js.map +1 -0
- package/dist/{chunk-4J7G5SY4.js → chunk-NZBZ7IS2.js} +72 -24
- package/dist/chunk-NZBZ7IS2.js.map +1 -0
- package/dist/{chunk-3TBLDMJA.js → chunk-O4KMGRXE.js} +5 -2
- package/dist/chunk-O4KMGRXE.js.map +1 -0
- package/dist/{chunk-7TWUCYER.js → chunk-PNRA7FAD.js} +7 -7
- package/dist/{chunk-5I4M26Q7.js → chunk-QBSFOKY6.js} +4 -4
- package/dist/{chunk-E53DSZEN.js → chunk-QR6G5KF4.js} +3 -3
- package/dist/{chunk-CJ2ZR7UA.js → chunk-QUENPGWZ.js} +261 -211
- package/dist/chunk-QUENPGWZ.js.map +1 -0
- package/dist/{chunk-4UH4BTGK.js → chunk-QVJPH7SH.js} +84 -84
- package/dist/{chunk-UYLMNVY6.js → chunk-R3KHKU7M.js} +16 -9
- package/dist/chunk-R3KHKU7M.js.map +1 -0
- package/dist/{chunk-JBPKEARU.js → chunk-RKNJBZ55.js} +4 -4
- package/dist/{chunk-WDISJRMG.js → chunk-RMMVQQA6.js} +2 -2
- package/dist/{chunk-JVLCVFQ4.js → chunk-RNHVVMFN.js} +3 -3
- package/dist/{chunk-QJAQNXWI.js → chunk-RVO6TCTU.js} +81 -84
- package/dist/chunk-RVO6TCTU.js.map +1 -0
- package/dist/chunk-S2HLHAZ4.js +16 -0
- package/dist/chunk-S2HLHAZ4.js.map +1 -0
- package/dist/{chunk-KWMXR7XS.js → chunk-S2V7RUCL.js} +8 -1
- package/dist/{chunk-KWMXR7XS.js.map → chunk-S2V7RUCL.js.map} +1 -1
- package/dist/{chunk-5SM35XZR.js → chunk-S5NZBKKQ.js} +2 -2
- package/dist/{chunk-VNA7W7QF.js → chunk-SVH57F5Z.js} +12 -4
- package/dist/chunk-SVH57F5Z.js.map +1 -0
- package/dist/{chunk-WIPEXG6R.js → chunk-SXIMQLGV.js} +2 -2
- package/dist/{chunk-RVLJEII5.js → chunk-SYUBB3WM.js} +256 -187
- package/dist/chunk-SYUBB3WM.js.map +1 -0
- package/dist/{chunk-VCD4PSK2.js → chunk-TQZ4DVBC.js} +7 -4
- package/dist/chunk-TQZ4DVBC.js.map +1 -0
- package/dist/{chunk-7K5Q6COX.js → chunk-TVVEYCNW.js} +4 -4
- package/dist/{chunk-YV32N67O.js → chunk-URS5GSM7.js} +1 -1
- package/dist/chunk-URS5GSM7.js.map +1 -0
- package/dist/{chunk-4B77XSG5.js → chunk-UV72DEZD.js} +5 -5
- package/dist/{chunk-BJKPPZ6Z.js → chunk-UW66OZTD.js} +2 -2
- package/dist/{chunk-XYTOI63Z.js → chunk-V2TNYF6Q.js} +19 -11
- package/dist/chunk-V2TNYF6Q.js.map +1 -0
- package/dist/{chunk-S2BBISHU.js → chunk-VANZKHTN.js} +3 -3
- package/dist/chunk-VHFXP27N.js +250 -0
- package/dist/chunk-VHFXP27N.js.map +1 -0
- package/dist/chunk-VL35ZFSZ.js +102 -0
- package/dist/chunk-VL35ZFSZ.js.map +1 -0
- package/dist/{chunk-3Y224NYC.js → chunk-VYISFWVX.js} +2 -2
- package/dist/{chunk-JE7EK33X.js → chunk-W2V7UESE.js} +2 -2
- package/dist/{chunk-TIHMZFIV.js → chunk-W3IC7QOY.js} +3 -3
- package/dist/{chunk-NRV4Y3PM.js → chunk-W4FBGYGK.js} +1 -1
- package/dist/{chunk-P2BM76KT.js → chunk-WAS4HV46.js} +174 -43
- package/dist/chunk-WAS4HV46.js.map +1 -0
- package/dist/{chunk-57QKLRBV.js → chunk-WB7JSQCP.js} +2 -1
- package/dist/chunk-WB7JSQCP.js.map +1 -0
- package/dist/{chunk-A5OJCXZL.js → chunk-WZ3TOIDW.js} +15 -4
- package/dist/chunk-WZ3TOIDW.js.map +1 -0
- package/dist/{chunk-MU7ZHSZE.js → chunk-WZFAPHIK.js} +2 -2
- package/dist/{chunk-T2TTP3KU.js → chunk-X4IDNPOS.js} +2 -2
- package/dist/{chunk-UVIKWC7M.js → chunk-XAGYS7X6.js} +17 -17
- package/dist/{chunk-BLAKS3CP.js → chunk-XL3TATMJ.js} +3 -3
- package/dist/{chunk-W4XJFLAL.js → chunk-XPRJSHNI.js} +2 -2
- package/dist/{chunk-5TFP4CUL.js → chunk-XQ3HXAQH.js} +14 -11
- package/dist/chunk-XQ3HXAQH.js.map +1 -0
- package/dist/{chunk-E6EE5B67.js → chunk-YK6BDDHP.js} +4 -4
- package/dist/{chunk-ES36HTSC.js → chunk-YLHM5BQQ.js} +3 -3
- package/dist/{chunk-ULARSG5Z.js → chunk-YN6ASZUG.js} +10 -8
- package/dist/{chunk-ULARSG5Z.js.map → chunk-YN6ASZUG.js.map} +1 -1
- package/dist/{chunk-VOUOLGIP.js → chunk-YRFAYOFQ.js} +11 -13
- package/dist/chunk-YRFAYOFQ.js.map +1 -0
- package/dist/{chunk-IKKWIPYN.js → chunk-YYQAKIDJ.js} +37 -1
- package/dist/chunk-YYQAKIDJ.js.map +1 -0
- package/dist/{chunk-GF22HWS2.js → chunk-Z54EM5YZ.js} +4 -4
- package/dist/{chunk-64UDOIMI.js → chunk-ZLQ37WJX.js} +2 -2
- package/dist/{cli-BUGN3d6_.d.ts → cli-BHBswmUa.d.ts} +5 -5
- package/dist/cli.d.ts +16 -12
- package/dist/cli.js +138 -123
- package/dist/compounding/engine.d.ts +3 -2
- package/dist/compounding/engine.js +25 -23
- package/dist/compounding/preference-consolidator.d.ts +2 -1
- package/dist/compression-optimizer.d.ts +2 -1
- package/dist/config.d.ts +2 -1
- package/dist/config.js +10 -8
- package/dist/connectors/codex-materialize-runner.d.ts +2 -1
- package/dist/connectors/codex-materialize-runner.js +24 -22
- package/dist/connectors/codex-materialize.d.ts +2 -1
- package/dist/connectors/index.d.ts +2 -1
- package/dist/connectors/index.js +27 -25
- package/dist/consolidation-provenance-check.d.ts +3 -2
- package/dist/consolidation-provenance-check.js +4 -4
- package/dist/consolidation-undo.d.ts +3 -2
- package/dist/consolidation-undo.js +10 -7
- package/dist/consolidation-undo.js.map +1 -1
- package/dist/contradiction/index.d.ts +3 -2
- package/dist/converge-config.d.ts +2 -1
- package/dist/convergence-refresh.d.ts +4 -3
- package/dist/convergence-refresh.js +28 -26
- package/dist/conversation-index/backend.d.ts +2 -1
- package/dist/conversation-index/backend.js +2 -2
- package/dist/conversation-index/chunker.d.ts +2 -1
- package/dist/conversation-index/faiss-adapter.d.ts +2 -1
- package/dist/conversation-index/indexer.d.ts +2 -1
- package/dist/conversation-index/search.d.ts +2 -1
- package/dist/corpus-watermark.d.ts +2 -1
- package/dist/corpus-watermark.js +43 -41
- package/dist/day-summary.d.ts +2 -1
- package/dist/delinearize.d.ts +2 -1
- package/dist/direct-answer-wiring.d.ts +2 -1
- package/dist/direct-answer-wiring.js +2 -2
- package/dist/direct-answer.d.ts +2 -1
- package/dist/embedding-fallback.d.ts +2 -1
- package/dist/embedding-fallback.js +2 -2
- package/dist/enrichment/index.d.ts +2 -1
- package/dist/entity-retrieval-boundaries.js +1 -1
- package/dist/entity-retrieval.d.ts +3 -2
- package/dist/entity-retrieval.js +25 -23
- package/dist/entity-schema.d.ts +2 -1
- package/dist/explicit-capture.d.ts +9 -8
- package/dist/explicit-capture.js +11 -9
- package/dist/external-wiki-access.d.ts +127 -0
- package/dist/external-wiki-access.js +187 -0
- package/dist/external-wiki-access.js.map +1 -0
- package/dist/external-wiki-cli.d.ts +13 -0
- package/dist/external-wiki-cli.js +10 -0
- package/dist/external-wiki-cli.js.map +1 -0
- package/dist/external-wiki-collection-registration.d.ts +39 -0
- package/dist/external-wiki-collection-registration.js +79 -0
- package/dist/external-wiki-collection-registration.js.map +1 -0
- package/dist/external-wiki-collection.d.ts +50 -0
- package/dist/external-wiki-collection.js +387 -0
- package/dist/external-wiki-collection.js.map +1 -0
- package/dist/external-wiki-config.d.ts +13 -0
- package/dist/external-wiki-config.js +13 -0
- package/dist/external-wiki-config.js.map +1 -0
- package/dist/external-wiki-guard.d.ts +11 -0
- package/dist/external-wiki-guard.js +18 -0
- package/dist/external-wiki-guard.js.map +1 -0
- package/dist/external-wiki-mcp-tools.d.ts +123 -0
- package/dist/external-wiki-mcp-tools.js +8 -0
- package/dist/external-wiki-mcp-tools.js.map +1 -0
- package/dist/external-wiki-search.d.ts +42 -0
- package/dist/external-wiki-search.js +11 -0
- package/dist/external-wiki-search.js.map +1 -0
- package/dist/external-wiki.d.ts +39 -0
- package/dist/external-wiki.js +14 -0
- package/dist/external-wiki.js.map +1 -0
- package/dist/extraction-error-classification.d.ts +2 -1
- package/dist/extraction-faithfulness.d.ts +2 -1
- package/dist/extraction-judge-telemetry.d.ts +2 -1
- package/dist/extraction-judge-training.d.ts +2 -1
- package/dist/extraction-judge.d.ts +2 -1
- package/dist/extraction-liveness.d.ts +2 -1
- package/dist/extraction-source-grounding-helpers.d.ts +5 -3
- package/dist/extraction-source-grounding-helpers.js +1 -1
- package/dist/extraction-source-grounding-rules.d.ts +2 -1
- package/dist/extraction-source-grounding-rules.js +2 -2
- package/dist/extraction-source-grounding.d.ts +2 -1
- package/dist/extraction-source-grounding.js +5 -5
- package/dist/extraction.d.ts +2 -1
- package/dist/extraction.js +46 -43
- package/dist/fallback-llm.d.ts +2 -1
- package/dist/{first-start-migration-F2QJD66E.js → first-start-migration-ZSHEFEI3.js} +10 -12
- package/dist/{first-start-migration-F2QJD66E.js.map → first-start-migration-ZSHEFEI3.js.map} +1 -1
- package/dist/graph-dashboard-diff.d.ts +2 -1
- package/dist/graph-dashboard-key.d.ts +2 -1
- package/dist/graph-dashboard-parser.d.ts +2 -1
- package/dist/graph-edge-reinforcement.d.ts +2 -1
- package/dist/graph-snapshot.d.ts +2 -1
- package/dist/graph.d.ts +2 -1
- package/dist/harmonic-retrieval.js +2 -2
- package/dist/importance.d.ts +2 -1
- package/dist/importers/index.d.ts +2 -1
- package/dist/in-flight-reads.d.ts +2 -1
- package/dist/index.d.ts +443 -430
- package/dist/index.js +304 -269
- package/dist/intent.d.ts +2 -1
- package/dist/lcm/engine.d.ts +2 -1
- package/dist/lcm/engine.js +2 -2
- package/dist/lcm/index.d.ts +2 -1
- package/dist/lcm/index.js +7 -7
- package/dist/lcm/tools.d.ts +2 -1
- package/dist/lifecycle.d.ts +2 -1
- package/dist/live-connectors-runner.d.ts +2 -1
- package/dist/local-llm.d.ts +2 -1
- package/dist/local-llm.js +2 -2
- package/dist/local-model-endpoint.d.ts +2 -1
- package/dist/maintenance/memory-governance.d.ts +2 -1
- package/dist/maintenance/memory-governance.js +25 -23
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.d.ts +3 -2
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +25 -23
- package/dist/maintenance/rebuild-memory-projection.d.ts +3 -2
- package/dist/maintenance/rebuild-memory-projection.js +27 -25
- package/dist/{maintenance-LbuS2rUA.d.ts → maintenance-CoRikzIt.d.ts} +3 -3
- package/dist/mcp-memory-inspector-app.d.ts +14 -10
- package/dist/mcp-read-only-tools.js +1 -1
- package/dist/memory-action-policy.d.ts +2 -1
- package/dist/memory-cache.d.ts +2 -1
- package/dist/memory-lifecycle-ledger-utils.d.ts +2 -1
- package/dist/memory-projection-store.d.ts +2 -1
- package/dist/memory-provenance.d.ts +2 -1
- package/dist/memory-snapshot.d.ts +10 -0
- package/dist/memory-snapshot.js +8 -0
- package/dist/memory-snapshot.js.map +1 -0
- package/dist/memory-worth-outcomes.d.ts +3 -2
- package/dist/models-json.d.ts +2 -1
- package/dist/namespaces/migrate.d.ts +4 -3
- package/dist/namespaces/migrate.js +41 -39
- package/dist/namespaces/principal.d.ts +2 -1
- package/dist/namespaces/search.d.ts +2 -1
- package/dist/namespaces/search.js +18 -18
- package/dist/namespaces/storage.d.ts +4 -3
- package/dist/namespaces/storage.js +24 -22
- package/dist/native-knowledge.d.ts +2 -1
- package/dist/offline-sync-impression-drain.d.ts +2 -1
- package/dist/offline-sync-impression-drain.js +11 -9
- package/dist/offline-sync.d.ts +29 -3
- package/dist/offline-sync.js +6 -2
- package/dist/operator-doctor-corpus.d.ts +2 -1
- package/dist/operator-doctor-corpus.js +46 -44
- package/dist/operator-doctor-replica.d.ts +2 -1
- package/dist/operator-doctor-replica.js +3 -3
- package/dist/operator-toolkit.d.ts +4 -3
- package/dist/operator-toolkit.js +60 -55
- package/dist/orchestration/compression-guideline-coordinator.d.ts +3 -2
- package/dist/orchestration/maintenance.d.ts +5 -4
- package/dist/orchestration/maintenance.js +37 -33
- package/dist/{orchestrator-rHiWt32X.d.ts → orchestrator-BJeq7Pw1.d.ts} +14 -7
- package/dist/orchestrator.d.ts +9 -8
- package/dist/orchestrator.js +200 -186
- package/dist/page-versioning.js +3 -3
- package/dist/patterns-cli.d.ts +2 -1
- package/dist/{pipeline-W_97O8BV.d.ts → pipeline-CNjY4wk3.d.ts} +1 -1
- package/dist/policy-runtime.d.ts +2 -1
- package/dist/policy-runtime.js +1 -1
- package/dist/proactive-contention.d.ts +2 -1
- package/dist/provenance.d.ts +2 -1
- package/dist/provenance.js +2 -2
- package/dist/{qmd-LWtMofAf.d.ts → qmd-C0UDZidt.d.ts} +9 -7
- package/dist/qmd-preflight.d.ts +5 -4
- package/dist/qmd-preflight.js +2 -2
- package/dist/qmd-recall-cache.d.ts +2 -1
- package/dist/qmd.d.ts +4 -3
- package/dist/qmd.js +8 -8
- package/dist/recall-concurrency-config.d.ts +2 -1
- package/dist/recall-disclosure-escalation.d.ts +2 -1
- package/dist/recall-explain-renderer.d.ts +2 -1
- package/dist/recall-explain-renderer.js +3 -3
- package/dist/recall-memory-map.d.ts +2 -1
- package/dist/recall-planner-llm.d.ts +2 -1
- package/dist/recall-state.d.ts +2 -1
- package/dist/recall-tag-filter.d.ts +2 -1
- package/dist/recall-timings.d.ts +2 -1
- package/dist/recall-xray-cli.d.ts +2 -1
- package/dist/recall-xray-cli.js +4 -4
- package/dist/recall-xray-renderer.d.ts +2 -1
- package/dist/recall-xray-renderer.js +3 -3
- package/dist/recall-xray.d.ts +8 -1
- package/dist/recall-xray.js +2 -2
- package/dist/reconcile/cursor.d.ts +12 -2
- package/dist/reconcile/cursor.js +46 -7
- package/dist/reconcile/cursor.js.map +1 -1
- package/dist/reconcile/manifest.d.ts +9 -2
- package/dist/reconcile/manifest.js +15 -268
- package/dist/reconcile/manifest.js.map +1 -1
- package/dist/reconcile/plan.d.ts +4 -1
- package/dist/reconcile/plan.js +4 -4
- package/dist/replay/normalizers/chatgpt.d.ts +2 -1
- package/dist/replay/normalizers/claude.d.ts +2 -1
- package/dist/replay/normalizers/openclaw.d.ts +2 -1
- package/dist/replay/normalizers/shared.d.ts +2 -1
- package/dist/replay/runner.d.ts +2 -1
- package/dist/replay/types.d.ts +2 -1
- package/dist/replica-divergence.d.ts +2 -1
- package/dist/replica-divergence.js +2 -2
- package/dist/replica-peers-config.d.ts +2 -1
- package/dist/resolve-auth-token.d.ts +2 -1
- package/dist/resume-bundles.js +12 -10
- package/dist/retrieval-agents.d.ts +4 -3
- package/dist/retrieval-agents.js +2 -2
- package/dist/retrieval-tiers.d.ts +2 -1
- package/dist/routing/engine.d.ts +2 -1
- package/dist/routing/store.d.ts +2 -1
- package/dist/salvage-envelope.d.ts +2 -1
- package/dist/schemas.d.ts +54 -54
- package/dist/{scope-profiles-BiQKOE-p.d.ts → scope-profiles-BJzp2F5A.d.ts} +1 -1
- package/dist/search/embed-helper.d.ts +2 -1
- package/dist/search/embed-helper.js +3 -3
- package/dist/search/factory.d.ts +4 -2
- package/dist/search/factory.js +20 -18
- package/dist/search/index.d.ts +2 -1
- package/dist/search/index.js +20 -20
- package/dist/search/lancedb-backend.d.ts +2 -1
- package/dist/search/lancedb-backend.js +4 -4
- package/dist/search/meilisearch-backend.d.ts +2 -1
- package/dist/search/meilisearch-backend.js +4 -4
- package/dist/search/noop-backend.d.ts +2 -1
- package/dist/search/orama-backend.d.ts +2 -1
- package/dist/search/orama-backend.js +4 -4
- package/dist/search/port.d.ts +18 -1
- package/dist/search/port.js +1 -1
- package/dist/search/remote-backend.d.ts +2 -1
- package/dist/search/remote-backend.js +2 -2
- package/dist/secure-store/index.js +2 -2
- package/dist/{semantic-consolidation-dHYCyqgh.d.ts → semantic-consolidation-D4KAZO2G.d.ts} +1 -1
- package/dist/semantic-consolidation.d.ts +3 -2
- package/dist/semantic-consolidation.js +26 -24
- package/dist/semantic-rule-promotion.js +24 -22
- package/dist/semantic-rule-verifier.d.ts +2 -1
- package/dist/semantic-rule-verifier.js +25 -23
- package/dist/{service-DJG3KCQ4.d.ts → service-DWC4tq7p.d.ts} +2 -2
- package/dist/session-observer-bands.d.ts +2 -1
- package/dist/session-observer-state.d.ts +2 -1
- package/dist/shared-context/manager.d.ts +10 -9
- package/dist/shared-context/manager.js +2 -2
- package/dist/signal.d.ts +2 -1
- package/dist/source-agent-qualifier.d.ts +2 -1
- package/dist/source-agent-qualifier.js +43 -40
- package/dist/{storage-F9FVh-w9.d.ts → storage-DPGjB-8e.d.ts} +28 -13
- package/dist/storage.d.ts +3 -2
- package/dist/storage.js +26 -24
- package/dist/summarizer.d.ts +2 -1
- package/dist/summarizer.js +5 -5
- package/dist/summary-snapshot.d.ts +2 -1
- package/dist/temporal-supersession.d.ts +3 -2
- package/dist/temporal-timeline-recall.d.ts +2 -1
- package/dist/temporal-validity.d.ts +2 -1
- package/dist/threading.d.ts +2 -1
- package/dist/tier-migration.d.ts +3 -2
- package/dist/tier-migration.js +1 -1
- package/dist/tier-routing.d.ts +2 -1
- package/dist/tool-scoped-memory.d.ts +5 -1
- package/dist/tool-scoped-memory.js +3 -1
- package/dist/topics.d.ts +2 -1
- package/dist/transcript.d.ts +2 -1
- package/dist/transfer/capsule-import.js +4 -4
- package/dist/transfer/types.d.ts +66 -66
- package/dist/trust-score-stage.d.ts +2 -1
- package/dist/trust-score.d.ts +2 -1
- package/dist/{types-rEwubvim.d.ts → types-yX_FwERf.d.ts} +8 -1
- package/dist/types.d.ts +2 -1
- package/dist/types.js +1 -1
- package/dist/utility-runtime.d.ts +2 -1
- package/dist/verified-recall.js +25 -23
- package/dist/write-envelope.d.ts +2 -1
- package/package.json +2 -2
- package/src/abort-error.ts +17 -0
- package/src/access-admin-ops-surface.ts +1 -0
- package/src/access-boundary.ts +1 -0
- package/src/access-coding-context-resolution.ts +42 -0
- package/src/access-extraction-force-flush.ts +38 -2
- package/src/access-http-lcm-compaction.ts +5 -2
- package/src/access-http-offline-stream.ts +80 -0
- package/src/access-http.test.ts +310 -3
- package/src/access-http.ts +84 -77
- package/src/access-mcp-output-schemas.ts +36 -0
- package/src/access-mcp.test.ts +95 -1
- package/src/access-mcp.ts +7 -9
- package/src/access-observe-helpers.ts +64 -22
- package/src/access-observe-write-surface.ts +8 -0
- package/src/access-offline-manifest.ts +54 -0
- package/src/access-operations-batch.ts +3 -3
- package/src/access-operations.ts +13 -7
- package/src/access-recall-concurrency.ts +3 -27
- package/src/access-recall-surface.ts +3 -0
- package/src/access-service-health.test.ts +32 -7
- package/src/access-service-namespace.test.ts +55 -0
- package/src/access-service-observe-idempotency.test.ts +34 -2
- package/src/access-service-observe-lcm-parity.test.ts +183 -23
- package/src/access-service-observe-scope.test.ts +160 -1
- package/src/access-service-offline-file-content.test.ts +345 -1
- package/src/access-service.ts +88 -62
- package/src/access-surface-catalog.ts +4 -0
- package/src/admin/admin-surfaces.ts +2 -0
- package/src/binary-lifecycle/pipeline.test.ts +106 -1
- package/src/binary-lifecycle/pipeline.ts +3 -0
- package/src/coding/git-context.test.ts +47 -0
- package/src/coding/git-context.ts +129 -27
- package/src/config.test.ts +24 -0
- package/src/config.ts +9 -12
- package/src/connector-provenance.test.ts +101 -0
- package/src/consolidation-undo.ts +3 -0
- package/src/convergence-refresh.ts +14 -2
- package/src/correction/correction-access-wiring.ts +9 -7
- package/src/correction/correction-executor.test.ts +206 -2
- package/src/correction/correction-executor.ts +29 -20
- package/src/correction/correction-planner.test.ts +36 -0
- package/src/correction/correction-planner.ts +9 -15
- package/src/correction/correction-service.ts +3 -1
- package/src/correction/correction-storage-integration.test.ts +77 -0
- package/src/correction/correction-surfaces.test.ts +41 -28
- package/src/correction/passive-capture.test.ts +59 -0
- package/src/correction/passive-capture.ts +4 -1
- package/src/entity-retrieval-boundaries.ts +17 -4
- package/src/entity-retrieval.ts +27 -6
- package/src/external-wiki-access.test.ts +65 -0
- package/src/external-wiki-access.ts +31 -0
- package/src/external-wiki-cli.ts +100 -0
- package/src/external-wiki-collection-registration.test.ts +163 -0
- package/src/external-wiki-collection-registration.ts +101 -0
- package/src/external-wiki-collection.test.ts +502 -0
- package/src/external-wiki-collection.ts +503 -0
- package/src/external-wiki-config.test.ts +135 -0
- package/src/external-wiki-config.ts +100 -0
- package/src/external-wiki-guard.ts +83 -0
- package/src/external-wiki-mcp-tools.ts +23 -0
- package/src/external-wiki-search.test.ts +367 -0
- package/src/external-wiki-search.ts +362 -0
- package/src/external-wiki.test.ts +240 -0
- package/src/external-wiki.ts +427 -0
- package/src/extraction-scope-source-agent.test.ts +21 -0
- package/src/extraction-source-grounding-helpers.ts +243 -53
- package/src/extraction-source-grounding-rules.ts +133 -39
- package/src/extraction-source-grounding.test.ts +363 -33
- package/src/extraction-timeout.test.ts +1 -0
- package/src/extraction-watermark.test.ts +150 -7
- package/src/extraction.ts +8 -1
- package/src/index.ts +9 -5
- package/src/maintenance/first-start-migration.ts +11 -11
- package/src/mcp-read-only-tools.ts +1 -0
- package/src/memory-snapshot.ts +15 -0
- package/src/offline-sync.test.ts +194 -0
- package/src/offline-sync.ts +217 -13
- package/src/orchestration/external-wiki-recall-guard.test.ts +94 -0
- package/src/orchestration/extraction-persist.ts +19 -2
- package/src/orchestration/extraction-run-helpers.ts +37 -19
- package/src/orchestration/extraction-run.test.ts +171 -2
- package/src/orchestration/extraction-run.ts +11 -13
- package/src/orchestration/extraction-watermark.ts +106 -17
- package/src/orchestration/generic-recall-paths.ts +14 -0
- package/src/orchestration/orchestrator-helpers.ts +2 -0
- package/src/orchestration/orchestrator-init.ts +9 -0
- package/src/orchestration/recall-internal-deps.ts +6 -0
- package/src/orchestration/recall-internal.ts +154 -33
- package/src/orchestration/recall-rerank-coordinator.ts +60 -25
- package/src/orchestration/recall-search-pipeline.test.ts +75 -1
- package/src/orchestration/recall-search-pipeline.ts +50 -10
- package/src/orchestrator-convergence-refresh.test.ts +36 -2
- package/src/orchestrator.ts +13 -3
- package/src/page-versioning.ts +5 -19
- package/src/procedural/procedure-recall.ts +5 -1
- package/src/provenance-surfaces.test.ts +3 -0
- package/src/qmd-client.test.ts +78 -17
- package/src/qmd.test.ts +24 -0
- package/src/qmd.ts +224 -315
- package/src/recall-explain-renderer.ts +3 -0
- package/src/recall-rerank-coordinator.test.ts +61 -0
- package/src/recall-xray-renderer.test.ts +6 -0
- package/src/recall-xray.test.ts +88 -1
- package/src/recall-xray.ts +15 -0
- package/src/reconcile/cursor.test.ts +48 -0
- package/src/reconcile/cursor.ts +58 -11
- package/src/reconcile/manifest.test.ts +4 -0
- package/src/reconcile/manifest.ts +41 -51
- package/src/reconcile/plan.test.ts +4 -0
- package/src/reconcile/plan.ts +28 -16
- package/src/search/factory.ts +6 -6
- package/src/search/port.ts +25 -9
- package/src/secure-store/secure-fs.ts +20 -12
- package/src/secure-store/secure-store.test.ts +41 -2
- package/src/spaces/index.test.ts +61 -2
- package/src/spaces/index.ts +44 -18
- package/src/storage/entity-alias-config.ts +97 -0
- package/src/storage/entity-canonical-id-lock.ts +53 -23
- package/src/storage/entity-canonical-id-migration.ts +53 -22
- package/src/storage/entity-canonical-id-references.ts +3 -0
- package/src/storage/entity-id-safety.ts +7 -0
- package/src/storage/entity-store.ts +6 -2
- package/src/storage/memory-frontmatter-metadata.ts +4 -9
- package/src/storage/memory-migration-serialization.ts +10 -15
- package/src/storage/tombstone-blocked-capture-mutation.ts +52 -64
- package/src/storage/tombstone-blocked-capture-sync.ts +244 -199
- package/src/storage-contract/cache-coherence.test.ts +99 -0
- package/src/storage-deletion-revisions.test.ts +91 -0
- package/src/storage-fact-hash-index-defer.test.ts +460 -170
- package/src/storage.ts +572 -284
- package/src/testing/subjects/first-start-tier-migration.test.ts +75 -0
- package/src/tier-migration.ts +10 -12
- package/src/tool-scoped-memory.ts +10 -0
- package/src/transfer/capsule-import.ts +13 -0
- package/src/transfer/capsule-merge.ts +13 -0
- package/src/trust-score-recall-paths.test.ts +75 -1
- package/src/types.ts +7 -3
- package/dist/capsule-merge-IDWJPCWK.js.map +0 -1
- package/dist/chunk-3CE77VAP.js.map +0 -1
- package/dist/chunk-3TBLDMJA.js.map +0 -1
- package/dist/chunk-4J7G5SY4.js.map +0 -1
- package/dist/chunk-57QKLRBV.js.map +0 -1
- package/dist/chunk-5TFP4CUL.js.map +0 -1
- package/dist/chunk-7XC2HX75.js.map +0 -1
- package/dist/chunk-A5OJCXZL.js.map +0 -1
- package/dist/chunk-BUE5E2HL.js.map +0 -1
- package/dist/chunk-CJ2ZR7UA.js.map +0 -1
- package/dist/chunk-CUM2BBPN.js.map +0 -1
- package/dist/chunk-D3J5SLQK.js.map +0 -1
- package/dist/chunk-DL7ZD3JH.js.map +0 -1
- package/dist/chunk-DLVPUX7U.js.map +0 -1
- package/dist/chunk-E6PNLPGJ.js.map +0 -1
- package/dist/chunk-ECK75GDJ.js.map +0 -1
- package/dist/chunk-HREE4JHI.js.map +0 -1
- package/dist/chunk-HZFHQ4AQ.js.map +0 -1
- package/dist/chunk-IKKWIPYN.js.map +0 -1
- package/dist/chunk-J7VGGECD.js.map +0 -1
- package/dist/chunk-N5Z4EVOR.js.map +0 -1
- package/dist/chunk-NVRYW264.js.map +0 -1
- package/dist/chunk-P2BM76KT.js.map +0 -1
- package/dist/chunk-PVGDJXVK.js +0 -21
- package/dist/chunk-QJAQNXWI.js.map +0 -1
- package/dist/chunk-RN7DY3FC.js.map +0 -1
- package/dist/chunk-RVLJEII5.js.map +0 -1
- package/dist/chunk-S2NCTZGJ.js.map +0 -1
- package/dist/chunk-TDHTVMPG.js.map +0 -1
- package/dist/chunk-UYLMNVY6.js.map +0 -1
- package/dist/chunk-VCD4PSK2.js.map +0 -1
- package/dist/chunk-VNA7W7QF.js.map +0 -1
- package/dist/chunk-VOUOLGIP.js.map +0 -1
- package/dist/chunk-VWAXN2BN.js.map +0 -1
- package/dist/chunk-WOCNN776.js.map +0 -1
- package/dist/chunk-XYTOI63Z.js.map +0 -1
- package/dist/chunk-YV32N67O.js.map +0 -1
- /package/dist/{auto-sync-5OE5QOZB.js.map → auto-sync-UPTUVE4X.js.map} +0 -0
- /package/dist/{chunk-E5UK4VPE.js.map → chunk-2FSTB6BJ.js.map} +0 -0
- /package/dist/{chunk-5ZE7QHTK.js.map → chunk-2X2T2UVE.js.map} +0 -0
- /package/dist/{chunk-P4DRWEYC.js.map → chunk-3COYXTGM.js.map} +0 -0
- /package/dist/{chunk-5IVLTFOV.js.map → chunk-44N6ESJ4.js.map} +0 -0
- /package/dist/{chunk-HO3QBJEY.js.map → chunk-5546W5SI.js.map} +0 -0
- /package/dist/{chunk-AAIUERNB.js.map → chunk-5QJQHBLE.js.map} +0 -0
- /package/dist/{chunk-6CZPDBJS.js.map → chunk-5U7ID3EZ.js.map} +0 -0
- /package/dist/{chunk-DNWXFTLD.js.map → chunk-A4IJCD2Z.js.map} +0 -0
- /package/dist/{chunk-PKNLM44P.js.map → chunk-AC5OWJLV.js.map} +0 -0
- /package/dist/{chunk-LZ4LDKHZ.js.map → chunk-AMAUBUKY.js.map} +0 -0
- /package/dist/{chunk-S5SLVSVY.js.map → chunk-BQIFZ2MP.js.map} +0 -0
- /package/dist/{chunk-Q6IP2ARR.js.map → chunk-CSOYVTRX.js.map} +0 -0
- /package/dist/{chunk-XOQSEF7X.js.map → chunk-CVILPI77.js.map} +0 -0
- /package/dist/{chunk-4LMA77JH.js.map → chunk-E5XQIWAL.js.map} +0 -0
- /package/dist/{chunk-WUNIWKY4.js.map → chunk-ELIL2A37.js.map} +0 -0
- /package/dist/{chunk-OQ5PRDDS.js.map → chunk-ERZ2R42X.js.map} +0 -0
- /package/dist/{chunk-U7GW7NE7.js.map → chunk-FIK3CQNA.js.map} +0 -0
- /package/dist/{chunk-33PLLLL7.js.map → chunk-GFCVUY6G.js.map} +0 -0
- /package/dist/{chunk-VUPTKTDV.js.map → chunk-GUAL4PQH.js.map} +0 -0
- /package/dist/{chunk-CINZGPSJ.js.map → chunk-GUMZC2BO.js.map} +0 -0
- /package/dist/{chunk-H24WNPA2.js.map → chunk-GWFSVJ4P.js.map} +0 -0
- /package/dist/{chunk-TSH56VPU.js.map → chunk-HAYSYUAB.js.map} +0 -0
- /package/dist/{chunk-PDLBLTOK.js.map → chunk-HC3PBX23.js.map} +0 -0
- /package/dist/{chunk-KXB4VXHY.js.map → chunk-JIYDRBVZ.js.map} +0 -0
- /package/dist/{chunk-HLPD7B7P.js.map → chunk-JZH4LWHB.js.map} +0 -0
- /package/dist/{chunk-AV5ZEH4M.js.map → chunk-KVJRXN2E.js.map} +0 -0
- /package/dist/{chunk-WFTIGIIS.js.map → chunk-L6CQ7WIW.js.map} +0 -0
- /package/dist/{chunk-227UFSEQ.js.map → chunk-LEPOP46W.js.map} +0 -0
- /package/dist/{chunk-EJUEXZHX.js.map → chunk-LLJMAULE.js.map} +0 -0
- /package/dist/{chunk-QN25OCUF.js.map → chunk-LPYDOLSM.js.map} +0 -0
- /package/dist/{chunk-AS7YMSL6.js.map → chunk-M23RF3LJ.js.map} +0 -0
- /package/dist/{chunk-OAEQLRCY.js.map → chunk-MO4HSXHZ.js.map} +0 -0
- /package/dist/{chunk-3F2LKUMU.js.map → chunk-NIS256NW.js.map} +0 -0
- /package/dist/{chunk-YIAA2X3D.js.map → chunk-NK5RGJ65.js.map} +0 -0
- /package/dist/{chunk-7TWUCYER.js.map → chunk-PNRA7FAD.js.map} +0 -0
- /package/dist/{chunk-5I4M26Q7.js.map → chunk-QBSFOKY6.js.map} +0 -0
- /package/dist/{chunk-E53DSZEN.js.map → chunk-QR6G5KF4.js.map} +0 -0
- /package/dist/{chunk-4UH4BTGK.js.map → chunk-QVJPH7SH.js.map} +0 -0
- /package/dist/{chunk-JBPKEARU.js.map → chunk-RKNJBZ55.js.map} +0 -0
- /package/dist/{chunk-WDISJRMG.js.map → chunk-RMMVQQA6.js.map} +0 -0
- /package/dist/{chunk-JVLCVFQ4.js.map → chunk-RNHVVMFN.js.map} +0 -0
- /package/dist/{chunk-5SM35XZR.js.map → chunk-S5NZBKKQ.js.map} +0 -0
- /package/dist/{chunk-WIPEXG6R.js.map → chunk-SXIMQLGV.js.map} +0 -0
- /package/dist/{chunk-7K5Q6COX.js.map → chunk-TVVEYCNW.js.map} +0 -0
- /package/dist/{chunk-4B77XSG5.js.map → chunk-UV72DEZD.js.map} +0 -0
- /package/dist/{chunk-BJKPPZ6Z.js.map → chunk-UW66OZTD.js.map} +0 -0
- /package/dist/{chunk-S2BBISHU.js.map → chunk-VANZKHTN.js.map} +0 -0
- /package/dist/{chunk-3Y224NYC.js.map → chunk-VYISFWVX.js.map} +0 -0
- /package/dist/{chunk-JE7EK33X.js.map → chunk-W2V7UESE.js.map} +0 -0
- /package/dist/{chunk-TIHMZFIV.js.map → chunk-W3IC7QOY.js.map} +0 -0
- /package/dist/{chunk-NRV4Y3PM.js.map → chunk-W4FBGYGK.js.map} +0 -0
- /package/dist/{chunk-MU7ZHSZE.js.map → chunk-WZFAPHIK.js.map} +0 -0
- /package/dist/{chunk-T2TTP3KU.js.map → chunk-X4IDNPOS.js.map} +0 -0
- /package/dist/{chunk-UVIKWC7M.js.map → chunk-XAGYS7X6.js.map} +0 -0
- /package/dist/{chunk-BLAKS3CP.js.map → chunk-XL3TATMJ.js.map} +0 -0
- /package/dist/{chunk-W4XJFLAL.js.map → chunk-XPRJSHNI.js.map} +0 -0
- /package/dist/{chunk-E6EE5B67.js.map → chunk-YK6BDDHP.js.map} +0 -0
- /package/dist/{chunk-ES36HTSC.js.map → chunk-YLHM5BQQ.js.map} +0 -0
- /package/dist/{chunk-GF22HWS2.js.map → chunk-Z54EM5YZ.js.map} +0 -0
- /package/dist/{chunk-64UDOIMI.js.map → chunk-ZLQ37WJX.js.map} +0 -0
package/src/storage.ts
CHANGED
|
@@ -4,18 +4,21 @@ import {
|
|
|
4
4
|
readdir,
|
|
5
5
|
readFile,
|
|
6
6
|
realpath,
|
|
7
|
+
rename,
|
|
7
8
|
stat,
|
|
8
9
|
writeFile,
|
|
9
10
|
mkdir,
|
|
10
11
|
unlink,
|
|
11
12
|
appendFile,
|
|
12
13
|
open,
|
|
14
|
+
type FileHandle,
|
|
13
15
|
} from "node:fs/promises";
|
|
14
16
|
import { appendFileSync, createReadStream, mkdirSync, readFileSync, statSync, type Dirent } from "node:fs";
|
|
15
|
-
import { createHash } from "node:crypto";
|
|
17
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
16
18
|
import { normalizeContent, computeContentHash } from "./content-hash.js";
|
|
17
19
|
import path from "node:path";
|
|
18
20
|
import { log } from "./logger.js";
|
|
21
|
+
import { createMemorySnapshot } from "./memory-snapshot.js";
|
|
19
22
|
import { assertMemoryFrontmatterId, warnProjectionFallback } from "./storage-guards.js";
|
|
20
23
|
import { MemoryReadStore } from "./storage/memory-read-store.js";
|
|
21
24
|
import { renderProfileWithLastUpdated } from "./storage/profile-header.js";
|
|
@@ -45,10 +48,13 @@ import {
|
|
|
45
48
|
import { EntityCanonicalIdMigrationRunner } from "./storage/entity-canonical-id-migration-runner.js";
|
|
46
49
|
import { rememberRawFrontmatter } from "./storage/memory-frontmatter-metadata.js";
|
|
47
50
|
import { createMemoryEntityRefSerializer } from "./storage/memory-migration-serialization.js";
|
|
51
|
+
import { readEntityAliasConfigSync } from "./storage/entity-alias-config.js";
|
|
52
|
+
import { assertSafeEntityId } from "./storage/entity-id-safety.js";
|
|
48
53
|
export { normalizeEntityName } from "./entity-id-normalization.js";
|
|
49
54
|
import { isErrnoCode } from "./utils/errno.js";
|
|
50
55
|
import { getCategoryDir, categoryDirName } from "./utils/category-dir.js";
|
|
51
56
|
import { decodeYamlScalar } from "./utils/yaml-scalar.js";
|
|
57
|
+
import { withHeldFileLock, type HeldFileLockController } from "./utils/serialize-mutations.js";
|
|
52
58
|
import { qmdCollectionPathParts, qmdResultPathCandidates } from "./orchestration/qmd-result-resolver.js";
|
|
53
59
|
import {
|
|
54
60
|
clearMemoryCache,
|
|
@@ -72,6 +78,7 @@ import {
|
|
|
72
78
|
} from "./in-flight-reads.js";
|
|
73
79
|
import { rotateMarkdownFileToArchive } from "./hygiene.js";
|
|
74
80
|
import { sanitizeMemoryContent } from "./sanitize.js";
|
|
81
|
+
import { withholdToolScopedFromSharedNamespace } from "./tool-scoped-memory.js";
|
|
75
82
|
import {
|
|
76
83
|
serializeProvenanceFields,
|
|
77
84
|
parseProvenanceSources,
|
|
@@ -191,6 +198,11 @@ import {
|
|
|
191
198
|
parseTombstoneBlockedOfflineSyncMemory,
|
|
192
199
|
type TombstoneBlockedCaptureIndexOptions,
|
|
193
200
|
} from "./storage/tombstone-blocked-capture-index.js";
|
|
201
|
+
import {
|
|
202
|
+
buildCapturePathLockIdentity,
|
|
203
|
+
isQueuedReviewMemory,
|
|
204
|
+
tombstoneBlocked,
|
|
205
|
+
} from "./storage/tombstone-blocked-capture-mutation.js";
|
|
194
206
|
export { ContentHashIndex, FactHashIndexNotAuthoritativeError };
|
|
195
207
|
export type { ContentHashIndexLockOptions };
|
|
196
208
|
export {
|
|
@@ -264,6 +276,37 @@ type OfflineSyncDigestCacheEntry = {
|
|
|
264
276
|
bytes: number;
|
|
265
277
|
};
|
|
266
278
|
|
|
279
|
+
type DeletionRevisionMetadata = {
|
|
280
|
+
version: 1;
|
|
281
|
+
deletions: Array<{ path: string; mtimeMs: number }>;
|
|
282
|
+
};
|
|
283
|
+
|
|
284
|
+
const DELETION_REVISION_MAX_MTIME_MS = 8_640_000_000_000_000;
|
|
285
|
+
const DELETION_REVISION_LOCK_STALE_MS = 60_000;
|
|
286
|
+
const DELETION_REVISION_LOCK_MAX_WAIT_MS = 120_000;
|
|
287
|
+
|
|
288
|
+
function isValidDeletionRevisionPath(value: unknown): value is string {
|
|
289
|
+
return (
|
|
290
|
+
typeof value === "string" &&
|
|
291
|
+
value.length > 0 &&
|
|
292
|
+
!value.includes("\\") &&
|
|
293
|
+
!value.includes("\0") &&
|
|
294
|
+
!path.posix.isAbsolute(value) &&
|
|
295
|
+
path.posix.normalize(value) === value &&
|
|
296
|
+
value !== "." &&
|
|
297
|
+
value !== ".." &&
|
|
298
|
+
!value.startsWith("../")
|
|
299
|
+
);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
function deletionRevisionPathIdentity(value: string): string {
|
|
303
|
+
return value
|
|
304
|
+
.normalize("NFC")
|
|
305
|
+
.toUpperCase()
|
|
306
|
+
.toLowerCase()
|
|
307
|
+
.replace(/\u00df/g, "ss");
|
|
308
|
+
}
|
|
309
|
+
|
|
267
310
|
export interface ReextractJobRequest {
|
|
268
311
|
memoryId: string;
|
|
269
312
|
model: string;
|
|
@@ -343,6 +386,7 @@ function serializeFrontmatter(fm: MemoryFrontmatter): string {
|
|
|
343
386
|
const safe = /^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(fm.sourceConnector);
|
|
344
387
|
lines.push(`sourceConnector: ${safe ? fm.sourceConnector : JSON.stringify(fm.sourceConnector)}`);
|
|
345
388
|
}
|
|
389
|
+
if (fm.toolScoped === true) lines.push("toolScoped: true");
|
|
346
390
|
if (fm.supersedes) lines.push(`supersedes: ${fm.supersedes}`);
|
|
347
391
|
if (fm.expiresAt) lines.push(`expiresAt: ${fm.expiresAt}`);
|
|
348
392
|
if (fm.lineage && fm.lineage.length > 0) {
|
|
@@ -609,7 +653,7 @@ function parseReinforcementCountField(raw: string | undefined): number | undefin
|
|
|
609
653
|
}
|
|
610
654
|
|
|
611
655
|
export function parseFrontmatter(raw: string): { frontmatter: MemoryFrontmatter; content: string } | null {
|
|
612
|
-
const match = raw.match(/^---\n([\s\S]*?)\n
|
|
656
|
+
const match = raw.match(/^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)([\s\S]*)$/);
|
|
613
657
|
if (!match) return null;
|
|
614
658
|
|
|
615
659
|
const fmBlock = match[1];
|
|
@@ -867,6 +911,7 @@ export function parseFrontmatter(raw: string): { frontmatter: MemoryFrontmatter;
|
|
|
867
911
|
tags,
|
|
868
912
|
entityRef: fm.entityRef || undefined,
|
|
869
913
|
sourceConnector: fm.sourceConnector ? decodeYamlScalar(fm.sourceConnector) || undefined : undefined,
|
|
914
|
+
toolScoped: fm.toolScoped === "true" ? true : undefined,
|
|
870
915
|
supersedes: fm.supersedes || undefined,
|
|
871
916
|
expiresAt: fm.expiresAt || undefined,
|
|
872
917
|
lineage: lineage && lineage.length > 0 ? lineage : undefined,
|
|
@@ -1024,7 +1069,6 @@ function inferCurrentStateStatus(
|
|
|
1024
1069
|
return inferMemoryStatus(frontmatter, pathRel, fallbackStatus);
|
|
1025
1070
|
}
|
|
1026
1071
|
|
|
1027
|
-
|
|
1028
1072
|
/**
|
|
1029
1073
|
* Simple Levenshtein distance between two strings.
|
|
1030
1074
|
*/
|
|
@@ -1720,6 +1764,7 @@ export interface WriteMemoryOptions {
|
|
|
1720
1764
|
sources?: ProvenanceSource[];
|
|
1721
1765
|
provenance?: "verified" | "unverified" | "none";
|
|
1722
1766
|
sourceConnector?: string;
|
|
1767
|
+
toolScoped?: true;
|
|
1723
1768
|
}
|
|
1724
1769
|
|
|
1725
1770
|
/**
|
|
@@ -1735,6 +1780,7 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
1735
1780
|
private knowledgeIndexCache: { result: string; builtAt: number } | null = null;
|
|
1736
1781
|
private artifactIndexCache: { memories: MemoryFile[]; loadedAtMs: number; writeVersion: number } | null = null;
|
|
1737
1782
|
private projectionLedgerLagManager = new ProjectionLedgerLagManager();
|
|
1783
|
+
private static readonly loadedMemorySnapshots = new WeakMap<MemoryFile, string>();
|
|
1738
1784
|
static readonly KNOWLEDGE_INDEX_CACHE_TTL_MS = 600_000; // 10 minutes (entity mutations invalidate)
|
|
1739
1785
|
/** Read by storage/memory-read-store.ts (decomposition). */
|
|
1740
1786
|
static readonly ARTIFACT_INDEX_CACHE_TTL_MS = 60_000; // 1 minute
|
|
@@ -2005,9 +2051,7 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
2005
2051
|
setSecureStoreKey(key: Buffer | null, encryptOnWrite = true): void {
|
|
2006
2052
|
if (!this.applySecureStoreKey(key, encryptOnWrite) || key === null) return;
|
|
2007
2053
|
void this.entityCanonicalIdMigration.triggerAfterUnlock().catch((error: unknown) => {
|
|
2008
|
-
log.warn(
|
|
2009
|
-
`secure-store unlock migration failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
2010
|
-
);
|
|
2054
|
+
log.warn(`secure-store unlock migration failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
2011
2055
|
});
|
|
2012
2056
|
}
|
|
2013
2057
|
|
|
@@ -2316,10 +2360,7 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
2316
2360
|
return path.join(this.stateDir, `.${kind}-version.log`);
|
|
2317
2361
|
}
|
|
2318
2362
|
|
|
2319
|
-
private bumpSharedVersion(
|
|
2320
|
-
kind: SharedVersionKind,
|
|
2321
|
-
fallbackMap: Map<string, number>
|
|
2322
|
-
): number {
|
|
2363
|
+
private bumpSharedVersion(kind: SharedVersionKind, fallbackMap: Map<string, number>): number {
|
|
2323
2364
|
const filePath = this.versionFilePath(kind);
|
|
2324
2365
|
try {
|
|
2325
2366
|
mkdirSync(this.stateDir, { recursive: true });
|
|
@@ -2334,10 +2375,7 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
2334
2375
|
}
|
|
2335
2376
|
}
|
|
2336
2377
|
|
|
2337
|
-
private readSharedVersion(
|
|
2338
|
-
kind: SharedVersionKind,
|
|
2339
|
-
fallbackMap: Map<string, number>
|
|
2340
|
-
): number {
|
|
2378
|
+
private readSharedVersion(kind: SharedVersionKind, fallbackMap: Map<string, number>): number {
|
|
2341
2379
|
const filePath = this.versionFilePath(kind);
|
|
2342
2380
|
try {
|
|
2343
2381
|
return statSync(filePath).size;
|
|
@@ -2364,15 +2402,14 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
2364
2402
|
}
|
|
2365
2403
|
|
|
2366
2404
|
/**
|
|
2367
|
-
* Entity
|
|
2368
|
-
* The migration fingerprint keys on this instead of memory-status, so
|
|
2369
|
-
* supersede/archive/delete no longer re-trigger discovery scans (#2213).
|
|
2405
|
+
* Entity content revision used by migration discovery and entity-page cache coherence.
|
|
2370
2406
|
*/
|
|
2371
2407
|
getEntityMutationVersion(): number {
|
|
2372
2408
|
return this.readSharedVersion("entity-mutation", StorageManager.entityMutationVersionByDir);
|
|
2373
2409
|
}
|
|
2374
2410
|
|
|
2375
2411
|
protected bumpEntityMutationVersion(): void {
|
|
2412
|
+
invalidateForScope(this.baseDir, "entity-write");
|
|
2376
2413
|
this.bumpSharedVersion("entity-mutation", StorageManager.entityMutationVersionByDir);
|
|
2377
2414
|
}
|
|
2378
2415
|
|
|
@@ -2646,6 +2683,217 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
2646
2683
|
return resolved;
|
|
2647
2684
|
}
|
|
2648
2685
|
|
|
2686
|
+
private parseDeletionRevisionMetadata(raw: string): Map<string, number> {
|
|
2687
|
+
let parsed: unknown;
|
|
2688
|
+
try {
|
|
2689
|
+
parsed = JSON.parse(raw);
|
|
2690
|
+
} catch {
|
|
2691
|
+
throw new Error("Deletion revision metadata is invalid.");
|
|
2692
|
+
}
|
|
2693
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
2694
|
+
throw new Error("Deletion revision metadata is invalid.");
|
|
2695
|
+
}
|
|
2696
|
+
const root = parsed as Record<string, unknown>;
|
|
2697
|
+
if (
|
|
2698
|
+
Object.keys(root).sort().join(",") !== "deletions,version" ||
|
|
2699
|
+
root.version !== 1 ||
|
|
2700
|
+
!Array.isArray(root.deletions)
|
|
2701
|
+
) {
|
|
2702
|
+
throw new Error("Deletion revision metadata is invalid.");
|
|
2703
|
+
}
|
|
2704
|
+
const revisions = new Map<string, number>();
|
|
2705
|
+
const pathByIdentity = new Map<string, string>();
|
|
2706
|
+
for (const rawEntry of root.deletions) {
|
|
2707
|
+
if (!rawEntry || typeof rawEntry !== "object" || Array.isArray(rawEntry)) {
|
|
2708
|
+
throw new Error("Deletion revision metadata is invalid.");
|
|
2709
|
+
}
|
|
2710
|
+
const entry = rawEntry as Record<string, unknown>;
|
|
2711
|
+
if (
|
|
2712
|
+
Object.keys(entry).sort().join(",") !== "mtimeMs,path" ||
|
|
2713
|
+
!isValidDeletionRevisionPath(entry.path) ||
|
|
2714
|
+
typeof entry.mtimeMs !== "number" ||
|
|
2715
|
+
!Number.isFinite(entry.mtimeMs) ||
|
|
2716
|
+
entry.mtimeMs < 0 ||
|
|
2717
|
+
entry.mtimeMs > DELETION_REVISION_MAX_MTIME_MS ||
|
|
2718
|
+
revisions.has(entry.path)
|
|
2719
|
+
) {
|
|
2720
|
+
throw new Error("Deletion revision metadata is invalid.");
|
|
2721
|
+
}
|
|
2722
|
+
const identity = deletionRevisionPathIdentity(entry.path);
|
|
2723
|
+
if (pathByIdentity.has(identity)) {
|
|
2724
|
+
throw new Error("Deletion revision metadata is invalid.");
|
|
2725
|
+
}
|
|
2726
|
+
pathByIdentity.set(identity, entry.path);
|
|
2727
|
+
revisions.set(entry.path, entry.mtimeMs);
|
|
2728
|
+
}
|
|
2729
|
+
return new Map([...revisions.entries()].sort(([left], [right]) => (left < right ? -1 : left > right ? 1 : 0)));
|
|
2730
|
+
}
|
|
2731
|
+
|
|
2732
|
+
private async readDeletionRevisionMetadata(): Promise<Map<string, number>> {
|
|
2733
|
+
let raw: string;
|
|
2734
|
+
try {
|
|
2735
|
+
raw = await readFile(this.deletionRevisionMetadataPath, "utf8");
|
|
2736
|
+
} catch (error) {
|
|
2737
|
+
if (isErrnoCode(error, "ENOENT")) return new Map();
|
|
2738
|
+
throw new Error("Deletion revision metadata is unavailable.");
|
|
2739
|
+
}
|
|
2740
|
+
return this.parseDeletionRevisionMetadata(raw);
|
|
2741
|
+
}
|
|
2742
|
+
|
|
2743
|
+
private async writeDeletionRevisionMetadata(
|
|
2744
|
+
revisions: ReadonlyMap<string, number>,
|
|
2745
|
+
lock: HeldFileLockController
|
|
2746
|
+
): Promise<void> {
|
|
2747
|
+
const deletions = [...revisions.entries()]
|
|
2748
|
+
.sort(([left], [right]) => (left < right ? -1 : left > right ? 1 : 0))
|
|
2749
|
+
.map(([entryPath, mtimeMs]) => ({ path: entryPath, mtimeMs }));
|
|
2750
|
+
const metadata: DeletionRevisionMetadata = { version: 1, deletions };
|
|
2751
|
+
const temporaryPath = `${this.deletionRevisionMetadataPath}.${process.pid}.${randomUUID()}.tmp`;
|
|
2752
|
+
let handle: FileHandle | null = null;
|
|
2753
|
+
try {
|
|
2754
|
+
handle = await open(temporaryPath, "wx", 0o600);
|
|
2755
|
+
await handle.writeFile(`${JSON.stringify(metadata)}\n`, "utf8");
|
|
2756
|
+
await handle.sync();
|
|
2757
|
+
await handle.close();
|
|
2758
|
+
handle = null;
|
|
2759
|
+
if (!(await lock.refresh())) {
|
|
2760
|
+
throw new Error("Deletion revision metadata lock was lost.");
|
|
2761
|
+
}
|
|
2762
|
+
await rename(temporaryPath, this.deletionRevisionMetadataPath);
|
|
2763
|
+
} finally {
|
|
2764
|
+
if (handle !== null) await handle.close().catch(() => undefined);
|
|
2765
|
+
await unlink(temporaryPath).catch((error: unknown) => {
|
|
2766
|
+
if (!isErrnoCode(error, "ENOENT")) throw error;
|
|
2767
|
+
});
|
|
2768
|
+
}
|
|
2769
|
+
}
|
|
2770
|
+
|
|
2771
|
+
private async withDeletionRevisionLock<T>(task: (lock: HeldFileLockController) => Promise<T>): Promise<T> {
|
|
2772
|
+
return withHeldFileLock(
|
|
2773
|
+
this.deletionRevisionLockPath,
|
|
2774
|
+
{
|
|
2775
|
+
staleMs: DELETION_REVISION_LOCK_STALE_MS,
|
|
2776
|
+
maxWaitMs: DELETION_REVISION_LOCK_MAX_WAIT_MS,
|
|
2777
|
+
},
|
|
2778
|
+
async (acquired, lock) => {
|
|
2779
|
+
if (!acquired) throw new Error("Deletion revision metadata lock is unavailable.");
|
|
2780
|
+
return task(lock);
|
|
2781
|
+
}
|
|
2782
|
+
);
|
|
2783
|
+
}
|
|
2784
|
+
|
|
2785
|
+
async readDeletionRevisions(): Promise<ReadonlyMap<string, number>> {
|
|
2786
|
+
return this.withDeletionRevisionLock(async () => this.readDeletionRevisionMetadata());
|
|
2787
|
+
}
|
|
2788
|
+
|
|
2789
|
+
async recordReplicatedDeletionRevision(filePath: string, mtimeMs: number): Promise<void> {
|
|
2790
|
+
const target = this.assertManagedStoragePath(filePath, "storage.recordReplicatedDeletionRevision");
|
|
2791
|
+
if (
|
|
2792
|
+
typeof mtimeMs !== "number" ||
|
|
2793
|
+
!Number.isFinite(mtimeMs) ||
|
|
2794
|
+
mtimeMs < 0 ||
|
|
2795
|
+
mtimeMs > DELETION_REVISION_MAX_MTIME_MS
|
|
2796
|
+
) {
|
|
2797
|
+
throw new Error("Deletion revision timestamp is invalid.");
|
|
2798
|
+
}
|
|
2799
|
+
const relativePath = path.relative(this.baseDir, target).split(path.sep).join("/");
|
|
2800
|
+
if (!isValidDeletionRevisionPath(relativePath)) {
|
|
2801
|
+
throw new Error("Deletion revision path is invalid.");
|
|
2802
|
+
}
|
|
2803
|
+
await this.withDeletionRevisionLock(async (lock) => {
|
|
2804
|
+
const revisions = await this.readDeletionRevisionMetadata();
|
|
2805
|
+
const identity = deletionRevisionPathIdentity(relativePath);
|
|
2806
|
+
let existingPath: string | undefined;
|
|
2807
|
+
for (const candidatePath of revisions.keys()) {
|
|
2808
|
+
if (deletionRevisionPathIdentity(candidatePath) === identity) {
|
|
2809
|
+
existingPath = candidatePath;
|
|
2810
|
+
break;
|
|
2811
|
+
}
|
|
2812
|
+
}
|
|
2813
|
+
const existingMtimeMs = existingPath === undefined ? undefined : revisions.get(existingPath);
|
|
2814
|
+
if (existingMtimeMs !== undefined && existingMtimeMs >= mtimeMs) return;
|
|
2815
|
+
|
|
2816
|
+
const updated = new Map(revisions);
|
|
2817
|
+
if (existingPath !== undefined) updated.delete(existingPath);
|
|
2818
|
+
updated.set(relativePath, mtimeMs);
|
|
2819
|
+
await this.writeDeletionRevisionMetadata(updated, lock);
|
|
2820
|
+
});
|
|
2821
|
+
}
|
|
2822
|
+
|
|
2823
|
+
protected async writeManagedStorageFile(filePath: string, write: () => Promise<void>): Promise<void> {
|
|
2824
|
+
const target = this.assertManagedStoragePath(filePath, "storage.writeManagedStorageFile");
|
|
2825
|
+
const relativePath = path.relative(this.baseDir, target).split(path.sep).join("/");
|
|
2826
|
+
if (!isValidDeletionRevisionPath(relativePath)) {
|
|
2827
|
+
throw new Error("Deletion revision path is invalid.");
|
|
2828
|
+
}
|
|
2829
|
+
await this.withDeletionRevisionLock(async (lock) => {
|
|
2830
|
+
const before = await this.readDeletionRevisionMetadata();
|
|
2831
|
+
const identity = deletionRevisionPathIdentity(relativePath);
|
|
2832
|
+
const existingPath = [...before.keys()].find(
|
|
2833
|
+
(candidatePath) => deletionRevisionPathIdentity(candidatePath) === identity
|
|
2834
|
+
);
|
|
2835
|
+
await write();
|
|
2836
|
+
if (existingPath === undefined) return;
|
|
2837
|
+
const updated = new Map(before);
|
|
2838
|
+
updated.delete(existingPath);
|
|
2839
|
+
await this.writeDeletionRevisionMetadata(updated, lock);
|
|
2840
|
+
});
|
|
2841
|
+
}
|
|
2842
|
+
|
|
2843
|
+
protected async deleteManagedStorageFile(filePath: string, deletionMtimeMs?: number | null): Promise<boolean> {
|
|
2844
|
+
const target = this.assertManagedStoragePath(filePath, "storage.deleteManagedStorageFile");
|
|
2845
|
+
if (
|
|
2846
|
+
deletionMtimeMs !== undefined &&
|
|
2847
|
+
deletionMtimeMs !== null &&
|
|
2848
|
+
(typeof deletionMtimeMs !== "number" ||
|
|
2849
|
+
!Number.isFinite(deletionMtimeMs) ||
|
|
2850
|
+
deletionMtimeMs < 0 ||
|
|
2851
|
+
deletionMtimeMs > DELETION_REVISION_MAX_MTIME_MS)
|
|
2852
|
+
) {
|
|
2853
|
+
throw new Error("Deletion revision timestamp is invalid.");
|
|
2854
|
+
}
|
|
2855
|
+
return this.withDeletionRevisionLock(async (lock) => {
|
|
2856
|
+
try {
|
|
2857
|
+
await lstat(target);
|
|
2858
|
+
} catch (error) {
|
|
2859
|
+
if (isErrnoCode(error, "ENOENT")) return false;
|
|
2860
|
+
throw error;
|
|
2861
|
+
}
|
|
2862
|
+
const relativePath = path.relative(this.baseDir, target).split(path.sep).join("/");
|
|
2863
|
+
if (!isValidDeletionRevisionPath(relativePath)) {
|
|
2864
|
+
throw new Error("Deletion revision path is invalid.");
|
|
2865
|
+
}
|
|
2866
|
+
const revision = deletionMtimeMs === null ? undefined : (deletionMtimeMs ?? Date.now());
|
|
2867
|
+
const before = await this.readDeletionRevisionMetadata();
|
|
2868
|
+
const identity = deletionRevisionPathIdentity(relativePath);
|
|
2869
|
+
let existingPath: string | undefined;
|
|
2870
|
+
for (const candidatePath of before.keys()) {
|
|
2871
|
+
if (deletionRevisionPathIdentity(candidatePath) === identity) {
|
|
2872
|
+
existingPath = candidatePath;
|
|
2873
|
+
break;
|
|
2874
|
+
}
|
|
2875
|
+
}
|
|
2876
|
+
const existing = existingPath === undefined ? undefined : before.get(existingPath);
|
|
2877
|
+
const changed =
|
|
2878
|
+
(existingPath !== undefined && existingPath !== relativePath) ||
|
|
2879
|
+
(revision === undefined ? existing !== undefined : existing !== revision);
|
|
2880
|
+
if (changed) {
|
|
2881
|
+
const updated = new Map(before);
|
|
2882
|
+
if (existingPath !== undefined) updated.delete(existingPath);
|
|
2883
|
+
if (revision !== undefined) updated.set(relativePath, revision);
|
|
2884
|
+
await this.writeDeletionRevisionMetadata(updated, lock);
|
|
2885
|
+
}
|
|
2886
|
+
try {
|
|
2887
|
+
await unlink(target);
|
|
2888
|
+
return true;
|
|
2889
|
+
} catch (error) {
|
|
2890
|
+
if (changed) await this.writeDeletionRevisionMetadata(before, lock);
|
|
2891
|
+
if (isErrnoCode(error, "ENOENT")) return false;
|
|
2892
|
+
throw error;
|
|
2893
|
+
}
|
|
2894
|
+
});
|
|
2895
|
+
}
|
|
2896
|
+
|
|
2649
2897
|
async readOfflineSyncFile(filePath: string): Promise<Buffer> {
|
|
2650
2898
|
const target = this.assertManagedStoragePath(filePath, "storage.readOfflineSyncFile");
|
|
2651
2899
|
return readMaybeEncryptedFileBuffer(target, this._secureStoreKey, this.baseDir);
|
|
@@ -2929,6 +3177,12 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
2929
3177
|
private get offlineSyncDigestCachePath(): string {
|
|
2930
3178
|
return path.join(this.baseDir, ".offline-sync", "digest-cache.v1.json");
|
|
2931
3179
|
}
|
|
3180
|
+
private get deletionRevisionMetadataPath(): string {
|
|
3181
|
+
return path.join(this.baseDir, ".offline-sync", "deletion-revisions.v1.json");
|
|
3182
|
+
}
|
|
3183
|
+
private get deletionRevisionLockPath(): string {
|
|
3184
|
+
return `${this.deletionRevisionMetadataPath}.lock`;
|
|
3185
|
+
}
|
|
2932
3186
|
private get entitySynthesisQueuePath(): string {
|
|
2933
3187
|
return path.join(this.stateDir, "entity-synthesis-queue.json");
|
|
2934
3188
|
}
|
|
@@ -3062,7 +3316,7 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
3062
3316
|
() => this.currentHistoricalIds(),
|
|
3063
3317
|
(identity) => store.appendTombstone({ ...input, rawContent: strippedRawContent, ...identity }),
|
|
3064
3318
|
(tombstoneId) => store.revoke(tombstoneId, input.createdBy),
|
|
3065
|
-
input.sourceMemoryId
|
|
3319
|
+
input.sourceMemoryId
|
|
3066
3320
|
);
|
|
3067
3321
|
} catch (err) {
|
|
3068
3322
|
log.warn(`tombstone append failed (memory=${input.sourceMemoryId}): ${err}`);
|
|
@@ -3455,12 +3709,12 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
3455
3709
|
private readonly entityCanonicalIdMigration = new EntityCanonicalIdMigrationRunner(
|
|
3456
3710
|
() => !(this._secureStoreRequired && !this.isSecureStoreUnlocked()),
|
|
3457
3711
|
() => this.runLegacyEntityCanonicalIdMigration(),
|
|
3458
|
-
() => entityMigration.getFingerprint(this.baseDir, this.entitiesDir, () => String(this.getEntityMutationVersion()))
|
|
3712
|
+
() => entityMigration.getFingerprint(this.baseDir, this.entitiesDir, () => String(this.getEntityMutationVersion()))
|
|
3459
3713
|
);
|
|
3460
3714
|
normalizeEntityName(raw: string, type: string): string {
|
|
3461
3715
|
return entityRefs.resolveHistoricalEntityCanonicalId(
|
|
3462
3716
|
this.entityStore.normalizeEntityName(raw, type),
|
|
3463
|
-
this.currentHistoricalIds()
|
|
3717
|
+
this.currentHistoricalIds()
|
|
3464
3718
|
);
|
|
3465
3719
|
}
|
|
3466
3720
|
|
|
@@ -3485,27 +3739,28 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
3485
3739
|
|
|
3486
3740
|
private loadAliasesSync(): void {
|
|
3487
3741
|
const aliasPath = path.join(this.baseDir, "config", "aliases.json");
|
|
3488
|
-
// Re-derive from the file on every call: a reload after the file was
|
|
3489
|
-
// fixed, emptied, or removed must never leave a previous table active.
|
|
3490
3742
|
this.userAliases = {};
|
|
3743
|
+
const raw = readEntityAliasConfigSync(this.baseDir);
|
|
3744
|
+
if (raw === undefined) return;
|
|
3745
|
+
let parsed: unknown;
|
|
3491
3746
|
try {
|
|
3492
|
-
|
|
3493
|
-
|
|
3494
|
-
|
|
3495
|
-
|
|
3496
|
-
|
|
3497
|
-
|
|
3498
|
-
|
|
3499
|
-
|
|
3747
|
+
parsed = JSON.parse(raw);
|
|
3748
|
+
} catch {
|
|
3749
|
+
log.debug("invalid config/aliases.json — using built-in aliases only");
|
|
3750
|
+
return;
|
|
3751
|
+
}
|
|
3752
|
+
if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
|
|
3753
|
+
const cleaned: Record<string, string> = {};
|
|
3754
|
+
for (const [key, value] of Object.entries(parsed)) {
|
|
3755
|
+
if (typeof value === "string" && value.trim().length > 0) {
|
|
3756
|
+
assertSafeEntityId(value);
|
|
3757
|
+
cleaned[key] = value;
|
|
3500
3758
|
}
|
|
3501
|
-
this.userAliases = cleaned;
|
|
3502
|
-
log.debug(`loaded ${Object.keys(cleaned).length} entity aliases from ${aliasPath}`);
|
|
3503
|
-
} else {
|
|
3504
|
-
log.warn(`ignoring ${aliasPath}: payload must be a JSON object mapping variant → canonical strings`);
|
|
3505
3759
|
}
|
|
3506
|
-
|
|
3507
|
-
|
|
3508
|
-
|
|
3760
|
+
this.userAliases = cleaned;
|
|
3761
|
+
log.debug(`loaded ${Object.keys(cleaned).length} entity aliases from ${aliasPath}`);
|
|
3762
|
+
} else {
|
|
3763
|
+
log.warn(`ignoring ${aliasPath}: payload must be a JSON object mapping variant → canonical strings`);
|
|
3509
3764
|
}
|
|
3510
3765
|
}
|
|
3511
3766
|
private async runLegacyEntityCanonicalIdMigration(): Promise<string | undefined> {
|
|
@@ -3513,7 +3768,7 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
3513
3768
|
this as unknown as EntityCanonicalIdMigrationHost,
|
|
3514
3769
|
(content) => parseEntityFile(content, this.entitySchemas),
|
|
3515
3770
|
(entity) => serializeEntityFile(entity, this.entitySchemas),
|
|
3516
|
-
createMemoryEntityRefSerializer(serializeFrontmatter)
|
|
3771
|
+
createMemoryEntityRefSerializer(serializeFrontmatter)
|
|
3517
3772
|
);
|
|
3518
3773
|
return completionFingerprint;
|
|
3519
3774
|
}
|
|
@@ -3690,6 +3945,15 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
3690
3945
|
if (!sanitized.clean) {
|
|
3691
3946
|
log.warn(`memory content sanitized for ${id}; violations=${sanitized.violations.join(", ")}`);
|
|
3692
3947
|
}
|
|
3948
|
+
if (
|
|
3949
|
+
options.toolScoped ||
|
|
3950
|
+
withholdToolScopedFromSharedNamespace({
|
|
3951
|
+
content: sanitized.text,
|
|
3952
|
+
sourceConnector: options.sourceConnector,
|
|
3953
|
+
})
|
|
3954
|
+
) {
|
|
3955
|
+
fm.toolScoped = true;
|
|
3956
|
+
}
|
|
3693
3957
|
|
|
3694
3958
|
// Persist the raw-content dedup hash on the frontmatter so archive and
|
|
3695
3959
|
// consolidation paths can remove the correct hash from ContentHashIndex
|
|
@@ -3754,14 +4018,41 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
3754
4018
|
await this.writeTombstoneBlockedMemory(filePath, fileContent, fm, sanitized.text, async () => {
|
|
3755
4019
|
this.invalidateAllMemoriesCache();
|
|
3756
4020
|
});
|
|
4021
|
+
if (refIds && typeof rawEntityRef === "string") {
|
|
4022
|
+
const refBeforeRepair = fm.entityRef;
|
|
4023
|
+
try {
|
|
4024
|
+
await entityRefs.repairEntityRefAfterJournalMove({
|
|
4025
|
+
stateDir: this.stateDir,
|
|
4026
|
+
currentIds: () => this.currentHistoricalIds(),
|
|
4027
|
+
idsAtResolve: refIds,
|
|
4028
|
+
rawRef: rawEntityRef,
|
|
4029
|
+
frontmatter: fm,
|
|
4030
|
+
rewrite: async () => {
|
|
4031
|
+
await applyTombstoneGate();
|
|
4032
|
+
await this.writeTombstoneBlockedMemory(
|
|
4033
|
+
filePath,
|
|
4034
|
+
`${serializeFrontmatter(fm)}\n\n${sanitized.text}\n`,
|
|
4035
|
+
fm,
|
|
4036
|
+
sanitized.text,
|
|
4037
|
+
async () => this.invalidateAllMemoriesCache()
|
|
4038
|
+
);
|
|
4039
|
+
this.invalidateAllMemoriesCache();
|
|
4040
|
+
},
|
|
4041
|
+
});
|
|
4042
|
+
} catch (err) {
|
|
4043
|
+
await unlink(filePath).catch(() => undefined);
|
|
4044
|
+
this.invalidateAllMemoriesCache();
|
|
4045
|
+
await this.rebuildTombstoneBlockedCaptureAfterInvalidationForPath(filePath);
|
|
4046
|
+
throw err;
|
|
4047
|
+
}
|
|
4048
|
+
await this.entityRefRepair.syncProjection(id, refBeforeRepair, fm.entityRef);
|
|
4049
|
+
}
|
|
3757
4050
|
return null;
|
|
3758
4051
|
};
|
|
3759
|
-
const duplicateBlocked =
|
|
3760
|
-
|
|
3761
|
-
|
|
3762
|
-
|
|
3763
|
-
)
|
|
3764
|
-
: await persistFile();
|
|
4052
|
+
const duplicateBlocked = await this.withTombstoneBlockedCaptureWriteLock(persistFile, [
|
|
4053
|
+
buildCapturePathLockIdentity(filePath),
|
|
4054
|
+
buildExplicitCaptureDedupKey(sanitized.text, category, fm.sourceConnector),
|
|
4055
|
+
]);
|
|
3765
4056
|
if (duplicateBlocked) {
|
|
3766
4057
|
return {
|
|
3767
4058
|
id: duplicateBlocked.frontmatter.id,
|
|
@@ -3770,38 +4061,6 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
3770
4061
|
duplicateOf: duplicateBlocked.frontmatter.id,
|
|
3771
4062
|
};
|
|
3772
4063
|
}
|
|
3773
|
-
if (refIds && typeof rawEntityRef === "string") {
|
|
3774
|
-
const refBeforeRepair = fm.entityRef;
|
|
3775
|
-
try {
|
|
3776
|
-
await entityRefs.repairEntityRefAfterJournalMove({
|
|
3777
|
-
stateDir: this.stateDir,
|
|
3778
|
-
currentIds: () => this.currentHistoricalIds(),
|
|
3779
|
-
idsAtResolve: refIds,
|
|
3780
|
-
rawRef: rawEntityRef,
|
|
3781
|
-
frontmatter: fm,
|
|
3782
|
-
rewrite: async () => {
|
|
3783
|
-
// Re-gate under the final ref, then rewrite THROUGH the blocked-
|
|
3784
|
-
// capture surface so any verdict change keeps the index consistent.
|
|
3785
|
-
await applyTombstoneGate();
|
|
3786
|
-
await this.writeTombstoneBlockedMemory(
|
|
3787
|
-
filePath,
|
|
3788
|
-
`${serializeFrontmatter(fm)}\n\n${sanitized.text}\n`,
|
|
3789
|
-
fm,
|
|
3790
|
-
sanitized.text,
|
|
3791
|
-
async () => this.invalidateAllMemoriesCache(),
|
|
3792
|
-
);
|
|
3793
|
-
this.invalidateAllMemoriesCache();
|
|
3794
|
-
},
|
|
3795
|
-
});
|
|
3796
|
-
} catch (err) {
|
|
3797
|
-
// Remove the just-created file before propagating (§14): it would
|
|
3798
|
-
// linger un-bumped/un-indexed and a retry would duplicate it.
|
|
3799
|
-
await unlink(filePath).catch(() => undefined);
|
|
3800
|
-
this.invalidateAllMemoriesCache();
|
|
3801
|
-
throw err;
|
|
3802
|
-
}
|
|
3803
|
-
await this.entityRefRepair.syncProjection(id, refBeforeRepair, fm.entityRef);
|
|
3804
|
-
}
|
|
3805
4064
|
await this.patchHotMemoriesCache({ addedPath: filePath }, "memory-create");
|
|
3806
4065
|
this.notifyMemoryWrite(filePath);
|
|
3807
4066
|
await this.appendGeneratedMemoryLifecycleEventFailOpen("storage.writeMemory", {
|
|
@@ -4073,6 +4332,7 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
4073
4332
|
intentActionType?: string;
|
|
4074
4333
|
intentEntityTypes?: string[];
|
|
4075
4334
|
sourceConnector?: string;
|
|
4335
|
+
toolScoped?: true;
|
|
4076
4336
|
} = {}
|
|
4077
4337
|
): Promise<string> {
|
|
4078
4338
|
await this.ensureDirectories();
|
|
@@ -4098,6 +4358,7 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
4098
4358
|
intentActionType: options.intentActionType,
|
|
4099
4359
|
intentEntityTypes: options.intentEntityTypes,
|
|
4100
4360
|
...(options.sourceConnector ? { sourceConnector: options.sourceConnector } : {}),
|
|
4361
|
+
...(options.toolScoped ? { toolScoped: true as const } : {}),
|
|
4101
4362
|
};
|
|
4102
4363
|
|
|
4103
4364
|
const sanitized = sanitizeMemoryContent(quote);
|
|
@@ -4227,16 +4488,10 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
4227
4488
|
if (newBullets.length === 0) return;
|
|
4228
4489
|
|
|
4229
4490
|
if (!existing) {
|
|
4230
|
-
const content = [
|
|
4231
|
-
"# Behavioral Profile",
|
|
4232
|
-
"",
|
|
4233
|
-
...newBullets.map((b) => `- ${b}`),
|
|
4234
|
-
"",
|
|
4235
|
-
].join("\n");
|
|
4491
|
+
const content = ["# Behavioral Profile", "", ...newBullets.map((b) => `- ${b}`), ""].join("\n");
|
|
4236
4492
|
await this.writeProfile(content);
|
|
4237
4493
|
} else {
|
|
4238
|
-
const withBullets =
|
|
4239
|
-
existing.trimEnd() + "\n" + newBullets.map((b) => `- ${b}`).join("\n") + "\n";
|
|
4494
|
+
const withBullets = existing.trimEnd() + "\n" + newBullets.map((b) => `- ${b}`).join("\n") + "\n";
|
|
4240
4495
|
await this.writeProfile(withBullets);
|
|
4241
4496
|
}
|
|
4242
4497
|
}
|
|
@@ -4251,13 +4506,19 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
4251
4506
|
return lineCount > threshold;
|
|
4252
4507
|
}
|
|
4253
4508
|
|
|
4509
|
+
private rememberMemorySnapshot<T extends MemoryFile | null>(memory: T): T {
|
|
4510
|
+
if (memory !== null && !StorageManager.loadedMemorySnapshots.has(memory)) {
|
|
4511
|
+
StorageManager.loadedMemorySnapshots.set(memory, createMemorySnapshot(memory));
|
|
4512
|
+
}
|
|
4513
|
+
return memory;
|
|
4514
|
+
}
|
|
4515
|
+
|
|
4516
|
+
private rememberMemorySnapshots(memories: MemoryFile[]): MemoryFile[] {
|
|
4517
|
+
for (const memory of memories) this.rememberMemorySnapshot(memory);
|
|
4518
|
+
return memories;
|
|
4519
|
+
}
|
|
4520
|
+
|
|
4254
4521
|
async readAllMemories(): Promise<MemoryFile[]> {
|
|
4255
|
-
// Version-keyed hot-memories cache (issue #1902): once populated, serve the
|
|
4256
|
-
// full parsed corpus from memory within a version epoch. getCachedMemories
|
|
4257
|
-
// returns null when the sentinel is 0 (fresh/test dirs) or the stored
|
|
4258
|
-
// version differs from the current on-disk sentinel (a peer or local write
|
|
4259
|
-
// bumped it), so a stale entry is never served — the miss falls through to
|
|
4260
|
-
// a fresh disk scan below.
|
|
4261
4522
|
if (this.hotMemoriesCacheEnabled) {
|
|
4262
4523
|
const cached = getCachedMemories(
|
|
4263
4524
|
this.baseDir,
|
|
@@ -4265,13 +4526,8 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
4265
4526
|
this.hotCacheKeyId(),
|
|
4266
4527
|
this.hotCacheTtlMs()
|
|
4267
4528
|
);
|
|
4268
|
-
|
|
4269
|
-
// for a cached EMPTY corpus, which is falsy — a truthiness guard would
|
|
4270
|
-
// force a full disk scan on every read of an empty/near-empty store.
|
|
4271
|
-
if (cached !== null) return cached;
|
|
4529
|
+
if (cached !== null) return this.rememberMemorySnapshots(cached);
|
|
4272
4530
|
}
|
|
4273
|
-
// Deduplicate concurrent reads for the same directory so multiple
|
|
4274
|
-
// callers in the same recall share one disk scan.
|
|
4275
4531
|
// Snapshot the secure-store key identity ONCE (issue #1902, Codex Medium):
|
|
4276
4532
|
// hotCacheKeyId() can change mid-scan if setSecureStoreKey(null/other) runs
|
|
4277
4533
|
// during the await. Recomputing it at publish time would store K-decrypted
|
|
@@ -4281,13 +4537,9 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
4281
4537
|
// key change can't orphan the slot registered under the old identity.
|
|
4282
4538
|
const keyId = this.hotCacheKeyId();
|
|
4283
4539
|
const inFlight = getInFlightRead(this.baseDir, keyId);
|
|
4284
|
-
if (inFlight) return inFlight;
|
|
4540
|
+
if (inFlight) return this.rememberMemorySnapshots(await inFlight);
|
|
4285
4541
|
|
|
4286
4542
|
const readPromise = (async (): Promise<MemoryFile[]> => {
|
|
4287
|
-
// Capture the version BEFORE the scan and store under it. If a concurrent
|
|
4288
|
-
// bump (peer or local write) lands during the scan, the stored entry's
|
|
4289
|
-
// version is older than the sentinel, so the next getCachedMemories()
|
|
4290
|
-
// rejects it (version mismatch → rescan) — correct, never stale.
|
|
4291
4543
|
const version = this.getMemoryCorpusVersion();
|
|
4292
4544
|
const memories = await this._readAllMemoriesFromDisk();
|
|
4293
4545
|
// Publish only if neither the corpus version NOR the key identity changed
|
|
@@ -4301,11 +4553,8 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
4301
4553
|
})();
|
|
4302
4554
|
setInFlightRead(this.baseDir, keyId, readPromise);
|
|
4303
4555
|
try {
|
|
4304
|
-
return await readPromise;
|
|
4556
|
+
return this.rememberMemorySnapshots(await readPromise);
|
|
4305
4557
|
} finally {
|
|
4306
|
-
// Only delete if we still own the slot for our snapshot key identity —
|
|
4307
|
-
// invalidateAllMemoriesCache() may have already cleared it and a new read
|
|
4308
|
-
// may have claimed it (the expected-promise guard enforces owner-only).
|
|
4309
4558
|
deleteInFlightRead(this.baseDir, keyId, readPromise);
|
|
4310
4559
|
}
|
|
4311
4560
|
}
|
|
@@ -4601,15 +4850,18 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
4601
4850
|
const raw = await readMaybeEncryptedFile(fullPath, this._secureStoreKey, this.baseDir);
|
|
4602
4851
|
const parsed = parseFrontmatter(raw);
|
|
4603
4852
|
if (!parsed) return null;
|
|
4604
|
-
return rememberRawFrontmatter(
|
|
4605
|
-
|
|
4606
|
-
|
|
4607
|
-
|
|
4608
|
-
|
|
4609
|
-
|
|
4610
|
-
|
|
4611
|
-
|
|
4612
|
-
|
|
4853
|
+
return rememberRawFrontmatter(
|
|
4854
|
+
{
|
|
4855
|
+
path: fullPath,
|
|
4856
|
+
frontmatter: normalizeFrontmatterForPath(
|
|
4857
|
+
parsed.frontmatter,
|
|
4858
|
+
toMemoryPathRel(this.baseDir, fullPath),
|
|
4859
|
+
parsed.content
|
|
4860
|
+
),
|
|
4861
|
+
content: parsed.content,
|
|
4862
|
+
} satisfies MemoryFile,
|
|
4863
|
+
raw
|
|
4864
|
+
);
|
|
4613
4865
|
} catch (err) {
|
|
4614
4866
|
// Re-throw store-locked errors so a locked encrypted store fails
|
|
4615
4867
|
// loudly rather than appearing as an empty memory corpus (Cursor
|
|
@@ -4737,7 +4989,7 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
4737
4989
|
}
|
|
4738
4990
|
|
|
4739
4991
|
async readAllColdMemories(): Promise<MemoryFile[]> {
|
|
4740
|
-
return this.memoryReadStore.readAllColdMemories();
|
|
4992
|
+
return this.rememberMemorySnapshots(await this.memoryReadStore.readAllColdMemories());
|
|
4741
4993
|
}
|
|
4742
4994
|
|
|
4743
4995
|
/**
|
|
@@ -4760,15 +5012,20 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
4760
5012
|
const raw = await readMaybeEncryptedFile(fullPath, this._secureStoreKey, this.baseDir);
|
|
4761
5013
|
const parsed = parseFrontmatter(raw);
|
|
4762
5014
|
if (parsed) {
|
|
4763
|
-
memories.push(
|
|
4764
|
-
|
|
4765
|
-
|
|
4766
|
-
|
|
4767
|
-
|
|
4768
|
-
|
|
4769
|
-
|
|
4770
|
-
|
|
4771
|
-
|
|
5015
|
+
memories.push(
|
|
5016
|
+
rememberRawFrontmatter(
|
|
5017
|
+
{
|
|
5018
|
+
path: fullPath,
|
|
5019
|
+
frontmatter: normalizeFrontmatterForPath(
|
|
5020
|
+
parsed.frontmatter,
|
|
5021
|
+
toMemoryPathRel(this.baseDir, fullPath),
|
|
5022
|
+
parsed.content
|
|
5023
|
+
),
|
|
5024
|
+
content: parsed.content,
|
|
5025
|
+
},
|
|
5026
|
+
raw
|
|
5027
|
+
)
|
|
5028
|
+
);
|
|
4772
5029
|
}
|
|
4773
5030
|
} catch (err) {
|
|
4774
5031
|
// Re-throw store-locked errors — a locked encrypted store
|
|
@@ -4784,11 +5041,11 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
4784
5041
|
};
|
|
4785
5042
|
|
|
4786
5043
|
await readDir(root);
|
|
4787
|
-
return memories;
|
|
5044
|
+
return this.rememberMemorySnapshots(memories);
|
|
4788
5045
|
}
|
|
4789
5046
|
|
|
4790
5047
|
async readMemoryByPath(filePath: string): Promise<MemoryFile | null> {
|
|
4791
|
-
return this.memoryReadStore.readMemoryByPath(filePath);
|
|
5048
|
+
return this.rememberMemorySnapshot(await this.memoryReadStore.readMemoryByPath(filePath));
|
|
4792
5049
|
}
|
|
4793
5050
|
|
|
4794
5051
|
private resolveTierRootDir(tier: "hot" | "cold"): string {
|
|
@@ -4816,12 +5073,6 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
4816
5073
|
// corrections/ is flat (no date subdir); preserved across tier moves.
|
|
4817
5074
|
return path.join(root, "corrections", `${memory.frontmatter.id}.md`);
|
|
4818
5075
|
}
|
|
4819
|
-
// Every other category — decisions/, preferences/, reasoning-traces/, ...
|
|
4820
|
-
// plus the facts/ fallback for fact/entity/unknown — resolves through the
|
|
4821
|
-
// shared categoryDirName() chokepoint so tier moves land in the SAME dir the
|
|
4822
|
-
// writer used, instead of funneling non-{correction,procedure,reasoning_trace}
|
|
4823
|
-
// categories into facts/ (issue #564 PR 3 preserved reasoning-traces/; #1546
|
|
4824
|
-
// generalizes it to every category dir).
|
|
4825
5076
|
const dir = categoryDirName(memory.frontmatter.category);
|
|
4826
5077
|
return path.join(root, dir, this.resolveMemoryDateDir(memory), `${memory.frontmatter.id}.md`);
|
|
4827
5078
|
}
|
|
@@ -4838,7 +5089,7 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
4838
5089
|
`${serializeFrontmatter(frontmatter)}\n\n${memory.content}\n`,
|
|
4839
5090
|
this.resolveWriteKey(),
|
|
4840
5091
|
{},
|
|
4841
|
-
this.baseDir
|
|
5092
|
+
this.baseDir
|
|
4842
5093
|
);
|
|
4843
5094
|
// Snapshot pre-write destination bytes (raw — encryption-agnostic) so a
|
|
4844
5095
|
// repair failure restores them or removes a fresh copy (§14): a retained
|
|
@@ -4876,25 +5127,67 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
4876
5127
|
this.invalidateAllMemoriesCache();
|
|
4877
5128
|
this.notifyCatalogWrite();
|
|
4878
5129
|
}
|
|
4879
|
-
async moveMemoryToPath(memory: MemoryFile, targetPath: string): Promise<
|
|
4880
|
-
await this.
|
|
4881
|
-
|
|
4882
|
-
|
|
4883
|
-
|
|
4884
|
-
|
|
4885
|
-
|
|
4886
|
-
|
|
4887
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
4888
|
-
if (!message.includes("ENOENT")) {
|
|
4889
|
-
throw err;
|
|
5130
|
+
async moveMemoryToPath(memory: MemoryFile, targetPath: string): Promise<boolean> {
|
|
5131
|
+
const changed = await this.withTombstoneBlockedMemoryPathLock(
|
|
5132
|
+
memory.path,
|
|
5133
|
+
async (current) => {
|
|
5134
|
+
const destination = await this.readMemoryByPath(targetPath);
|
|
5135
|
+
if (current?.frontmatter.id !== memory.frontmatter.id) {
|
|
5136
|
+
if (current === null && destination?.frontmatter.id === memory.frontmatter.id) return false;
|
|
5137
|
+
throw new Error(`memory ${memory.frontmatter.id} changed before its tier move`);
|
|
4890
5138
|
}
|
|
4891
|
-
|
|
4892
|
-
|
|
4893
|
-
|
|
4894
|
-
|
|
4895
|
-
|
|
4896
|
-
|
|
5139
|
+
const callerSnapshot = StorageManager.loadedMemorySnapshots.get(memory);
|
|
5140
|
+
const currentSnapshot = createMemorySnapshot(current);
|
|
5141
|
+
if (
|
|
5142
|
+
callerSnapshot === undefined
|
|
5143
|
+
? current.frontmatter.updated !== memory.frontmatter.updated
|
|
5144
|
+
: currentSnapshot !== callerSnapshot
|
|
5145
|
+
) {
|
|
5146
|
+
throw new Error(`memory ${memory.frontmatter.id} changed before its tier move`);
|
|
5147
|
+
}
|
|
5148
|
+
const coordinate =
|
|
5149
|
+
tombstoneBlocked(current.frontmatter) ||
|
|
5150
|
+
isQueuedReviewMemory(current) ||
|
|
5151
|
+
(destination !== null && tombstoneBlocked(destination.frontmatter)) ||
|
|
5152
|
+
isQueuedReviewMemory(destination);
|
|
5153
|
+
const index = this.getTombstoneBlockedCaptureIndex();
|
|
5154
|
+
const marker = coordinate ? await index.prepareWrite() : undefined;
|
|
5155
|
+
const projectedPath = toMemoryPathRel(this.baseDir, targetPath);
|
|
5156
|
+
let durable = false;
|
|
5157
|
+
try {
|
|
5158
|
+
if (destination?.frontmatter.id === current.frontmatter.id) {
|
|
5159
|
+
await this.deleteManagedStorageFile(current.path);
|
|
5160
|
+
durable = true;
|
|
5161
|
+
this.invalidateAllMemoriesCache();
|
|
5162
|
+
updateProjectedMemoryPath(this.baseDir, current.frontmatter.id, projectedPath);
|
|
5163
|
+
} else {
|
|
5164
|
+
await this.writeMemoryFileAtomic(targetPath, current);
|
|
5165
|
+
if (memory.frontmatter.entityRef !== current.frontmatter.entityRef) {
|
|
5166
|
+
memory.frontmatter.entityRef = current.frontmatter.entityRef;
|
|
5167
|
+
}
|
|
5168
|
+
durable = true;
|
|
5169
|
+
const sourcePath = path.resolve(current.path);
|
|
5170
|
+
const destPath = path.resolve(targetPath);
|
|
5171
|
+
if (sourcePath !== destPath) {
|
|
5172
|
+
await this.deleteManagedStorageFile(current.path);
|
|
5173
|
+
this.invalidateAllMemoriesCache();
|
|
5174
|
+
updateProjectedMemoryPath(this.baseDir, current.frontmatter.id, projectedPath);
|
|
5175
|
+
}
|
|
5176
|
+
}
|
|
5177
|
+
if (marker !== undefined) await this.rebuildTombstoneBlockedCaptureAfterInvalidation(marker);
|
|
5178
|
+
} catch (error) {
|
|
5179
|
+
if (marker !== undefined && !durable) await index.discardWrite(marker).catch(() => index.markUntrusted());
|
|
5180
|
+
if (marker !== undefined && durable) index.markUntrusted();
|
|
5181
|
+
throw error;
|
|
5182
|
+
}
|
|
5183
|
+
return true;
|
|
5184
|
+
},
|
|
5185
|
+
[targetPath]
|
|
5186
|
+
);
|
|
5187
|
+
if (this.isColdOrArchiveTierPath(memory.path) || this.isColdOrArchiveTierPath(targetPath)) {
|
|
5188
|
+
this.invalidateColdMemoriesCache();
|
|
4897
5189
|
}
|
|
5190
|
+
return changed;
|
|
4898
5191
|
}
|
|
4899
5192
|
|
|
4900
5193
|
async migrateMemoryToTier(
|
|
@@ -4907,31 +5200,10 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
4907
5200
|
if (sourcePath === destPath) {
|
|
4908
5201
|
return { changed: false, targetPath };
|
|
4909
5202
|
}
|
|
4910
|
-
|
|
4911
|
-
|
|
4912
|
-
if (existing?.frontmatter.id === memory.frontmatter.id) {
|
|
4913
|
-
try {
|
|
4914
|
-
await unlink(memory.path);
|
|
4915
|
-
} catch (err) {
|
|
4916
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
4917
|
-
if (!message.includes("ENOENT")) {
|
|
4918
|
-
throw err;
|
|
4919
|
-
}
|
|
4920
|
-
}
|
|
4921
|
-
updateProjectedMemoryPath(this.baseDir, memory.frontmatter.id, toMemoryPathRel(this.baseDir, targetPath));
|
|
4922
|
-
this.bumpMemoryStatusVersion();
|
|
4923
|
-
return { changed: false, targetPath };
|
|
4924
|
-
}
|
|
4925
|
-
|
|
4926
|
-
await this.moveMemoryToPath(memory, targetPath);
|
|
4927
|
-
this.invalidateAllMemoriesCache();
|
|
4928
|
-
// If moving to cold, also invalidate the cold-scan cache so the next
|
|
4929
|
-
// readAllColdMemories() call sees the newly-demoted file (Finding UOGi fix).
|
|
4930
|
-
if (targetTier === "cold") {
|
|
4931
|
-
this.invalidateColdMemoriesCache();
|
|
4932
|
-
}
|
|
5203
|
+
const changed = await this.moveMemoryToPath(memory, targetPath);
|
|
5204
|
+
if (!changed) return { changed: false, targetPath };
|
|
4933
5205
|
this.bumpMemoryStatusVersion();
|
|
4934
|
-
return { changed
|
|
5206
|
+
return { changed, targetPath };
|
|
4935
5207
|
}
|
|
4936
5208
|
|
|
4937
5209
|
private get archiveDir(): string {
|
|
@@ -4959,7 +5231,7 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
4959
5231
|
archivedAt: now.toISOString(),
|
|
4960
5232
|
updated: now.toISOString(),
|
|
4961
5233
|
},
|
|
4962
|
-
refIdsAtWrite
|
|
5234
|
+
refIdsAtWrite
|
|
4963
5235
|
);
|
|
4964
5236
|
const fileContent = `${serializeFrontmatter(updatedFm)}\n\n${current.content}\n`;
|
|
4965
5237
|
const destPath = path.join(destDir, path.basename(current.path));
|
|
@@ -4970,7 +5242,11 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
4970
5242
|
if (typeof current.frontmatter.entityRef === "string") {
|
|
4971
5243
|
try {
|
|
4972
5244
|
await this.entityRefRepair.repair(
|
|
4973
|
-
destPath,
|
|
5245
|
+
destPath,
|
|
5246
|
+
updatedFm,
|
|
5247
|
+
current.frontmatter.entityRef,
|
|
5248
|
+
refIdsAtWrite,
|
|
5249
|
+
current.content
|
|
4974
5250
|
);
|
|
4975
5251
|
} catch (err) {
|
|
4976
5252
|
// Restore/remove the destination before reporting failure (§14):
|
|
@@ -4983,7 +5259,7 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
4983
5259
|
throw err;
|
|
4984
5260
|
}
|
|
4985
5261
|
}
|
|
4986
|
-
await
|
|
5262
|
+
if (!(await this.deleteManagedStorageFile(current.path))) return null;
|
|
4987
5263
|
markDurable();
|
|
4988
5264
|
markProjectedMemoryPathInvalid(this.baseDir, current.frontmatter.id);
|
|
4989
5265
|
this.invalidateAllMemoriesCache();
|
|
@@ -5076,25 +5352,21 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
5076
5352
|
return null;
|
|
5077
5353
|
}
|
|
5078
5354
|
|
|
5079
|
-
|
|
5080
5355
|
async invalidateMemory(id: string): Promise<boolean> {
|
|
5081
5356
|
const memories = await this.readAllMemories();
|
|
5082
5357
|
const memory = memories.find((candidate) => candidate.frontmatter.id === id);
|
|
5083
5358
|
if (!memory) return false;
|
|
5084
5359
|
|
|
5085
|
-
return await this.runTombstoneBlockedInvalidation(
|
|
5086
|
-
|
|
5087
|
-
|
|
5088
|
-
|
|
5089
|
-
|
|
5090
|
-
|
|
5091
|
-
|
|
5092
|
-
|
|
5093
|
-
|
|
5094
|
-
|
|
5095
|
-
return true;
|
|
5096
|
-
}
|
|
5097
|
-
);
|
|
5360
|
+
return await this.runTombstoneBlockedInvalidation(memory, async (current, rebuildMarker, markDurable) => {
|
|
5361
|
+
if (!(await this.deleteManagedStorageFile(current.path))) return false;
|
|
5362
|
+
markDurable();
|
|
5363
|
+
markProjectedMemoryPathInvalid(this.baseDir, id);
|
|
5364
|
+
this.invalidateAllMemoriesCache();
|
|
5365
|
+
await this.rebuildTombstoneBlockedCaptureAfterInvalidation(rebuildMarker);
|
|
5366
|
+
this.bumpMemoryStatusVersion();
|
|
5367
|
+
log.debug(`invalidated memory ${id}`);
|
|
5368
|
+
return true;
|
|
5369
|
+
});
|
|
5098
5370
|
}
|
|
5099
5371
|
|
|
5100
5372
|
async updateMemory(
|
|
@@ -5122,7 +5394,7 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
5122
5394
|
? { sourceConnector: options.sourceConnector }
|
|
5123
5395
|
: {}),
|
|
5124
5396
|
},
|
|
5125
|
-
refIdsAtWrite
|
|
5397
|
+
refIdsAtWrite
|
|
5126
5398
|
);
|
|
5127
5399
|
const sanitized = sanitizeMemoryContent(newContent);
|
|
5128
5400
|
if (!sanitized.clean) {
|
|
@@ -5134,8 +5406,12 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
5134
5406
|
});
|
|
5135
5407
|
if (typeof memory.frontmatter.entityRef === "string") {
|
|
5136
5408
|
await this.entityRefRepair.repair(
|
|
5137
|
-
memory.path,
|
|
5138
|
-
|
|
5409
|
+
memory.path,
|
|
5410
|
+
updated,
|
|
5411
|
+
memory.frontmatter.entityRef,
|
|
5412
|
+
refIdsAtWrite,
|
|
5413
|
+
sanitized.text,
|
|
5414
|
+
{ onFailRestore: memory }
|
|
5139
5415
|
);
|
|
5140
5416
|
}
|
|
5141
5417
|
await this.patchHotMemoriesCache({ addedPath: memory.path });
|
|
@@ -5170,7 +5446,7 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
5170
5446
|
const resolveIds = this.currentHistoricalIds();
|
|
5171
5447
|
const updated: MemoryFrontmatter = entityRefs.canonicalizeEntityRefOption(
|
|
5172
5448
|
{ ...memory.frontmatter, ...patch },
|
|
5173
|
-
resolveIds
|
|
5449
|
+
resolveIds
|
|
5174
5450
|
);
|
|
5175
5451
|
const refIds = typeof updated.entityRef === "string" ? resolveIds : null;
|
|
5176
5452
|
const afterStatus = updated.status ?? "active";
|
|
@@ -5185,10 +5461,9 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
5185
5461
|
});
|
|
5186
5462
|
const rawMergedRef = typeof patch.entityRef === "string" ? patch.entityRef : memory.frontmatter.entityRef;
|
|
5187
5463
|
if (refIds && typeof rawMergedRef === "string") {
|
|
5188
|
-
await this.entityRefRepair.repair(
|
|
5189
|
-
|
|
5190
|
-
|
|
5191
|
-
);
|
|
5464
|
+
await this.entityRefRepair.repair(memory.path, updated, rawMergedRef, refIds, memory.content, {
|
|
5465
|
+
onFailRestore: memory,
|
|
5466
|
+
});
|
|
5192
5467
|
}
|
|
5193
5468
|
await this.patchHotMemoriesCache({ addedPath: memory.path });
|
|
5194
5469
|
if (memory.path.includes(`${path.sep}cold${path.sep}`)) {
|
|
@@ -6336,26 +6611,31 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
6336
6611
|
: memoryMap.get(entry.memoryId);
|
|
6337
6612
|
if (!memory) continue;
|
|
6338
6613
|
|
|
6339
|
-
const rowIds = this.currentHistoricalIds();
|
|
6340
|
-
const newFm: MemoryFrontmatter = entityRefs.canonicalizeEntityRefOption(
|
|
6341
|
-
{ ...memory.frontmatter, accessCount: entry.newCount, lastAccessed: entry.lastAccessed },
|
|
6342
|
-
rowIds,
|
|
6343
|
-
);
|
|
6344
|
-
|
|
6345
6614
|
try {
|
|
6346
|
-
const
|
|
6347
|
-
|
|
6348
|
-
|
|
6349
|
-
|
|
6350
|
-
|
|
6351
|
-
|
|
6352
|
-
{ onFailRestore: memory },
|
|
6615
|
+
const applied = await this.withTombstoneBlockedMemoryPathLock(memory.path, async (current) => {
|
|
6616
|
+
if (current?.frontmatter.id !== entry.memoryId) return null;
|
|
6617
|
+
const rowIds = this.currentHistoricalIds();
|
|
6618
|
+
const newFm: MemoryFrontmatter = entityRefs.canonicalizeEntityRefOption(
|
|
6619
|
+
{ ...current.frontmatter, accessCount: entry.newCount, lastAccessed: entry.lastAccessed },
|
|
6620
|
+
rowIds
|
|
6353
6621
|
);
|
|
6354
|
-
|
|
6355
|
-
|
|
6356
|
-
|
|
6622
|
+
const fileContent = `${serializeFrontmatter(newFm)}\n\n${current.content}\n`;
|
|
6623
|
+
await this.writeTombstoneBlockedFrontmatter(current, fileContent, newFm);
|
|
6624
|
+
if (typeof current.frontmatter.entityRef === "string") {
|
|
6625
|
+
await this.entityRefRepair.repair(
|
|
6626
|
+
current.path,
|
|
6627
|
+
newFm,
|
|
6628
|
+
current.frontmatter.entityRef,
|
|
6629
|
+
rowIds,
|
|
6630
|
+
current.content,
|
|
6631
|
+
{ onFailRestore: current }
|
|
6632
|
+
);
|
|
6633
|
+
}
|
|
6634
|
+
return { current, newFm };
|
|
6635
|
+
});
|
|
6636
|
+
if (applied === null) continue;
|
|
6357
6637
|
if (warm) {
|
|
6358
|
-
updateCacheOnWrite(this.baseDir, { ...
|
|
6638
|
+
updateCacheOnWrite(this.baseDir, { ...applied.current, frontmatter: applied.newFm }, keyId);
|
|
6359
6639
|
}
|
|
6360
6640
|
appliedPatches.set(path.resolve(memory.path), {
|
|
6361
6641
|
accessCount: entry.newCount,
|
|
@@ -6602,6 +6882,7 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
6602
6882
|
observedAt?: string;
|
|
6603
6883
|
eventTimeSource?: "extracted" | "assumed";
|
|
6604
6884
|
sourceConnector?: string;
|
|
6885
|
+
toolScoped?: true;
|
|
6605
6886
|
} = {}
|
|
6606
6887
|
): Promise<string> {
|
|
6607
6888
|
await this.ensureDirectories();
|
|
@@ -6616,6 +6897,10 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
6616
6897
|
const validAt = normalizeMemoryWriteTimestamp("validAt", options.validAt);
|
|
6617
6898
|
const chunkInvalidAt = normalizeMemoryWriteTimestamp("invalidAt", options.invalidAt);
|
|
6618
6899
|
const chunkObservedAt = normalizeMemoryWriteTimestamp("observedAt", options.observedAt);
|
|
6900
|
+
const sanitized = sanitizeMemoryContent(content);
|
|
6901
|
+
if (!sanitized.clean) {
|
|
6902
|
+
log.warn(`chunk content sanitized for ${id}; violations=${sanitized.violations.join(", ")}`);
|
|
6903
|
+
}
|
|
6619
6904
|
|
|
6620
6905
|
const fm: MemoryFrontmatter = {
|
|
6621
6906
|
id,
|
|
@@ -6645,28 +6930,17 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
6645
6930
|
...(options.sources ? { sources: options.sources } : {}),
|
|
6646
6931
|
...(options.provenance ? { provenance: options.provenance } : {}),
|
|
6647
6932
|
...(options.sourceConnector ? { sourceConnector: options.sourceConnector } : {}),
|
|
6933
|
+
...(options.toolScoped ||
|
|
6934
|
+
withholdToolScopedFromSharedNamespace({
|
|
6935
|
+
content: sanitized.text,
|
|
6936
|
+
sourceConnector: options.sourceConnector,
|
|
6937
|
+
})
|
|
6938
|
+
? { toolScoped: true as const }
|
|
6939
|
+
: {}),
|
|
6648
6940
|
};
|
|
6649
6941
|
|
|
6650
|
-
const sanitized = sanitizeMemoryContent(content);
|
|
6651
|
-
if (!sanitized.clean) {
|
|
6652
|
-
log.warn(`chunk content sanitized for ${id}; violations=${sanitized.violations.join(", ")}`);
|
|
6653
|
-
}
|
|
6654
6942
|
const filePath = await this.resolveCategoryWritePath(category, id, today);
|
|
6655
6943
|
const fileContent = `${serializeFrontmatter(fm)}\n\n${sanitized.text}\n`;
|
|
6656
|
-
// A retried chunk write lands on the SAME deterministic path, so the
|
|
6657
|
-
// target can already hold a valid prior chunk: snapshot it, and a repair
|
|
6658
|
-
// failure restores it — unlink only a file THIS invocation created
|
|
6659
|
-
// (Codex P2, round 22).
|
|
6660
|
-
let priorChunk: MemoryFile | null = null;
|
|
6661
|
-
try {
|
|
6662
|
-
const priorRaw = await readMaybeEncryptedFile(filePath, this._secureStoreKey, this.baseDir);
|
|
6663
|
-
const parsedPrior = parseFrontmatter(priorRaw);
|
|
6664
|
-
if (parsedPrior) {
|
|
6665
|
-
priorChunk = { path: filePath, frontmatter: parsedPrior.frontmatter, content: parsedPrior.content };
|
|
6666
|
-
}
|
|
6667
|
-
} catch {
|
|
6668
|
-
priorChunk = null;
|
|
6669
|
-
}
|
|
6670
6944
|
|
|
6671
6945
|
const written = await this.writeTombstoneBlockedChunk(
|
|
6672
6946
|
filePath,
|
|
@@ -6674,24 +6948,19 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
6674
6948
|
fm,
|
|
6675
6949
|
sanitized.text,
|
|
6676
6950
|
() => this.findExistingTombstoneBlockedMemory(sanitized.text, category, fm.sourceConnector),
|
|
6677
|
-
async () => {
|
|
6951
|
+
async (priorChunk) => {
|
|
6952
|
+
if (refIds && typeof rawEntityRef === "string") {
|
|
6953
|
+
await this.entityRefRepair.repair(filePath, fm, rawEntityRef, refIds, sanitized.text, {
|
|
6954
|
+
regateFact: true,
|
|
6955
|
+
...(priorChunk ? { onFailRestore: priorChunk } : { onFailRemove: filePath }),
|
|
6956
|
+
});
|
|
6957
|
+
}
|
|
6678
6958
|
// Keep the version-keyed hot-memories cache coherent with the new chunk
|
|
6679
6959
|
// file (issue #1902) — same single-file patch path writeMemory uses.
|
|
6680
6960
|
await this.patchHotMemoriesCache({ addedPath: filePath }, "memory-create");
|
|
6681
6961
|
log.debug(`wrote chunk ${id} (${chunkIndex + 1}/${chunkTotal}) to ${filePath}`);
|
|
6682
6962
|
}
|
|
6683
6963
|
);
|
|
6684
|
-
// Repair only when THIS chunk persisted: a tombstone-dedupe result
|
|
6685
|
-
// returns an existing id without writing filePath, and an unconditional
|
|
6686
|
-
// repair rewrite would create a stray second chunk from scratch. The
|
|
6687
|
-
// rewrite RE-GATES under the final ref (Bugbot): a journal move into
|
|
6688
|
-
// tombstone-blocked identity space must not leave a fact chunk active.
|
|
6689
|
-
if (written === id && refIds && typeof rawEntityRef === "string") {
|
|
6690
|
-
await this.entityRefRepair.repair(filePath, fm, rawEntityRef, refIds, sanitized.text, {
|
|
6691
|
-
regateFact: true,
|
|
6692
|
-
...(priorChunk ? { onFailRestore: priorChunk } : { onFailRemove: filePath }),
|
|
6693
|
-
});
|
|
6694
|
-
}
|
|
6695
6964
|
return written;
|
|
6696
6965
|
}
|
|
6697
6966
|
|
|
@@ -6720,25 +6989,33 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
6720
6989
|
if (!oldMemory) return false;
|
|
6721
6990
|
|
|
6722
6991
|
const now = new Date().toISOString();
|
|
6723
|
-
|
|
6724
|
-
|
|
6725
|
-
const updatedFm: MemoryFrontmatter = entityRefs.canonicalizeEntityRefOption(
|
|
6726
|
-
{ ...oldMemory.frontmatter, status: "superseded", supersededBy: newMemoryId, supersededAt: now, updated: now },
|
|
6727
|
-
refIdsAtWrite,
|
|
6728
|
-
);
|
|
6729
|
-
|
|
6730
|
-
const fileContent = `${serializeFrontmatter(updatedFm)}\n\n${oldMemory.content}\n`;
|
|
6992
|
+
let currentBefore = oldMemory;
|
|
6993
|
+
let updatedFm = oldMemory.frontmatter;
|
|
6731
6994
|
|
|
6732
6995
|
try {
|
|
6733
|
-
await this.
|
|
6734
|
-
|
|
6735
|
-
|
|
6736
|
-
|
|
6737
|
-
|
|
6738
|
-
|
|
6739
|
-
|
|
6996
|
+
const written = await this.withTombstoneBlockedMemoryPathLock(oldMemory.path, async (current) => {
|
|
6997
|
+
if (current?.frontmatter.id !== oldMemoryId) return false;
|
|
6998
|
+
currentBefore = current;
|
|
6999
|
+
const refIdsAtWrite = this.currentHistoricalIds();
|
|
7000
|
+
updatedFm = entityRefs.canonicalizeEntityRefOption(
|
|
7001
|
+
{ ...current.frontmatter, status: "superseded", supersededBy: newMemoryId, supersededAt: now, updated: now },
|
|
7002
|
+
refIdsAtWrite
|
|
6740
7003
|
);
|
|
6741
|
-
|
|
7004
|
+
const fileContent = `${serializeFrontmatter(updatedFm)}\n\n${current.content}\n`;
|
|
7005
|
+
await this.writeTombstoneBlockedFrontmatter(current, fileContent, updatedFm);
|
|
7006
|
+
if (typeof current.frontmatter.entityRef === "string") {
|
|
7007
|
+
await this.entityRefRepair.repair(
|
|
7008
|
+
current.path,
|
|
7009
|
+
updatedFm,
|
|
7010
|
+
current.frontmatter.entityRef,
|
|
7011
|
+
refIdsAtWrite,
|
|
7012
|
+
current.content,
|
|
7013
|
+
{ onFailRestore: current }
|
|
7014
|
+
);
|
|
7015
|
+
}
|
|
7016
|
+
return true;
|
|
7017
|
+
});
|
|
7018
|
+
if (!written) return false;
|
|
6742
7019
|
// Advance the corpus sentinel immediately after the on-disk write, BEFORE
|
|
6743
7020
|
// the awaited lifecycle append (Cursor Medium, #1902). Otherwise a warm
|
|
6744
7021
|
// hot-memories cache keeps serving the pre-supersede snapshot during the
|
|
@@ -6751,8 +7028,8 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
6751
7028
|
timestamp: now,
|
|
6752
7029
|
actor: "storage.supersedeMemory",
|
|
6753
7030
|
reasonCode: reason,
|
|
6754
|
-
before: this.summarizeLifecycleState(
|
|
6755
|
-
after: this.summarizeLifecycleState(updatedFm,
|
|
7031
|
+
before: this.summarizeLifecycleState(currentBefore.frontmatter, currentBefore.path),
|
|
7032
|
+
after: this.summarizeLifecycleState(updatedFm, currentBefore.path),
|
|
6756
7033
|
relatedMemoryIds: [newMemoryId],
|
|
6757
7034
|
});
|
|
6758
7035
|
this.bumpMemoryStatusVersion();
|
|
@@ -6762,14 +7039,14 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
6762
7039
|
// so emitting covers each exactly once (rule 22); facts only. One
|
|
6763
7040
|
// tombstone PER derived supersession key (thread Oci-Y) so a
|
|
6764
7041
|
// paraphrased re-write is caught on the keyed tier.
|
|
6765
|
-
if (
|
|
7042
|
+
if (currentBefore.frontmatter.category === "fact") {
|
|
6766
7043
|
for (const input of buildRetiredFactTombstoneInputs(
|
|
6767
7044
|
{
|
|
6768
7045
|
id: oldMemoryId,
|
|
6769
|
-
content: stripCitationForTemplate(
|
|
6770
|
-
contentHash:
|
|
7046
|
+
content: stripCitationForTemplate(currentBefore.content, this.citationTemplate),
|
|
7047
|
+
contentHash: currentBefore.frontmatter.contentHash,
|
|
6771
7048
|
entityRef: updatedFm.entityRef,
|
|
6772
|
-
structuredAttributes:
|
|
7049
|
+
structuredAttributes: currentBefore.frontmatter.structuredAttributes,
|
|
6773
7050
|
},
|
|
6774
7051
|
{
|
|
6775
7052
|
reason: "contradiction_resolution",
|
|
@@ -6783,7 +7060,7 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
6783
7060
|
}
|
|
6784
7061
|
|
|
6785
7062
|
// Audit-trail correction — sealed even INSIDE the engine (#2022 review).
|
|
6786
|
-
const auditBody = `Superseded: ${
|
|
7063
|
+
const auditBody = `Superseded: ${currentBefore.content}\n\nReason: ${reason}`;
|
|
6787
7064
|
const auditInput = {
|
|
6788
7065
|
content: auditBody,
|
|
6789
7066
|
category: "correction" as const,
|
|
@@ -6854,22 +7131,33 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
6854
7131
|
if (!memory) continue;
|
|
6855
7132
|
|
|
6856
7133
|
const now = new Date().toISOString();
|
|
6857
|
-
|
|
6858
|
-
|
|
6859
|
-
{ ...memory.frontmatter, status: "archived", archivedAt: now, updated: now },
|
|
6860
|
-
rowIds,
|
|
6861
|
-
);
|
|
7134
|
+
let currentBefore = memory;
|
|
7135
|
+
let updatedFm = memory.frontmatter;
|
|
6862
7136
|
|
|
6863
7137
|
try {
|
|
6864
|
-
const
|
|
6865
|
-
|
|
6866
|
-
|
|
6867
|
-
|
|
6868
|
-
|
|
6869
|
-
|
|
6870
|
-
|
|
7138
|
+
const written = await this.withTombstoneBlockedMemoryPathLock(memory.path, async (current) => {
|
|
7139
|
+
if (current?.frontmatter.id !== id) return false;
|
|
7140
|
+
currentBefore = current;
|
|
7141
|
+
const rowIds = this.currentHistoricalIds();
|
|
7142
|
+
updatedFm = entityRefs.canonicalizeEntityRefOption(
|
|
7143
|
+
{ ...current.frontmatter, status: "archived", archivedAt: now, updated: now },
|
|
7144
|
+
rowIds
|
|
6871
7145
|
);
|
|
6872
|
-
|
|
7146
|
+
const fileContent = `${serializeFrontmatter(updatedFm)}\n\n${current.content}\n`;
|
|
7147
|
+
await this.writeTombstoneBlockedFrontmatter(current, fileContent, updatedFm);
|
|
7148
|
+
if (typeof current.frontmatter.entityRef === "string") {
|
|
7149
|
+
await this.entityRefRepair.repair(
|
|
7150
|
+
current.path,
|
|
7151
|
+
updatedFm,
|
|
7152
|
+
current.frontmatter.entityRef,
|
|
7153
|
+
rowIds,
|
|
7154
|
+
current.content,
|
|
7155
|
+
{ onFailRestore: current }
|
|
7156
|
+
);
|
|
7157
|
+
}
|
|
7158
|
+
return true;
|
|
7159
|
+
});
|
|
7160
|
+
if (!written) continue;
|
|
6873
7161
|
// Per-file corpus bump BEFORE the awaited lifecycle append (#1902):
|
|
6874
7162
|
// the end-of-loop status bump fires only after the whole batch.
|
|
6875
7163
|
this.bumpMemoryCorpusVersion();
|
|
@@ -6879,8 +7167,8 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
|
|
|
6879
7167
|
timestamp: updatedFm.archivedAt ?? updatedFm.updated,
|
|
6880
7168
|
actor: "storage.archiveMemories",
|
|
6881
7169
|
reasonCode: `summary:${summaryId}`,
|
|
6882
|
-
before: this.summarizeLifecycleState(
|
|
6883
|
-
after: this.summarizeLifecycleState(updatedFm,
|
|
7170
|
+
before: this.summarizeLifecycleState(currentBefore.frontmatter, currentBefore.path),
|
|
7171
|
+
after: this.summarizeLifecycleState(updatedFm, currentBefore.path),
|
|
6884
7172
|
relatedMemoryIds: [summaryId],
|
|
6885
7173
|
});
|
|
6886
7174
|
archived++;
|