@remnic/core 9.4.2 → 9.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/access-admin-ops-surface.d.ts +6 -6
- package/dist/access-admin-ops-surface.js +28 -28
- package/dist/access-boundary.d.ts +27 -8
- package/dist/access-boundary.js +33 -29
- package/dist/access-cli.js +83 -81
- package/dist/access-cli.js.map +1 -1
- package/dist/access-http.d.ts +52 -6
- package/dist/access-http.js +40 -38
- package/dist/access-identity-continuity-surface.d.ts +5 -5
- package/dist/access-identity-continuity-surface.js +28 -28
- package/dist/access-lcm-surface.d.ts +6 -6
- package/dist/access-lcm-surface.js +28 -28
- package/dist/access-mcp.d.ts +16 -6
- package/dist/access-mcp.js +37 -35
- package/dist/access-observe-write-surface.d.ts +6 -6
- package/dist/access-observe-write-surface.js +28 -28
- package/dist/access-operations-batch.js +33 -32
- package/dist/access-operations.d.ts +9 -9
- package/dist/access-operations.js +35 -34
- package/dist/access-recall-surface.d.ts +6 -6
- package/dist/access-recall-surface.js +28 -28
- package/dist/access-schema.d.ts +4 -4
- package/dist/access-schema.js +4 -4
- package/dist/{access-service-m-2VO_Ig.d.ts → access-service-CXJaql3A.d.ts} +4 -4
- package/dist/access-service.d.ts +6 -6
- package/dist/access-service.js +28 -28
- package/dist/access-surface-catalog.d.ts +6 -6
- package/dist/access-surface-catalog.js +1 -0
- package/dist/access-surface-catalog.js.map +1 -1
- package/dist/access-token-capabilities.d.ts +174 -0
- package/dist/access-token-capabilities.js +33 -0
- package/dist/action-confidence.d.ts +1 -1
- package/dist/active-memory-bridge.d.ts +1 -1
- package/dist/active-recall.d.ts +1 -1
- package/dist/active-recall.js +2 -2
- package/dist/adapters/index.js +4 -4
- package/dist/adapters/registry.js +2 -2
- package/dist/{auto-sync-HMHQHUAG.js → auto-sync-4A5YBWYO.js} +4 -4
- package/dist/behavior-learner.d.ts +1 -1
- package/dist/behavior-signals.d.ts +1 -1
- package/dist/bootstrap.d.ts +5 -5
- package/dist/briefing.d.ts +2 -2
- package/dist/briefing.js +9 -9
- package/dist/buffer-surprise-report.d.ts +1 -1
- package/dist/buffer.d.ts +2 -2
- package/dist/calibration.d.ts +1 -1
- package/dist/capabilities.d.ts +1 -1
- package/dist/{capsule-crypto-CZJSLEFG.js → capsule-crypto-RAARDY3M.js} +2 -2
- package/dist/capsule-crypto-RAARDY3M.js.map +1 -0
- package/dist/{catalog-BxWokdC2.d.ts → catalog-C9cu67Ig.d.ts} +1 -1
- package/dist/causal-behavior.d.ts +1 -1
- package/dist/causal-behavior.js +5 -5
- package/dist/causal-chain.js +3 -3
- package/dist/causal-consolidation.d.ts +1 -1
- package/dist/causal-consolidation.js +13 -13
- package/dist/causal-retrieval.js +3 -3
- package/dist/causal-trajectory-graph.d.ts +1 -1
- package/dist/causal-trajectory.js +1 -1
- package/dist/{chunk-6ZIETXZ2.js → chunk-23JFRB73.js} +2 -2
- package/dist/{chunk-IC6QX5TC.js → chunk-3XIY7MDQ.js} +6 -6
- package/dist/{chunk-FZGGZAAU.js → chunk-4GNEDXDI.js} +146 -2
- package/dist/chunk-4GNEDXDI.js.map +1 -0
- package/dist/{chunk-LOR6ZM5R.js → chunk-4LV23CHK.js} +2 -2
- package/dist/{chunk-E2SPGGUI.js → chunk-4OKLXWDZ.js} +13 -6
- package/dist/chunk-4OKLXWDZ.js.map +1 -0
- package/dist/{chunk-AER6MT24.js → chunk-6SXVCD7W.js} +2 -2
- package/dist/{chunk-OHDJ34CC.js → chunk-72WG5QKN.js} +2 -2
- package/dist/{chunk-CZAZX7JP.js → chunk-7MW3CVLD.js} +4 -4
- package/dist/{chunk-CXLNZXG5.js → chunk-7XGSIUP5.js} +1 -1
- package/dist/{chunk-CZAA5N5S.js → chunk-AYZJID4S.js} +2 -2
- package/dist/{chunk-M7XQSUBB.js → chunk-B3ABVQ36.js} +116 -9
- package/dist/chunk-B3ABVQ36.js.map +1 -0
- package/dist/{chunk-6BISDEN6.js → chunk-BEM4D2QG.js} +14 -14
- package/dist/{chunk-ZPOROUTX.js → chunk-CYWA2CXR.js} +5 -5
- package/dist/{chunk-M5QKGHCR.js → chunk-CYWCKFCL.js} +5 -5
- package/dist/chunk-D7FOKIY5.js +173 -0
- package/dist/chunk-D7FOKIY5.js.map +1 -0
- package/dist/{chunk-4BFRBP45.js → chunk-DEG5ULFJ.js} +2 -2
- package/dist/{chunk-JLR3JSTL.js → chunk-DS7MM2ES.js} +3 -3
- package/dist/{chunk-2BFLDH5F.js → chunk-EEIROWEG.js} +2 -2
- package/dist/{chunk-5QZDMSSN.js → chunk-FKCRGLRD.js} +237 -82
- package/dist/{chunk-5QZDMSSN.js.map → chunk-FKCRGLRD.js.map} +1 -1
- package/dist/{chunk-X4A62ET7.js → chunk-H2DXDQCQ.js} +17 -17
- package/dist/{chunk-27FLVMDC.js → chunk-HLN7RROI.js} +7 -7
- package/dist/chunk-IC2TCZJ2.js +54 -0
- package/dist/chunk-IC2TCZJ2.js.map +1 -0
- package/dist/{chunk-2U2A5HF4.js → chunk-J3XHPFEU.js} +6 -6
- package/dist/{chunk-AKUCU7CI.js → chunk-JI5AVXYO.js} +5 -5
- package/dist/{chunk-KCJ5H6XQ.js → chunk-JSNVWNGX.js} +2 -2
- package/dist/{chunk-7Z2DZNWN.js → chunk-KL4UAXUY.js} +43 -2
- package/dist/{chunk-7Z2DZNWN.js.map → chunk-KL4UAXUY.js.map} +1 -1
- package/dist/{chunk-FLVL4L3L.js → chunk-KTULX4YO.js} +4 -4
- package/dist/{chunk-ILFJ7AVS.js → chunk-LADFWYHY.js} +35 -21
- package/dist/chunk-LADFWYHY.js.map +1 -0
- package/dist/{chunk-437S3G37.js → chunk-LNQUAJNC.js} +1 -1
- package/dist/{chunk-EPGWWCZF.js → chunk-LR5DZ56F.js} +6 -6
- package/dist/{chunk-YDSWRD33.js → chunk-N3JDIRBW.js} +4 -4
- package/dist/{chunk-OUMTBFSQ.js → chunk-NKCPUHCI.js} +5 -5
- package/dist/{chunk-7QWMTOIF.js → chunk-P454KXD6.js} +112 -34
- package/dist/chunk-P454KXD6.js.map +1 -0
- package/dist/{chunk-DR6PEJU3.js → chunk-PCLIWBGD.js} +44 -59
- package/dist/chunk-PCLIWBGD.js.map +1 -0
- package/dist/{chunk-BGTAL46Y.js → chunk-PNLFN2PZ.js} +2 -2
- package/dist/{chunk-P6SYWE4G.js → chunk-PVUJ6WVV.js} +10 -10
- package/dist/{chunk-YPEMNNNY.js → chunk-RGK27ELN.js} +6 -6
- package/dist/{chunk-2QSZNTDO.js → chunk-RKNJBZ55.js} +4 -4
- package/dist/{chunk-66FLU5BT.js → chunk-SIRPLF54.js} +6 -6
- package/dist/{chunk-M7GGMGMZ.js → chunk-SVOHGUMI.js} +1202 -126
- package/dist/chunk-SVOHGUMI.js.map +1 -0
- package/dist/{chunk-HRCACVHL.js → chunk-TLUDFPZL.js} +2 -2
- package/dist/{chunk-2FOD2YY3.js → chunk-UFUKHGZD.js} +236 -103
- package/dist/chunk-UFUKHGZD.js.map +1 -0
- package/dist/{chunk-2MR3MFQB.js → chunk-UPSAT4PY.js} +2 -2
- package/dist/{chunk-4P4626RY.js → chunk-UTRJFDP2.js} +4 -4
- package/dist/{chunk-CGS7UKWM.js → chunk-VCW74PNH.js} +2 -2
- package/dist/{chunk-5GPPACXK.js → chunk-VSMRDBFT.js} +2 -1
- package/dist/{chunk-NG7YBCJO.js → chunk-XCL57M6Q.js} +4 -4
- package/dist/{chunk-CLX5VDNY.js → chunk-Y4RKAQZ7.js} +4 -4
- package/dist/{chunk-DGYCWCQ7.js → chunk-Y7UNNAZD.js} +2 -2
- package/dist/{chunk-EZ25VE3G.js → chunk-YNDLCWXS.js} +4 -4
- package/dist/{chunk-XN3TUUX2.js → chunk-YQB32INI.js} +2 -2
- package/dist/{cli-EiBBOt3r.d.ts → cli-CqdPA6z9.d.ts} +3 -3
- package/dist/cli.d.ts +7 -7
- package/dist/cli.js +61 -59
- package/dist/compounding/engine.d.ts +2 -2
- package/dist/compounding/engine.js +9 -9
- package/dist/compounding/preference-consolidator.d.ts +1 -1
- package/dist/compression-optimizer.d.ts +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/config.js +2 -2
- package/dist/connectors/codex-materialize-runner.d.ts +1 -1
- package/dist/connectors/codex-materialize-runner.js +9 -9
- package/dist/connectors/codex-materialize.d.ts +1 -1
- package/dist/connectors/index.d.ts +1 -1
- package/dist/connectors/index.js +13 -11
- package/dist/consolidation-provenance-check.d.ts +2 -2
- package/dist/consolidation-undo.d.ts +2 -2
- package/dist/contradiction/index.d.ts +2 -2
- package/dist/contradiction/index.js +4 -4
- package/dist/conversation-index/backend.d.ts +1 -1
- package/dist/conversation-index/backend.js +2 -2
- package/dist/conversation-index/chunker.d.ts +1 -1
- package/dist/conversation-index/faiss-adapter.d.ts +1 -1
- package/dist/conversation-index/indexer.d.ts +1 -1
- package/dist/conversation-index/search.d.ts +1 -1
- package/dist/dashboard-runtime.js +2 -2
- package/dist/day-summary.d.ts +1 -1
- package/dist/delinearize.d.ts +1 -1
- package/dist/direct-answer-wiring.d.ts +1 -1
- package/dist/direct-answer.d.ts +1 -1
- package/dist/embedding-fallback.d.ts +1 -1
- package/dist/enrichment/index.d.ts +1 -1
- package/dist/entity-retrieval.d.ts +2 -2
- package/dist/entity-retrieval.js +9 -9
- package/dist/entity-schema.d.ts +1 -1
- package/dist/explicit-capture.d.ts +5 -5
- package/dist/extraction-faithfulness.d.ts +1 -1
- package/dist/extraction-judge-telemetry.d.ts +1 -1
- package/dist/extraction-judge-training.d.ts +1 -1
- package/dist/extraction-judge.d.ts +1 -1
- package/dist/extraction.d.ts +1 -1
- package/dist/fallback-llm.d.ts +1 -1
- package/dist/{first-start-migration-DY6YCRC2.js → first-start-migration-VBJQL6OI.js} +5 -5
- package/dist/graph-dashboard-diff.d.ts +1 -1
- package/dist/graph-dashboard-key.d.ts +1 -1
- package/dist/graph-dashboard-parser.d.ts +1 -1
- package/dist/graph-edge-reinforcement.d.ts +1 -1
- package/dist/graph-snapshot.d.ts +1 -1
- package/dist/graph.d.ts +1 -1
- package/dist/identity-continuity.d.ts +1 -1
- package/dist/importance.d.ts +1 -1
- package/dist/index.d.ts +271 -17
- package/dist/index.js +163 -99
- package/dist/intent.d.ts +1 -1
- package/dist/lcm/engine.d.ts +1 -1
- package/dist/lcm/engine.js +2 -2
- package/dist/lcm/index.d.ts +1 -1
- package/dist/lcm/index.js +2 -2
- package/dist/lcm/tools.d.ts +1 -1
- package/dist/lifecycle.d.ts +1 -1
- package/dist/live-connectors-runner.d.ts +1 -1
- package/dist/local-llm.d.ts +1 -1
- package/dist/local-model-endpoint.d.ts +1 -1
- package/dist/maintenance/memory-governance.d.ts +1 -1
- package/dist/maintenance/memory-governance.js +10 -10
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +9 -9
- package/dist/maintenance/rebuild-memory-projection.js +11 -11
- package/dist/mcp-memory-inspector-app.d.ts +6 -6
- package/dist/mcp-read-only-tools.d.ts +16 -0
- package/dist/mcp-read-only-tools.js +8 -0
- package/dist/mcp-read-only-tools.js.map +1 -0
- package/dist/memory-action-policy.d.ts +1 -1
- package/dist/memory-cache.d.ts +1 -1
- package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
- package/dist/memory-projection-store.d.ts +1 -1
- package/dist/memory-provenance.d.ts +1 -1
- package/dist/memory-worth-outcomes.d.ts +2 -2
- package/dist/models-json.d.ts +1 -1
- package/dist/namespaces/migrate.d.ts +3 -3
- package/dist/namespaces/migrate.js +19 -19
- package/dist/namespaces/principal.d.ts +1 -1
- package/dist/namespaces/search.d.ts +1 -1
- package/dist/namespaces/search.js +10 -10
- package/dist/namespaces/storage.d.ts +3 -3
- package/dist/namespaces/storage.js +9 -9
- package/dist/native-knowledge.d.ts +1 -1
- package/dist/operator-toolkit.d.ts +2 -2
- package/dist/operator-toolkit.js +25 -25
- package/dist/orchestration/compression-guideline-coordinator.d.ts +2 -2
- package/dist/orchestration/maintenance.d.ts +2 -2
- package/dist/orchestration/maintenance.js +11 -11
- package/dist/{orchestrator-B2Y28Z9t.d.ts → orchestrator-CWFrT8AF.d.ts} +91 -60
- package/dist/orchestrator.d.ts +5 -5
- package/dist/orchestrator.js +85 -83
- package/dist/patterns-cli.d.ts +1 -1
- package/dist/policy-runtime.d.ts +1 -1
- package/dist/provenance.d.ts +1 -1
- package/dist/{qmd-Db9mOkzB.d.ts → qmd--fnPMK60.d.ts} +1 -1
- package/dist/qmd-preflight.d.ts +2 -2
- package/dist/qmd-recall-cache.d.ts +1 -1
- package/dist/qmd.d.ts +2 -2
- package/dist/recall-disclosure-escalation.d.ts +1 -1
- package/dist/recall-explain-renderer.d.ts +1 -1
- package/dist/recall-planner-llm.d.ts +1 -1
- package/dist/recall-state.d.ts +1 -1
- package/dist/recall-tag-filter.d.ts +1 -1
- package/dist/recall-timings.d.ts +1 -1
- package/dist/recall-xray-cli.d.ts +1 -1
- package/dist/recall-xray-renderer.d.ts +1 -1
- package/dist/recall-xray.d.ts +1 -1
- package/dist/resolve-auth-token.d.ts +1 -1
- package/dist/resume-bundles.js +4 -4
- package/dist/retrieval-agents.d.ts +2 -2
- package/dist/retrieval-tiers.d.ts +1 -1
- package/dist/routing/engine.d.ts +1 -1
- package/dist/routing/store.d.ts +1 -1
- package/dist/schemas.d.ts +22 -22
- package/dist/search/document-scanner.js +2 -2
- package/dist/search/embed-helper.d.ts +1 -1
- package/dist/search/factory.d.ts +1 -1
- package/dist/search/factory.js +9 -9
- package/dist/search/index.d.ts +1 -1
- package/dist/search/index.js +13 -13
- package/dist/search/lancedb-backend.d.ts +1 -1
- package/dist/search/lancedb-backend.js +3 -3
- package/dist/search/meilisearch-backend.d.ts +1 -1
- package/dist/search/meilisearch-backend.js +3 -3
- package/dist/search/noop-backend.d.ts +1 -1
- package/dist/search/orama-backend.d.ts +1 -1
- package/dist/search/orama-backend.js +3 -3
- package/dist/search/port.d.ts +1 -1
- package/dist/search/remote-backend.d.ts +1 -1
- package/dist/{semantic-consolidation-BDVIbLRw.d.ts → semantic-consolidation-O5lMZ4LG.d.ts} +1 -1
- package/dist/semantic-consolidation.d.ts +2 -2
- package/dist/semantic-consolidation.js +11 -11
- package/dist/semantic-rule-promotion.js +9 -9
- package/dist/semantic-rule-verifier.d.ts +1 -1
- package/dist/semantic-rule-verifier.js +10 -10
- package/dist/session-observer-bands.d.ts +1 -1
- package/dist/session-observer-state.d.ts +1 -1
- package/dist/shared-context/manager.d.ts +1 -1
- package/dist/signal.d.ts +1 -1
- package/dist/storage-C1maCNbc.d.ts +1591 -0
- package/dist/storage.d.ts +5 -1239
- package/dist/storage.js +8 -8
- package/dist/summarizer.d.ts +1 -1
- package/dist/summary-snapshot.d.ts +1 -1
- package/dist/temporal-supersession.d.ts +2 -2
- package/dist/temporal-validity.d.ts +1 -1
- package/dist/threading.d.ts +1 -1
- package/dist/tier-migration.d.ts +2 -2
- package/dist/tier-routing.d.ts +1 -1
- package/dist/{tier-stats-TG6GUZ6N.js → tier-stats-5XF4UBRQ.js} +4 -4
- package/dist/tokens.d.ts +17 -2
- package/dist/tokens.js +3 -1
- package/dist/topics.d.ts +1 -1
- package/dist/transcript.d.ts +1 -1
- package/dist/transfer/backup.js +2 -2
- package/dist/transfer/capsule-export.js +3 -3
- package/dist/transfer/capsule-import.js +3 -3
- package/dist/transfer/types.d.ts +12 -12
- package/dist/trust-score-stage.d.ts +1 -1
- package/dist/trust-score.d.ts +1 -1
- package/dist/{types-ljkd82rn.d.ts → types-CGgcNWCG.d.ts} +31 -1
- package/dist/types.d.ts +1 -1
- package/dist/utility-runtime.d.ts +1 -1
- package/dist/verified-recall.js +10 -10
- package/package.json +2 -2
- package/src/access-boundary.test.ts +62 -0
- package/src/access-boundary.ts +165 -126
- package/src/access-http.test.ts +781 -0
- package/src/access-http.ts +334 -108
- package/src/access-mcp.test.ts +264 -0
- package/src/access-mcp.ts +45 -70
- package/src/access-operations-batch.ts +35 -12
- package/src/access-surface-catalog.test.ts +22 -14
- package/src/access-surface-catalog.ts +6 -3
- package/src/access-token-capabilities.test.ts +844 -0
- package/src/access-token-capabilities.ts +391 -0
- package/src/chat/chat-mcp.test.ts +232 -0
- package/src/chat/chat-session.ts +34 -0
- package/src/cli-wearables-fuse.test.ts +197 -0
- package/src/cli.ts +25 -0
- package/src/index.ts +14 -0
- package/src/mcp-read-only-tools.ts +61 -0
- package/src/storage.ts +16 -0
- package/src/tokens.ts +32 -3
- package/src/wearables/cli.test.ts +102 -0
- package/src/wearables/cli.ts +65 -0
- package/src/wearables/config.test.ts +32 -0
- package/src/wearables/config.ts +52 -0
- package/src/wearables/day-store.test.ts +246 -0
- package/src/wearables/day-store.ts +272 -3
- package/src/wearables/fusion/cluster.ts +230 -0
- package/src/wearables/fusion/fuse.ts +218 -0
- package/src/wearables/fusion/fusion.test.ts +2575 -0
- package/src/wearables/fusion/index.ts +50 -0
- package/src/wearables/fusion/reconcile.ts +831 -0
- package/src/wearables/fusion/reconstruct.ts +251 -0
- package/src/wearables/fusion/store.ts +480 -0
- package/src/wearables/fusion/types.ts +228 -0
- package/src/wearables/index.ts +41 -0
- package/src/wearables/service.test.ts +1030 -2
- package/src/wearables/service.ts +258 -16
- package/src/wearables/speakers.test.ts +128 -0
- package/src/wearables/speakers.ts +58 -4
- package/src/wearables/storage-io.test.ts +146 -0
- package/src/wearables/types.ts +31 -0
- package/dist/chunk-2FOD2YY3.js.map +0 -1
- package/dist/chunk-7QWMTOIF.js.map +0 -1
- package/dist/chunk-DR6PEJU3.js.map +0 -1
- package/dist/chunk-E2SPGGUI.js.map +0 -1
- package/dist/chunk-FZGGZAAU.js.map +0 -1
- package/dist/chunk-ILFJ7AVS.js.map +0 -1
- package/dist/chunk-M7GGMGMZ.js.map +0 -1
- package/dist/chunk-M7XQSUBB.js.map +0 -1
- /package/dist/{capsule-crypto-CZJSLEFG.js.map → access-token-capabilities.js.map} +0 -0
- /package/dist/{auto-sync-HMHQHUAG.js.map → auto-sync-4A5YBWYO.js.map} +0 -0
- /package/dist/{chunk-6ZIETXZ2.js.map → chunk-23JFRB73.js.map} +0 -0
- /package/dist/{chunk-IC6QX5TC.js.map → chunk-3XIY7MDQ.js.map} +0 -0
- /package/dist/{chunk-LOR6ZM5R.js.map → chunk-4LV23CHK.js.map} +0 -0
- /package/dist/{chunk-AER6MT24.js.map → chunk-6SXVCD7W.js.map} +0 -0
- /package/dist/{chunk-OHDJ34CC.js.map → chunk-72WG5QKN.js.map} +0 -0
- /package/dist/{chunk-CZAZX7JP.js.map → chunk-7MW3CVLD.js.map} +0 -0
- /package/dist/{chunk-CXLNZXG5.js.map → chunk-7XGSIUP5.js.map} +0 -0
- /package/dist/{chunk-CZAA5N5S.js.map → chunk-AYZJID4S.js.map} +0 -0
- /package/dist/{chunk-6BISDEN6.js.map → chunk-BEM4D2QG.js.map} +0 -0
- /package/dist/{chunk-ZPOROUTX.js.map → chunk-CYWA2CXR.js.map} +0 -0
- /package/dist/{chunk-M5QKGHCR.js.map → chunk-CYWCKFCL.js.map} +0 -0
- /package/dist/{chunk-4BFRBP45.js.map → chunk-DEG5ULFJ.js.map} +0 -0
- /package/dist/{chunk-JLR3JSTL.js.map → chunk-DS7MM2ES.js.map} +0 -0
- /package/dist/{chunk-2BFLDH5F.js.map → chunk-EEIROWEG.js.map} +0 -0
- /package/dist/{chunk-X4A62ET7.js.map → chunk-H2DXDQCQ.js.map} +0 -0
- /package/dist/{chunk-27FLVMDC.js.map → chunk-HLN7RROI.js.map} +0 -0
- /package/dist/{chunk-2U2A5HF4.js.map → chunk-J3XHPFEU.js.map} +0 -0
- /package/dist/{chunk-AKUCU7CI.js.map → chunk-JI5AVXYO.js.map} +0 -0
- /package/dist/{chunk-KCJ5H6XQ.js.map → chunk-JSNVWNGX.js.map} +0 -0
- /package/dist/{chunk-FLVL4L3L.js.map → chunk-KTULX4YO.js.map} +0 -0
- /package/dist/{chunk-437S3G37.js.map → chunk-LNQUAJNC.js.map} +0 -0
- /package/dist/{chunk-EPGWWCZF.js.map → chunk-LR5DZ56F.js.map} +0 -0
- /package/dist/{chunk-YDSWRD33.js.map → chunk-N3JDIRBW.js.map} +0 -0
- /package/dist/{chunk-OUMTBFSQ.js.map → chunk-NKCPUHCI.js.map} +0 -0
- /package/dist/{chunk-BGTAL46Y.js.map → chunk-PNLFN2PZ.js.map} +0 -0
- /package/dist/{chunk-P6SYWE4G.js.map → chunk-PVUJ6WVV.js.map} +0 -0
- /package/dist/{chunk-YPEMNNNY.js.map → chunk-RGK27ELN.js.map} +0 -0
- /package/dist/{chunk-2QSZNTDO.js.map → chunk-RKNJBZ55.js.map} +0 -0
- /package/dist/{chunk-66FLU5BT.js.map → chunk-SIRPLF54.js.map} +0 -0
- /package/dist/{chunk-HRCACVHL.js.map → chunk-TLUDFPZL.js.map} +0 -0
- /package/dist/{chunk-2MR3MFQB.js.map → chunk-UPSAT4PY.js.map} +0 -0
- /package/dist/{chunk-4P4626RY.js.map → chunk-UTRJFDP2.js.map} +0 -0
- /package/dist/{chunk-CGS7UKWM.js.map → chunk-VCW74PNH.js.map} +0 -0
- /package/dist/{chunk-5GPPACXK.js.map → chunk-VSMRDBFT.js.map} +0 -0
- /package/dist/{chunk-NG7YBCJO.js.map → chunk-XCL57M6Q.js.map} +0 -0
- /package/dist/{chunk-CLX5VDNY.js.map → chunk-Y4RKAQZ7.js.map} +0 -0
- /package/dist/{chunk-DGYCWCQ7.js.map → chunk-Y7UNNAZD.js.map} +0 -0
- /package/dist/{chunk-EZ25VE3G.js.map → chunk-YNDLCWXS.js.map} +0 -0
- /package/dist/{chunk-XN3TUUX2.js.map → chunk-YQB32INI.js.map} +0 -0
- /package/dist/{first-start-migration-DY6YCRC2.js.map → first-start-migration-VBJQL6OI.js.map} +0 -0
- /package/dist/{tier-stats-TG6GUZ6N.js.map → tier-stats-5XF4UBRQ.js.map} +0 -0
|
@@ -0,0 +1,1591 @@
|
|
|
1
|
+
import { M as MemoryFile, P as PluginConfig, u as MemoryStatus, t as MemoryCategory, ae as ImportanceScore, ar as MemoryLink, p as MemoryFrontmatter, F as FaithfulnessFrontmatter, J as ProvenanceSource, a7 as EntityStructuredSection, as as BufferState, at as MetaState, a2 as MemoryActionEvent, w as MemoryLifecycleEvent, X as BufferSurpriseEvent, B as BehaviorSignalEvent, a3 as CompressionGuidelineOptimizerState, aa as ContinuityIncidentOpenInput, a8 as ContinuityIncidentRecord, a9 as ContinuityIncidentCloseInput, ab as ContinuityImprovementLoop, ad as ContinuityLoopUpsertInput, ac as ContinuityLoopReviewInput, au as FileHygieneConfig, av as EntityRelationship, aw as EntityActivityEntry, E as EntityFile, ax as AccessTrackingEntry, v as MemoryProjectionCurrentState, ay as MemorySummary, ap as TopicScore, az as EntityTimelineEntry } from './types-CGgcNWCG.js';
|
|
2
|
+
import { VersioningConfig } from './page-versioning.js';
|
|
3
|
+
import { ConsolidationOperator } from './consolidation-operator.js';
|
|
4
|
+
import { ProjectedMemoryBrowseOptions, ProjectedMemoryBrowsePage, readProjectedGovernanceRecord } from './memory-projection-store.js';
|
|
5
|
+
import './structured-attributes.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Wearable cross-source fusion — shared types (issue #1810).
|
|
9
|
+
*
|
|
10
|
+
* Fusion merges same-day conversations from multiple enabled wearable
|
|
11
|
+
* sources into `FusedWearableConversation` artifacts: one reconciled
|
|
12
|
+
* timeline per real-world conversation, with per-segment source
|
|
13
|
+
* provenance and unresolved conflicts surfaced as `disagreements[]`.
|
|
14
|
+
*
|
|
15
|
+
* Everything in this module is DETERMINISTIC — no LLM calls. LLM-assisted
|
|
16
|
+
* reconciliation, memory-extraction over fused artifacts, and full
|
|
17
|
+
* segment-level alignment are deferred follow-ups (see PR body).
|
|
18
|
+
*/
|
|
19
|
+
/**
|
|
20
|
+
* One normalized segment fed into fusion. Speaker labels are already
|
|
21
|
+
* resolved through the speaker registry (`resolveSpeaker`), and text is
|
|
22
|
+
* post-cleanup + post-redaction — fusion consumes the same material day
|
|
23
|
+
* transcripts store, never raw provider output.
|
|
24
|
+
*/
|
|
25
|
+
interface FusionSegmentInput {
|
|
26
|
+
/** Resolved speaker label (e.g. "Jane", "Me (you)", "Speaker 0"). */
|
|
27
|
+
speaker: string;
|
|
28
|
+
/** Whether this speaker is the wearer. */
|
|
29
|
+
isSelf: boolean;
|
|
30
|
+
/** Utterance text. */
|
|
31
|
+
text: string;
|
|
32
|
+
/** ISO 8601 start, when known. */
|
|
33
|
+
startIso?: string;
|
|
34
|
+
/** ISO 8601 end, when known. */
|
|
35
|
+
endIso?: string;
|
|
36
|
+
}
|
|
37
|
+
/** One normalized conversation fed into fusion. */
|
|
38
|
+
interface FusionConversationInput {
|
|
39
|
+
/** Source id this conversation came from. */
|
|
40
|
+
source: string;
|
|
41
|
+
/** Provider-stable conversation id within that source. */
|
|
42
|
+
conversationId: string;
|
|
43
|
+
/** Provider title, when available. */
|
|
44
|
+
title?: string;
|
|
45
|
+
/** Provider summary, when available. */
|
|
46
|
+
summary?: string;
|
|
47
|
+
/** ISO 8601 conversation start. */
|
|
48
|
+
startIso: string;
|
|
49
|
+
/** ISO 8601 conversation end, when known. */
|
|
50
|
+
endIso?: string;
|
|
51
|
+
/** Ordered normalized segments. */
|
|
52
|
+
segments: FusionSegmentInput[];
|
|
53
|
+
}
|
|
54
|
+
/** Why a particular source's text was chosen for a fused segment. */
|
|
55
|
+
type SegmentPickReason = "only-source" | "higher-trust" | "more-complete" | "tie-break";
|
|
56
|
+
/** Kind of unresolved conflict surfaced during reconciliation. */
|
|
57
|
+
type DisagreementKind = "asr-text" | "speaker" | "timestamp";
|
|
58
|
+
/** Per-segment record of where the chosen text came from and what else was considered. */
|
|
59
|
+
interface FusedSegmentProvenance {
|
|
60
|
+
/** Source id the chosen text came from. */
|
|
61
|
+
source: string;
|
|
62
|
+
/** Conversation id within that source. */
|
|
63
|
+
conversationId: string;
|
|
64
|
+
/** Trust weight of the chosen source at reconciliation time (0..1). */
|
|
65
|
+
sourceTrust: number;
|
|
66
|
+
/** Why this source won the pick. */
|
|
67
|
+
reason: SegmentPickReason;
|
|
68
|
+
/** Other sources that offered a candidate text for this window/speaker. */
|
|
69
|
+
alternatives: Array<{
|
|
70
|
+
source: string;
|
|
71
|
+
text: string;
|
|
72
|
+
}>;
|
|
73
|
+
/** The chosen source's ORIGINAL start time (ISO), when known. The fused
|
|
74
|
+
* segment is emitted on the group/window ANCHOR timeline position so
|
|
75
|
+
* pre-sorted chronology stays valid even when the higher-trust source's
|
|
76
|
+
* clock is later than the anchor; this preserves WHERE the chosen text
|
|
77
|
+
* was actually recorded for provenance/traceability. */
|
|
78
|
+
sourceStartIso?: string;
|
|
79
|
+
/** The chosen source's ORIGINAL end time (ISO), when known (see sourceStartIso). */
|
|
80
|
+
sourceEndIso?: string;
|
|
81
|
+
}
|
|
82
|
+
/** One reconciled utterance in a fused conversation. */
|
|
83
|
+
interface FusedSegment {
|
|
84
|
+
/** Reconciled speaker label. */
|
|
85
|
+
speaker: string;
|
|
86
|
+
/** Whether this speaker is the wearer. */
|
|
87
|
+
isSelf: boolean;
|
|
88
|
+
/** Reconciled utterance text. */
|
|
89
|
+
text: string;
|
|
90
|
+
/** Window start (ISO), when known. */
|
|
91
|
+
startIso?: string;
|
|
92
|
+
/** Window end (ISO), when known. */
|
|
93
|
+
endIso?: string;
|
|
94
|
+
/** 0..1 confidence in this segment's text + attribution. */
|
|
95
|
+
confidence: number;
|
|
96
|
+
provenance: FusedSegmentProvenance;
|
|
97
|
+
}
|
|
98
|
+
/** An unresolved conflict that reconciliation could not settle deterministically. */
|
|
99
|
+
interface FusedDisagreement {
|
|
100
|
+
kind: DisagreementKind;
|
|
101
|
+
/**
|
|
102
|
+
* What the disagreement concerns — an ISO window anchor, a speaker
|
|
103
|
+
* label, or "(no timestamp)" for un-timestamped windows.
|
|
104
|
+
*/
|
|
105
|
+
subject: string;
|
|
106
|
+
/** The conflicting candidates that could not be auto-resolved. */
|
|
107
|
+
candidates: Array<{
|
|
108
|
+
source: string;
|
|
109
|
+
value: string;
|
|
110
|
+
}>;
|
|
111
|
+
/** Best-effort provisional winner; marked uncertain, NOT authoritative. */
|
|
112
|
+
provisional?: {
|
|
113
|
+
source: string;
|
|
114
|
+
value: string;
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
/** A reconciled speaker that appears in the fused conversation. */
|
|
118
|
+
interface FusedSpeaker {
|
|
119
|
+
/** Display label. */
|
|
120
|
+
label: string;
|
|
121
|
+
/** Whether this speaker is the wearer. */
|
|
122
|
+
isSelf: boolean;
|
|
123
|
+
/**
|
|
124
|
+
* 0..1 — lowered when a speaker could not be confidently matched
|
|
125
|
+
* across sources (e.g. a generic diarization label seen in one
|
|
126
|
+
* source only).
|
|
127
|
+
*/
|
|
128
|
+
confidence: number;
|
|
129
|
+
/** Source ids that produced this speaker. */
|
|
130
|
+
sources: string[];
|
|
131
|
+
}
|
|
132
|
+
/** Record of one source conversation that fed a fused conversation. */
|
|
133
|
+
interface FusedContribution {
|
|
134
|
+
source: string;
|
|
135
|
+
conversationId: string;
|
|
136
|
+
startIso: string;
|
|
137
|
+
endIso?: string;
|
|
138
|
+
segmentCount: number;
|
|
139
|
+
}
|
|
140
|
+
/** How a fused conversation was assembled. */
|
|
141
|
+
interface FusedConversationProvenance {
|
|
142
|
+
/** Source conversations that fed this cluster. */
|
|
143
|
+
contributions: FusedContribution[];
|
|
144
|
+
/** Max gap (ms) two conversations could span and still merge. */
|
|
145
|
+
proximityGapMs: number;
|
|
146
|
+
/** Max drift (ms) for two segments to align across sources. */
|
|
147
|
+
windowToleranceMs: number;
|
|
148
|
+
/** Clustering method (deterministic, time-proximity based). */
|
|
149
|
+
method: "time-proximity";
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* A real-world conversation reconstructed from one or more wearable
|
|
153
|
+
* sources recording at the same time. The fused artifact.
|
|
154
|
+
*/
|
|
155
|
+
interface FusedWearableConversation {
|
|
156
|
+
/** Stable content-hash id (deterministic from inputs; idempotent). */
|
|
157
|
+
id: string;
|
|
158
|
+
/** YYYY-MM-DD the conversation was recorded. */
|
|
159
|
+
date: string;
|
|
160
|
+
/** Earliest start across contributing sources. */
|
|
161
|
+
startIso: string;
|
|
162
|
+
/** Latest end across contributing sources, when known. */
|
|
163
|
+
endIso?: string;
|
|
164
|
+
/** Source ids that contributed at least one conversation. */
|
|
165
|
+
sources: string[];
|
|
166
|
+
/** Reconciled speakers (deduped across sources). */
|
|
167
|
+
speakers: FusedSpeaker[];
|
|
168
|
+
/** Provider title, when any source supplied one. */
|
|
169
|
+
title?: string;
|
|
170
|
+
/** Provider summary, when any source supplied one. */
|
|
171
|
+
summary?: string;
|
|
172
|
+
/** Aligned, reconciled segments in chronological order. */
|
|
173
|
+
segments: FusedSegment[];
|
|
174
|
+
/** Unresolved conflicts surfaced during reconciliation. */
|
|
175
|
+
disagreements: FusedDisagreement[];
|
|
176
|
+
provenance: FusedConversationProvenance;
|
|
177
|
+
}
|
|
178
|
+
/** Options for a fusion pass. */
|
|
179
|
+
interface FusionOptions {
|
|
180
|
+
/** Max gap (ms) between conversations to merge into one cluster. */
|
|
181
|
+
proximityGapMs?: number;
|
|
182
|
+
/** Max drift (ms) for two segments to align across sources. */
|
|
183
|
+
windowToleranceMs?: number;
|
|
184
|
+
/** Per-source trust weights (unknown sources default to 0.8). */
|
|
185
|
+
sourceTrust?: Record<string, number>;
|
|
186
|
+
}
|
|
187
|
+
/** Result of fusing one day across all sources. */
|
|
188
|
+
interface FusionDayResult {
|
|
189
|
+
date: string;
|
|
190
|
+
conversations: FusedWearableConversation[];
|
|
191
|
+
/** Distinct source ids that contributed any conversation. */
|
|
192
|
+
sources: string[];
|
|
193
|
+
/** SHA-256 over the canonical input serialization + effective fusion config (idempotency key). */
|
|
194
|
+
contentHash: string;
|
|
195
|
+
}
|
|
196
|
+
/** Frontmatter persisted on a fused-day derived file. */
|
|
197
|
+
interface FusedDayMeta {
|
|
198
|
+
kind: "wearable-fusion";
|
|
199
|
+
date: string;
|
|
200
|
+
sourceCount: number;
|
|
201
|
+
conversationCount: number;
|
|
202
|
+
contentHash: string;
|
|
203
|
+
/**
|
|
204
|
+
* SHA-256 over the canonical serialized body (`hashFusionBody`). Stored
|
|
205
|
+
* so the skip-unchanged path can detect a body whose bytes drifted from
|
|
206
|
+
* the recomputed artifact even when `contentHash` + conversation count
|
|
207
|
+
* still match — forcing a self-repair rewrite on body-level corruption.
|
|
208
|
+
*/
|
|
209
|
+
bodyHash: string;
|
|
210
|
+
fusedAt: string;
|
|
211
|
+
}
|
|
212
|
+
/** A parsed fused-day derived file. */
|
|
213
|
+
interface FusedDayFile {
|
|
214
|
+
meta: FusedDayMeta;
|
|
215
|
+
conversations: FusedWearableConversation[];
|
|
216
|
+
/**
|
|
217
|
+
* False when the JSON body failed to parse (truncated/corrupt). A
|
|
218
|
+
* legitimately empty (`[]`) body parses fine — parseOk stays true — so
|
|
219
|
+
* callers can distinguish "nothing to fuse" from a broken file and force
|
|
220
|
+
* a self-repair rewrite even when the frontmatter hash matches and the
|
|
221
|
+
* parsed conversation count is also zero.
|
|
222
|
+
*/
|
|
223
|
+
parseOk: boolean;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Wearable cross-source fusion — derived-day file serialization.
|
|
228
|
+
*
|
|
229
|
+
* One derived file per fused day, stored ALONGSIDE raw source transcripts
|
|
230
|
+
* (under the wearables tree) but never overwriting them. Format mirrors
|
|
231
|
+
* the day-transcript convention: YAML frontmatter (`kind:
|
|
232
|
+
* wearable-fusion`) + a JSON body carrying the structured
|
|
233
|
+
* `FusedWearableConversation[]`. The frontmatter `contentHash` is the
|
|
234
|
+
* idempotency key derived from inputs plus the effective fusion config,
|
|
235
|
+
* so an unchanged re-run (same inputs AND config) produces a
|
|
236
|
+
* byte-identical file.
|
|
237
|
+
*/
|
|
238
|
+
|
|
239
|
+
declare const FUSION_KIND: "wearable-fusion";
|
|
240
|
+
/** Hash the canonical JSON body for idempotent skip-unchanged checks. */
|
|
241
|
+
declare function hashFusionBody(conversations: readonly FusedWearableConversation[]): string;
|
|
242
|
+
declare function composeFusionDayMeta(date: string, conversations: readonly FusedWearableConversation[], sources: readonly string[], contentHash: string, fusedAt: string): FusedDayMeta;
|
|
243
|
+
/** Serialize meta + conversations into the persisted file format. */
|
|
244
|
+
declare function serializeFusionDay(meta: FusedDayMeta, conversations: readonly FusedWearableConversation[]): string;
|
|
245
|
+
/**
|
|
246
|
+
* Parse a persisted fused-day file. Returns null when the content does
|
|
247
|
+
* not look like a fusion artifact (wrong kind / missing frontmatter) so
|
|
248
|
+
* callers can distinguish "not fused" from a malformed file. A non-null
|
|
249
|
+
* result carries `parseOk`: false when the JSON body failed to parse, was
|
|
250
|
+
* not an array, or held a malformed element (conversations is empty in
|
|
251
|
+
* that case), true for a well-formed (incl. legitimately-empty `[]`)
|
|
252
|
+
* body — so the skip-unchanged path can force a self-repair rewrite
|
|
253
|
+
* regardless of the recomputed conversation count or body hash.
|
|
254
|
+
*/
|
|
255
|
+
declare function parseFusionDay(raw: string): FusedDayFile | null;
|
|
256
|
+
/**
|
|
257
|
+
* Encrypted-at-rest + atomic file IO the fusion artifact store needs.
|
|
258
|
+
* Satisfied by StorageManager (which owns the secure-store key + atomic
|
|
259
|
+
* write path) and injected so this module performs NO direct fs — the
|
|
260
|
+
* derived files inherit the same encrypted-at-rest + atomic-write
|
|
261
|
+
* semantics as raw day transcripts without this module knowing the key.
|
|
262
|
+
*/
|
|
263
|
+
interface FusionFileIo {
|
|
264
|
+
writeFile(filePath: string, content: string): Promise<void>;
|
|
265
|
+
/** Read a file; rejects with ENOENT when it is absent. */
|
|
266
|
+
readFile(filePath: string): Promise<string>;
|
|
267
|
+
/** Directory entries; rejects with ENOENT when the directory is absent. */
|
|
268
|
+
readDir(dirPath: string): Promise<string[]>;
|
|
269
|
+
/** Remove a file; rejects with ENOENT when it is absent. */
|
|
270
|
+
deleteFile(filePath: string): Promise<void>;
|
|
271
|
+
/**
|
|
272
|
+
* Resolve a path through symlinks (node:fs/promises realpath); rejects
|
|
273
|
+
* with ENOENT when the path is absent. Used by the symlink-containment
|
|
274
|
+
* guard so a symlinked `_fusion` dir (or a symlinked wearables root)
|
|
275
|
+
* that resolves outside the memory dir is rejected before any
|
|
276
|
+
* read/write/delete (AGENTS.md #3).
|
|
277
|
+
*/
|
|
278
|
+
realpath(filePath: string): Promise<string>;
|
|
279
|
+
/**
|
|
280
|
+
* Stat a path WITHOUT following a trailing symlink
|
|
281
|
+
* (node:fs/promises lstat); rejects with ENOENT when the path is
|
|
282
|
+
* absent. Used to detect a pre-existing symlink at the fusion
|
|
283
|
+
* artifact directory itself, which is rejected even when its
|
|
284
|
+
* target resolves inside the memory dir (issue #1849).
|
|
285
|
+
*/
|
|
286
|
+
lstat(filePath: string): Promise<{
|
|
287
|
+
isSymbolicLink: boolean;
|
|
288
|
+
}>;
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Owns the derived fused-day artifact files under
|
|
292
|
+
* `<wearablesDir>/_fusion/<YYYY-MM-DD>.md`. Path construction, date
|
|
293
|
+
* validation, and newest-first listing live here (relocated out of the
|
|
294
|
+
* root storage module — issue #1810 ratchet); the bytes flow through the
|
|
295
|
+
* injected secure IO.
|
|
296
|
+
*/
|
|
297
|
+
declare class FusionArtifactStore {
|
|
298
|
+
private readonly wearablesDir;
|
|
299
|
+
private readonly memoryDir;
|
|
300
|
+
private readonly io;
|
|
301
|
+
constructor(wearablesDir: string, memoryDir: string, io: FusionFileIo);
|
|
302
|
+
fusedDayPath(date: string): string;
|
|
303
|
+
writeFusedDay(date: string, serialized: string): Promise<void>;
|
|
304
|
+
/** Read a stored fused-day artifact; null when absent. */
|
|
305
|
+
readFusedDay(date: string): Promise<string | null>;
|
|
306
|
+
/**
|
|
307
|
+
* Remove a stored fused-day artifact. Idempotent: a no-op when the
|
|
308
|
+
* artifact is already absent. Used to clear a now-stale derived file
|
|
309
|
+
* before a fusion run that deliberately refuses to fuse (e.g. a day
|
|
310
|
+
* whose sources later conflict on timezone) so fusedConversations()
|
|
311
|
+
* does not keep serving a stale view (issue #1849).
|
|
312
|
+
*/
|
|
313
|
+
deleteFusedDay(date: string): Promise<void>;
|
|
314
|
+
/** List dates with stored fused artifacts, newest first. */
|
|
315
|
+
listFusedDays(): Promise<string[]>;
|
|
316
|
+
/**
|
|
317
|
+
* Reject a symlinked/traversing fusion artifact path before any IO. The
|
|
318
|
+
* fusion dir (`<wearablesDir>/_fusion`) and its parents are followed
|
|
319
|
+
* directly by the secure IO; a symlink placed there (attacker-writable
|
|
320
|
+
* or a malformed memory dir) would otherwise be followed and
|
|
321
|
+
* read/write/delete outside the allowed root (AGENTS.md pattern #3).
|
|
322
|
+
*
|
|
323
|
+
* Containment is anchored to the real MEMORY-DIR root, not the
|
|
324
|
+
* wearables dir, AND the wearables root is checked explicitly: if
|
|
325
|
+
* `wearablesDir` itself is a symlink that resolves outside memoryDir, a
|
|
326
|
+
* leaf candidate like `<wearablesDir>/_fusion/<date>.md` may not yet
|
|
327
|
+
* exist (so its realpath ENOENT-skips) and the write would silently
|
|
328
|
+
* create the file inside the symlinked escape target. Checking
|
|
329
|
+
* `wearablesDir` itself — which resolves through the symlink when it
|
|
330
|
+
* exists — closes that gap, while the per-leaf checks catch a nested
|
|
331
|
+
* `_fusion` or per-file symlink. Absent paths are allowed (a fresh
|
|
332
|
+
* write creates them lexically under the root; only a path that
|
|
333
|
+
* resolves to an existing target can redirect IO). Mirrors
|
|
334
|
+
* `assertPathInsideRoot` in the storage walkers.
|
|
335
|
+
*/
|
|
336
|
+
private assertPathContained;
|
|
337
|
+
/**
|
|
338
|
+
* Refuse a pre-existing symbolic link at the `<wearablesDir>/_fusion`
|
|
339
|
+
* directory. Unlike `assertNoEscape` (which follows the link and only
|
|
340
|
+
* rejects when the target lands outside the memory dir), this catches a
|
|
341
|
+
* fusion root that aliases an in-bounds path — e.g. a `_fusion` link
|
|
342
|
+
* pointed at a raw source transcript — so fusion IO never writes
|
|
343
|
+
* through it and overwrites the aliased file. Absent dirs are allowed
|
|
344
|
+
* (a fresh write creates a real directory lexically under the root).
|
|
345
|
+
*/
|
|
346
|
+
private assertFusionDirNotSymlinked;
|
|
347
|
+
/**
|
|
348
|
+
* Refuse a candidate whose realpath escapes the memory root. Absent
|
|
349
|
+
* candidates are allowed: a missing path cannot yet redirect IO, and
|
|
350
|
+
* the secure write creates it lexically under the root.
|
|
351
|
+
*/
|
|
352
|
+
private assertNoEscape;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
/** Why a tombstone was emitted. */
|
|
356
|
+
type TombstoneReason = "correction" | "supersession" | "retraction" | "contradiction_resolution";
|
|
357
|
+
/** Who emitted the tombstone. */
|
|
358
|
+
type TombstoneCreatedBy = "user_correction" | "contradiction_resolution" | "supersession" | "chat";
|
|
359
|
+
/** Tier that matched on lookup. */
|
|
360
|
+
type TombstoneMatchTier = "exact" | "normalized" | "keyed" | "semantic";
|
|
361
|
+
/**
|
|
362
|
+
* A single append-only tombstone log entry.
|
|
363
|
+
*
|
|
364
|
+
* `kind: "tombstone"` blocks; `kind: "revocation"` re-allows. The log is
|
|
365
|
+
* never rewritten — the NEWEST matching entry wins at lookup (rule 25).
|
|
366
|
+
*/
|
|
367
|
+
interface TombstoneEntry {
|
|
368
|
+
/** Stable tombstone id (`tomb-<ts>-<rand>`). */
|
|
369
|
+
id: string;
|
|
370
|
+
kind: "tombstone" | "revocation";
|
|
371
|
+
reason: TombstoneReason;
|
|
372
|
+
/** The memory that was retired. */
|
|
373
|
+
sourceMemoryId: string;
|
|
374
|
+
/** sha256 of the retired memory's rawContent (rule 23). */
|
|
375
|
+
contentHash: string;
|
|
376
|
+
/** `ContentHashIndex.normalizeContent(rawContent)` — the pre-hash form. */
|
|
377
|
+
normalizedText: string;
|
|
378
|
+
entityRef?: string;
|
|
379
|
+
/** Structured-attribute supersession key when one existed. */
|
|
380
|
+
supersessionKey?: string;
|
|
381
|
+
/** Namespace scope (rule 42). */
|
|
382
|
+
namespace: string;
|
|
383
|
+
createdAt: string;
|
|
384
|
+
createdBy: TombstoneCreatedBy;
|
|
385
|
+
/** For `kind: "revocation"`: the tombstone id being revoked. */
|
|
386
|
+
revokes?: string;
|
|
387
|
+
}
|
|
388
|
+
/** A positive block decision returned by `TombstoneStore.lookup`. */
|
|
389
|
+
interface TombstoneMatch {
|
|
390
|
+
tombstoneId: string;
|
|
391
|
+
matchedTier: TombstoneMatchTier;
|
|
392
|
+
reason: TombstoneReason;
|
|
393
|
+
}
|
|
394
|
+
/** Inputs to a lookup. At least one discriminator must be present.
|
|
395
|
+
*
|
|
396
|
+
* Issue #1579 thread Ociag/Oci-W: `supersessionKeys` (plural) lets the write
|
|
397
|
+
* chokepoint check EVERY derived key, not just the first. Emitters register
|
|
398
|
+
* one tombstone per matched key (temporal-supersession, rebuild), so a block
|
|
399
|
+
* can live on any later key; querying only `supersessionKeys[0]` missed it
|
|
400
|
+
* and the retired fact resurrected as active. `supersessionKey` (singular)
|
|
401
|
+
* remains for direct/unit callers; `lookup` checks the union of both. */
|
|
402
|
+
interface TombstoneLookupQuery {
|
|
403
|
+
contentHash?: string;
|
|
404
|
+
normalizedText?: string;
|
|
405
|
+
entityRef?: string;
|
|
406
|
+
/** Single supersession key (direct/unit callers). */
|
|
407
|
+
supersessionKey?: string;
|
|
408
|
+
/** All derived supersession keys (write chokepoint). The keyed tier is
|
|
409
|
+
* checked for each; the first active match wins. */
|
|
410
|
+
supersessionKeys?: string[];
|
|
411
|
+
namespace: string;
|
|
412
|
+
}
|
|
413
|
+
/** Configuration for a tombstone store instance. */
|
|
414
|
+
interface TombstoneStoreOptions {
|
|
415
|
+
enabled: boolean;
|
|
416
|
+
semanticMatch: boolean;
|
|
417
|
+
semanticThreshold: number;
|
|
418
|
+
/** sha256 of raw content — wired to `ContentHashIndex.computeHash`. */
|
|
419
|
+
hashContent: (raw: string) => string;
|
|
420
|
+
/** Normalize raw content — wired to `ContentHashIndex.normalizeContent`. */
|
|
421
|
+
normalizeText: (raw: string) => string;
|
|
422
|
+
/**
|
|
423
|
+
* Optional cosine similarity in [0, 1] for the semantic tier. When
|
|
424
|
+
* undefined or when `semanticMatch` is false, the semantic tier is
|
|
425
|
+
* skipped entirely.
|
|
426
|
+
*/
|
|
427
|
+
semanticSimilarity?: (a: string, b: string) => number;
|
|
428
|
+
/**
|
|
429
|
+
* Cross-process write-lock timings for the tombstone JSONL mutation lock
|
|
430
|
+
* (issue #1639). The secure-store append is a read-merge-write (read
|
|
431
|
+
* encrypted → decrypt → concat → re-encrypt → atomic rename), so two
|
|
432
|
+
* Remnic processes appending concurrently can each read the same contents
|
|
433
|
+
* and the last writer drops the other's entry — breaking the
|
|
434
|
+
* non-resurrection invariant. The lock serializes the mutation across
|
|
435
|
+
* processes. When omitted, defaults that fit the short tombstone critical
|
|
436
|
+
* section (mirroring the summary-snapshot lock): staleMs 30s, maxWaitMs 5s,
|
|
437
|
+
* heartbeatMs floor(staleMs/3).
|
|
438
|
+
*/
|
|
439
|
+
readonly lockStaleMs?: number;
|
|
440
|
+
readonly lockMaxWaitMs?: number;
|
|
441
|
+
readonly lockHeartbeatMs?: number;
|
|
442
|
+
}
|
|
443
|
+
/** Injected file I/O — the StorageManager wires its secure-store-aware
|
|
444
|
+
* implementations so tombstones are encrypted at rest alongside other state.
|
|
445
|
+
* `stat` is optional; when provided the store tracks the file mtime itself and
|
|
446
|
+
* runs a cross-process staleness probe on each access (#1579). */
|
|
447
|
+
interface TombstoneFileIo {
|
|
448
|
+
read: (filePath: string) => Promise<string>;
|
|
449
|
+
append: (filePath: string, content: string) => Promise<void>;
|
|
450
|
+
write: (filePath: string, content: string) => Promise<void>;
|
|
451
|
+
stat?: (filePath: string) => {
|
|
452
|
+
mtimeMs: number;
|
|
453
|
+
};
|
|
454
|
+
}
|
|
455
|
+
/** Aggregate stats for `remnic doctor`. */
|
|
456
|
+
interface TombstoneStats {
|
|
457
|
+
count: number;
|
|
458
|
+
revoked: number;
|
|
459
|
+
lastAppendAt: string | null;
|
|
460
|
+
corruptedLines: number;
|
|
461
|
+
/** Whether the in-memory index matches the on-disk file (rebuild check). */
|
|
462
|
+
loaded: boolean;
|
|
463
|
+
}
|
|
464
|
+
/**
|
|
465
|
+
* The instance-scoped tombstone store. One per StorageManager (rule 11),
|
|
466
|
+
* namespace-scoped via `namespace` + the on-disk path (rule 42).
|
|
467
|
+
*
|
|
468
|
+
* The in-memory index is built lazily on first access and invalidated on
|
|
469
|
+
* append + by the StorageManager's cache-invalidation chokepoint (rule 25).
|
|
470
|
+
*/
|
|
471
|
+
declare class TombstoneStore {
|
|
472
|
+
private readonly filePath;
|
|
473
|
+
private readonly namespace;
|
|
474
|
+
private readonly options;
|
|
475
|
+
private readonly io;
|
|
476
|
+
private entries;
|
|
477
|
+
/** contentHash → tombstone id (newest) — exact tier. */
|
|
478
|
+
private readonly byHash;
|
|
479
|
+
/** normalizedText → tombstone id (newest) — normalized tier. */
|
|
480
|
+
private readonly byNormalized;
|
|
481
|
+
/** entityRef\0supersessionKey → tombstone id (newest) — keyed tier. */
|
|
482
|
+
private readonly byKey;
|
|
483
|
+
/** Tombstone ids that have a later revocation entry. */
|
|
484
|
+
private readonly revokedIds;
|
|
485
|
+
/** id → entry index (newest only, for revocation lookups). */
|
|
486
|
+
private readonly byId;
|
|
487
|
+
private loaded;
|
|
488
|
+
private loadPromise;
|
|
489
|
+
private corruptedLines;
|
|
490
|
+
private lastAppendAt;
|
|
491
|
+
/**
|
|
492
|
+
* Last-seen mtime of the JSONL file (cross-process staleness probe, #1579).
|
|
493
|
+
* Tracked inside the store so the StorageManager wiring stays thin. When the
|
|
494
|
+
* file's mtime advances past this value between accesses, the in-memory index
|
|
495
|
+
* is stale (a peer process appended) and is reloaded before the next lookup.
|
|
496
|
+
*/
|
|
497
|
+
private fileMtimeMs;
|
|
498
|
+
constructor(filePath: string, namespace: string, options: TombstoneStoreOptions, io: TombstoneFileIo);
|
|
499
|
+
/**
|
|
500
|
+
* Resolved cross-process write-lock timings (issue #1639). Defaults mirror
|
|
501
|
+
* the summary-snapshot lock: a tombstone append critical section is
|
|
502
|
+
* sub-second, so a stale lock older than 30s is a crashed holder; bounded
|
|
503
|
+
* acquisition gives up after 5s and strict-fails rather than clobbering a
|
|
504
|
+
* concurrent writer (which would reintroduce the lost-write race this lock
|
|
505
|
+
* closes).
|
|
506
|
+
*/
|
|
507
|
+
private readonly lockStaleMs;
|
|
508
|
+
private readonly lockMaxWaitMs;
|
|
509
|
+
private readonly lockHeartbeatMs;
|
|
510
|
+
/**
|
|
511
|
+
* Sibling advisory lockfile: `<tombstones>.jsonl` → `<tombstones>.lock`.
|
|
512
|
+
* Shared by append, revoke, and rebuild so every JSONL mutation serializes
|
|
513
|
+
* against the others across processes (issue #1639: "shared with rebuilds").
|
|
514
|
+
*/
|
|
515
|
+
private get lockPath();
|
|
516
|
+
/** Lazy load + build the in-memory index. Idempotent. */
|
|
517
|
+
load(): Promise<void>;
|
|
518
|
+
private loadInternal;
|
|
519
|
+
private resetIndex;
|
|
520
|
+
/**
|
|
521
|
+
* Index an entry. Later entries (higher array index = newer createdAt)
|
|
522
|
+
* OVERRIDE earlier ones at each tier key — the newest matching entry wins
|
|
523
|
+
* (rule 25). Revocation entries mark their target as revoked.
|
|
524
|
+
*/
|
|
525
|
+
private indexEntry;
|
|
526
|
+
/** Invalidate the in-memory cache (rule 25). The next access reloads. */
|
|
527
|
+
invalidate(): void;
|
|
528
|
+
/**
|
|
529
|
+
* Cross-process staleness probe (#1579). If the file's mtime advanced since
|
|
530
|
+
* the last load/own-write, a peer process appended and our in-memory index is
|
|
531
|
+
* stale — invalidate AND reload in place so the next lookup sees the new
|
|
532
|
+
* entries. Best-effort: a stat error is swallowed (the loaded index is
|
|
533
|
+
* retained rather than crashing the write path). No-op when no `stat` was
|
|
534
|
+
* injected or when the mtime is unchanged. After our own append/revoke/rebuild
|
|
535
|
+
* `markWritten` records the new mtime, so this probe does not fire for our
|
|
536
|
+
* own writes (only for peer-process appends).
|
|
537
|
+
*/
|
|
538
|
+
ensureFreshAgainstDisk(): Promise<void>;
|
|
539
|
+
/**
|
|
540
|
+
* Record the file mtime after THIS process writes (append / revoke / rebuild)
|
|
541
|
+
* so `ensureFreshAgainstDisk` does not treat our own write as a peer append
|
|
542
|
+
* and throw away the just-updated in-memory index (#1579 — avoids a needless
|
|
543
|
+
* invalidate+reload in the hot write path).
|
|
544
|
+
*/
|
|
545
|
+
private markWritten;
|
|
546
|
+
private recordFileMtime;
|
|
547
|
+
/**
|
|
548
|
+
* Append a tombstone entry. Serialized via `serializeMutations` keyed by
|
|
549
|
+
* file path so concurrent appends do not interleave, with rejection recovery
|
|
550
|
+
* (rule 40 — a single failed append never poisons the chain). The in-memory
|
|
551
|
+
* index is updated AFTER the durable append succeeds.
|
|
552
|
+
*
|
|
553
|
+
* Returns the new tombstone id.
|
|
554
|
+
*/
|
|
555
|
+
appendTombstone(input: {
|
|
556
|
+
reason: TombstoneReason;
|
|
557
|
+
createdBy: TombstoneCreatedBy;
|
|
558
|
+
sourceMemoryId: string;
|
|
559
|
+
rawContent: string;
|
|
560
|
+
entityRef?: string;
|
|
561
|
+
supersessionKey?: string;
|
|
562
|
+
createdAt?: string;
|
|
563
|
+
/**
|
|
564
|
+
* Pre-computed canonical contentHash from the retired memory's frontmatter.
|
|
565
|
+
* When provided, used directly so the tombstone's exact tier matches the
|
|
566
|
+
* hash writeMemory computes on re-extraction (issue #1579 review: cited
|
|
567
|
+
* facts must not slip past the chokepoint because the emitter hashed the
|
|
568
|
+
* citation-annotated body instead of the canonical source).
|
|
569
|
+
*/
|
|
570
|
+
contentHash?: string;
|
|
571
|
+
}): Promise<string>;
|
|
572
|
+
/**
|
|
573
|
+
* Append a revocation entry referencing `tombstoneId`. The log is
|
|
574
|
+
* append-only; lookup treats a revoked tombstone as re-allowed (rule 25).
|
|
575
|
+
*/
|
|
576
|
+
revoke(tombstoneId: string, createdBy: TombstoneCreatedBy): Promise<string>;
|
|
577
|
+
private serializeAppend;
|
|
578
|
+
/**
|
|
579
|
+
* Acquire the cross-process tombstone write lock and run `task` under it
|
|
580
|
+
* (issue #1639). Strict-fail on acquisition timeout: the secure-store append
|
|
581
|
+
* is a read-merge-write, so a best-effort unlocked run would clobber a
|
|
582
|
+
* concurrent writer — reintroducing the lost-write race this lock closes.
|
|
583
|
+
* The thrown error surfaces to the caller (rule 34: never silently drop);
|
|
584
|
+
* rebuild recovers the tombstone on the next maintenance cycle.
|
|
585
|
+
*
|
|
586
|
+
* In-process callers are already serialized by serializeMutations (one key
|
|
587
|
+
* for append/revoke/rebuild), so this lock only contends across processes —
|
|
588
|
+
* the single-process daemon (default deployment) acquires it immediately.
|
|
589
|
+
*/
|
|
590
|
+
private withWriteLock;
|
|
591
|
+
/**
|
|
592
|
+
* Look up whether `query` is blocked by an active (non-revoked) tombstone.
|
|
593
|
+
* Tiers are checked in order: exact (contentHash) → normalized → keyed →
|
|
594
|
+
* semantic (off by default). Returns the first active match, or `null`.
|
|
595
|
+
*
|
|
596
|
+
* Namespace isolation (rule 42): only entries with `namespace === query.namespace`
|
|
597
|
+
* match. The store is per-namespace, so this is belt-and-suspenders.
|
|
598
|
+
*/
|
|
599
|
+
lookup(query: TombstoneLookupQuery): TombstoneMatch | null;
|
|
600
|
+
/** Aggregate stats for the doctor / x-ray surfaces. */
|
|
601
|
+
stats(): TombstoneStats;
|
|
602
|
+
/** Read-only snapshot of all entries (for rebuild + tests). */
|
|
603
|
+
snapshot(): readonly TombstoneEntry[];
|
|
604
|
+
/**
|
|
605
|
+
* Rebuild the in-memory index + JSONL from the supplied retired-memory
|
|
606
|
+
* records + existing entries (preserving revocations). Byte-stable: entries
|
|
607
|
+
* are sorted by (createdAt, id) before write (rule 38).
|
|
608
|
+
*
|
|
609
|
+
* Returns the count of tombstone entries written.
|
|
610
|
+
*/
|
|
611
|
+
rebuild(retiredMemories: ReadonlyArray<RetiredMemoryRecord>): Promise<number>;
|
|
612
|
+
}
|
|
613
|
+
/** A retired memory projected into the shape `TombstoneStore.rebuild` consumes. */
|
|
614
|
+
interface RetiredMemoryRecord {
|
|
615
|
+
memoryId: string;
|
|
616
|
+
rawContent: string;
|
|
617
|
+
entityRef?: string;
|
|
618
|
+
supersessionKey?: string;
|
|
619
|
+
reason: TombstoneReason;
|
|
620
|
+
createdBy: TombstoneCreatedBy;
|
|
621
|
+
createdAt: string;
|
|
622
|
+
/** Canonical contentHash from the retired memory's frontmatter (#1579). */
|
|
623
|
+
contentHash?: string;
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
interface ReextractJobRequest {
|
|
627
|
+
memoryId: string;
|
|
628
|
+
model: string;
|
|
629
|
+
requestedAt: string;
|
|
630
|
+
source: "cli-migrate";
|
|
631
|
+
}
|
|
632
|
+
interface MemoryLifecycleEventWriteOptions {
|
|
633
|
+
at?: Date;
|
|
634
|
+
actor?: string;
|
|
635
|
+
reasonCode?: string;
|
|
636
|
+
ruleVersion?: string;
|
|
637
|
+
relatedMemoryIds?: string[];
|
|
638
|
+
correlationId?: string;
|
|
639
|
+
}
|
|
640
|
+
declare function parseFrontmatterStringValue(rawValue: string | undefined): string | undefined;
|
|
641
|
+
declare function parseFrontmatter(raw: string): {
|
|
642
|
+
frontmatter: MemoryFrontmatter;
|
|
643
|
+
content: string;
|
|
644
|
+
} | null;
|
|
645
|
+
declare function normalizeFrontmatterForPath(frontmatter: MemoryFrontmatter, pathRel: string, content?: string): MemoryFrontmatter;
|
|
646
|
+
/**
|
|
647
|
+
* Normalize an entity name to a canonical form.
|
|
648
|
+
* Strips non-alphanumeric chars, collapses hyphens, removes type prefix duplication.
|
|
649
|
+
* e.g. "My Project" → "my-project"
|
|
650
|
+
*
|
|
651
|
+
* Checks caller-provided user aliases first, then built-in aliases. Alias
|
|
652
|
+
* tables are instance state on StorageManager (issue #1534) — use
|
|
653
|
+
* `storageManager.normalizeEntityName(raw, type)` when normalizing within a
|
|
654
|
+
* store, or pass `storageManager.entityAliases` explicitly. Without an
|
|
655
|
+
* aliases argument only the built-in structural aliases apply.
|
|
656
|
+
*/
|
|
657
|
+
declare function normalizeEntityName(raw: string, type: string, aliases?: Readonly<Record<string, string>>): string;
|
|
658
|
+
/**
|
|
659
|
+
* Content-hash dedup index for facts.
|
|
660
|
+
* Normalizes content (lowercase, strip punctuation, collapse whitespace),
|
|
661
|
+
* computes SHA-256, and stores hashes in a line-delimited file.
|
|
662
|
+
* Prevents writing semantically identical facts.
|
|
663
|
+
*/
|
|
664
|
+
declare class ContentHashIndex {
|
|
665
|
+
private hashes;
|
|
666
|
+
private dirty;
|
|
667
|
+
private readonly filePath;
|
|
668
|
+
private readonly secureStoreKeyProvider;
|
|
669
|
+
private readonly secureStoreWriteKeyProvider;
|
|
670
|
+
private readonly memoryDir;
|
|
671
|
+
constructor(stateDir: string, secureStoreKeyProvider?: () => Buffer | null, secureStoreWriteKeyProvider?: () => Buffer | null, memoryDir?: string);
|
|
672
|
+
/** Load existing hashes from disk. Safe to call multiple times. */
|
|
673
|
+
load(): Promise<void>;
|
|
674
|
+
/** Check if content already exists in the index. */
|
|
675
|
+
has(content: string): boolean;
|
|
676
|
+
/** Add content hash to the index. */
|
|
677
|
+
add(content: string): void;
|
|
678
|
+
get size(): number;
|
|
679
|
+
/** Clear all loaded hashes so the next save rewrites the index from scratch. */
|
|
680
|
+
clear(): void;
|
|
681
|
+
/** Persist index to disk if changed. */
|
|
682
|
+
save(): Promise<void>;
|
|
683
|
+
/** Remove a hash from the index (used when archiving/deleting). */
|
|
684
|
+
remove(content: string): void;
|
|
685
|
+
/**
|
|
686
|
+
* Remove a pre-computed SHA-256 hash directly from the index without
|
|
687
|
+
* re-hashing. Use this when the caller already holds the stored hash
|
|
688
|
+
* (e.g. `memory.frontmatter.contentHash`) to avoid the double-hash bug
|
|
689
|
+
* where `remove(hash)` would compute `hash(hash)` and never match the
|
|
690
|
+
* entry.
|
|
691
|
+
*/
|
|
692
|
+
removeByHash(hash: string): void;
|
|
693
|
+
/**
|
|
694
|
+
* Add a pre-computed SHA-256 hash directly to the index without re-hashing.
|
|
695
|
+
* Use this when the caller already holds the stored hash
|
|
696
|
+
* (e.g. `memory.frontmatter.contentHash`) so that the index records the raw
|
|
697
|
+
* content hash rather than re-hashing the citation-annotated body.
|
|
698
|
+
*
|
|
699
|
+
* @internal Only called from `StorageManager.ensureFactHashIndexAuthoritative`.
|
|
700
|
+
* Not part of the public API — prefer `add(content)` for external callers.
|
|
701
|
+
*/
|
|
702
|
+
addByHash(hash: string): void;
|
|
703
|
+
/** Normalize content (delegates to content-hash.ts for a single source of truth). */
|
|
704
|
+
static normalizeContent(content: string): string;
|
|
705
|
+
/** Compute SHA-256 hash (delegates to content-hash.ts for a single source of truth). */
|
|
706
|
+
static computeHash(content: string): string;
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
declare function normalizeAttributePairs(pairs: Record<string, string>): string;
|
|
710
|
+
declare function normalizeStructuredSectionFacts(facts: string[]): string[];
|
|
711
|
+
declare function compileEntityFacts(timeline: EntityTimelineEntry[], structuredSections: EntityStructuredSection[]): string[];
|
|
712
|
+
declare function compareEntityTimestamps(left?: string, right?: string): number;
|
|
713
|
+
declare function countEntityStructuredFacts(entity: EntityFile): number;
|
|
714
|
+
declare function fingerprintEntityStructuredFacts(entity: Pick<EntityFile, "structuredSections">): string | undefined;
|
|
715
|
+
declare function isEntitySynthesisStale(entity: EntityFile): boolean;
|
|
716
|
+
/**
|
|
717
|
+
* Parse an entity markdown file into a structured EntityFile.
|
|
718
|
+
* Backward compatible: old files without new sections get empty arrays.
|
|
719
|
+
*/
|
|
720
|
+
declare function parseEntityFile(content: string, entitySchemas?: PluginConfig["entitySchemas"]): EntityFile;
|
|
721
|
+
/**
|
|
722
|
+
* Serialize an EntityFile back to markdown.
|
|
723
|
+
* Writes the compiled-truth + timeline format while remaining parse-compatible
|
|
724
|
+
* with the legacy in-memory `summary` and `facts` fields.
|
|
725
|
+
*/
|
|
726
|
+
declare function serializeEntityFile(entity: EntityFile, entitySchemas?: PluginConfig["entitySchemas"]): string;
|
|
727
|
+
declare function buildEntitySchemaCacheKey(entitySchemas?: PluginConfig["entitySchemas"]): string;
|
|
728
|
+
/**
|
|
729
|
+
* Full-schema type guard for a `BUFFER_SURPRISE` telemetry row
|
|
730
|
+
* (issue #563 PR 3).
|
|
731
|
+
*
|
|
732
|
+
* The reader applies `limit` over the count of VALID rows, so
|
|
733
|
+
* applying only a partial check (e.g. "has a finite surpriseScore")
|
|
734
|
+
* and then deferring the rest of validation to
|
|
735
|
+
* `reportBufferSurpriseDistribution` would silently count
|
|
736
|
+
* schema-incomplete rows toward the limit, pushing genuinely-valid
|
|
737
|
+
* earlier rows out of the report window. Validate everything the
|
|
738
|
+
* downstream report requires at read time so the limit semantics and
|
|
739
|
+
* the distribution semantics stay consistent.
|
|
740
|
+
*/
|
|
741
|
+
declare function isValidBufferSurpriseEvent(value: unknown): value is BufferSurpriseEvent;
|
|
742
|
+
/** Result of {@link StorageManager.writeMemory} (issue #1645). Carries the
|
|
743
|
+
* persisted id PLUS the non-resurrection tombstone-block outcome (#1579) so
|
|
744
|
+
* post-write callers can observe it — NEVER a silent no-op (rule 34). */
|
|
745
|
+
interface MemoryWriteResult {
|
|
746
|
+
/** The persisted memory id. */
|
|
747
|
+
id: string;
|
|
748
|
+
/** True when the #1579 tombstone chokepoint downgraded this write to
|
|
749
|
+
* `pending_review` + `blockedBy`. Callers gate active post-write work on this. */
|
|
750
|
+
tombstoneBlocked: boolean;
|
|
751
|
+
/** The tombstone id that blocked the write, when `tombstoneBlocked`. */
|
|
752
|
+
blockedBy?: string;
|
|
753
|
+
}
|
|
754
|
+
declare class StorageManager {
|
|
755
|
+
private readonly baseDir;
|
|
756
|
+
private readonly entitySchemas?;
|
|
757
|
+
private knowledgeIndexCache;
|
|
758
|
+
private artifactIndexCache;
|
|
759
|
+
/** Read by storage/entity-store.ts (decomposition), hence not `private`. */
|
|
760
|
+
static readonly KNOWLEDGE_INDEX_CACHE_TTL_MS = 600000;
|
|
761
|
+
/** Read by storage/memory-read-store.ts (decomposition). */
|
|
762
|
+
static readonly ARTIFACT_INDEX_CACHE_TTL_MS = 60000;
|
|
763
|
+
private static readonly artifactWriteVersionByDir;
|
|
764
|
+
private static readonly memoryStatusVersionByDir;
|
|
765
|
+
private static readonly secureStoreEntityCacheKeyIds;
|
|
766
|
+
private static nextSecureStoreEntityCacheKeyId;
|
|
767
|
+
private static readonly coldWriteVersionByDir;
|
|
768
|
+
private static readonly allMemoriesInFlight;
|
|
769
|
+
/** Read by storage/memory-read-store.ts (decomposition). */
|
|
770
|
+
static readonly COLD_SCAN_CACHE_TTL_MS = 30000;
|
|
771
|
+
/** Read by storage/memory-read-store.ts (decomposition). */
|
|
772
|
+
static readonly coldMemoriesCache: Map<string, {
|
|
773
|
+
memories: MemoryFile[];
|
|
774
|
+
loadedAt: number;
|
|
775
|
+
coldVersion: number;
|
|
776
|
+
}>;
|
|
777
|
+
/** Read by storage/memory-read-store.ts (decomposition). */
|
|
778
|
+
static readonly QUESTIONS_CACHE_TTL_MS = 60000;
|
|
779
|
+
/** Read by storage/memory-read-store.ts (decomposition). */
|
|
780
|
+
static readonly questionsCache: Map<string, {
|
|
781
|
+
questions: Array<{
|
|
782
|
+
id: string;
|
|
783
|
+
question: string;
|
|
784
|
+
context: string;
|
|
785
|
+
priority: number;
|
|
786
|
+
resolved: boolean;
|
|
787
|
+
created: string;
|
|
788
|
+
filePath: string;
|
|
789
|
+
}>;
|
|
790
|
+
loadedAt: number;
|
|
791
|
+
}>;
|
|
792
|
+
private factHashIndex;
|
|
793
|
+
private factHashIndexLoadPromise;
|
|
794
|
+
private factHashIndexAuthoritative;
|
|
795
|
+
private factHashIndexAuthoritativePromise;
|
|
796
|
+
private readonly secureAppendChains;
|
|
797
|
+
private offlineSyncDigestCache;
|
|
798
|
+
private offlineSyncDigestCacheLoadPromise;
|
|
799
|
+
private offlineSyncDigestCacheWriteChain;
|
|
800
|
+
private offlineSyncDigestCacheWriteTimer;
|
|
801
|
+
/** Optional: set by the orchestrator after construction to enable template-aware citation stripping during legacy hash rebuild. */
|
|
802
|
+
citationTemplate: string;
|
|
803
|
+
/** Post-write catalog hook (#1522). Installed by the namespace router; fire-and-forget. */
|
|
804
|
+
onCatalogWrite?: () => void;
|
|
805
|
+
private notifyCatalogWrite;
|
|
806
|
+
private tombstoneStore;
|
|
807
|
+
private tombstoneStoreLoadPromise;
|
|
808
|
+
private tombstonesConfig;
|
|
809
|
+
/** Page-versioning configuration. Set by the orchestrator after construction. */
|
|
810
|
+
private _versioningConfig;
|
|
811
|
+
/** Set the page-versioning configuration. When `enabled` is false (default), all versioning calls are no-ops. */
|
|
812
|
+
setVersioningConfig(config: VersioningConfig): void;
|
|
813
|
+
/**
|
|
814
|
+
* At-rest encryption key (issue #690 PR 3/4).
|
|
815
|
+
*
|
|
816
|
+
* When non-null, every memory file read is decrypted and every write
|
|
817
|
+
* is encrypted using the secure-fs layer. When null, the storage
|
|
818
|
+
* layer operates in plain-text mode (legacy/unencrypted store).
|
|
819
|
+
*
|
|
820
|
+
* Set by the orchestrator after init/unlock; cleared on lock.
|
|
821
|
+
* The key buffer is NEVER logged or serialized.
|
|
822
|
+
*/
|
|
823
|
+
private _secureStoreKey;
|
|
824
|
+
/**
|
|
825
|
+
* When true (and `_secureStoreKey` is non-null), new writes are
|
|
826
|
+
* encrypted. Set to false to pause encryption of new writes while
|
|
827
|
+
* still decrypting existing files.
|
|
828
|
+
*/
|
|
829
|
+
private _secureStoreEncryptOnWrite;
|
|
830
|
+
/**
|
|
831
|
+
* When true, the secure-store is configured as required — writes
|
|
832
|
+
* MUST be encrypted and a locked store MUST reject writes rather
|
|
833
|
+
* than silently falling back to plaintext. Set by the orchestrator
|
|
834
|
+
* from `resolveRecallAuxiliaryCapabilities(config).secureStore`.
|
|
835
|
+
*/
|
|
836
|
+
private _secureStoreRequired;
|
|
837
|
+
/**
|
|
838
|
+
* Set or clear the at-rest encryption key.
|
|
839
|
+
*
|
|
840
|
+
* Pass a 32-byte Buffer to enable encryption; pass null to clear
|
|
841
|
+
* (lock) the store. The caller is responsible for key lifecycle —
|
|
842
|
+
* this method does not zero the buffer on replacement; the keyring
|
|
843
|
+
* module (`keyring.ts`) owns zeroization.
|
|
844
|
+
*/
|
|
845
|
+
setSecureStoreKey(key: Buffer | null, encryptOnWrite?: boolean): void;
|
|
846
|
+
private getEntityCacheSecureStoreKey;
|
|
847
|
+
/**
|
|
848
|
+
* Mark the secure-store as required for this storage instance.
|
|
849
|
+
* When required and locked, writes throw SecureStoreLockedError
|
|
850
|
+
* rather than silently writing plaintext.
|
|
851
|
+
*/
|
|
852
|
+
setSecureStoreRequired(required: boolean): void;
|
|
853
|
+
/** Return true iff the secure-store key is currently set (store is unlocked). */
|
|
854
|
+
isSecureStoreUnlocked(): boolean;
|
|
855
|
+
/**
|
|
856
|
+
* Resolve the effective write key.
|
|
857
|
+
*
|
|
858
|
+
* - If `_secureStoreEncryptOnWrite` is false: returns null (plain write).
|
|
859
|
+
* - If `_secureStoreEncryptOnWrite` is true AND key is set: returns key.
|
|
860
|
+
* - If `_secureStoreEncryptOnWrite` is true AND key is null AND
|
|
861
|
+
* `_secureStoreRequired` is true: throws SecureStoreLockedError so the
|
|
862
|
+
* write fails loudly rather than silently writing plaintext (P1 finding
|
|
863
|
+
* from Cursor review of PR #767).
|
|
864
|
+
* - If `_secureStoreEncryptOnWrite` is true AND key is null AND
|
|
865
|
+
* `_secureStoreRequired` is false: returns null (unencrypted store).
|
|
866
|
+
*/
|
|
867
|
+
private resolveWriteKey;
|
|
868
|
+
/**
|
|
869
|
+
* Snapshot the current content of a page before overwriting.
|
|
870
|
+
* No-op when versioning is disabled or the file does not yet exist.
|
|
871
|
+
*/
|
|
872
|
+
private snapshotBeforeWrite;
|
|
873
|
+
/**
|
|
874
|
+
* Consolidation provenance helper (issue #561 PR 2).
|
|
875
|
+
*
|
|
876
|
+
* Captures the current on-disk content of a source memory as a
|
|
877
|
+
* page-version snapshot so the downstream consolidated write can record a
|
|
878
|
+
* `derived_from` pointer that actually resolves. Returns the
|
|
879
|
+
* `"<relative-path>:<versionId>"` entry expected by the `derived_from`
|
|
880
|
+
* frontmatter field.
|
|
881
|
+
*
|
|
882
|
+
* Returns `null` when versioning is disabled (snapshots would not be
|
|
883
|
+
* created), when the file does not exist (nothing to snapshot), or when
|
|
884
|
+
* the snapshot write itself fails (best-effort — callers skip the entry
|
|
885
|
+
* rather than block the consolidation).
|
|
886
|
+
*/
|
|
887
|
+
snapshotForProvenance(filePath: string): Promise<string | null>;
|
|
888
|
+
constructor(baseDir: string, entitySchemas?: PluginConfig["entitySchemas"]);
|
|
889
|
+
/**
|
|
890
|
+
* The LIVE class object of this instance (issue #1809 review of the
|
|
891
|
+
* storage decomposition): extracted store modules must read/write the
|
|
892
|
+
* shared static caches (questionsCache, coldMemoriesCache, ...) through
|
|
893
|
+
* the SAME class binding the host methods use. Referencing the imported
|
|
894
|
+
* `StorageManager` symbol from a split bundle chunk can yield a second
|
|
895
|
+
* class copy with its own statics, split-braining the caches
|
|
896
|
+
* (resolveQuestion clears copy A while readQuestions reads copy B).
|
|
897
|
+
*/
|
|
898
|
+
get storageManagerClass(): typeof StorageManager;
|
|
899
|
+
/** The root directory of this storage instance. */
|
|
900
|
+
/** MemoryReadStore (storage.ts decomposition). Lazy; selfDeps live wiring. */
|
|
901
|
+
private _memoryReadStore;
|
|
902
|
+
private get memoryReadStore();
|
|
903
|
+
/** EntityStore (storage.ts decomposition). Lazy; selfDeps live wiring. */
|
|
904
|
+
private _entityStore;
|
|
905
|
+
private get entityStore();
|
|
906
|
+
/** IdentityContinuityStore (storage.ts decomposition). Lazy; selfDeps live wiring. */
|
|
907
|
+
private _identityContinuityStore;
|
|
908
|
+
private get identityContinuityStore();
|
|
909
|
+
get dir(): string;
|
|
910
|
+
private identityFilePath;
|
|
911
|
+
private versionFilePath;
|
|
912
|
+
private bumpSharedVersion;
|
|
913
|
+
private readSharedVersion;
|
|
914
|
+
private bumpMemoryStatusVersion;
|
|
915
|
+
getMemoryStatusVersion(): number;
|
|
916
|
+
private bumpArtifactWriteVersion;
|
|
917
|
+
private getArtifactWriteVersion;
|
|
918
|
+
private get wearablesDir();
|
|
919
|
+
/**
|
|
920
|
+
* Resolve the on-disk path for a source/day transcript. Throws on
|
|
921
|
+
* malformed inputs — source ids and dates reach this from CLI/MCP/HTTP
|
|
922
|
+
* surfaces and must never become path traversal.
|
|
923
|
+
*/
|
|
924
|
+
wearableTranscriptPath(sourceId: string, date: string): string;
|
|
925
|
+
writeWearableDayTranscript(sourceId: string, date: string, serialized: string): Promise<void>;
|
|
926
|
+
/** Read a stored day transcript; null when the day has no file. */
|
|
927
|
+
readWearableDayTranscript(sourceId: string, date: string): Promise<string | null>;
|
|
928
|
+
listWearableTranscriptDays(sourceId?: string): Promise<Array<{
|
|
929
|
+
source: string;
|
|
930
|
+
date: string;
|
|
931
|
+
}>>;
|
|
932
|
+
private _fusionStore?;
|
|
933
|
+
/** Derived fusion-day IO; file IO lives in wearables/fusion (#1810). */
|
|
934
|
+
fusionArtifactStore(): FusionArtifactStore;
|
|
935
|
+
/**
|
|
936
|
+
* Locate a wearable-sourced memory by exact (trimmed) content,
|
|
937
|
+
* ignoring the "[Attributes: ...]" suffix writeMemory appends for
|
|
938
|
+
* structuredAttributes — callers pass the raw fact text. Used by the
|
|
939
|
+
* smart trust pipeline to find an earlier borderline write when the
|
|
940
|
+
* same fact re-extracts with stronger evidence.
|
|
941
|
+
*/
|
|
942
|
+
findWearableMemoryByContent(content: string): Promise<{
|
|
943
|
+
id: string;
|
|
944
|
+
status: MemoryStatus | undefined;
|
|
945
|
+
} | null>;
|
|
946
|
+
/**
|
|
947
|
+
* Promote a pending_review wearable memory to active in place,
|
|
948
|
+
* merging updated trust evidence into structuredAttributes. Returns
|
|
949
|
+
* false when the memory is missing or no longer pending_review (a
|
|
950
|
+
* concurrent review decision wins), or when the row is tombstone-blocked
|
|
951
|
+
* (`blockedBy` — issue #1579 threads OcuDx/Ocu1l): writeMemoryFrontmatter
|
|
952
|
+
* bypasses the writeMemory chokepoint, so a blocked row must first be
|
|
953
|
+
* cleared via revokeTombstone before promotion can proceed.
|
|
954
|
+
*/
|
|
955
|
+
promoteWearableMemory(id: string, attributeUpdates: Record<string, string>, confidence?: number): Promise<boolean>;
|
|
956
|
+
/**
|
|
957
|
+
* Demote a pending_review wearable memory to rejected when a re-pass
|
|
958
|
+
* produced an explicit judge-reject verdict, merging the evidence.
|
|
959
|
+
* Returns false when the memory is missing or no longer
|
|
960
|
+
* pending_review — active rows are NEVER auto-demoted (operator
|
|
961
|
+
* approvals and accrued recall signals win; contradiction scans and
|
|
962
|
+
* supersession own active-row retirement).
|
|
963
|
+
*/
|
|
964
|
+
demoteWearableMemory(id: string, attributeUpdates: Record<string, string>): Promise<boolean>;
|
|
965
|
+
private get factsDir();
|
|
966
|
+
private get correctionsDir();
|
|
967
|
+
private get proceduresDir();
|
|
968
|
+
private get reasoningTracesDir();
|
|
969
|
+
private get entitiesDir();
|
|
970
|
+
private resolveEntityFilePath;
|
|
971
|
+
private readStorageSecureFile;
|
|
972
|
+
private writeStorageSecureFile;
|
|
973
|
+
private writeStorageSecureFileChunks;
|
|
974
|
+
private assertManagedStoragePath;
|
|
975
|
+
readOfflineSyncFile(filePath: string): Promise<Buffer>;
|
|
976
|
+
digestOfflineSyncFile(filePath: string): Promise<{
|
|
977
|
+
sha256: string;
|
|
978
|
+
bytes: number;
|
|
979
|
+
}>;
|
|
980
|
+
private loadOfflineSyncDigestCache;
|
|
981
|
+
private readOfflineSyncDigestCache;
|
|
982
|
+
private rememberOfflineSyncDigest;
|
|
983
|
+
private scheduleOfflineSyncDigestCacheWrite;
|
|
984
|
+
private queueOfflineSyncDigestCacheWrite;
|
|
985
|
+
private offlineSyncFileIsEncrypted;
|
|
986
|
+
writeOfflineSyncFile(filePath: string, content: Buffer): Promise<void>;
|
|
987
|
+
writeOfflineSyncStagingFile(filePath: string, content: Buffer): Promise<void>;
|
|
988
|
+
writeOfflineSyncFileChunks(filePath: string, chunks: AsyncIterable<Buffer>): Promise<void>;
|
|
989
|
+
deleteOfflineSyncFile(filePath: string): Promise<void>;
|
|
990
|
+
private invalidateAfterOfflineSyncMutation;
|
|
991
|
+
createContentHashIndex(): ContentHashIndex;
|
|
992
|
+
private appendStorageSecureFile;
|
|
993
|
+
private appendStorageSecureFileUnlocked;
|
|
994
|
+
private get stateDir();
|
|
995
|
+
private get offlineSyncDigestCachePath();
|
|
996
|
+
private get entitySynthesisQueuePath();
|
|
997
|
+
private get factHashIndexReadyPath();
|
|
998
|
+
/**
|
|
999
|
+
* The on-disk tombstone log path. Lives under `<stateDir>/tombstones.jsonl`
|
|
1000
|
+
* so it is co-located with the fact-hash index and encrypted at rest when
|
|
1001
|
+
* the secure-store is enabled (the StorageManager's secure read/write
|
|
1002
|
+
* helpers are injected into the store).
|
|
1003
|
+
*/
|
|
1004
|
+
private get tombstonesPath();
|
|
1005
|
+
/**
|
|
1006
|
+
* Configure the tombstone invariant for this storage instance. Installed
|
|
1007
|
+
* by the orchestrator after construction (same pattern as
|
|
1008
|
+
* `setVersioningConfig` / `citationTemplate`). When `enabled` is false
|
|
1009
|
+
* (default until the orchestrator wires config), the chokepoint check is a
|
|
1010
|
+
* no-op — pre-feature behavior for rollback safety (rule 30).
|
|
1011
|
+
*/
|
|
1012
|
+
setTombstonesConfig(config: {
|
|
1013
|
+
enabled: boolean;
|
|
1014
|
+
semanticMatch: boolean;
|
|
1015
|
+
semanticThreshold: number;
|
|
1016
|
+
namespace: string;
|
|
1017
|
+
}): void;
|
|
1018
|
+
private buildTombstoneStore;
|
|
1019
|
+
/**
|
|
1020
|
+
* Lazily load the tombstone store. Mirrors the fact-hash-index lazy-load
|
|
1021
|
+
* pattern: a single in-flight load promise dedups concurrent first-access.
|
|
1022
|
+
* The cross-process staleness probe lives inside the store now (#1579): on
|
|
1023
|
+
* each cached access it stats its own file and invalidates if a peer process
|
|
1024
|
+
* appended, so the next lookup reloads from disk. If the probe just
|
|
1025
|
+
* invalidated the store, fall through to the reload branch — returning null
|
|
1026
|
+
* here was the original regression (the chokepoint threw and failed OPEN).
|
|
1027
|
+
*/
|
|
1028
|
+
getTombstoneStore(): Promise<TombstoneStore>;
|
|
1029
|
+
/**
|
|
1030
|
+
* Whether tombstones are enabled on this storage. Callers that need to
|
|
1031
|
+
* distinguish "tombstones disabled" (null return is expected) from
|
|
1032
|
+
* "persistence failed" (appendTombstone swallows store errors and also
|
|
1033
|
+
* returns null) use this to fail closed when enabled (#1580 review OgIqp).
|
|
1034
|
+
*/
|
|
1035
|
+
isTombstonesEnabled(): boolean;
|
|
1036
|
+
/**
|
|
1037
|
+
* Append a tombstone for a retired memory (issue #1579 emitters).
|
|
1038
|
+
* Best-effort: a tombstone append failure MUST NOT fail the supersession /
|
|
1039
|
+
* correction that triggered it (gotcha #13 / rule 34). The memory is
|
|
1040
|
+
* already retired on disk; the tombstone is the non-resurrection guard.
|
|
1041
|
+
*/
|
|
1042
|
+
appendTombstone(input: {
|
|
1043
|
+
reason: TombstoneReason;
|
|
1044
|
+
createdBy: TombstoneCreatedBy;
|
|
1045
|
+
sourceMemoryId: string;
|
|
1046
|
+
rawContent: string;
|
|
1047
|
+
entityRef?: string;
|
|
1048
|
+
supersessionKey?: string;
|
|
1049
|
+
createdAt?: string;
|
|
1050
|
+
/** Canonical contentHash from the retired memory's frontmatter (#1579). */
|
|
1051
|
+
contentHash?: string;
|
|
1052
|
+
}): Promise<string | null>;
|
|
1053
|
+
/**
|
|
1054
|
+
* Revoke a tombstone (re-allow the content). Used by the review-queue
|
|
1055
|
+
* approval path when an operator approves a blocked memory.
|
|
1056
|
+
*/
|
|
1057
|
+
revokeTombstone(tombstoneId: string, createdBy: TombstoneCreatedBy): Promise<string | null>;
|
|
1058
|
+
/** Aggregate tombstone stats for `remnic doctor`. */
|
|
1059
|
+
getTombstoneStats(): Promise<TombstoneStats | null>;
|
|
1060
|
+
/**
|
|
1061
|
+
* Rebuild the tombstone log from retired memories on disk. Exposed for
|
|
1062
|
+
* `remnic doctor --rebuild-tombstones` and tests.
|
|
1063
|
+
*/
|
|
1064
|
+
rebuildTombstonesFromFiles(): Promise<number>;
|
|
1065
|
+
private getFactHashIndex;
|
|
1066
|
+
private ensureFactHashIndexAuthoritative;
|
|
1067
|
+
private get questionsDir();
|
|
1068
|
+
private get artifactsDir();
|
|
1069
|
+
private get identityDir();
|
|
1070
|
+
private get identityAnchorPath();
|
|
1071
|
+
private get identityIncidentsDir();
|
|
1072
|
+
private get identityAuditsWeeklyDir();
|
|
1073
|
+
private get identityAuditsMonthlyDir();
|
|
1074
|
+
private get identityImprovementLoopsPath();
|
|
1075
|
+
private get identityReflectionsPath();
|
|
1076
|
+
private get profilePath();
|
|
1077
|
+
private get memoryActionsPath();
|
|
1078
|
+
private get memoryLifecycleLedgerPath();
|
|
1079
|
+
private get compressionGuidelinesPath();
|
|
1080
|
+
private get compressionGuidelineDraftPath();
|
|
1081
|
+
private get compressionGuidelineStatePath();
|
|
1082
|
+
private get compressionGuidelineDraftStatePath();
|
|
1083
|
+
private get behaviorSignalsPath();
|
|
1084
|
+
/**
|
|
1085
|
+
* Buffer surprise telemetry ledger (issue #563 PR 3).
|
|
1086
|
+
*
|
|
1087
|
+
* Append-only JSONL of per-turn `BUFFER_SURPRISE` events emitted by
|
|
1088
|
+
* `SmartBuffer` when `bufferSurpriseTriggerEnabled` is on. Each row
|
|
1089
|
+
* captures the score, the threshold in force at the time, whether the
|
|
1090
|
+
* turn caused an extract_now upgrade, and the buffer size. Kept in
|
|
1091
|
+
* `state/` alongside the other append-only ledgers so cleanup and
|
|
1092
|
+
* governance sweeps can treat it uniformly.
|
|
1093
|
+
*/
|
|
1094
|
+
private get bufferSurpriseLedgerPath();
|
|
1095
|
+
/**
|
|
1096
|
+
* Entity alias table loaded from THIS store's config/aliases.json.
|
|
1097
|
+
* Instance-scoped on purpose (issue #1534): multiple StorageManager
|
|
1098
|
+
* instances in one process (namespaces, hosted profiles, tenants) must
|
|
1099
|
+
* never share alias state — the previous module-level table let whichever
|
|
1100
|
+
* store loaded last rewrite every other store's canonical entity ids.
|
|
1101
|
+
*/
|
|
1102
|
+
private userAliases;
|
|
1103
|
+
normalizeEntityName(raw: string, type: string): string;
|
|
1104
|
+
/**
|
|
1105
|
+
* Read-only view of this store's user alias table, for call sites that
|
|
1106
|
+
* normalize outside the manager (pass it to the free `normalizeEntityName`).
|
|
1107
|
+
*/
|
|
1108
|
+
get entityAliases(): Readonly<Record<string, string>>;
|
|
1109
|
+
/**
|
|
1110
|
+
* Reload user-defined entity aliases from config/aliases.json in the memory
|
|
1111
|
+
* store. File format: { "variant": "canonical", ... }. The constructor
|
|
1112
|
+
* already loads aliases, so this is only needed to pick up file changes
|
|
1113
|
+
* (e.g. orchestrator.initialize() re-running on a live instance).
|
|
1114
|
+
* Non-object payloads and non-string or empty alias values are ignored.
|
|
1115
|
+
*/
|
|
1116
|
+
loadAliases(): Promise<void>;
|
|
1117
|
+
private loadAliasesSync;
|
|
1118
|
+
ensureDirectories(): Promise<void>;
|
|
1119
|
+
/**
|
|
1120
|
+
* Resolve the on-disk write path for a memory of the given category, creating
|
|
1121
|
+
* the target directory. Category routing goes through the shared
|
|
1122
|
+
* `getCategoryDir()` chokepoint (utils/category-dir.ts → CATEGORY_DIR_MAP) so
|
|
1123
|
+
* decision/preference/moment/etc. outputs land in their dedicated dirs
|
|
1124
|
+
* (`decisions/`, `preferences/`, ...) instead of collapsing into `facts/`
|
|
1125
|
+
* (issue #1546; CLAUDE.md rule 39). `correction` keeps its historical flat
|
|
1126
|
+
* layout (no `<date>` subdir) as the corrections pipeline expects; every other
|
|
1127
|
+
* category — including `fact`/`entity`, which fall back to `facts/` — is dated
|
|
1128
|
+
* as `<dir>/<date>/`. Read/scan/reindex already iterate every category dir
|
|
1129
|
+
* (RECALL_FALLBACK_DIRS; QMD scans baseDir recursively), so writes stay found.
|
|
1130
|
+
*/
|
|
1131
|
+
private resolveCategoryWritePath;
|
|
1132
|
+
writeMemory(category: MemoryCategory, content: string, options?: {
|
|
1133
|
+
actor?: string;
|
|
1134
|
+
confidence?: number;
|
|
1135
|
+
tags?: string[];
|
|
1136
|
+
entityRef?: string;
|
|
1137
|
+
source?: string;
|
|
1138
|
+
supersedes?: string;
|
|
1139
|
+
lineage?: string[];
|
|
1140
|
+
importance?: ImportanceScore;
|
|
1141
|
+
links?: MemoryLink[];
|
|
1142
|
+
intentGoal?: string;
|
|
1143
|
+
intentActionType?: string;
|
|
1144
|
+
intentEntityTypes?: string[];
|
|
1145
|
+
artifactType?: MemoryFrontmatter["artifactType"];
|
|
1146
|
+
sourceMemoryId?: string;
|
|
1147
|
+
sourceTurnId?: string;
|
|
1148
|
+
memoryKind?: MemoryFrontmatter["memoryKind"];
|
|
1149
|
+
expiresAt?: string;
|
|
1150
|
+
validAt?: string;
|
|
1151
|
+
observedAt?: string;
|
|
1152
|
+
eventTimeSource?: "extracted" | "assumed";
|
|
1153
|
+
invalidAt?: string;
|
|
1154
|
+
structuredAttributes?: Record<string, string>;
|
|
1155
|
+
/**
|
|
1156
|
+
* When provided, this string is used as the source for the fact-content
|
|
1157
|
+
* dedup hash index instead of the persisted body (`content`).
|
|
1158
|
+
*
|
|
1159
|
+
* Use this when the persisted body differs from the canonical fact text
|
|
1160
|
+
* — for example when `content` is a citation-annotated variant of a raw
|
|
1161
|
+
* fact. Passing the raw fact as `contentHashSource` ensures that
|
|
1162
|
+
* `hasFactContentHash(rawFact)` returns `true` after the write, so
|
|
1163
|
+
* subsequent extractions of the same logical fact are correctly deduped
|
|
1164
|
+
* even when their citation timestamp differs.
|
|
1165
|
+
*/
|
|
1166
|
+
contentHashSource?: string;
|
|
1167
|
+
status?: MemoryStatus;
|
|
1168
|
+
/**
|
|
1169
|
+
* Consolidation provenance (issue #561 PR 2). When the caller is a
|
|
1170
|
+
* consolidation / supersession / dedup-merge path, these fields wire
|
|
1171
|
+
* the page-version snapshots the new memory was derived from and the
|
|
1172
|
+
* operator that produced it. Persisted onto frontmatter as
|
|
1173
|
+
* `derived_from` + `derived_via`; validated at serialize time.
|
|
1174
|
+
*/
|
|
1175
|
+
derivedFrom?: string[];
|
|
1176
|
+
derivedVia?: ConsolidationOperator;
|
|
1177
|
+
/**
|
|
1178
|
+
* Faithfulness gate verdict (issue #1576). When provided, persisted to
|
|
1179
|
+
* frontmatter so downstream readers (TrustScore #1577, review queue)
|
|
1180
|
+
* can consume it. Absent = gate was off or fact predates #1576.
|
|
1181
|
+
*/
|
|
1182
|
+
faithfulness?: FaithfulnessFrontmatter;
|
|
1183
|
+
/**
|
|
1184
|
+
* Claim-level provenance spans (issue #1575 PR 2). When provided,
|
|
1185
|
+
* persisted to frontmatter so downstream readers (memory_get, x-ray,
|
|
1186
|
+
* faithfulness gate #1576) can consume them. Absent = fact predates
|
|
1187
|
+
* #1575 or provenance was disabled.
|
|
1188
|
+
*/
|
|
1189
|
+
sources?: ProvenanceSource[];
|
|
1190
|
+
provenance?: "verified" | "unverified" | "none";
|
|
1191
|
+
}): Promise<MemoryWriteResult>;
|
|
1192
|
+
hasFactContentHash(content: string): Promise<boolean>;
|
|
1193
|
+
private factContentHashForRemoval;
|
|
1194
|
+
private addActiveFactContentHash;
|
|
1195
|
+
/**
|
|
1196
|
+
* Re-register a fact's contentHash in the dedup index after a tombstone
|
|
1197
|
+
* block is lifted on approval (issue #1579 thread ObnTy). `writeMemory`
|
|
1198
|
+
* skips hash-index registration for tombstone-blocked facts (rule 44); when
|
|
1199
|
+
* the review queue later promotes such a fact back to `status: active`, the
|
|
1200
|
+
* hash must enter the index or the next extraction of the same content
|
|
1201
|
+
* creates a second active fact. Reads the memory by id so the caller (the
|
|
1202
|
+
* review CLI) does not need to re-parse the file. No-op for non-facts or
|
|
1203
|
+
* facts that are not active.
|
|
1204
|
+
*/
|
|
1205
|
+
restoreFactHashAfterApproval(memoryId: string): Promise<void>;
|
|
1206
|
+
private syncFactHashIndexAfterRewrite;
|
|
1207
|
+
removeFactContentHashesForMemories(memories: MemoryFile[]): Promise<void>;
|
|
1208
|
+
isFactContentHashAuthoritative(): Promise<boolean>;
|
|
1209
|
+
writeArtifact(quote: string, options?: {
|
|
1210
|
+
actor?: string;
|
|
1211
|
+
tags?: string[];
|
|
1212
|
+
confidence?: number;
|
|
1213
|
+
artifactType?: MemoryFrontmatter["artifactType"];
|
|
1214
|
+
sourceMemoryId?: string;
|
|
1215
|
+
sourceTurnId?: string;
|
|
1216
|
+
intentGoal?: string;
|
|
1217
|
+
intentActionType?: string;
|
|
1218
|
+
intentEntityTypes?: string[];
|
|
1219
|
+
}): Promise<string>;
|
|
1220
|
+
private readAllArtifactsCached;
|
|
1221
|
+
searchArtifacts(query: string, maxResults: number): Promise<MemoryFile[]>;
|
|
1222
|
+
writeEntity(name: string, type: string, facts: string[], options?: {
|
|
1223
|
+
timestamp?: string;
|
|
1224
|
+
source?: string;
|
|
1225
|
+
sessionKey?: string;
|
|
1226
|
+
principal?: string;
|
|
1227
|
+
structuredSections?: EntityStructuredSection[];
|
|
1228
|
+
}): Promise<string>;
|
|
1229
|
+
readProfile(): Promise<string>;
|
|
1230
|
+
writeProfile(content: string): Promise<void>;
|
|
1231
|
+
/**
|
|
1232
|
+
* Normalize a string for fuzzy profile dedup: lowercase, strip punctuation, collapse whitespace.
|
|
1233
|
+
*/
|
|
1234
|
+
private static normalizeForDedup;
|
|
1235
|
+
/**
|
|
1236
|
+
* Check if a new bullet is a fuzzy duplicate of any existing bullet.
|
|
1237
|
+
* Returns true if the new bullet should be skipped.
|
|
1238
|
+
*/
|
|
1239
|
+
private static isFuzzyDuplicate;
|
|
1240
|
+
appendToProfile(updates: string[]): Promise<void>;
|
|
1241
|
+
/** Check if profile.md exceeds the max line cap and needs LLM consolidation */
|
|
1242
|
+
profileNeedsConsolidation(triggerLines?: number): Promise<boolean>;
|
|
1243
|
+
readAllMemories(): Promise<MemoryFile[]>;
|
|
1244
|
+
/** Invalidate the readAllMemories() cache after writes that add/remove memories. */
|
|
1245
|
+
/** Public cache invalidation for callers that need authoritative disk reads
|
|
1246
|
+
* (e.g. projection verify/rebuild). */
|
|
1247
|
+
invalidateAllMemoriesCacheForDir(): void;
|
|
1248
|
+
/** Invalidate only the cache layers affected by direct tier file deletes. */
|
|
1249
|
+
invalidateMemoryCachesForTiers(tiers: Iterable<"hot" | "cold" | "archive">): void;
|
|
1250
|
+
/** Clear ALL static caches. Use in tests that write files directly
|
|
1251
|
+
* (bypassing StorageManager.writeMemory) to avoid stale reads. */
|
|
1252
|
+
static clearAllStaticCaches(): void;
|
|
1253
|
+
/** Cancel any in-flight concurrent read so the next readAllMemories()
|
|
1254
|
+
* starts a fresh disk scan and sees the just-written data.
|
|
1255
|
+
*
|
|
1256
|
+
* Finding UvBq (PR #402 round-11): this method intentionally does NOT
|
|
1257
|
+
* invalidate the cold-scan cache. Ordinary hot-tier writes (writeMemory)
|
|
1258
|
+
* do not change cold-tier content, so evicting the cold cache on every hot
|
|
1259
|
+
* write was defeating the burst-dedup optimisation — the cold cache was
|
|
1260
|
+
* cleared before applyTemporalSupersession ran, causing a full cold-tree
|
|
1261
|
+
* disk scan on every write in a burst. Cold cache invalidation is handled
|
|
1262
|
+
* exclusively by invalidateColdMemoriesCache(), which is called only when
|
|
1263
|
+
* cold content actually changes (hot→cold demotions, writeMemoryFileAtomic
|
|
1264
|
+
* inside cold/, archiveMemory, etc.). */
|
|
1265
|
+
private invalidateAllMemoriesCache;
|
|
1266
|
+
/**
|
|
1267
|
+
* Invalidate the cold-scan cache for this storage root and bump the
|
|
1268
|
+
* on-disk cold-version sentinel so that other processes (gateway, CLI) see
|
|
1269
|
+
* the change immediately on their next readAllColdMemories() call.
|
|
1270
|
+
*
|
|
1271
|
+
* Must be called whenever a memory is written INTO the cold tier — hot→cold
|
|
1272
|
+
* demotion, atomic writes inside cold/, archiving a cold memory, etc.
|
|
1273
|
+
* NOT called on ordinary hot-tier writes (those don't change cold contents).
|
|
1274
|
+
*
|
|
1275
|
+
* Finding UvUy (PR #402 round-11): bumping the sentinel here makes the
|
|
1276
|
+
* per-process in-memory cache safe across process boundaries.
|
|
1277
|
+
*/
|
|
1278
|
+
private invalidateColdMemoriesCache;
|
|
1279
|
+
/** Return the current cold-write version counter for this storage root.
|
|
1280
|
+
* Reads the on-disk sentinel (state/cold-write.log) so it reflects writes
|
|
1281
|
+
* made by other processes. */
|
|
1282
|
+
private readColdWriteVersion;
|
|
1283
|
+
/** Bump the on-disk cold-write version sentinel and update the in-process
|
|
1284
|
+
* fallback map. Called by invalidateColdMemoriesCache(). */
|
|
1285
|
+
private bumpColdWriteVersion;
|
|
1286
|
+
private normalizeMemoryReadBatchSize;
|
|
1287
|
+
private collectActiveMemoryPaths;
|
|
1288
|
+
private readParsedMemoriesFromPaths;
|
|
1289
|
+
private readWindowUpdatedMs;
|
|
1290
|
+
private filterWindowPathsByUpdatedAfter;
|
|
1291
|
+
private orderWindowPaths;
|
|
1292
|
+
private readWindowBoundedBatch;
|
|
1293
|
+
readMemoriesWindow(options?: {
|
|
1294
|
+
maxMemories?: number;
|
|
1295
|
+
batchSize?: number;
|
|
1296
|
+
updatedAfter?: Date;
|
|
1297
|
+
}): Promise<{
|
|
1298
|
+
memories: MemoryFile[];
|
|
1299
|
+
filePaths: string[];
|
|
1300
|
+
}>;
|
|
1301
|
+
private _readAllMemoriesFromDisk;
|
|
1302
|
+
readAllColdMemories(): Promise<MemoryFile[]>;
|
|
1303
|
+
/**
|
|
1304
|
+
* Read archived memory markdown files under archive/.
|
|
1305
|
+
* Used by long-term recall fallback when hot recall has no hits.
|
|
1306
|
+
*/
|
|
1307
|
+
readArchivedMemories(): Promise<MemoryFile[]>;
|
|
1308
|
+
readMemoryByPath(filePath: string): Promise<MemoryFile | null>;
|
|
1309
|
+
private resolveTierRootDir;
|
|
1310
|
+
private resolveMemoryDateDir;
|
|
1311
|
+
private isArtifactMemory;
|
|
1312
|
+
buildTierMemoryPath(memory: MemoryFile, tier: "hot" | "cold"): string;
|
|
1313
|
+
private writeMemoryFileAtomic;
|
|
1314
|
+
moveMemoryToPath(memory: MemoryFile, targetPath: string): Promise<void>;
|
|
1315
|
+
migrateMemoryToTier(memory: MemoryFile, targetTier: "hot" | "cold"): Promise<{
|
|
1316
|
+
changed: boolean;
|
|
1317
|
+
targetPath: string;
|
|
1318
|
+
}>;
|
|
1319
|
+
private get archiveDir();
|
|
1320
|
+
/**
|
|
1321
|
+
* Archive a memory by moving it from facts/ to archive/YYYY-MM-DD/.
|
|
1322
|
+
* Updates frontmatter with archived status before moving.
|
|
1323
|
+
* Returns the new file path on success, null on failure.
|
|
1324
|
+
*/
|
|
1325
|
+
archiveMemory(memory: MemoryFile, lifecycle?: MemoryLifecycleEventWriteOptions): Promise<string | null>;
|
|
1326
|
+
readEntities(): Promise<string[]>;
|
|
1327
|
+
readEntity(name: string): Promise<string>;
|
|
1328
|
+
listEntityNames(): Promise<string[]>;
|
|
1329
|
+
/**
|
|
1330
|
+
* Find an existing entity that fuzzy-matches the proposed name.
|
|
1331
|
+
* Returns the existing entity filename (without .md) or null if no match.
|
|
1332
|
+
*
|
|
1333
|
+
* Matching priority:
|
|
1334
|
+
* 1. Exact normalized match (handled by normalizeEntityName already)
|
|
1335
|
+
* 2. Dehyphenated match: "jane-doe" vs "janedoe"
|
|
1336
|
+
* 3. Substring containment: "handle-janedoe" contains "janedoe"
|
|
1337
|
+
* 4. Levenshtein ≤ 2 on dehyphenated names
|
|
1338
|
+
*/
|
|
1339
|
+
findMatchingEntity(proposedName: string, type: string): Promise<string | null>;
|
|
1340
|
+
invalidateMemory(id: string): Promise<boolean>;
|
|
1341
|
+
updateMemory(id: string, newContent: string, options?: {
|
|
1342
|
+
supersedes?: string;
|
|
1343
|
+
lineage?: string[];
|
|
1344
|
+
actor?: string;
|
|
1345
|
+
}): Promise<boolean>;
|
|
1346
|
+
/**
|
|
1347
|
+
* Update frontmatter fields without changing memory content.
|
|
1348
|
+
* Returns false when the memory is not found.
|
|
1349
|
+
*/
|
|
1350
|
+
writeMemoryFrontmatter(memory: MemoryFile, patch: Partial<MemoryFrontmatter>, lifecycle?: MemoryLifecycleEventWriteOptions): Promise<boolean>;
|
|
1351
|
+
/**
|
|
1352
|
+
* Update frontmatter by memory ID.
|
|
1353
|
+
* Prefer writeMemoryFrontmatter(memory, patch) in batch loops to avoid full-corpus rescans.
|
|
1354
|
+
*/
|
|
1355
|
+
updateMemoryFrontmatter(id: string, patch: Partial<MemoryFrontmatter>): Promise<boolean>;
|
|
1356
|
+
/** Remove memories past their TTL expiresAt date */
|
|
1357
|
+
cleanExpiredTTL(): Promise<MemoryFile[]>;
|
|
1358
|
+
loadBuffer(): Promise<BufferState>;
|
|
1359
|
+
saveBuffer(state: BufferState): Promise<void>;
|
|
1360
|
+
loadMeta(): Promise<MetaState>;
|
|
1361
|
+
saveMeta(state: MetaState): Promise<void>;
|
|
1362
|
+
appendMemoryActionEvents(events: MemoryActionEvent[]): Promise<number>;
|
|
1363
|
+
appendMemoryLifecycleEvents(events: MemoryLifecycleEvent[]): Promise<number>;
|
|
1364
|
+
appendBufferSurpriseEvents(events: BufferSurpriseEvent[]): Promise<number>;
|
|
1365
|
+
readBufferSurpriseEvents(options?: {
|
|
1366
|
+
limit?: number;
|
|
1367
|
+
}): Promise<BufferSurpriseEvent[]>;
|
|
1368
|
+
appendBehaviorSignals(events: BehaviorSignalEvent[]): Promise<number>;
|
|
1369
|
+
appendReextractJobs(events: ReextractJobRequest[]): Promise<number>;
|
|
1370
|
+
readReextractJobs(limit?: number): Promise<ReextractJobRequest[]>;
|
|
1371
|
+
readBehaviorSignals(limit?: number): Promise<BehaviorSignalEvent[]>;
|
|
1372
|
+
readMemoryActionEvents(limit?: number): Promise<MemoryActionEvent[]>;
|
|
1373
|
+
readMemoryActionEventRows(limit?: number): Promise<Array<{
|
|
1374
|
+
line: number;
|
|
1375
|
+
event: MemoryActionEvent;
|
|
1376
|
+
}>>;
|
|
1377
|
+
readAllMemoryLifecycleEvents(): Promise<MemoryLifecycleEvent[]>;
|
|
1378
|
+
readMemoryLifecycleEvents(limit?: number): Promise<MemoryLifecycleEvent[]>;
|
|
1379
|
+
writeCompressionGuidelines(content: string): Promise<void>;
|
|
1380
|
+
readCompressionGuidelines(): Promise<string | null>;
|
|
1381
|
+
writeCompressionGuidelineDraft(content: string): Promise<void>;
|
|
1382
|
+
readCompressionGuidelineDraft(): Promise<string | null>;
|
|
1383
|
+
writeCompressionGuidelineOptimizerState(state: CompressionGuidelineOptimizerState): Promise<void>;
|
|
1384
|
+
writeCompressionGuidelineDraftState(state: CompressionGuidelineOptimizerState): Promise<void>;
|
|
1385
|
+
readCompressionGuidelineOptimizerState(): Promise<CompressionGuidelineOptimizerState | null>;
|
|
1386
|
+
readCompressionGuidelineDraftState(): Promise<CompressionGuidelineOptimizerState | null>;
|
|
1387
|
+
activateCompressionGuidelineDraft(options?: {
|
|
1388
|
+
expectedContentHash?: string;
|
|
1389
|
+
expectedGuidelineVersion?: number;
|
|
1390
|
+
}): Promise<boolean>;
|
|
1391
|
+
private readCompressionGuidelineStateFile;
|
|
1392
|
+
writeIdentityAnchor(content: string): Promise<void>;
|
|
1393
|
+
readIdentityAnchor(): Promise<string | null>;
|
|
1394
|
+
appendContinuityIncident(input: ContinuityIncidentOpenInput): Promise<ContinuityIncidentRecord>;
|
|
1395
|
+
readContinuityIncidents(limit?: number, state?: "open" | "closed" | "all"): Promise<ContinuityIncidentRecord[]>;
|
|
1396
|
+
closeContinuityIncident(id: string, closure: ContinuityIncidentCloseInput): Promise<ContinuityIncidentRecord | null>;
|
|
1397
|
+
writeIdentityAudit(period: "weekly" | "monthly", key: string, content: string): Promise<string>;
|
|
1398
|
+
readIdentityAudit(period: "weekly" | "monthly", key: string): Promise<string | null>;
|
|
1399
|
+
writeIdentityImprovementLoops(content: string): Promise<void>;
|
|
1400
|
+
readIdentityImprovementLoops(): Promise<string | null>;
|
|
1401
|
+
readIdentityImprovementLoopRegister(): Promise<ContinuityImprovementLoop[]>;
|
|
1402
|
+
upsertIdentityImprovementLoop(input: ContinuityLoopUpsertInput): Promise<ContinuityImprovementLoop>;
|
|
1403
|
+
reviewIdentityImprovementLoop(id: string, input: ContinuityLoopReviewInput): Promise<ContinuityImprovementLoop | null>;
|
|
1404
|
+
private generateId;
|
|
1405
|
+
writeQuestion(question: string, context: string, priority: number): Promise<string>;
|
|
1406
|
+
readQuestions(opts?: {
|
|
1407
|
+
unresolvedOnly?: boolean;
|
|
1408
|
+
}): Promise<Array<{
|
|
1409
|
+
id: string;
|
|
1410
|
+
question: string;
|
|
1411
|
+
context: string;
|
|
1412
|
+
priority: number;
|
|
1413
|
+
resolved: boolean;
|
|
1414
|
+
created: string;
|
|
1415
|
+
filePath: string;
|
|
1416
|
+
}>>;
|
|
1417
|
+
/** Invalidate the questions cache (call after writing a question). */
|
|
1418
|
+
invalidateQuestionsCache(): void;
|
|
1419
|
+
private parseQuestionFile;
|
|
1420
|
+
private extractFrontmatterValue;
|
|
1421
|
+
resolveQuestion(id: string): Promise<boolean>;
|
|
1422
|
+
readIdentity(workspaceDir: string, namespace?: string): Promise<string>;
|
|
1423
|
+
writeIdentity(workspaceDir: string, content: string, namespace?: string): Promise<void>;
|
|
1424
|
+
/** Max size for IDENTITY.md before we stop appending reflections (15KB leaves room under 20KB gateway limit) */
|
|
1425
|
+
private static readonly IDENTITY_MAX_BYTES;
|
|
1426
|
+
/** Minimum interval between reflections (1 hour) */
|
|
1427
|
+
private static readonly REFLECTION_COOLDOWN_MS;
|
|
1428
|
+
appendToIdentity(workspaceDir: string, reflection: string, opts?: {
|
|
1429
|
+
hygiene?: FileHygieneConfig;
|
|
1430
|
+
namespace?: string;
|
|
1431
|
+
}): Promise<void>;
|
|
1432
|
+
readIdentityReflections(): Promise<string | null>;
|
|
1433
|
+
writeIdentityReflections(content: string): Promise<void>;
|
|
1434
|
+
appendIdentityReflection(reflection: string): Promise<void>;
|
|
1435
|
+
/**
|
|
1436
|
+
* Add a relationship to an entity file.
|
|
1437
|
+
* Deduplicates by target+label.
|
|
1438
|
+
*/
|
|
1439
|
+
addEntityRelationship(name: string, rel: EntityRelationship): Promise<void>;
|
|
1440
|
+
/**
|
|
1441
|
+
* Add an activity entry to an entity file.
|
|
1442
|
+
* Prepends to the beginning, prunes oldest entries beyond maxEntries.
|
|
1443
|
+
*/
|
|
1444
|
+
addEntityActivity(name: string, entry: EntityActivityEntry, maxEntries: number): Promise<void>;
|
|
1445
|
+
/**
|
|
1446
|
+
* Add an alias to an entity file. Deduplicates.
|
|
1447
|
+
*/
|
|
1448
|
+
addEntityAlias(name: string, alias: string): Promise<void>;
|
|
1449
|
+
updateEntitySynthesis(name: string, synthesis: string, options?: {
|
|
1450
|
+
entityUpdatedAt?: string;
|
|
1451
|
+
synthesisStructuredFactCount?: number;
|
|
1452
|
+
synthesisStructuredFactDigest?: string;
|
|
1453
|
+
synthesisTimelineCount?: number;
|
|
1454
|
+
updatedAt?: string;
|
|
1455
|
+
incrementVersion?: boolean;
|
|
1456
|
+
}): Promise<void>;
|
|
1457
|
+
/**
|
|
1458
|
+
* Backward-compatible alias for legacy callers/tests.
|
|
1459
|
+
*/
|
|
1460
|
+
updateEntitySummary(name: string, summary: string): Promise<void>;
|
|
1461
|
+
readEntitySynthesisQueue(): Promise<string[]>;
|
|
1462
|
+
refreshEntitySynthesisQueue(): Promise<string[]>;
|
|
1463
|
+
removeEntitySynthesisQueueEntries(entityNames: string[]): Promise<void>;
|
|
1464
|
+
migrateEntityFilesToCompiledTruthTimeline(): Promise<{
|
|
1465
|
+
total: number;
|
|
1466
|
+
migrated: number;
|
|
1467
|
+
}>;
|
|
1468
|
+
readAllEntityFiles(): Promise<EntityFile[]>;
|
|
1469
|
+
/**
|
|
1470
|
+
* Score an entity based on recency, frequency, activity, type priority,
|
|
1471
|
+
* and relationship density.
|
|
1472
|
+
*
|
|
1473
|
+
* score = recency*0.40 + frequency*0.25 + activity*0.15 + typePriority*0.10 + relationshipDensity*0.10
|
|
1474
|
+
*/
|
|
1475
|
+
static scoreEntity(entity: EntityFile, now: Date): number;
|
|
1476
|
+
buildKnowledgeIndex(config: PluginConfig, overrides?: {
|
|
1477
|
+
maxEntities?: number;
|
|
1478
|
+
maxChars?: number;
|
|
1479
|
+
}): Promise<{
|
|
1480
|
+
result: string;
|
|
1481
|
+
cached: boolean;
|
|
1482
|
+
}>;
|
|
1483
|
+
/** Invalidate the Knowledge Index cache (call after entity mutations). */
|
|
1484
|
+
invalidateKnowledgeIndexCache(): void;
|
|
1485
|
+
/** Max lines for profile.md before LLM consolidation triggers */
|
|
1486
|
+
private static readonly PROFILE_MAX_LINES;
|
|
1487
|
+
mergeFragmentedEntities(): Promise<number>;
|
|
1488
|
+
cleanExpiredCommitments(decayDays: number): Promise<MemoryFile[]>;
|
|
1489
|
+
/**
|
|
1490
|
+
* Flush batched access tracking updates to disk.
|
|
1491
|
+
* Called during consolidation or when buffer exceeds max size.
|
|
1492
|
+
*/
|
|
1493
|
+
flushAccessTracking(entries: AccessTrackingEntry[]): Promise<number>;
|
|
1494
|
+
/**
|
|
1495
|
+
* Get a memory by its ID.
|
|
1496
|
+
*/
|
|
1497
|
+
getMemoryById(id: string): Promise<MemoryFile | null>;
|
|
1498
|
+
/**
|
|
1499
|
+
* Check which of the given memory IDs actually exist on disk.
|
|
1500
|
+
*
|
|
1501
|
+
* Uses a lightweight directory scan (collectActiveMemoryPaths) that reads
|
|
1502
|
+
* file names without parsing frontmatter — much cheaper than readAllMemories()
|
|
1503
|
+
* for simple existence checks like citation usage tracking.
|
|
1504
|
+
*
|
|
1505
|
+
* Returns the subset of `ids` that correspond to real memory files.
|
|
1506
|
+
*/
|
|
1507
|
+
filterExistingMemoryIds(ids: string[]): Promise<Set<string>>;
|
|
1508
|
+
getProjectedMemoryState(id: string): Promise<MemoryProjectionCurrentState | null>;
|
|
1509
|
+
browseProjectedMemories(options: ProjectedMemoryBrowseOptions): Promise<ProjectedMemoryBrowsePage | null>;
|
|
1510
|
+
getProjectedGovernanceRecord(): Promise<ReturnType<typeof readProjectedGovernanceRecord>>;
|
|
1511
|
+
private toProjectedCurrentState;
|
|
1512
|
+
getMemoryTimeline(memoryId: string, limit?: number): Promise<MemoryLifecycleEvent[]>;
|
|
1513
|
+
/**
|
|
1514
|
+
* Write a memory chunk with parent reference.
|
|
1515
|
+
* Chunk IDs follow format: {parentId}-chunk-{index}
|
|
1516
|
+
*/
|
|
1517
|
+
writeChunk(parentId: string, chunkIndex: number, chunkTotal: number, category: MemoryCategory, content: string, options?: {
|
|
1518
|
+
confidence?: number;
|
|
1519
|
+
tags?: string[];
|
|
1520
|
+
entityRef?: string;
|
|
1521
|
+
source?: string;
|
|
1522
|
+
importance?: ImportanceScore;
|
|
1523
|
+
intentGoal?: string;
|
|
1524
|
+
intentActionType?: string;
|
|
1525
|
+
intentEntityTypes?: string[];
|
|
1526
|
+
memoryKind?: MemoryFrontmatter["memoryKind"];
|
|
1527
|
+
validAt?: string;
|
|
1528
|
+
/** Lifecycle status (issue #1576): pending_review chunks stay out of active recall. */
|
|
1529
|
+
status?: MemoryStatus;
|
|
1530
|
+
/**
|
|
1531
|
+
* Tombstone block provenance (issue #1645): when the parent fact was
|
|
1532
|
+
* tombstone-blocked, propagate the tombstone id onto each chunk so an
|
|
1533
|
+
* independently-surfaced chunk (memory_get/x-ray/doctor) reveals the block
|
|
1534
|
+
* and the chunk stays pending_review, never an active resurrection.
|
|
1535
|
+
*/
|
|
1536
|
+
blockedBy?: string;
|
|
1537
|
+
/** Faithfulness gate verdict (issue #1576), propagated from the parent fact. */
|
|
1538
|
+
faithfulness?: FaithfulnessFrontmatter;
|
|
1539
|
+
/** Claim-level provenance spans (issue #1575 PR 2), propagated from the parent fact so a chunk surfaced independently (memory_get/x-ray) preserves them (chatgpt-codex-connector thread Ocvmo). */
|
|
1540
|
+
sources?: ProvenanceSource[];
|
|
1541
|
+
/** Coarse provenance tag (issue #1575 PR 2), propagated from the parent. */
|
|
1542
|
+
provenance?: "verified" | "unverified" | "none";
|
|
1543
|
+
invalidAt?: string;
|
|
1544
|
+
observedAt?: string;
|
|
1545
|
+
eventTimeSource?: "extracted" | "assumed";
|
|
1546
|
+
}): Promise<string>;
|
|
1547
|
+
/**
|
|
1548
|
+
* Get all chunks for a given parent memory ID.
|
|
1549
|
+
* Returns chunks sorted by chunkIndex.
|
|
1550
|
+
*/
|
|
1551
|
+
getChunksForParent(parentId: string): Promise<MemoryFile[]>;
|
|
1552
|
+
/**
|
|
1553
|
+
* Mark a memory as superseded by another.
|
|
1554
|
+
* Updates the old memory's status and adds the supersededBy link.
|
|
1555
|
+
*/
|
|
1556
|
+
supersedeMemory(oldMemoryId: string, newMemoryId: string, reason: string): Promise<boolean>;
|
|
1557
|
+
private get summariesDir();
|
|
1558
|
+
/**
|
|
1559
|
+
* Write a memory summary.
|
|
1560
|
+
*/
|
|
1561
|
+
writeSummary(summary: MemorySummary): Promise<void>;
|
|
1562
|
+
/**
|
|
1563
|
+
* Get all summaries.
|
|
1564
|
+
*/
|
|
1565
|
+
readSummaries(): Promise<MemorySummary[]>;
|
|
1566
|
+
/**
|
|
1567
|
+
* Archive memories (mark as archived, not delete).
|
|
1568
|
+
*/
|
|
1569
|
+
archiveMemories(memoryIds: string[], summaryId: string): Promise<number>;
|
|
1570
|
+
/**
|
|
1571
|
+
* Save topic scores to meta.json.
|
|
1572
|
+
*/
|
|
1573
|
+
saveTopics(topics: TopicScore[]): Promise<void>;
|
|
1574
|
+
/**
|
|
1575
|
+
* Load topic scores from meta.json.
|
|
1576
|
+
*/
|
|
1577
|
+
loadTopics(): Promise<{
|
|
1578
|
+
topics: TopicScore[];
|
|
1579
|
+
updatedAt: string | null;
|
|
1580
|
+
}>;
|
|
1581
|
+
/**
|
|
1582
|
+
* Add links to an existing memory.
|
|
1583
|
+
*/
|
|
1584
|
+
addLinksToMemory(memoryId: string, links: MemoryLink[], lifecycle?: MemoryLifecycleEventWriteOptions): Promise<boolean>;
|
|
1585
|
+
private summarizeLifecycleState;
|
|
1586
|
+
private frontmatterPatchEventType;
|
|
1587
|
+
private appendGeneratedMemoryLifecycleEvent;
|
|
1588
|
+
private appendGeneratedMemoryLifecycleEventFailOpen;
|
|
1589
|
+
}
|
|
1590
|
+
|
|
1591
|
+
export { countEntityStructuredFacts as A, fingerprintEntityStructuredFacts as B, ContentHashIndex as C, type DisagreementKind as D, isEntitySynthesisStale as E, FusionArtifactStore as F, isValidBufferSurpriseEvent as G, normalizeEntityName as H, normalizeFrontmatterForPath as I, normalizeStructuredSectionFacts as J, parseFrontmatter as K, parseFrontmatterStringValue as L, type MemoryWriteResult as M, type ReextractJobRequest as R, StorageManager as S, type FusedWearableConversation as a, type FusionConversationInput as b, type FusedSpeaker as c, type FusedSegment as d, type FusedDisagreement as e, type FusionOptions as f, type FusionDayResult as g, FUSION_KIND as h, type FusedContribution as i, type FusedConversationProvenance as j, type FusedDayFile as k, type FusedDayMeta as l, type FusedSegmentProvenance as m, type FusionSegmentInput as n, type SegmentPickReason as o, composeFusionDayMeta as p, hashFusionBody as q, normalizeAttributePairs as r, parseEntityFile as s, parseFusionDay as t, serializeEntityFile as u, serializeFusionDay as v, type MemoryLifecycleEventWriteOptions as w, buildEntitySchemaCacheKey as x, compareEntityTimestamps as y, compileEntityFacts as z };
|