@remnic/core 9.30.0 → 9.31.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 +10 -10
- package/dist/access-admin-ops-surface.js +50 -44
- package/dist/access-authorization-probe.d.ts +10 -10
- package/dist/access-authorization-probe.js +51 -45
- package/dist/access-boundary.d.ts +13 -11
- package/dist/access-boundary.js +50 -44
- package/dist/access-cli.js +168 -123
- package/dist/access-cli.js.map +1 -1
- package/dist/access-extraction-force-flush.d.ts +119 -0
- package/dist/access-extraction-force-flush.js +166 -0
- package/dist/access-health-types.d.ts +1 -1
- package/dist/access-http-lcm-compaction.d.ts +47 -13
- package/dist/access-http-lcm-compaction.js +7 -3
- package/dist/access-http-lifecycle-flush.d.ts +132 -0
- package/dist/access-http-lifecycle-flush.js +9 -0
- package/dist/access-http-lifecycle-flush.js.map +1 -0
- package/dist/access-http.d.ts +11 -10
- package/dist/access-http.js +66 -59
- package/dist/access-identity-continuity-surface.d.ts +8 -8
- package/dist/access-identity-continuity-surface.js +50 -44
- package/dist/access-lcm-surface.d.ts +10 -10
- package/dist/access-lcm-surface.js +50 -44
- package/dist/access-mcp-output-schemas.js +1 -1
- package/dist/access-mcp.d.ts +16 -10
- package/dist/access-mcp.js +58 -52
- package/dist/access-memory-search-fanout.d.ts +2 -2
- package/dist/{access-namespace-preflight-VfXssvoI.d.ts → access-namespace-preflight-D4vW97H1.d.ts} +1 -1
- package/dist/access-namespace-preflight.d.ts +3 -3
- package/dist/access-namespace-preflight.js +50 -44
- package/dist/access-observe-helpers.d.ts +22 -0
- package/dist/access-observe-helpers.js +10 -0
- package/dist/access-observe-helpers.js.map +1 -0
- package/dist/access-observe-write-surface.d.ts +51 -47
- package/dist/access-observe-write-surface.js +50 -44
- package/dist/access-operations-batch.js +53 -47
- package/dist/access-operations.d.ts +11 -11
- package/dist/access-operations.js +55 -49
- package/dist/access-recall-concurrency.d.ts +10 -10
- package/dist/access-recall-concurrency.js +50 -44
- package/dist/access-recall-response.d.ts +10 -10
- package/dist/access-recall-response.js +50 -44
- package/dist/access-recall-surface.d.ts +10 -10
- package/dist/access-recall-surface.js +50 -44
- package/dist/access-schema.d.ts +37 -7
- package/dist/access-schema.js +5 -3
- package/dist/{access-service-B5RwVsTV.d.ts → access-service-B6PZ_xUL.d.ts} +44 -20
- package/dist/access-service-helpers.d.ts +113 -0
- package/dist/access-service-helpers.js +8 -0
- package/dist/access-service-helpers.js.map +1 -0
- package/dist/access-service.d.ts +10 -10
- package/dist/access-service.js +50 -44
- package/dist/access-surface-catalog.d.ts +10 -10
- package/dist/access-surface-catalog.js +2 -0
- package/dist/access-surface-catalog.js.map +1 -1
- package/dist/access-wearables-meetings-surface.d.ts +3 -3
- 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 +1 -1
- package/dist/adapters/index.js +7 -7
- package/dist/adapters/registry.js +3 -3
- package/dist/behavior-learner.d.ts +1 -1
- package/dist/behavior-signals.d.ts +1 -1
- package/dist/bootstrap.d.ts +8 -8
- package/dist/briefing.d.ts +2 -2
- package/dist/briefing.js +14 -14
- package/dist/buffer-surprise-report.d.ts +1 -1
- package/dist/buffer-turn-helpers.d.ts +5 -0
- package/dist/buffer-turn-helpers.js +24 -0
- package/dist/buffer-turn-helpers.js.map +1 -0
- package/dist/buffer.d.ts +17 -4
- package/dist/buffer.js +21 -1
- package/dist/bulk-import/index.d.ts +3 -3
- package/dist/calibration.d.ts +1 -1
- package/dist/capabilities.d.ts +1 -1
- package/dist/{capsule-crypto-GWVG7LGC.js → capsule-crypto-7FJQINUR.js} +2 -2
- package/dist/capsule-crypto-7FJQINUR.js.map +1 -0
- package/dist/{capsule-merge-5KKJQBWQ.js → capsule-merge-2H2IUTBT.js} +4 -4
- package/dist/{catalog-V7inUQdp.d.ts → catalog-CGFYmTT8.d.ts} +1 -1
- package/dist/causal-behavior.d.ts +1 -1
- package/dist/causal-behavior.js +2 -2
- package/dist/causal-chain.js +2 -2
- package/dist/causal-consolidation.d.ts +1 -1
- package/dist/causal-consolidation.js +19 -19
- package/dist/causal-retrieval.js +2 -2
- package/dist/causal-trajectory-graph.d.ts +1 -1
- package/dist/causal-trajectory.js +1 -1
- package/dist/{chunk-LEPOP46W.js → chunk-227UFSEQ.js} +4 -4
- package/dist/{chunk-GIBMDSJ2.js → chunk-27P5YVDU.js} +2 -2
- package/dist/{chunk-2SA56WMI.js → chunk-2LTDWSR6.js} +4 -4
- package/dist/{chunk-OWHERGF2.js → chunk-2NLLXCJG.js} +2 -2
- package/dist/{chunk-YTSNAUXN.js → chunk-3F2LKUMU.js} +22 -8
- package/dist/chunk-3F2LKUMU.js.map +1 -0
- package/dist/chunk-3QL24R5Y.js +9 -0
- package/dist/chunk-3QL24R5Y.js.map +1 -0
- package/dist/chunk-4RNZMRAV.js +60 -0
- package/dist/chunk-4RNZMRAV.js.map +1 -0
- package/dist/{chunk-6U7F52DE.js → chunk-4XHR3I67.js} +60 -60
- package/dist/chunk-5IVLTFOV.js +65 -0
- package/dist/chunk-5IVLTFOV.js.map +1 -0
- package/dist/{chunk-2EUVEDF5.js → chunk-5XA7PQ5I.js} +2 -2
- package/dist/{chunk-ALSGMEJR.js → chunk-65ZPVYTA.js} +7 -7
- package/dist/{chunk-5VQJBH2G.js → chunk-6TAUHL33.js} +2 -2
- package/dist/{chunk-HUHX2OCX.js → chunk-7DRETLP5.js} +1 -1
- package/dist/chunk-7DRETLP5.js.map +1 -0
- package/dist/{chunk-RGIWINDN.js → chunk-7G5MH4NT.js} +30 -30
- package/dist/{chunk-WVO4G37W.js → chunk-7TEZUUGM.js} +3 -3
- package/dist/{chunk-MJCGLM25.js → chunk-7VUAG236.js} +5 -5
- package/dist/{chunk-M3C2V3PV.js → chunk-AJEMDQNA.js} +12 -12
- package/dist/{chunk-RKNJBZ55.js → chunk-AU7Q3LSC.js} +7 -7
- package/dist/{chunk-ACXPX4AG.js → chunk-BR2K43MK.js} +2 -2
- package/dist/{chunk-IYZ5K7MU.js → chunk-BUE5E2HL.js} +4 -187
- package/dist/chunk-BUE5E2HL.js.map +1 -0
- package/dist/{chunk-CZRYLSSW.js → chunk-BUGVGH4N.js} +2 -2
- package/dist/{chunk-YTQNQ4KB.js → chunk-C4VQMFVM.js} +3 -3
- package/dist/{chunk-ZPSVBSOF.js → chunk-CIVDJD6P.js} +3 -3
- package/dist/{chunk-K5GB36ME.js → chunk-CZDOT5I2.js} +2 -2
- package/dist/{chunk-VI2JQPNQ.js → chunk-E4PWACUN.js} +2 -2
- package/dist/{chunk-D2ANTDGO.js → chunk-E6BMSH7U.js} +2 -2
- package/dist/{chunk-P5PXWTW7.js → chunk-EJCAV3QZ.js} +3 -3
- package/dist/{chunk-CKMO4RDY.js → chunk-EMDLM3LW.js} +4 -4
- package/dist/chunk-ER7W6H4T.js +112 -0
- package/dist/chunk-ER7W6H4T.js.map +1 -0
- package/dist/{chunk-6FUPCJUL.js → chunk-FI4F5X2V.js} +54 -54
- package/dist/chunk-FI4F5X2V.js.map +1 -0
- package/dist/{chunk-LGHKJABJ.js → chunk-GOUILH55.js} +40 -18
- package/dist/chunk-GOUILH55.js.map +1 -0
- package/dist/{chunk-G5R3D5UP.js → chunk-GTTAHHD3.js} +2 -2
- package/dist/{chunk-H5CPS5JP.js → chunk-H36LJIPD.js} +3 -3
- package/dist/{chunk-AITCS2RC.js → chunk-IJ7HK452.js} +4 -4
- package/dist/{chunk-D3LMYTBV.js → chunk-J7WZUL2K.js} +9 -9
- package/dist/{chunk-5W4ZLBEZ.js → chunk-JCFTIQBR.js} +2 -2
- package/dist/{chunk-XOZ4ALGB.js → chunk-KE353EWI.js} +3 -3
- package/dist/{chunk-W5EG6LE3.js → chunk-KIT6M7EB.js} +3 -3
- package/dist/{chunk-5W7CTZ2E.js → chunk-KQAFEZQX.js} +4 -4
- package/dist/{chunk-Z54EM5YZ.js → chunk-MAXVH44E.js} +7 -7
- package/dist/{chunk-WZFAPHIK.js → chunk-MU7ZHSZE.js} +2 -2
- package/dist/chunk-N5Z4EVOR.js +123 -0
- package/dist/chunk-N5Z4EVOR.js.map +1 -0
- package/dist/{chunk-66772WBP.js → chunk-NFXQJHJD.js} +5 -5
- package/dist/{chunk-AZ5BTEKX.js → chunk-NQUF7XKR.js} +2 -2
- package/dist/{chunk-W4FBGYGK.js → chunk-NRV4Y3PM.js} +1 -1
- package/dist/{chunk-NHWB6HG2.js → chunk-NYCGIQRA.js} +2 -2
- package/dist/{chunk-4WKA6I65.js → chunk-OGCNZPKX.js} +1119 -309
- package/dist/chunk-OGCNZPKX.js.map +1 -0
- package/dist/{chunk-QJAQNXWI.js → chunk-ONHRRJZM.js} +6 -6
- package/dist/{chunk-FDAMS4PK.js → chunk-PNPOWBGC.js} +2 -2
- package/dist/{chunk-IC6CBHCA.js → chunk-QGENAYVS.js} +2 -2
- package/dist/{chunk-GBJ4RDFR.js → chunk-QIHIHZYC.js} +66 -91
- package/dist/chunk-QIHIHZYC.js.map +1 -0
- package/dist/{chunk-PUS63Q3G.js → chunk-RUYJ7TWU.js} +517 -2011
- package/dist/chunk-RUYJ7TWU.js.map +1 -0
- package/dist/{chunk-4A6YGWQN.js → chunk-TL4TO3EA.js} +115 -120
- package/dist/chunk-TL4TO3EA.js.map +1 -0
- package/dist/{chunk-SPJXKAVF.js → chunk-U52AKICI.js} +14 -13
- package/dist/chunk-U52AKICI.js.map +1 -0
- package/dist/chunk-ULARSG5Z.js +203 -0
- package/dist/chunk-ULARSG5Z.js.map +1 -0
- package/dist/{chunk-62U4J2GN.js → chunk-UR77VKF7.js} +2 -2
- package/dist/{chunk-JCBWCYEJ.js → chunk-VANLTS5F.js} +2 -2
- package/dist/{chunk-4Z4XNEWZ.js → chunk-VCD4PSK2.js} +56 -12
- package/dist/chunk-VCD4PSK2.js.map +1 -0
- package/dist/{chunk-RMMVQQA6.js → chunk-WDISJRMG.js} +2 -2
- package/dist/{chunk-B6JDYXL7.js → chunk-WWUVONGW.js} +7 -1
- package/dist/chunk-WWUVONGW.js.map +1 -0
- package/dist/{chunk-UVYI6VIX.js → chunk-X7Y7WX73.js} +1 -1
- package/dist/{chunk-TH2LSRMG.js → chunk-XHDIB4T4.js} +2 -2
- package/dist/{chunk-CVILPI77.js → chunk-XOQSEF7X.js} +6 -6
- package/dist/{chunk-LBOD4U5B.js → chunk-YFOMN2II.js} +6 -6
- package/dist/{chunk-RPW2NOU6.js → chunk-YIAA2X3D.js} +41 -1
- package/dist/chunk-YIAA2X3D.js.map +1 -0
- package/dist/chunk-YPC7W6GA.js +1604 -0
- package/dist/chunk-YPC7W6GA.js.map +1 -0
- package/dist/{chunk-I5NLEENJ.js → chunk-Z4SWV4VW.js} +3 -3
- package/dist/{chunk-PHWUFPCO.js → chunk-ZCPP5OW6.js} +61 -53
- package/dist/chunk-ZCPP5OW6.js.map +1 -0
- package/dist/{cli-C4GbETPC.d.ts → cli-BptUDTtp.d.ts} +5 -5
- package/dist/cli.d.ts +12 -12
- package/dist/cli.js +91 -84
- package/dist/compounding/engine.d.ts +2 -2
- package/dist/compounding/engine.js +14 -14
- 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 +1 -1
- package/dist/connectors/codex-materialize-runner.d.ts +1 -1
- package/dist/connectors/codex-materialize-runner.js +14 -14
- package/dist/connectors/codex-materialize.d.ts +1 -1
- package/dist/connectors/index.d.ts +1 -1
- package/dist/connectors/index.js +17 -17
- package/dist/consolidation-provenance-check.d.ts +2 -2
- package/dist/consolidation-provenance-check.js +5 -5
- package/dist/consolidation-undo.d.ts +2 -2
- package/dist/consolidation-undo.js +3 -3
- 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/corpus-watermark.d.ts +1 -1
- package/dist/corpus-watermark.js +26 -26
- 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 +14 -14
- package/dist/entity-schema.d.ts +1 -1
- package/dist/explicit-capture.d.ts +8 -8
- package/dist/extraction-error-classification.d.ts +1 -1
- 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-liveness.d.ts +1 -1
- package/dist/extraction-source-grounding-rules.d.ts +1 -1
- package/dist/extraction-source-grounding.d.ts +15 -2
- package/dist/extraction-source-grounding.js +10 -1
- package/dist/extraction.d.ts +2 -15
- package/dist/extraction.js +5 -4
- package/dist/fallback-llm.d.ts +1 -1
- 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/importance.d.ts +1 -1
- package/dist/importers/index.d.ts +1 -1
- package/dist/in-flight-reads.d.ts +1 -1
- package/dist/index.d.ts +19 -19
- package/dist/index.js +215 -207
- package/dist/intent.d.ts +1 -1
- package/dist/lcm/engine.d.ts +1 -1
- package/dist/lcm/engine.js +3 -3
- package/dist/lcm/index.d.ts +1 -1
- package/dist/lcm/index.js +6 -6
- 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-helpers.d.ts +7 -0
- package/dist/local-llm-helpers.js +16 -0
- package/dist/local-llm-helpers.js.map +1 -0
- package/dist/local-llm.d.ts +3 -6
- package/dist/local-llm.js +2 -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 +14 -14
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.d.ts +2 -2
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +14 -14
- package/dist/maintenance/rebuild-memory-projection.d.ts +2 -2
- package/dist/maintenance/rebuild-memory-projection.js +15 -15
- package/dist/{maintenance-CL30NWtc.d.ts → maintenance-b6f92bRz.d.ts} +3 -3
- package/dist/mcp-memory-inspector-app.d.ts +10 -10
- package/dist/memory-action-policy.d.ts +1 -1
- package/dist/memory-cache.d.ts +1 -1
- package/dist/memory-corpus-version.js +2 -2
- 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 +24 -24
- package/dist/namespaces/principal.d.ts +1 -1
- package/dist/namespaces/search.d.ts +1 -1
- package/dist/namespaces/search.js +9 -9
- package/dist/namespaces/storage.d.ts +3 -3
- package/dist/namespaces/storage.js +14 -14
- package/dist/native-knowledge.d.ts +1 -1
- package/dist/offline-sync-impression-drain.d.ts +1 -1
- package/dist/offline-sync-impression-drain.js +6 -5
- package/dist/operator-doctor-corpus.d.ts +1 -1
- package/dist/operator-doctor-corpus.js +29 -29
- package/dist/operator-doctor-replica.d.ts +1 -1
- package/dist/operator-doctor-replica.js +3 -3
- package/dist/operator-toolkit.d.ts +3 -3
- package/dist/operator-toolkit.js +38 -37
- package/dist/orchestration/compression-guideline-coordinator.d.ts +2 -2
- package/dist/orchestration/maintenance.d.ts +4 -4
- package/dist/orchestration/maintenance.js +22 -21
- package/dist/{orchestrator-CKTCRwWV.d.ts → orchestrator-3uGxC1qO.d.ts} +72 -34
- package/dist/orchestrator.d.ts +8 -8
- package/dist/orchestrator.js +167 -159
- package/dist/page-versioning.js +3 -3
- package/dist/patterns-cli.d.ts +1 -1
- package/dist/{pipeline-B7wj4rRZ.d.ts → pipeline-DepuNr-m.d.ts} +1 -1
- package/dist/policy-runtime.d.ts +1 -1
- package/dist/proactive-contention.d.ts +1 -1
- package/dist/provenance.d.ts +1 -1
- package/dist/{qmd-q9tg4dHp.d.ts → qmd-Dalr3Jby.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/qmd.js +4 -4
- package/dist/recall-concurrency-config.d.ts +1 -1
- package/dist/recall-disclosure-escalation.d.ts +1 -1
- package/dist/recall-explain-renderer.d.ts +1 -1
- package/dist/recall-explain-renderer.js +3 -3
- package/dist/recall-memory-map.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-cli.js +4 -4
- package/dist/recall-xray-renderer.d.ts +1 -1
- package/dist/recall-xray-renderer.js +3 -3
- package/dist/recall-xray.d.ts +1 -1
- package/dist/recall-xray.js +2 -2
- package/dist/replay/normalizers/chatgpt.d.ts +1 -1
- package/dist/replay/normalizers/claude.d.ts +1 -1
- package/dist/replay/normalizers/openclaw.d.ts +1 -1
- package/dist/replay/normalizers/shared.d.ts +1 -1
- package/dist/replay/runner.d.ts +1 -1
- package/dist/replay/types.d.ts +1 -1
- package/dist/replica-divergence.d.ts +1 -1
- package/dist/replica-divergence.js +2 -2
- package/dist/replica-peers-config.d.ts +1 -1
- package/dist/resolve-auth-token.d.ts +1 -1
- package/dist/resume-bundles.js +1 -1
- 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/salvage-envelope.d.ts +1 -1
- package/dist/{scope-profiles-CWDyglPM.d.ts → scope-profiles-BpiM5hTU.d.ts} +1 -1
- package/dist/search/embed-helper.d.ts +1 -1
- package/dist/search/factory.d.ts +1 -1
- package/dist/search/factory.js +8 -8
- package/dist/search/index.d.ts +1 -1
- package/dist/search/index.js +12 -12
- package/dist/search/lancedb-backend.d.ts +1 -1
- package/dist/search/meilisearch-backend.d.ts +1 -1
- package/dist/search/noop-backend.d.ts +1 -1
- package/dist/search/orama-backend.d.ts +1 -1
- package/dist/search/port.d.ts +1 -1
- package/dist/search/remote-backend.d.ts +1 -1
- package/dist/{semantic-consolidation-BUE3deLn.d.ts → semantic-consolidation-CMtVrf9f.d.ts} +1 -1
- package/dist/semantic-consolidation.d.ts +2 -2
- package/dist/semantic-consolidation.js +16 -16
- package/dist/semantic-rule-promotion.js +14 -14
- package/dist/semantic-rule-verifier.d.ts +1 -1
- package/dist/semantic-rule-verifier.js +14 -14
- package/dist/{service-CXgM0bQG.d.ts → service-DuAxwSgg.d.ts} +2 -2
- 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-DysJq-XH.d.ts → storage-CF0Ih8GP.d.ts} +1 -1
- package/dist/storage.d.ts +2 -2
- package/dist/storage.js +13 -13
- package/dist/summarizer.d.ts +1 -1
- package/dist/summarizer.js +3 -2
- package/dist/summary-snapshot.d.ts +1 -1
- package/dist/temporal-supersession.d.ts +2 -2
- package/dist/temporal-timeline-recall.d.ts +1 -1
- 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/tokens.js +2 -2
- 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 +2 -2
- package/dist/transfer/capsule-import.js +5 -5
- package/dist/trust-score-stage.d.ts +1 -1
- package/dist/trust-score.d.ts +1 -1
- package/dist/{types-aPPzhnjT.d.ts → types-BpaYvJ6v.d.ts} +22 -2
- package/dist/types.d.ts +1 -1
- package/dist/types.js +1 -1
- package/dist/utility-runtime.d.ts +1 -1
- package/dist/verified-recall.js +14 -14
- package/dist/write-envelope.d.ts +1 -1
- package/package.json +2 -2
- package/src/access-boundary.ts +3 -0
- package/src/access-cli.test.ts +93 -0
- package/src/access-cli.ts +56 -2
- package/src/access-extraction-force-flush.ts +177 -0
- package/src/access-http-extraction-force-flush.test.ts +132 -0
- package/src/access-http-lcm-compaction.ts +99 -22
- package/src/access-http-lifecycle-flush.ts +81 -0
- package/src/access-http.test.ts +227 -0
- package/src/access-http.ts +33 -40
- package/src/access-mcp-output-schemas.ts +6 -0
- package/src/access-mcp.test.ts +40 -0
- package/src/access-mcp.ts +32 -1
- package/src/access-observe-helpers.ts +180 -0
- package/src/access-observe-write-surface.ts +78 -19
- package/src/access-operations-batch.ts +2 -1
- package/src/access-schema-pi.test.ts +17 -0
- package/src/access-schema.ts +28 -11
- package/src/access-service-helpers.ts +46 -0
- package/src/access-service-observe-lcm-parity.test.ts +781 -31
- package/src/access-service-observe-scope.test.ts +88 -0
- package/src/access-service.ts +46 -128
- package/src/access-surface-catalog.test.ts +32 -0
- package/src/access-surface-catalog.ts +2 -0
- package/src/buffer-session.test.ts +148 -0
- package/src/buffer-turn-helpers.ts +152 -0
- package/src/buffer.ts +126 -201
- package/src/correction/correction-access-wiring.ts +79 -27
- package/src/correction/correction-executor.test.ts +542 -1
- package/src/correction/correction-executor.ts +309 -89
- package/src/correction/correction-planner.test.ts +35 -1
- package/src/correction/correction-planner.ts +50 -3
- package/src/correction/correction-service.ts +12 -7
- package/src/correction/correction-storage-integration.test.ts +172 -1
- package/src/correction/passive-capture.test.ts +35 -0
- package/src/correction/passive-capture.ts +17 -3
- package/src/extraction-source-grounding.ts +55 -1
- package/src/extraction-timeout.test.ts +51 -0
- package/src/extraction.ts +64 -90
- package/src/local-llm-headers-timeout.test.ts +48 -0
- package/src/local-llm-helpers.ts +58 -0
- package/src/local-llm.ts +62 -58
- package/src/orchestration/extraction-run-helpers.ts +309 -0
- package/src/orchestration/extraction-run.test.ts +350 -7
- package/src/orchestration/extraction-run.ts +327 -250
- package/src/orchestration/recall-internal-deps.ts +385 -0
- package/src/orchestration/recall-internal.ts +16 -375
- package/src/orchestration/session-context.ts +193 -18
- package/src/orchestration/turn-ingestion.ts +61 -11
- package/src/orchestrator-flush.test.ts +511 -5
- package/src/orchestrator.ts +8 -6
- package/src/types.ts +2 -2
- package/dist/chunk-4A6YGWQN.js.map +0 -1
- package/dist/chunk-4WKA6I65.js.map +0 -1
- package/dist/chunk-4Z4XNEWZ.js.map +0 -1
- package/dist/chunk-6FUPCJUL.js.map +0 -1
- package/dist/chunk-B6JDYXL7.js.map +0 -1
- package/dist/chunk-GBJ4RDFR.js.map +0 -1
- package/dist/chunk-HUHX2OCX.js.map +0 -1
- package/dist/chunk-IYZ5K7MU.js.map +0 -1
- package/dist/chunk-LGHKJABJ.js.map +0 -1
- package/dist/chunk-PHWUFPCO.js.map +0 -1
- package/dist/chunk-PUS63Q3G.js.map +0 -1
- package/dist/chunk-RPW2NOU6.js.map +0 -1
- package/dist/chunk-SPJXKAVF.js.map +0 -1
- package/dist/chunk-YTSNAUXN.js.map +0 -1
- /package/dist/{capsule-crypto-GWVG7LGC.js.map → access-extraction-force-flush.js.map} +0 -0
- /package/dist/{capsule-merge-5KKJQBWQ.js.map → capsule-merge-2H2IUTBT.js.map} +0 -0
- /package/dist/{chunk-LEPOP46W.js.map → chunk-227UFSEQ.js.map} +0 -0
- /package/dist/{chunk-GIBMDSJ2.js.map → chunk-27P5YVDU.js.map} +0 -0
- /package/dist/{chunk-2SA56WMI.js.map → chunk-2LTDWSR6.js.map} +0 -0
- /package/dist/{chunk-OWHERGF2.js.map → chunk-2NLLXCJG.js.map} +0 -0
- /package/dist/{chunk-6U7F52DE.js.map → chunk-4XHR3I67.js.map} +0 -0
- /package/dist/{chunk-2EUVEDF5.js.map → chunk-5XA7PQ5I.js.map} +0 -0
- /package/dist/{chunk-ALSGMEJR.js.map → chunk-65ZPVYTA.js.map} +0 -0
- /package/dist/{chunk-5VQJBH2G.js.map → chunk-6TAUHL33.js.map} +0 -0
- /package/dist/{chunk-RGIWINDN.js.map → chunk-7G5MH4NT.js.map} +0 -0
- /package/dist/{chunk-WVO4G37W.js.map → chunk-7TEZUUGM.js.map} +0 -0
- /package/dist/{chunk-MJCGLM25.js.map → chunk-7VUAG236.js.map} +0 -0
- /package/dist/{chunk-M3C2V3PV.js.map → chunk-AJEMDQNA.js.map} +0 -0
- /package/dist/{chunk-RKNJBZ55.js.map → chunk-AU7Q3LSC.js.map} +0 -0
- /package/dist/{chunk-ACXPX4AG.js.map → chunk-BR2K43MK.js.map} +0 -0
- /package/dist/{chunk-CZRYLSSW.js.map → chunk-BUGVGH4N.js.map} +0 -0
- /package/dist/{chunk-YTQNQ4KB.js.map → chunk-C4VQMFVM.js.map} +0 -0
- /package/dist/{chunk-ZPSVBSOF.js.map → chunk-CIVDJD6P.js.map} +0 -0
- /package/dist/{chunk-K5GB36ME.js.map → chunk-CZDOT5I2.js.map} +0 -0
- /package/dist/{chunk-VI2JQPNQ.js.map → chunk-E4PWACUN.js.map} +0 -0
- /package/dist/{chunk-D2ANTDGO.js.map → chunk-E6BMSH7U.js.map} +0 -0
- /package/dist/{chunk-P5PXWTW7.js.map → chunk-EJCAV3QZ.js.map} +0 -0
- /package/dist/{chunk-CKMO4RDY.js.map → chunk-EMDLM3LW.js.map} +0 -0
- /package/dist/{chunk-G5R3D5UP.js.map → chunk-GTTAHHD3.js.map} +0 -0
- /package/dist/{chunk-H5CPS5JP.js.map → chunk-H36LJIPD.js.map} +0 -0
- /package/dist/{chunk-AITCS2RC.js.map → chunk-IJ7HK452.js.map} +0 -0
- /package/dist/{chunk-D3LMYTBV.js.map → chunk-J7WZUL2K.js.map} +0 -0
- /package/dist/{chunk-5W4ZLBEZ.js.map → chunk-JCFTIQBR.js.map} +0 -0
- /package/dist/{chunk-XOZ4ALGB.js.map → chunk-KE353EWI.js.map} +0 -0
- /package/dist/{chunk-W5EG6LE3.js.map → chunk-KIT6M7EB.js.map} +0 -0
- /package/dist/{chunk-5W7CTZ2E.js.map → chunk-KQAFEZQX.js.map} +0 -0
- /package/dist/{chunk-Z54EM5YZ.js.map → chunk-MAXVH44E.js.map} +0 -0
- /package/dist/{chunk-WZFAPHIK.js.map → chunk-MU7ZHSZE.js.map} +0 -0
- /package/dist/{chunk-66772WBP.js.map → chunk-NFXQJHJD.js.map} +0 -0
- /package/dist/{chunk-AZ5BTEKX.js.map → chunk-NQUF7XKR.js.map} +0 -0
- /package/dist/{chunk-W4FBGYGK.js.map → chunk-NRV4Y3PM.js.map} +0 -0
- /package/dist/{chunk-NHWB6HG2.js.map → chunk-NYCGIQRA.js.map} +0 -0
- /package/dist/{chunk-QJAQNXWI.js.map → chunk-ONHRRJZM.js.map} +0 -0
- /package/dist/{chunk-FDAMS4PK.js.map → chunk-PNPOWBGC.js.map} +0 -0
- /package/dist/{chunk-IC6CBHCA.js.map → chunk-QGENAYVS.js.map} +0 -0
- /package/dist/{chunk-62U4J2GN.js.map → chunk-UR77VKF7.js.map} +0 -0
- /package/dist/{chunk-JCBWCYEJ.js.map → chunk-VANLTS5F.js.map} +0 -0
- /package/dist/{chunk-RMMVQQA6.js.map → chunk-WDISJRMG.js.map} +0 -0
- /package/dist/{chunk-UVYI6VIX.js.map → chunk-X7Y7WX73.js.map} +0 -0
- /package/dist/{chunk-TH2LSRMG.js.map → chunk-XHDIB4T4.js.map} +0 -0
- /package/dist/{chunk-CVILPI77.js.map → chunk-XOQSEF7X.js.map} +0 -0
- /package/dist/{chunk-LBOD4U5B.js.map → chunk-YFOMN2II.js.map} +0 -0
- /package/dist/{chunk-I5NLEENJ.js.map → chunk-Z4SWV4VW.js.map} +0 -0
|
@@ -7,22 +7,22 @@ import {
|
|
|
7
7
|
syncWearableSource,
|
|
8
8
|
wearableSourceLabel
|
|
9
9
|
} from "./chunk-UV72DEZD.js";
|
|
10
|
-
import {
|
|
11
|
-
runPeerProfileReasoner
|
|
12
|
-
} from "./chunk-I74SUMNI.js";
|
|
13
10
|
import {
|
|
14
11
|
CompressionGuidelineCoordinator
|
|
15
12
|
} from "./chunk-6LKEUCEM.js";
|
|
16
13
|
import {
|
|
17
14
|
ActivityStore,
|
|
18
15
|
MaintenanceScheduler
|
|
19
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-YFOMN2II.js";
|
|
17
|
+
import {
|
|
18
|
+
runPeerProfileReasoner
|
|
19
|
+
} from "./chunk-I74SUMNI.js";
|
|
20
20
|
import {
|
|
21
21
|
migrateFromEngram
|
|
22
22
|
} from "./chunk-7HYPN2GC.js";
|
|
23
23
|
import {
|
|
24
24
|
LcmEngine
|
|
25
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-MAXVH44E.js";
|
|
26
26
|
import {
|
|
27
27
|
chunkTranscriptEntries
|
|
28
28
|
} from "./chunk-TECVW3JP.js";
|
|
@@ -32,7 +32,7 @@ import {
|
|
|
32
32
|
import {
|
|
33
33
|
CompoundingEngine,
|
|
34
34
|
defaultTierMigrationCycleBudget
|
|
35
|
-
} from "./chunk-
|
|
35
|
+
} from "./chunk-E4PWACUN.js";
|
|
36
36
|
import {
|
|
37
37
|
SharedContextManager
|
|
38
38
|
} from "./chunk-AS7YMSL6.js";
|
|
@@ -41,9 +41,6 @@ import {
|
|
|
41
41
|
applyUtilityRankingRuntimeDelta,
|
|
42
42
|
loadUtilityRuntimeValues
|
|
43
43
|
} from "./chunk-LXOM6IQU.js";
|
|
44
|
-
import {
|
|
45
|
-
CODEX_THREAD_KEY_PREFIX
|
|
46
|
-
} from "./chunk-4EX5WZ4M.js";
|
|
47
44
|
import {
|
|
48
45
|
TierMigrationExecutor
|
|
49
46
|
} from "./chunk-VOUOLGIP.js";
|
|
@@ -56,16 +53,19 @@ import {
|
|
|
56
53
|
import {
|
|
57
54
|
extractTopics
|
|
58
55
|
} from "./chunk-UHGBNIOS.js";
|
|
59
|
-
import {
|
|
60
|
-
buildTargetedFactRecallSection,
|
|
61
|
-
shouldRecallTargetedFactEvidence
|
|
62
|
-
} from "./chunk-T67LUYCR.js";
|
|
63
56
|
import {
|
|
64
57
|
buildTemporalTimelineRecallSection
|
|
65
58
|
} from "./chunk-I6WYQSX4.js";
|
|
59
|
+
import {
|
|
60
|
+
CODEX_THREAD_KEY_PREFIX
|
|
61
|
+
} from "./chunk-4EX5WZ4M.js";
|
|
66
62
|
import {
|
|
67
63
|
HourlySummarizer
|
|
68
|
-
} from "./chunk-
|
|
64
|
+
} from "./chunk-NQUF7XKR.js";
|
|
65
|
+
import {
|
|
66
|
+
buildTargetedFactRecallSection,
|
|
67
|
+
shouldRecallTargetedFactEvidence
|
|
68
|
+
} from "./chunk-T67LUYCR.js";
|
|
69
69
|
import {
|
|
70
70
|
SessionObserverState
|
|
71
71
|
} from "./chunk-QFN4U7AG.js";
|
|
@@ -108,9 +108,6 @@ import {
|
|
|
108
108
|
reorderByRankedKeys,
|
|
109
109
|
rerankLocalOrNoop
|
|
110
110
|
} from "./chunk-LUDXM7MD.js";
|
|
111
|
-
import {
|
|
112
|
-
createRecallSectionMetricRecorder
|
|
113
|
-
} from "./chunk-C3AKM55W.js";
|
|
114
111
|
import {
|
|
115
112
|
LastRecallStore,
|
|
116
113
|
RecallHandleHistoryStore,
|
|
@@ -128,6 +125,9 @@ import {
|
|
|
128
125
|
import {
|
|
129
126
|
reorderRecallResultsWithMmr
|
|
130
127
|
} from "./chunk-YDBIWGNI.js";
|
|
128
|
+
import {
|
|
129
|
+
createRecallSectionMetricRecorder
|
|
130
|
+
} from "./chunk-C3AKM55W.js";
|
|
131
131
|
import {
|
|
132
132
|
applyReasoningTraceBoost
|
|
133
133
|
} from "./chunk-ZZTOURJI.js";
|
|
@@ -147,35 +147,13 @@ import {
|
|
|
147
147
|
import {
|
|
148
148
|
runLiveConnectorsOnce
|
|
149
149
|
} from "./chunk-HTIIXNJQ.js";
|
|
150
|
-
import {
|
|
151
|
-
hasBroadGraphIntent,
|
|
152
|
-
inferIntentFromText,
|
|
153
|
-
intentCompatibilityScore,
|
|
154
|
-
isTaskInitiationIntent,
|
|
155
|
-
planRecallMode
|
|
156
|
-
} from "./chunk-PD6O7AXF.js";
|
|
157
150
|
import {
|
|
158
151
|
classifyMemoryKind
|
|
159
152
|
} from "./chunk-YAZNBMNF.js";
|
|
160
|
-
import {
|
|
161
|
-
ExtractionEngine
|
|
162
|
-
} from "./chunk-GBJ4RDFR.js";
|
|
163
|
-
import {
|
|
164
|
-
parseMemoryActionEligibilityContext
|
|
165
|
-
} from "./chunk-TGTTESJS.js";
|
|
166
|
-
import {
|
|
167
|
-
ModelRegistry
|
|
168
|
-
} from "./chunk-WLZYGLJ4.js";
|
|
169
|
-
import {
|
|
170
|
-
LocalLlmClient
|
|
171
|
-
} from "./chunk-PHWUFPCO.js";
|
|
172
153
|
import {
|
|
173
154
|
buildFocusedListRecallSection,
|
|
174
155
|
shouldRecallFocusedListEvidence
|
|
175
156
|
} from "./chunk-OH7QLI6W.js";
|
|
176
|
-
import {
|
|
177
|
-
recordJudgeTrainingPair
|
|
178
|
-
} from "./chunk-PWFCHOB3.js";
|
|
179
157
|
import {
|
|
180
158
|
createDeferCountMap,
|
|
181
159
|
createVerdictCache,
|
|
@@ -188,9 +166,17 @@ import {
|
|
|
188
166
|
loadRedactionRules
|
|
189
167
|
} from "./chunk-LTHVM4XN.js";
|
|
190
168
|
import {
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
169
|
+
ExtractionEngine
|
|
170
|
+
} from "./chunk-QIHIHZYC.js";
|
|
171
|
+
import {
|
|
172
|
+
parseMemoryActionEligibilityContext
|
|
173
|
+
} from "./chunk-TGTTESJS.js";
|
|
174
|
+
import {
|
|
175
|
+
ModelRegistry
|
|
176
|
+
} from "./chunk-WLZYGLJ4.js";
|
|
177
|
+
import {
|
|
178
|
+
LocalLlmClient
|
|
179
|
+
} from "./chunk-ZCPP5OW6.js";
|
|
194
180
|
import {
|
|
195
181
|
pickFactEventTimeAnchor,
|
|
196
182
|
resolveFactEventTime
|
|
@@ -199,8 +185,8 @@ import {
|
|
|
199
185
|
buildExplicitCueRecallSection
|
|
200
186
|
} from "./chunk-TVIVY7KU.js";
|
|
201
187
|
import {
|
|
202
|
-
|
|
203
|
-
} from "./chunk-
|
|
188
|
+
recordJudgeTrainingPair
|
|
189
|
+
} from "./chunk-PWFCHOB3.js";
|
|
204
190
|
import {
|
|
205
191
|
EmbeddingFallback
|
|
206
192
|
} from "./chunk-E6EE5B67.js";
|
|
@@ -208,33 +194,40 @@ import {
|
|
|
208
194
|
buildEntityRecallSection,
|
|
209
195
|
entityRecentTranscriptLookbackHours,
|
|
210
196
|
readRecentEntityTranscriptEntries
|
|
211
|
-
} from "./chunk-
|
|
197
|
+
} from "./chunk-NFXQJHJD.js";
|
|
198
|
+
import {
|
|
199
|
+
buildEventOrderRecallSection,
|
|
200
|
+
shouldRecallEventOrderEvidence
|
|
201
|
+
} from "./chunk-DEOYTFA6.js";
|
|
212
202
|
import {
|
|
213
203
|
formatDaySummaryMemories
|
|
214
204
|
} from "./chunk-RPSYDM6C.js";
|
|
205
|
+
import {
|
|
206
|
+
tryDirectAnswer
|
|
207
|
+
} from "./chunk-Q6IP2ARR.js";
|
|
215
208
|
import {
|
|
216
209
|
builtInConnectorPackageSpecifier,
|
|
217
210
|
ensureBuiltInWearableConnectors,
|
|
218
211
|
getWearableConnector,
|
|
219
212
|
listWearableConnectors
|
|
220
|
-
} from "./chunk-
|
|
221
|
-
import {
|
|
222
|
-
normalizeReplaySessionKey
|
|
223
|
-
} from "./chunk-AJVLDJU6.js";
|
|
213
|
+
} from "./chunk-4XHR3I67.js";
|
|
224
214
|
import {
|
|
225
215
|
RoutingRulesStore
|
|
226
216
|
} from "./chunk-XL24QQ63.js";
|
|
217
|
+
import {
|
|
218
|
+
normalizeReplaySessionKey
|
|
219
|
+
} from "./chunk-AJVLDJU6.js";
|
|
227
220
|
import {
|
|
228
221
|
compareVerifiedEpisodeResults,
|
|
229
222
|
searchVerifiedEpisodes
|
|
230
|
-
} from "./chunk-
|
|
223
|
+
} from "./chunk-5XA7PQ5I.js";
|
|
231
224
|
import {
|
|
232
225
|
ThreadingManager
|
|
233
226
|
} from "./chunk-OJP3N7UK.js";
|
|
234
227
|
import {
|
|
235
228
|
compareVerifiedSemanticRuleResults,
|
|
236
229
|
searchVerifiedSemanticRules
|
|
237
|
-
} from "./chunk-
|
|
230
|
+
} from "./chunk-XHDIB4T4.js";
|
|
238
231
|
import {
|
|
239
232
|
searchWorkProductLedgerEntries
|
|
240
233
|
} from "./chunk-ZRWB5D4H.js";
|
|
@@ -247,11 +240,11 @@ import {
|
|
|
247
240
|
import {
|
|
248
241
|
runNamespaceMaintenanceFanout,
|
|
249
242
|
summarizeNamespaceMaintenanceHealth
|
|
250
|
-
} from "./chunk-
|
|
243
|
+
} from "./chunk-AJEMDQNA.js";
|
|
251
244
|
import {
|
|
252
245
|
NamespaceCatalog,
|
|
253
246
|
planNamespaceMaintenance
|
|
254
|
-
} from "./chunk-
|
|
247
|
+
} from "./chunk-H36LJIPD.js";
|
|
255
248
|
import {
|
|
256
249
|
isAboveImportanceThreshold,
|
|
257
250
|
scoreImportance
|
|
@@ -263,20 +256,20 @@ import {
|
|
|
263
256
|
EXTRACTION_JUDGE_VERDICT_CATEGORY,
|
|
264
257
|
recordJudgeVerdict
|
|
265
258
|
} from "./chunk-OZKOPQCM.js";
|
|
266
|
-
import {
|
|
267
|
-
recordEvalShadowRecall
|
|
268
|
-
} from "./chunk-3PY7VHV7.js";
|
|
269
259
|
import {
|
|
270
260
|
collectNativeKnowledgeChunks,
|
|
271
261
|
formatNativeKnowledgeSection,
|
|
272
262
|
searchNativeKnowledge
|
|
273
263
|
} from "./chunk-2DQ2XREU.js";
|
|
264
|
+
import {
|
|
265
|
+
recordEvalShadowRecall
|
|
266
|
+
} from "./chunk-3PY7VHV7.js";
|
|
274
267
|
import {
|
|
275
268
|
applyCommitmentLedgerLifecycle
|
|
276
269
|
} from "./chunk-LMDRGRJ2.js";
|
|
277
270
|
import {
|
|
278
|
-
|
|
279
|
-
} from "./chunk-
|
|
271
|
+
SmartBuffer
|
|
272
|
+
} from "./chunk-TL4TO3EA.js";
|
|
280
273
|
import {
|
|
281
274
|
buildConsolidationPrompt,
|
|
282
275
|
buildExtensionsBlockForConsolidation,
|
|
@@ -286,16 +279,26 @@ import {
|
|
|
286
279
|
materializeAfterSemanticConsolidation,
|
|
287
280
|
parseConsolidationResponse,
|
|
288
281
|
parseOperatorAwareConsolidationResponse
|
|
289
|
-
} from "./chunk-
|
|
282
|
+
} from "./chunk-PNPOWBGC.js";
|
|
283
|
+
import {
|
|
284
|
+
buildBehaviorSignalsForMemory,
|
|
285
|
+
dedupeBehaviorSignalsByMemoryAndHash
|
|
286
|
+
} from "./chunk-KD3QD3A5.js";
|
|
287
|
+
import {
|
|
288
|
+
BootstrapEngine
|
|
289
|
+
} from "./chunk-MYVPLJOO.js";
|
|
290
|
+
import {
|
|
291
|
+
isDisagreementPrompt
|
|
292
|
+
} from "./chunk-H3FZVNRN.js";
|
|
293
|
+
import {
|
|
294
|
+
BoxBuilder
|
|
295
|
+
} from "./chunk-B7RWBZXW.js";
|
|
290
296
|
import {
|
|
291
297
|
semanticChunkContent
|
|
292
298
|
} from "./chunk-P4BC54KI.js";
|
|
293
299
|
import {
|
|
294
300
|
chunkContent
|
|
295
301
|
} from "./chunk-UQ7RN5HK.js";
|
|
296
|
-
import {
|
|
297
|
-
SmartBuffer
|
|
298
|
-
} from "./chunk-4A6YGWQN.js";
|
|
299
302
|
import {
|
|
300
303
|
detectMeetings
|
|
301
304
|
} from "./chunk-IB26HVAJ.js";
|
|
@@ -313,22 +316,9 @@ import {
|
|
|
313
316
|
import {
|
|
314
317
|
buildRecallQueryPolicy
|
|
315
318
|
} from "./chunk-LBJBNWS2.js";
|
|
316
|
-
import {
|
|
317
|
-
buildBehaviorSignalsForMemory,
|
|
318
|
-
dedupeBehaviorSignalsByMemoryAndHash
|
|
319
|
-
} from "./chunk-KD3QD3A5.js";
|
|
320
|
-
import {
|
|
321
|
-
BootstrapEngine
|
|
322
|
-
} from "./chunk-MYVPLJOO.js";
|
|
323
|
-
import {
|
|
324
|
-
isDisagreementPrompt
|
|
325
|
-
} from "./chunk-H3FZVNRN.js";
|
|
326
|
-
import {
|
|
327
|
-
BoxBuilder
|
|
328
|
-
} from "./chunk-B7RWBZXW.js";
|
|
329
319
|
import {
|
|
330
320
|
MeetingsInputError
|
|
331
|
-
} from "./chunk-
|
|
321
|
+
} from "./chunk-FI4F5X2V.js";
|
|
332
322
|
import {
|
|
333
323
|
WearablesInputError,
|
|
334
324
|
describeErrorForOperator
|
|
@@ -342,17 +332,21 @@ import {
|
|
|
342
332
|
} from "./chunk-CEN6DW6X.js";
|
|
343
333
|
import {
|
|
344
334
|
RecallResultFormatter,
|
|
335
|
+
SessionContextCoordinator,
|
|
345
336
|
capturePassiveCorrections,
|
|
346
337
|
clusterByKey,
|
|
347
|
-
createCorrectionService,
|
|
348
338
|
detectPassiveCorrections
|
|
349
|
-
} from "./chunk-
|
|
339
|
+
} from "./chunk-OGCNZPKX.js";
|
|
350
340
|
import {
|
|
351
341
|
importCapsule
|
|
352
|
-
} from "./chunk-
|
|
342
|
+
} from "./chunk-65ZPVYTA.js";
|
|
353
343
|
import {
|
|
354
344
|
isCodingGraphInstalled
|
|
355
345
|
} from "./chunk-VQ7B2Q6M.js";
|
|
346
|
+
import {
|
|
347
|
+
listTrustZoneRecords,
|
|
348
|
+
searchTrustZoneRecords
|
|
349
|
+
} from "./chunk-JGSKJHF7.js";
|
|
356
350
|
import {
|
|
357
351
|
applyTrustScoreStage,
|
|
358
352
|
buildTrustSignalsForRerank,
|
|
@@ -361,9 +355,8 @@ import {
|
|
|
361
355
|
trustResultKey
|
|
362
356
|
} from "./chunk-GNVZQ5JN.js";
|
|
363
357
|
import {
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
} from "./chunk-JGSKJHF7.js";
|
|
358
|
+
buildXraySnapshot
|
|
359
|
+
} from "./chunk-BR2K43MK.js";
|
|
367
360
|
import {
|
|
368
361
|
boundRecallContextComposition,
|
|
369
362
|
composeRecallContext,
|
|
@@ -371,21 +364,15 @@ import {
|
|
|
371
364
|
formatCuriosityFooter,
|
|
372
365
|
selectCuriosityQuestion
|
|
373
366
|
} from "./chunk-AHVEHR6K.js";
|
|
374
|
-
import {
|
|
375
|
-
buildXraySnapshot
|
|
376
|
-
} from "./chunk-ACXPX4AG.js";
|
|
377
367
|
import {
|
|
378
368
|
objectiveStateStoreOverrideForNamespace,
|
|
379
369
|
searchObjectiveStateSnapshots
|
|
380
370
|
} from "./chunk-6HMYUWXR.js";
|
|
381
371
|
import {
|
|
382
|
-
combineNamespaces,
|
|
383
372
|
getConfiguredNamespaces,
|
|
384
|
-
resolveCodingNamespaceOverlay,
|
|
385
373
|
resolveNamespaceFromStorageDir,
|
|
386
|
-
resolveScopePlan
|
|
387
|
-
|
|
388
|
-
} from "./chunk-IYZ5K7MU.js";
|
|
374
|
+
resolveScopePlan
|
|
375
|
+
} from "./chunk-ULARSG5Z.js";
|
|
389
376
|
import {
|
|
390
377
|
ProfilingCollector
|
|
391
378
|
} from "./chunk-NLE6TSLG.js";
|
|
@@ -398,29 +385,80 @@ import {
|
|
|
398
385
|
import {
|
|
399
386
|
NamespaceSearchRouter,
|
|
400
387
|
namespaceCollectionName
|
|
401
|
-
} from "./chunk-
|
|
388
|
+
} from "./chunk-E6BMSH7U.js";
|
|
402
389
|
import {
|
|
403
390
|
createConversationIndexRuntime,
|
|
404
391
|
createSearchBackend
|
|
405
|
-
} from "./chunk-
|
|
392
|
+
} from "./chunk-J7WZUL2K.js";
|
|
406
393
|
import {
|
|
407
394
|
NoopSearchBackend
|
|
408
395
|
} from "./chunk-CYEPCZN5.js";
|
|
409
396
|
import {
|
|
410
397
|
NamespaceStorageRouter
|
|
411
|
-
} from "./chunk-
|
|
398
|
+
} from "./chunk-QGENAYVS.js";
|
|
412
399
|
import {
|
|
413
400
|
writeConversationChunks
|
|
414
401
|
} from "./chunk-72A4L5JJ.js";
|
|
415
|
-
import {
|
|
416
|
-
parseQmdExplain
|
|
417
|
-
} from "./chunk-QJAQNXWI.js";
|
|
418
402
|
import {
|
|
419
403
|
GraphIndex
|
|
420
404
|
} from "./chunk-L2DPF4DF.js";
|
|
405
|
+
import {
|
|
406
|
+
BulkImportBatchPartialFailureError,
|
|
407
|
+
COMPACTION_SIGNAL_MAX_AGE_MS,
|
|
408
|
+
ExtractionDeadlineError,
|
|
409
|
+
ExtractionRunCoordinator,
|
|
410
|
+
abortRecallError,
|
|
411
|
+
appendMemoryToGraphContext,
|
|
412
|
+
applyQueryAwareCandidateFilter,
|
|
413
|
+
buildMemoryPathById,
|
|
414
|
+
buildQmdIntentHint,
|
|
415
|
+
computeArtifactCandidateFetchLimit,
|
|
416
|
+
computeArtifactRecallLimit,
|
|
417
|
+
computeQmdHybridFetchLimit,
|
|
418
|
+
defaultWorkspaceDir,
|
|
419
|
+
filterHourlySummaryMarkdownForLocalDay,
|
|
420
|
+
formatDateInTimeZone,
|
|
421
|
+
isActivityDigestPath,
|
|
422
|
+
isArtifactMemoryPath,
|
|
423
|
+
isMeetingRecordPath,
|
|
424
|
+
lifecycleRecallScoreAdjustment,
|
|
425
|
+
mapRecallSourceToXrayServedBy,
|
|
426
|
+
mergeArtifactRecallCandidates,
|
|
427
|
+
normalizeIanaTimeZone,
|
|
428
|
+
parseFiniteDate,
|
|
429
|
+
parseGraphRecallRankedResults,
|
|
430
|
+
parseMemoryIntentSnapshot,
|
|
431
|
+
parseQmdRecallResults,
|
|
432
|
+
qmdStartupCollectionCheckWithTimeout,
|
|
433
|
+
raceRecallAbort,
|
|
434
|
+
resolvePersistedMemoryRelativePath,
|
|
435
|
+
resolveRecallModeDecision,
|
|
436
|
+
resolveRecallModeDecisionAsync,
|
|
437
|
+
resolveRecentThreadMemoryPaths,
|
|
438
|
+
sanitizeSessionKeyForFilename,
|
|
439
|
+
shouldFilterLifecycleRecallCandidate,
|
|
440
|
+
splitTurnsBySourceValidAt,
|
|
441
|
+
summarizeGraphShadowComparison,
|
|
442
|
+
targetSourceValidAtSortMs,
|
|
443
|
+
throwIfRecallAborted,
|
|
444
|
+
tokenizeRecallQuery,
|
|
445
|
+
utcDateKeysForLocalDay
|
|
446
|
+
} from "./chunk-YPC7W6GA.js";
|
|
447
|
+
import {
|
|
448
|
+
resolveCodingNamespaceOverlay
|
|
449
|
+
} from "./chunk-BUE5E2HL.js";
|
|
450
|
+
import {
|
|
451
|
+
inferIntentFromText,
|
|
452
|
+
intentCompatibilityScore,
|
|
453
|
+
isTaskInitiationIntent,
|
|
454
|
+
planRecallMode
|
|
455
|
+
} from "./chunk-PD6O7AXF.js";
|
|
456
|
+
import {
|
|
457
|
+
searchCausalTrajectories
|
|
458
|
+
} from "./chunk-NRV4Y3PM.js";
|
|
421
459
|
import {
|
|
422
460
|
buildChainFollowupGenerator
|
|
423
|
-
} from "./chunk-
|
|
461
|
+
} from "./chunk-BUGVGH4N.js";
|
|
424
462
|
import {
|
|
425
463
|
QmdResultResolver,
|
|
426
464
|
StorageManager,
|
|
@@ -439,7 +477,7 @@ import {
|
|
|
439
477
|
reconstructFusionInputs,
|
|
440
478
|
selfDeps,
|
|
441
479
|
serializeFusionDay
|
|
442
|
-
} from "./chunk-
|
|
480
|
+
} from "./chunk-7G5MH4NT.js";
|
|
443
481
|
import {
|
|
444
482
|
bodyIsEscaped,
|
|
445
483
|
decodeTranscriptBody,
|
|
@@ -470,28 +508,23 @@ import {
|
|
|
470
508
|
} from "./chunk-J6A3CX5N.js";
|
|
471
509
|
import {
|
|
472
510
|
confidenceTier
|
|
473
|
-
} from "./chunk-
|
|
511
|
+
} from "./chunk-7DRETLP5.js";
|
|
474
512
|
import {
|
|
475
513
|
namespaceIdentityFromToken,
|
|
476
514
|
namespaceIdentityToken,
|
|
477
515
|
normalizeNamespaceIdentity
|
|
478
516
|
} from "./chunk-EGGE52UU.js";
|
|
479
|
-
import {
|
|
480
|
-
assertPathInsideRoot
|
|
481
|
-
} from "./chunk-GCASGYIO.js";
|
|
482
517
|
import {
|
|
483
518
|
inferMemoryStatus,
|
|
484
519
|
isActiveMemoryStatus
|
|
485
520
|
} from "./chunk-ILGC6JH6.js";
|
|
521
|
+
import {
|
|
522
|
+
assertPathInsideRoot
|
|
523
|
+
} from "./chunk-GCASGYIO.js";
|
|
486
524
|
import {
|
|
487
525
|
lintWorkspaceFiles,
|
|
488
526
|
rotateMarkdownFileToArchive
|
|
489
527
|
} from "./chunk-DM2T26WE.js";
|
|
490
|
-
import {
|
|
491
|
-
applyFaithfulnessVerdict,
|
|
492
|
-
createFaithfulnessCounters,
|
|
493
|
-
runFaithfulnessGateBatch
|
|
494
|
-
} from "./chunk-JYIJNNN3.js";
|
|
495
528
|
import {
|
|
496
529
|
ContentHashIndex
|
|
497
530
|
} from "./chunk-FBUE6PD3.js";
|
|
@@ -507,9 +540,14 @@ import {
|
|
|
507
540
|
import {
|
|
508
541
|
normalizeTags
|
|
509
542
|
} from "./chunk-BT7NVCML.js";
|
|
543
|
+
import {
|
|
544
|
+
applyFaithfulnessVerdict,
|
|
545
|
+
createFaithfulnessCounters,
|
|
546
|
+
runFaithfulnessGateBatch
|
|
547
|
+
} from "./chunk-JYIJNNN3.js";
|
|
510
548
|
import {
|
|
511
549
|
bumpMemoryCorpusVersionForDir
|
|
512
|
-
} from "./chunk-
|
|
550
|
+
} from "./chunk-IJ7HK452.js";
|
|
513
551
|
import {
|
|
514
552
|
buildQmdRecallCacheKey,
|
|
515
553
|
getCachedQmdRecall,
|
|
@@ -520,9 +558,6 @@ import {
|
|
|
520
558
|
fallbackLlmRuntimeContextFromConfig,
|
|
521
559
|
gatewayTaskChainOptions
|
|
522
560
|
} from "./chunk-C23BYTJV.js";
|
|
523
|
-
import {
|
|
524
|
-
searchCausalTrajectories
|
|
525
|
-
} from "./chunk-W4FBGYGK.js";
|
|
526
561
|
import {
|
|
527
562
|
sanitizeMemoryContent
|
|
528
563
|
} from "./chunk-5GKPFL3S.js";
|
|
@@ -557,14 +592,9 @@ import {
|
|
|
557
592
|
assertIsDirectoryNotSymlink,
|
|
558
593
|
assertRealpathInsideRoot
|
|
559
594
|
} from "./chunk-GCGJW34D.js";
|
|
560
|
-
import {
|
|
561
|
-
parseFlexibleIsoTimestamp
|
|
562
|
-
} from "./chunk-P7FMDTKL.js";
|
|
563
595
|
import {
|
|
564
596
|
canReadNamespace,
|
|
565
|
-
canWriteNamespace,
|
|
566
597
|
defaultNamespaceForPrincipal,
|
|
567
|
-
recallNamespacesForPrincipal,
|
|
568
598
|
resolvePrincipal
|
|
569
599
|
} from "./chunk-3GD2HFR6.js";
|
|
570
600
|
import {
|
|
@@ -608,7 +638,6 @@ import {
|
|
|
608
638
|
ALL_CATEGORY_DIRS,
|
|
609
639
|
ALL_CATEGORY_KEYS,
|
|
610
640
|
RECALL_FALLBACK_DIRS,
|
|
611
|
-
categoryDirName,
|
|
612
641
|
getCategoryDir
|
|
613
642
|
} from "./chunk-VS2IYZRU.js";
|
|
614
643
|
import {
|
|
@@ -616,8 +645,8 @@ import {
|
|
|
616
645
|
} from "./chunk-3WCASNQZ.js";
|
|
617
646
|
|
|
618
647
|
// src/orchestrator.ts
|
|
619
|
-
import
|
|
620
|
-
import { createHash as
|
|
648
|
+
import path16 from "path";
|
|
649
|
+
import { createHash as createHash6 } from "crypto";
|
|
621
650
|
|
|
622
651
|
// src/orchestration/tier-migration-coordinator.ts
|
|
623
652
|
import path from "path";
|
|
@@ -2108,7 +2137,7 @@ var RecallRerankCoordinator = class _RecallRerankCoordinator {
|
|
|
2108
2137
|
namespaces,
|
|
2109
2138
|
{
|
|
2110
2139
|
readNamespaceMemories: async (ns) => (await this.getStorage(ns)).readAllMemories(),
|
|
2111
|
-
readMemoryFrontmatter: async (
|
|
2140
|
+
readMemoryFrontmatter: async (path31, preferredNamespace) => {
|
|
2112
2141
|
if (!fallbackReader) {
|
|
2113
2142
|
for (const ns of namespaces) {
|
|
2114
2143
|
try {
|
|
@@ -2120,7 +2149,7 @@ var RecallRerankCoordinator = class _RecallRerankCoordinator {
|
|
|
2120
2149
|
}
|
|
2121
2150
|
if (!fallbackReader) return null;
|
|
2122
2151
|
const memory = await this.readQmdResultMemory(
|
|
2123
|
-
|
|
2152
|
+
path31,
|
|
2124
2153
|
fallbackReader,
|
|
2125
2154
|
namespaces,
|
|
2126
2155
|
preferredNamespace
|
|
@@ -2719,1315 +2748,62 @@ var ContradictionLinkingCoordinator = class {
|
|
|
2719
2748
|
contradiction.supersededCreated,
|
|
2720
2749
|
contradiction.supersededTags
|
|
2721
2750
|
);
|
|
2722
|
-
}
|
|
2723
|
-
} catch (err) {
|
|
2724
|
-
log.warn(
|
|
2725
|
-
`contradiction auto-resolve supersede failed for ${contradiction.supersededId}: ${err}`
|
|
2726
|
-
);
|
|
2727
|
-
}
|
|
2728
|
-
}
|
|
2729
|
-
// ---------------------------------------------------------------------------
|
|
2730
|
-
// Memory Linking (Phase 3A)
|
|
2731
|
-
// ---------------------------------------------------------------------------
|
|
2732
|
-
/**
|
|
2733
|
-
* Suggest links for a new memory based on similar existing memories.
|
|
2734
|
-
*/
|
|
2735
|
-
async suggestLinksForMemory(content, category, namespaceScope) {
|
|
2736
|
-
if (!this.isSearchAvailable()) return [];
|
|
2737
|
-
const results = await this.searchAcrossNamespaces({
|
|
2738
|
-
query: content,
|
|
2739
|
-
namespaces: [namespaceScope],
|
|
2740
|
-
maxResults: 5,
|
|
2741
|
-
mode: "search"
|
|
2742
|
-
});
|
|
2743
|
-
if (results.length === 0) return [];
|
|
2744
|
-
const candidates = [];
|
|
2745
|
-
for (const result of results) {
|
|
2746
|
-
const memoryId = this.extractMemoryIdsFromResults([result])[0];
|
|
2747
|
-
if (!memoryId) continue;
|
|
2748
|
-
const resultNamespace = this.namespaceFromPath(result.path);
|
|
2749
|
-
if (resultNamespace !== namespaceScope) continue;
|
|
2750
|
-
const resultStorage = await this.storageForNamespace(resultNamespace);
|
|
2751
|
-
const memory = await resultStorage.getMemoryById(memoryId);
|
|
2752
|
-
if (memory && memory.frontmatter.status !== "superseded" && memory.frontmatter.status !== "forgotten") {
|
|
2753
|
-
candidates.push({
|
|
2754
|
-
id: memory.frontmatter.id,
|
|
2755
|
-
content: memory.content,
|
|
2756
|
-
category: memory.frontmatter.category
|
|
2757
|
-
});
|
|
2758
|
-
}
|
|
2759
|
-
}
|
|
2760
|
-
if (candidates.length === 0) return [];
|
|
2761
|
-
const extraction = this.getExtraction();
|
|
2762
|
-
const suggestions = await extraction.suggestLinks(
|
|
2763
|
-
{ content, category },
|
|
2764
|
-
candidates
|
|
2765
|
-
);
|
|
2766
|
-
if (!suggestions || suggestions.links.length === 0) return [];
|
|
2767
|
-
return suggestions.links.map((link) => ({
|
|
2768
|
-
targetId: link.targetId,
|
|
2769
|
-
linkType: link.linkType,
|
|
2770
|
-
strength: link.strength,
|
|
2771
|
-
reason: link.reason || void 0
|
|
2772
|
-
}));
|
|
2773
|
-
}
|
|
2774
|
-
};
|
|
2775
|
-
|
|
2776
|
-
// src/orchestration/extraction-run.ts
|
|
2777
|
-
import { createHash as createHash3 } from "crypto";
|
|
2778
|
-
|
|
2779
|
-
// src/orchestration/orchestrator-helpers.ts
|
|
2780
|
-
import { createHash as createHash2 } from "crypto";
|
|
2781
|
-
import os from "os";
|
|
2782
|
-
import path4 from "path";
|
|
2783
|
-
var BulkImportBatchPartialFailureError = class extends Error {
|
|
2784
|
-
partialResult;
|
|
2785
|
-
originalError;
|
|
2786
|
-
constructor(message, partialResult, originalError) {
|
|
2787
|
-
super(message);
|
|
2788
|
-
this.name = "BulkImportBatchPartialFailureError";
|
|
2789
|
-
this.partialResult = partialResult;
|
|
2790
|
-
this.originalError = originalError;
|
|
2791
|
-
}
|
|
2792
|
-
};
|
|
2793
|
-
function mapRecallSourceToXrayServedBy(source) {
|
|
2794
|
-
switch (source) {
|
|
2795
|
-
case "recent_scan":
|
|
2796
|
-
return "recent-scan";
|
|
2797
|
-
case "hot_qmd":
|
|
2798
|
-
case "hot_embedding":
|
|
2799
|
-
case "cold_fallback":
|
|
2800
|
-
case "none":
|
|
2801
|
-
return "hybrid";
|
|
2802
|
-
}
|
|
2803
|
-
const _exhaustive = source;
|
|
2804
|
-
void _exhaustive;
|
|
2805
|
-
return "hybrid";
|
|
2806
|
-
}
|
|
2807
|
-
var abortRecallError = abortError;
|
|
2808
|
-
function throwIfRecallAborted(signal, message = "recall aborted") {
|
|
2809
|
-
throwIfAborted(signal, message);
|
|
2810
|
-
}
|
|
2811
|
-
async function raceRecallAbort(promise, signal, message = "recall aborted") {
|
|
2812
|
-
throwIfRecallAborted(signal, message);
|
|
2813
|
-
if (!signal) return promise;
|
|
2814
|
-
let onAbort = null;
|
|
2815
|
-
const abortPromise = new Promise((_resolve, reject) => {
|
|
2816
|
-
onAbort = () => reject(abortRecallError(message));
|
|
2817
|
-
signal.addEventListener("abort", onAbort, { once: true });
|
|
2818
|
-
});
|
|
2819
|
-
try {
|
|
2820
|
-
return await Promise.race([promise, abortPromise]);
|
|
2821
|
-
} finally {
|
|
2822
|
-
if (onAbort) {
|
|
2823
|
-
signal.removeEventListener("abort", onAbort);
|
|
2824
|
-
}
|
|
2825
|
-
}
|
|
2826
|
-
}
|
|
2827
|
-
var COMPACTION_SIGNAL_MAX_AGE_MS = 60 * 60 * 1e3;
|
|
2828
|
-
var DEFAULT_QMD_STARTUP_COLLECTION_CHECK_TIMEOUT_MS = 1e4;
|
|
2829
|
-
function normalizeIanaTimeZone(value) {
|
|
2830
|
-
if (typeof value !== "string") return void 0;
|
|
2831
|
-
const trimmed = value.trim();
|
|
2832
|
-
if (!trimmed) return void 0;
|
|
2833
|
-
try {
|
|
2834
|
-
Intl.DateTimeFormat(void 0, { timeZone: trimmed });
|
|
2835
|
-
return trimmed;
|
|
2836
|
-
} catch {
|
|
2837
|
-
return void 0;
|
|
2838
|
-
}
|
|
2839
|
-
}
|
|
2840
|
-
function formatDateInTimeZone(date, timeZone) {
|
|
2841
|
-
const parts = new Intl.DateTimeFormat("en-US", {
|
|
2842
|
-
timeZone,
|
|
2843
|
-
year: "numeric",
|
|
2844
|
-
month: "2-digit",
|
|
2845
|
-
day: "2-digit"
|
|
2846
|
-
}).formatToParts(date);
|
|
2847
|
-
const get = (type) => parts.find((part) => part.type === type)?.value ?? "";
|
|
2848
|
-
return `${get("year")}-${get("month")}-${get("day")}`;
|
|
2849
|
-
}
|
|
2850
|
-
function utcDateKey(date) {
|
|
2851
|
-
return date.toISOString().slice(0, 10);
|
|
2852
|
-
}
|
|
2853
|
-
function utcDateKeysAround(date) {
|
|
2854
|
-
const dayMs = 864e5;
|
|
2855
|
-
const keys = [
|
|
2856
|
-
utcDateKey(new Date(date.getTime() - dayMs)),
|
|
2857
|
-
utcDateKey(date),
|
|
2858
|
-
utcDateKey(new Date(date.getTime() + dayMs))
|
|
2859
|
-
];
|
|
2860
|
-
return keys.filter((value, index, array) => array.indexOf(value) === index);
|
|
2861
|
-
}
|
|
2862
|
-
function utcDateKeysForLocalDay(date, timeZone) {
|
|
2863
|
-
const targetLocalDate = formatDateInTimeZone(date, timeZone);
|
|
2864
|
-
const keys = /* @__PURE__ */ new Set();
|
|
2865
|
-
const hourMs = 36e5;
|
|
2866
|
-
const scanStart = date.getTime() - 48 * hourMs;
|
|
2867
|
-
const scanEnd = date.getTime() + 48 * hourMs;
|
|
2868
|
-
for (let ms = scanStart; ms <= scanEnd; ms += hourMs) {
|
|
2869
|
-
const candidate = new Date(ms);
|
|
2870
|
-
if (formatDateInTimeZone(candidate, timeZone) === targetLocalDate) {
|
|
2871
|
-
keys.add(utcDateKey(candidate));
|
|
2872
|
-
}
|
|
2873
|
-
}
|
|
2874
|
-
return keys.size > 0 ? [...keys].sort() : utcDateKeysAround(date);
|
|
2875
|
-
}
|
|
2876
|
-
function parseFiniteDate(value) {
|
|
2877
|
-
if (typeof value !== "string" || value.trim().length === 0) return null;
|
|
2878
|
-
const parsed = new Date(value);
|
|
2879
|
-
return Number.isFinite(parsed.getTime()) ? parsed : null;
|
|
2880
|
-
}
|
|
2881
|
-
function filterHourlySummaryMarkdownForLocalDay(raw, utcDate, timeZone, targetLocalDate) {
|
|
2882
|
-
const hourHeaderPattern = /^## ([01]\d|2[0-3]):00[ \t]*$/gm;
|
|
2883
|
-
const matches = Array.from(raw.matchAll(hourHeaderPattern));
|
|
2884
|
-
if (matches.length === 0) return null;
|
|
2885
|
-
const firstSectionStart = matches[0]?.index ?? 0;
|
|
2886
|
-
const preamble = raw.slice(0, firstSectionStart).trim();
|
|
2887
|
-
const sections = [];
|
|
2888
|
-
for (let index = 0; index < matches.length; index += 1) {
|
|
2889
|
-
const match = matches[index];
|
|
2890
|
-
const hour = match[1];
|
|
2891
|
-
if (!hour) continue;
|
|
2892
|
-
const sectionTimestamp = parseFiniteDate(`${utcDate}T${hour}:00:00.000Z`);
|
|
2893
|
-
if (!sectionTimestamp || formatDateInTimeZone(sectionTimestamp, timeZone) !== targetLocalDate) {
|
|
2894
|
-
continue;
|
|
2895
|
-
}
|
|
2896
|
-
const sectionStart = match.index ?? 0;
|
|
2897
|
-
const sectionEnd = matches[index + 1]?.index ?? raw.length;
|
|
2898
|
-
const section = raw.slice(sectionStart, sectionEnd).trim();
|
|
2899
|
-
if (section.length > 0) sections.push(section);
|
|
2900
|
-
}
|
|
2901
|
-
if (sections.length === 0) return null;
|
|
2902
|
-
return [preamble, ...sections].filter((section) => section.length > 0).join("\n\n");
|
|
2903
|
-
}
|
|
2904
|
-
function qmdStartupCollectionCheckTimeoutMs() {
|
|
2905
|
-
const raw = process.env.REMNIC_QMD_STARTUP_COLLECTION_CHECK_TIMEOUT_MS ?? process.env.ENGRAM_QMD_STARTUP_COLLECTION_CHECK_TIMEOUT_MS;
|
|
2906
|
-
if (raw === void 0) return DEFAULT_QMD_STARTUP_COLLECTION_CHECK_TIMEOUT_MS;
|
|
2907
|
-
const parsed = Number(raw);
|
|
2908
|
-
return Number.isFinite(parsed) && parsed >= 1e3 ? Math.floor(parsed) : DEFAULT_QMD_STARTUP_COLLECTION_CHECK_TIMEOUT_MS;
|
|
2909
|
-
}
|
|
2910
|
-
async function qmdStartupCollectionCheckWithTimeout(promise, controller, label) {
|
|
2911
|
-
const timeoutMs = qmdStartupCollectionCheckTimeoutMs();
|
|
2912
|
-
let timer;
|
|
2913
|
-
let settled = false;
|
|
2914
|
-
const timeoutPromise = new Promise((resolve) => {
|
|
2915
|
-
timer = setTimeout(() => {
|
|
2916
|
-
if (settled) return;
|
|
2917
|
-
controller.abort();
|
|
2918
|
-
log.warn(
|
|
2919
|
-
`QMD startup collection check for ${label} timed out after ${timeoutMs}ms; keeping search enabled fail-open`
|
|
2920
|
-
);
|
|
2921
|
-
resolve("unknown");
|
|
2922
|
-
}, timeoutMs);
|
|
2923
|
-
timer.unref?.();
|
|
2924
|
-
});
|
|
2925
|
-
const checkedPromise = promise.catch((err) => {
|
|
2926
|
-
log.warn(
|
|
2927
|
-
`QMD startup collection check for ${label} failed; keeping search enabled fail-open: ${err}`
|
|
2928
|
-
);
|
|
2929
|
-
return "unknown";
|
|
2930
|
-
}).finally(() => {
|
|
2931
|
-
settled = true;
|
|
2932
|
-
if (timer) clearTimeout(timer);
|
|
2933
|
-
});
|
|
2934
|
-
return await Promise.race([checkedPromise, timeoutPromise]);
|
|
2935
|
-
}
|
|
2936
|
-
function defaultWorkspaceDir() {
|
|
2937
|
-
return path4.join(os.homedir(), ".openclaw", "workspace");
|
|
2938
|
-
}
|
|
2939
|
-
function sanitizeSessionKeyForFilename(sessionKey) {
|
|
2940
|
-
const readable = sessionKey.replace(/[^a-zA-Z0-9._-]/g, "_");
|
|
2941
|
-
const hash = createHash2("sha256").update(sessionKey).digest("hex").slice(0, 12);
|
|
2942
|
-
return `${readable}-${hash}`;
|
|
2943
|
-
}
|
|
2944
|
-
function sourceValidAtMs(turn) {
|
|
2945
|
-
if (typeof turn.sourceValidAt !== "string") return null;
|
|
2946
|
-
return parseFlexibleIsoTimestamp(turn.sourceValidAt.trim());
|
|
2947
|
-
}
|
|
2948
|
-
var SOURCE_VALID_AT_CONTEXT_TURNS = 2;
|
|
2949
|
-
function sourceValidAtSliceKey(turn, index) {
|
|
2950
|
-
const validAtMs = sourceValidAtMs(turn);
|
|
2951
|
-
return validAtMs === null ? `unknown:${index}` : String(validAtMs);
|
|
2952
|
-
}
|
|
2953
|
-
function asExtractionContextTurn(turn) {
|
|
2954
|
-
return { ...turn, extractionContextOnly: true };
|
|
2955
|
-
}
|
|
2956
|
-
function asExtractionTargetTurn(turn) {
|
|
2957
|
-
const { extractionContextOnly: _contextOnly, ...targetTurn } = turn;
|
|
2958
|
-
return targetTurn;
|
|
2959
|
-
}
|
|
2960
|
-
function sourceValidAtContextTurns(turns, targetStart, targetEnd, targetValidAtMs) {
|
|
2961
|
-
if (targetValidAtMs === null) return [];
|
|
2962
|
-
return turns.flatMap((turn, index) => {
|
|
2963
|
-
if (index >= targetStart && index < targetEnd) return [];
|
|
2964
|
-
const contextValidAtMs = sourceValidAtMs(turn);
|
|
2965
|
-
if (contextValidAtMs === null || contextValidAtMs > targetValidAtMs) {
|
|
2966
|
-
return [];
|
|
2967
|
-
}
|
|
2968
|
-
return [{ turn, index, validAtMs: contextValidAtMs }];
|
|
2969
|
-
}).sort((a, b) => {
|
|
2970
|
-
if (a.validAtMs < b.validAtMs) return -1;
|
|
2971
|
-
if (a.validAtMs > b.validAtMs) return 1;
|
|
2972
|
-
if (a.index === b.index) return 0;
|
|
2973
|
-
return a.index < b.index ? -1 : 1;
|
|
2974
|
-
}).slice(-SOURCE_VALID_AT_CONTEXT_TURNS).map(({ turn }) => asExtractionContextTurn(turn));
|
|
2975
|
-
}
|
|
2976
|
-
function targetSourceValidAtSortMs(turns) {
|
|
2977
|
-
let latestMs = null;
|
|
2978
|
-
for (const turn of turns) {
|
|
2979
|
-
if (turn.extractionContextOnly === true) continue;
|
|
2980
|
-
const validAtMs = sourceValidAtMs(turn);
|
|
2981
|
-
if (validAtMs === null) continue;
|
|
2982
|
-
if (latestMs === null || validAtMs > latestMs) {
|
|
2983
|
-
latestMs = validAtMs;
|
|
2984
|
-
}
|
|
2985
|
-
}
|
|
2986
|
-
return latestMs ?? Number.POSITIVE_INFINITY;
|
|
2987
|
-
}
|
|
2988
|
-
function sortSourceValidAtSlicesChronologically(slices) {
|
|
2989
|
-
return slices.map((turns, order) => ({
|
|
2990
|
-
turns,
|
|
2991
|
-
order,
|
|
2992
|
-
targetValidAtMs: targetSourceValidAtSortMs(turns)
|
|
2993
|
-
})).sort((a, b) => {
|
|
2994
|
-
if (a.targetValidAtMs < b.targetValidAtMs) return -1;
|
|
2995
|
-
if (a.targetValidAtMs > b.targetValidAtMs) return 1;
|
|
2996
|
-
if (a.order === b.order) return 0;
|
|
2997
|
-
return a.order < b.order ? -1 : 1;
|
|
2998
|
-
}).map((slice) => slice.turns);
|
|
2999
|
-
}
|
|
3000
|
-
function splitTurnsBySourceValidAt(turns, options = {}) {
|
|
3001
|
-
if (turns.length === 0) return [];
|
|
3002
|
-
if (!turns.some((turn) => sourceValidAtMs(turn) !== null)) {
|
|
3003
|
-
return [[...turns]];
|
|
3004
|
-
}
|
|
3005
|
-
const slices = [];
|
|
3006
|
-
let start = 0;
|
|
3007
|
-
while (start < turns.length) {
|
|
3008
|
-
const targetValidAtMs = sourceValidAtMs(turns[start]);
|
|
3009
|
-
const activeKey = sourceValidAtSliceKey(turns[start], start);
|
|
3010
|
-
let end = start + 1;
|
|
3011
|
-
while (end < turns.length && sourceValidAtSliceKey(turns[end], end) === activeKey) {
|
|
3012
|
-
end += 1;
|
|
3013
|
-
}
|
|
3014
|
-
const contextTurns = options.includeContext === false ? [] : sourceValidAtContextTurns(turns, start, end, targetValidAtMs);
|
|
3015
|
-
slices.push([
|
|
3016
|
-
...contextTurns,
|
|
3017
|
-
...turns.slice(start, end).map(asExtractionTargetTurn)
|
|
3018
|
-
]);
|
|
3019
|
-
start = end;
|
|
3020
|
-
}
|
|
3021
|
-
return sortSourceValidAtSlicesChronologically(slices);
|
|
3022
|
-
}
|
|
3023
|
-
function isArtifactMemoryPath(filePath) {
|
|
3024
|
-
return /(?:^|[\\/])artifacts(?:[\\/]|$)/i.test(filePath);
|
|
3025
|
-
}
|
|
3026
|
-
function isMeetingRecordPath(filePath) {
|
|
3027
|
-
return /(?:^|[\\/])meetings[\\/]\d{4}-\d{2}-\d{2}[\\/]mtg-\d{4}-\d{2}-\d{2}-[0-9a-f]{8}\.md$/i.test(filePath);
|
|
3028
|
-
}
|
|
3029
|
-
var ACTIVITY_DIGEST_TOPLEVEL = /^activity[\\/]\d{4}-\d{2}-\d{2}\.md$/i;
|
|
3030
|
-
var ACTIVITY_DIGEST_ANYWHERE = /(?:^|[\\/])activity[\\/]\d{4}-\d{2}-\d{2}\.md$/i;
|
|
3031
|
-
function isActivityDigestPath(filePath, memoryRoot) {
|
|
3032
|
-
if (memoryRoot !== void 0 && memoryRoot.length > 0) {
|
|
3033
|
-
const relative = path4.relative(memoryRoot, path4.resolve(memoryRoot, filePath));
|
|
3034
|
-
return ACTIVITY_DIGEST_TOPLEVEL.test(relative);
|
|
3035
|
-
}
|
|
3036
|
-
return ACTIVITY_DIGEST_ANYWHERE.test(filePath);
|
|
3037
|
-
}
|
|
3038
|
-
function buildCompressionGuidelinesMarkdown2(events, generatedAtIso = (/* @__PURE__ */ new Date()).toISOString()) {
|
|
3039
|
-
return buildCompressionGuidelinesMarkdown(events, generatedAtIso);
|
|
3040
|
-
}
|
|
3041
|
-
function applyQueryAwareCandidateFilter(candidates, candidatePaths) {
|
|
3042
|
-
if (!candidatePaths) return candidates;
|
|
3043
|
-
if (candidatePaths.size === 0) return [];
|
|
3044
|
-
const filtered = candidates.filter(
|
|
3045
|
-
(candidate) => candidatePaths.has(candidate.path)
|
|
3046
|
-
);
|
|
3047
|
-
return filtered.length > 0 ? filtered : candidates;
|
|
3048
|
-
}
|
|
3049
|
-
function tokenizeRecallQuery(prompt) {
|
|
3050
|
-
return prompt.toLowerCase().split(/[^a-z0-9]+/i).map((t) => t.trim()).filter((t) => t.length >= 3);
|
|
3051
|
-
}
|
|
3052
|
-
function hasLifecycleMetadata(frontmatter) {
|
|
3053
|
-
return frontmatter.lifecycleState !== void 0 || frontmatter.verificationState !== void 0 || frontmatter.policyClass !== void 0 || frontmatter.lastValidatedAt !== void 0 || frontmatter.decayScore !== void 0 || frontmatter.heatScore !== void 0;
|
|
3054
|
-
}
|
|
3055
|
-
function shouldFilterLifecycleRecallCandidate(frontmatter, options) {
|
|
3056
|
-
if (!options.lifecyclePolicyEnabled || !options.lifecycleFilterStaleEnabled)
|
|
3057
|
-
return false;
|
|
3058
|
-
if (!hasLifecycleMetadata(frontmatter)) return false;
|
|
3059
|
-
const lifecycleState = resolveLifecycleState(frontmatter);
|
|
3060
|
-
return lifecycleState === "stale" || lifecycleState === "archived";
|
|
3061
|
-
}
|
|
3062
|
-
function lifecycleRecallScoreAdjustment(frontmatter, options) {
|
|
3063
|
-
if (!options.lifecyclePolicyEnabled) return 0;
|
|
3064
|
-
if (!hasLifecycleMetadata(frontmatter)) return 0;
|
|
3065
|
-
let delta = 0;
|
|
3066
|
-
const lifecycleState = resolveLifecycleState(frontmatter);
|
|
3067
|
-
switch (lifecycleState) {
|
|
3068
|
-
case "active":
|
|
3069
|
-
delta += 0.05;
|
|
3070
|
-
break;
|
|
3071
|
-
case "validated":
|
|
3072
|
-
delta += 0.03;
|
|
3073
|
-
break;
|
|
3074
|
-
case "candidate":
|
|
3075
|
-
delta -= 0.01;
|
|
3076
|
-
break;
|
|
3077
|
-
case "stale":
|
|
3078
|
-
delta -= 0.06;
|
|
3079
|
-
break;
|
|
3080
|
-
case "archived":
|
|
3081
|
-
delta -= 0.08;
|
|
3082
|
-
break;
|
|
3083
|
-
}
|
|
3084
|
-
if (frontmatter.verificationState === "disputed") {
|
|
3085
|
-
delta -= 0.12;
|
|
3086
|
-
}
|
|
3087
|
-
return delta;
|
|
3088
|
-
}
|
|
3089
|
-
function computeArtifactRecallLimit(recallMode, recallResultLimit, verbatimArtifactsMaxRecall) {
|
|
3090
|
-
if (recallMode === "no_recall") return 0;
|
|
3091
|
-
if (Math.max(0, recallResultLimit) === 0) return 0;
|
|
3092
|
-
const base = Math.max(0, verbatimArtifactsMaxRecall);
|
|
3093
|
-
if (recallMode === "minimal") {
|
|
3094
|
-
return Math.min(base, Math.max(0, recallResultLimit));
|
|
3095
|
-
}
|
|
3096
|
-
return base;
|
|
3097
|
-
}
|
|
3098
|
-
function resolveEffectiveRecallMode(options) {
|
|
3099
|
-
return resolveRecallModeDecision(options).effectiveMode;
|
|
3100
|
-
}
|
|
3101
|
-
function finalizeRecallModeDecision(plannedModeRaw, options) {
|
|
3102
|
-
let plannedMode = plannedModeRaw;
|
|
3103
|
-
const graphExpandedIntentDetected = options.plannerEnabled && options.graphExpandedIntentEnabled === true && hasBroadGraphIntent(options.prompt);
|
|
3104
|
-
if (plannedMode !== "graph_mode" && graphExpandedIntentDetected) {
|
|
3105
|
-
plannedMode = "graph_mode";
|
|
3106
|
-
}
|
|
3107
|
-
if (plannedMode === "graph_mode" && (!options.graphRecallEnabled || !options.multiGraphMemoryEnabled)) {
|
|
3108
|
-
return {
|
|
3109
|
-
plannedMode,
|
|
3110
|
-
effectiveMode: "full",
|
|
3111
|
-
graphExpandedIntentDetected,
|
|
3112
|
-
graphReason: !options.graphRecallEnabled ? "graph recall disabled by config" : "multi-graph memory disabled by config"
|
|
3113
|
-
};
|
|
3114
|
-
}
|
|
3115
|
-
return {
|
|
3116
|
-
plannedMode,
|
|
3117
|
-
effectiveMode: plannedMode,
|
|
3118
|
-
graphExpandedIntentDetected
|
|
3119
|
-
};
|
|
3120
|
-
}
|
|
3121
|
-
function resolveRecallModeDecision(options) {
|
|
3122
|
-
const plannedMode = options.plannerEnabled ? planRecallMode(options.prompt) : "full";
|
|
3123
|
-
return finalizeRecallModeDecision(plannedMode, options);
|
|
3124
|
-
}
|
|
3125
|
-
async function resolveRecallModeDecisionAsync(options) {
|
|
3126
|
-
const heuristicDecision = resolveRecallModeDecision(options);
|
|
3127
|
-
const plannerLlmEnabled = options.caps.recallPlannerLlm;
|
|
3128
|
-
if (!options.plannerEnabled || !plannerLlmEnabled) {
|
|
3129
|
-
return heuristicDecision;
|
|
3130
|
-
}
|
|
3131
|
-
const { planRecallModeLLM } = await import("./recall-planner-llm.js");
|
|
3132
|
-
const planned = await planRecallModeLLM(
|
|
3133
|
-
options.prompt,
|
|
3134
|
-
options.hints,
|
|
3135
|
-
options.config,
|
|
3136
|
-
options.caps,
|
|
3137
|
-
options.llm,
|
|
3138
|
-
options.signal
|
|
3139
|
-
);
|
|
3140
|
-
if (options.config.recallPlannerShadowMode) {
|
|
3141
|
-
return {
|
|
3142
|
-
...heuristicDecision,
|
|
3143
|
-
plannerSource: planned.source,
|
|
3144
|
-
plannerReason: `shadow:${planned.reason}`,
|
|
3145
|
-
plannerLatencyMs: planned.latencyMs,
|
|
3146
|
-
plannerFallbackUsed: planned.fallbackUsed,
|
|
3147
|
-
plannerModelUsed: planned.modelUsed,
|
|
3148
|
-
plannerHeuristicMode: planned.heuristicMode,
|
|
3149
|
-
shadowLlmMode: planned.mode
|
|
3150
|
-
};
|
|
3151
|
-
}
|
|
3152
|
-
const llmDecision = finalizeRecallModeDecision(planned.mode, options);
|
|
3153
|
-
return {
|
|
3154
|
-
...llmDecision,
|
|
3155
|
-
plannerSource: planned.source,
|
|
3156
|
-
plannerReason: planned.reason,
|
|
3157
|
-
plannerLatencyMs: planned.latencyMs,
|
|
3158
|
-
plannerFallbackUsed: planned.fallbackUsed,
|
|
3159
|
-
plannerModelUsed: planned.modelUsed,
|
|
3160
|
-
plannerHeuristicMode: planned.heuristicMode
|
|
3161
|
-
};
|
|
3162
|
-
}
|
|
3163
|
-
function computeArtifactCandidateFetchLimit(targetCount) {
|
|
3164
|
-
const cappedTarget = Math.max(0, targetCount);
|
|
3165
|
-
if (cappedTarget === 0) return 0;
|
|
3166
|
-
const headroom = Math.max(8, cappedTarget * 4);
|
|
3167
|
-
return Math.min(200, cappedTarget + headroom);
|
|
3168
|
-
}
|
|
3169
|
-
function computeQmdHybridFetchLimit(recallFetchLimit, artifactsEnabled, maxArtifactRecall) {
|
|
3170
|
-
const cappedRecallLimit = Math.max(0, recallFetchLimit);
|
|
3171
|
-
if (cappedRecallLimit === 0) return 0;
|
|
3172
|
-
if (!artifactsEnabled) return cappedRecallLimit;
|
|
3173
|
-
const artifactHeadroom = Math.max(20, Math.max(0, maxArtifactRecall) * 8);
|
|
3174
|
-
return Math.min(400, cappedRecallLimit + artifactHeadroom);
|
|
3175
|
-
}
|
|
3176
|
-
function summarizeGraphShadowComparison(baseline, merged, topN) {
|
|
3177
|
-
const limit = Math.max(0, Math.floor(topN));
|
|
3178
|
-
const baselineTop = limit > 0 ? baseline.slice(0, limit) : [];
|
|
3179
|
-
const graphTop = limit > 0 ? merged.slice(0, limit) : [];
|
|
3180
|
-
const baselineByPath = new Map(
|
|
3181
|
-
baselineTop.map((item) => [item.path, item.score])
|
|
3182
|
-
);
|
|
3183
|
-
const graphByPath = new Map(graphTop.map((item) => [item.path, item.score]));
|
|
3184
|
-
let overlapCount = 0;
|
|
3185
|
-
let overlapDeltaSum = 0;
|
|
3186
|
-
for (const [p, baselineScore] of baselineByPath.entries()) {
|
|
3187
|
-
const graphScore = graphByPath.get(p);
|
|
3188
|
-
if (typeof graphScore !== "number") continue;
|
|
3189
|
-
overlapCount += 1;
|
|
3190
|
-
overlapDeltaSum += graphScore - baselineScore;
|
|
3191
|
-
}
|
|
3192
|
-
const baselineCount = baselineTop.length;
|
|
3193
|
-
return {
|
|
3194
|
-
baselineCount,
|
|
3195
|
-
graphCount: graphTop.length,
|
|
3196
|
-
overlapCount,
|
|
3197
|
-
overlapRatio: baselineCount > 0 ? overlapCount / baselineCount : 0,
|
|
3198
|
-
averageOverlapDelta: overlapCount > 0 ? overlapDeltaSum / overlapCount : 0
|
|
3199
|
-
};
|
|
3200
|
-
}
|
|
3201
|
-
function parseGraphRecallRankedResults(value) {
|
|
3202
|
-
if (!Array.isArray(value)) return [];
|
|
3203
|
-
const parsed = [];
|
|
3204
|
-
for (const entry of value) {
|
|
3205
|
-
if (!entry || typeof entry !== "object") continue;
|
|
3206
|
-
const candidate = entry;
|
|
3207
|
-
if (typeof candidate.path !== "string" || typeof candidate.score !== "number")
|
|
3208
|
-
continue;
|
|
3209
|
-
parsed.push({
|
|
3210
|
-
path: candidate.path,
|
|
3211
|
-
score: candidate.score,
|
|
3212
|
-
docid: typeof candidate.docid === "string" ? candidate.docid : void 0,
|
|
3213
|
-
sourceLabels: Array.isArray(candidate.sourceLabels) ? candidate.sourceLabels.filter(
|
|
3214
|
-
(item) => typeof item === "string"
|
|
3215
|
-
) : []
|
|
3216
|
-
});
|
|
3217
|
-
}
|
|
3218
|
-
return parsed.slice(0, 64);
|
|
3219
|
-
}
|
|
3220
|
-
function parseMemoryIntentSnapshot(value) {
|
|
3221
|
-
const candidate = value && typeof value === "object" ? value : {};
|
|
3222
|
-
return {
|
|
3223
|
-
goal: typeof candidate.goal === "string" ? candidate.goal : "unknown",
|
|
3224
|
-
actionType: typeof candidate.actionType === "string" ? candidate.actionType : "unknown",
|
|
3225
|
-
entityTypes: Array.isArray(candidate.entityTypes) ? candidate.entityTypes.filter(
|
|
3226
|
-
(item) => typeof item === "string"
|
|
3227
|
-
) : [],
|
|
3228
|
-
taskInitiation: candidate.taskInitiation === true
|
|
3229
|
-
};
|
|
3230
|
-
}
|
|
3231
|
-
function buildQmdIntentHint(intent) {
|
|
3232
|
-
const parts = [];
|
|
3233
|
-
if (intent.goal !== "unknown") {
|
|
3234
|
-
parts.push(`goal:${intent.goal.replace(/_/g, " ")}`);
|
|
3235
|
-
}
|
|
3236
|
-
if (intent.actionType !== "unknown") {
|
|
3237
|
-
parts.push(`action:${intent.actionType.replace(/_/g, " ")}`);
|
|
3238
|
-
}
|
|
3239
|
-
if (intent.entityTypes.length > 0) {
|
|
3240
|
-
parts.push(`entities:${intent.entityTypes.join(",")}`);
|
|
3241
|
-
}
|
|
3242
|
-
if (intent.taskInitiation === true) {
|
|
3243
|
-
parts.push("task_initiation");
|
|
3244
|
-
}
|
|
3245
|
-
return parts.length > 0 ? parts.join(" ") : void 0;
|
|
3246
|
-
}
|
|
3247
|
-
function parseQmdRecallResults(value) {
|
|
3248
|
-
if (!Array.isArray(value)) return [];
|
|
3249
|
-
const parsed = [];
|
|
3250
|
-
for (const entry of value) {
|
|
3251
|
-
if (!entry || typeof entry !== "object") continue;
|
|
3252
|
-
const candidate = entry;
|
|
3253
|
-
if (typeof candidate.path !== "string" || typeof candidate.score !== "number")
|
|
3254
|
-
continue;
|
|
3255
|
-
parsed.push({
|
|
3256
|
-
docid: typeof candidate.docid === "string" ? candidate.docid : "",
|
|
3257
|
-
path: candidate.path,
|
|
3258
|
-
snippet: typeof candidate.snippet === "string" ? candidate.snippet : "",
|
|
3259
|
-
score: candidate.score,
|
|
3260
|
-
explain: parseQmdExplain(candidate.explain),
|
|
3261
|
-
transport: candidate.transport === "daemon" || candidate.transport === "subprocess" || candidate.transport === "hybrid" || candidate.transport === "scoped_prefilter" ? candidate.transport : void 0
|
|
3262
|
-
});
|
|
3263
|
-
}
|
|
3264
|
-
return parsed.slice(0, 32);
|
|
3265
|
-
}
|
|
3266
|
-
function mergeArtifactRecallCandidates(candidatesByNamespace, limit) {
|
|
3267
|
-
const cappedLimit = Math.max(0, limit);
|
|
3268
|
-
if (cappedLimit === 0) return [];
|
|
3269
|
-
const out = [];
|
|
3270
|
-
const seen = /* @__PURE__ */ new Set();
|
|
3271
|
-
let offset = 0;
|
|
3272
|
-
while (out.length < cappedLimit) {
|
|
3273
|
-
let hasAnyCandidateAtOffset = false;
|
|
3274
|
-
for (const list of candidatesByNamespace) {
|
|
3275
|
-
if (offset >= list.length) continue;
|
|
3276
|
-
hasAnyCandidateAtOffset = true;
|
|
3277
|
-
const item = list[offset];
|
|
3278
|
-
const dedupeKey = `${item.frontmatter.id}:${item.frontmatter.sourceMemoryId ?? ""}:${item.content}`;
|
|
3279
|
-
if (seen.has(dedupeKey)) continue;
|
|
3280
|
-
seen.add(dedupeKey);
|
|
3281
|
-
out.push(item);
|
|
3282
|
-
if (out.length >= cappedLimit) break;
|
|
3283
|
-
}
|
|
3284
|
-
if (!hasAnyCandidateAtOffset) break;
|
|
3285
|
-
offset += 1;
|
|
3286
|
-
}
|
|
3287
|
-
return out;
|
|
3288
|
-
}
|
|
3289
|
-
function resolveRecentThreadMemoryPaths(options) {
|
|
3290
|
-
const maxRecent = Math.max(0, options.maxRecent);
|
|
3291
|
-
if (options.threadEpisodeIds.length === 0 || maxRecent === 0) return [];
|
|
3292
|
-
const pathById = options.pathById ?? buildMemoryPathById(options.allMemsForGraph, options.storageDir);
|
|
3293
|
-
if (pathById.size === 0) return [];
|
|
3294
|
-
const pendingReviewIds = new Set(
|
|
3295
|
-
(options.allMemsForGraph ?? []).filter((m) => m.frontmatter.status === "pending_review" && m.frontmatter.id).map((m) => m.frontmatter.id)
|
|
3296
|
-
);
|
|
3297
|
-
return options.threadEpisodeIds.filter((id) => id !== options.currentMemoryId).filter((id) => !pendingReviewIds.has(id)).slice(-maxRecent).map((id) => pathById.get(id)).filter((p) => typeof p === "string" && p.length > 0);
|
|
3298
|
-
}
|
|
3299
|
-
function buildMemoryPathById(allMemsForGraph, storageDir) {
|
|
3300
|
-
const pathById = /* @__PURE__ */ new Map();
|
|
3301
|
-
for (const mem of allMemsForGraph ?? []) {
|
|
3302
|
-
const id = mem.frontmatter.id;
|
|
3303
|
-
if (!id) continue;
|
|
3304
|
-
pathById.set(id, path4.relative(storageDir, mem.path));
|
|
3305
|
-
}
|
|
3306
|
-
return pathById;
|
|
3307
|
-
}
|
|
3308
|
-
function appendMemoryToGraphContext(options) {
|
|
3309
|
-
if (!Array.isArray(options.allMemsForGraph)) return;
|
|
3310
|
-
const nowIso = (/* @__PURE__ */ new Date()).toISOString();
|
|
3311
|
-
options.allMemsForGraph.push({
|
|
3312
|
-
path: path4.join(options.storageDir, options.memoryRelPath),
|
|
3313
|
-
content: options.content,
|
|
3314
|
-
frontmatter: {
|
|
3315
|
-
id: options.memoryId,
|
|
3316
|
-
category: options.category,
|
|
3317
|
-
created: nowIso,
|
|
3318
|
-
updated: nowIso,
|
|
3319
|
-
source: "extraction",
|
|
3320
|
-
confidence: 0.8,
|
|
3321
|
-
confidenceTier: "implied",
|
|
3322
|
-
tags: [],
|
|
3323
|
-
entityRef: options.entityRef,
|
|
3324
|
-
status: "active"
|
|
3325
|
-
}
|
|
3326
|
-
});
|
|
3327
|
-
}
|
|
3328
|
-
function resolvePersistedMemoryRelativePath(options) {
|
|
3329
|
-
const persisted = options.pathById.get(options.memoryId);
|
|
3330
|
-
if (persisted) return persisted;
|
|
3331
|
-
if (options.category === "correction") {
|
|
3332
|
-
return path4.join("corrections", `${options.memoryId}.md`);
|
|
3333
|
-
}
|
|
3334
|
-
const subtree = categoryDirName(options.category);
|
|
3335
|
-
const idParts = options.memoryId.split("-");
|
|
3336
|
-
const maybeTimestamp = Number(idParts[1]);
|
|
3337
|
-
if (Number.isFinite(maybeTimestamp) && maybeTimestamp > 0) {
|
|
3338
|
-
const day = new Date(maybeTimestamp).toISOString().slice(0, 10);
|
|
3339
|
-
return path4.join(subtree, day, `${options.memoryId}.md`);
|
|
3340
|
-
}
|
|
3341
|
-
return path4.join(subtree, `${options.memoryId}.md`);
|
|
3342
|
-
}
|
|
3343
|
-
|
|
3344
|
-
// src/orchestration/extraction-run.ts
|
|
3345
|
-
function deriveTopicsFromExtraction(result) {
|
|
3346
|
-
const topics = /* @__PURE__ */ new Set();
|
|
3347
|
-
for (const fact of result.facts ?? []) {
|
|
3348
|
-
for (const tag of fact.tags ?? []) {
|
|
3349
|
-
if (tag && tag.length >= 2) topics.add(tag.toLowerCase());
|
|
3350
|
-
}
|
|
3351
|
-
if (fact.entityRef) topics.add(fact.entityRef.toLowerCase());
|
|
3352
|
-
if (fact.category) topics.add(fact.category);
|
|
3353
|
-
}
|
|
3354
|
-
for (const entity of result.entities ?? []) {
|
|
3355
|
-
if (typeof entity.name === "string" && entity.name.length >= 2) {
|
|
3356
|
-
topics.add(entity.name.toLowerCase());
|
|
3357
|
-
}
|
|
3358
|
-
}
|
|
3359
|
-
return [...topics].slice(0, 16);
|
|
3360
|
-
}
|
|
3361
|
-
var EXTRACTION_RETRY_STATE_MAX_ENTRIES = 500;
|
|
3362
|
-
function computeExtractionRetryNextEligibleMs(attempts, scheduleMs, maxBackoffMs, jitterRatio, now, rng = Math.random) {
|
|
3363
|
-
const cap = Number.isFinite(maxBackoffMs) && maxBackoffMs > 0 ? maxBackoffMs : 0;
|
|
3364
|
-
if (!Array.isArray(scheduleMs) || scheduleMs.length === 0) {
|
|
3365
|
-
return now + cap;
|
|
3366
|
-
}
|
|
3367
|
-
const idx = Math.min(Math.max(attempts - 1, 0), scheduleMs.length - 1);
|
|
3368
|
-
const step = scheduleMs[idx];
|
|
3369
|
-
const base = Math.min(typeof step === "number" && step > 0 ? step : cap, cap);
|
|
3370
|
-
const jitter = 1 + (rng() * 2 - 1) * jitterRatio;
|
|
3371
|
-
return now + Math.max(0, Math.round(base * jitter));
|
|
3372
|
-
}
|
|
3373
|
-
function capExtractionRetryStateEntries(entries, maxEntries) {
|
|
3374
|
-
if (maxEntries <= 0) return [];
|
|
3375
|
-
const sorted = [...entries].sort((a, b) => a.firstFailedAt.localeCompare(b.firstFailedAt));
|
|
3376
|
-
return sorted.slice(-maxEntries);
|
|
3377
|
-
}
|
|
3378
|
-
var ExtractionRunCoordinator = class {
|
|
3379
|
-
constructor(deps) {
|
|
3380
|
-
this.deps = deps;
|
|
3381
|
-
}
|
|
3382
|
-
deps;
|
|
3383
|
-
recentExtractionFingerprints = /* @__PURE__ */ new Map();
|
|
3384
|
-
// Per-fingerprint extraction retry/backoff state (extraction hot-loop
|
|
3385
|
-
// hardening). Outer key = namespace, inner key = fingerprint. Hydrated lazily
|
|
3386
|
-
// from namespace-scoped meta so the hot path is a Map lookup; persisted back
|
|
3387
|
-
// to meta on change (restart-safe, cross-process coherent via the shared
|
|
3388
|
-
// meta.json). The breaker below is intentionally per-process in-memory
|
|
3389
|
-
// (mirrors local-llm.cooldownUntilMs); a restart clears it but the persisted
|
|
3390
|
-
// backoff still throttles, so a restart can't resurrect the hot loop.
|
|
3391
|
-
extractionRetryState = /* @__PURE__ */ new Map();
|
|
3392
|
-
hydratedRetryNamespaces = /* @__PURE__ */ new Set();
|
|
3393
|
-
providerBreaker = { consecutiveFailures: 0, openUntilMs: 0, state: "closed", lastReason: "" };
|
|
3394
|
-
get config() {
|
|
3395
|
-
return this.deps.config;
|
|
3396
|
-
}
|
|
3397
|
-
// -------------------------------------------------------------------------
|
|
3398
|
-
// Source-valid-at helpers (moved from orchestrator.ts module scope)
|
|
3399
|
-
// -------------------------------------------------------------------------
|
|
3400
|
-
latestSourceValidAtFromTurns(turns) {
|
|
3401
|
-
let latestMs = null;
|
|
3402
|
-
for (const turn of turns) {
|
|
3403
|
-
if (turn.extractionContextOnly === true) continue;
|
|
3404
|
-
if (typeof turn.sourceValidAt !== "string") continue;
|
|
3405
|
-
const parsed = parseFlexibleIsoTimestamp(turn.sourceValidAt.trim());
|
|
3406
|
-
if (parsed === null) continue;
|
|
3407
|
-
if (latestMs === null || parsed > latestMs) {
|
|
3408
|
-
latestMs = parsed;
|
|
3409
|
-
}
|
|
3410
|
-
}
|
|
3411
|
-
return latestMs === null ? void 0 : new Date(latestMs).toISOString();
|
|
3412
|
-
}
|
|
3413
|
-
// -------------------------------------------------------------------------
|
|
3414
|
-
// Extraction dedupe fingerprint helpers
|
|
3415
|
-
// -------------------------------------------------------------------------
|
|
3416
|
-
normalizeExtractionFingerprintTurns(turns) {
|
|
3417
|
-
if (!Array.isArray(turns) || turns.length === 0) return [];
|
|
3418
|
-
return turns.filter((turn) => turn.role === "user" || turn.role === "assistant").map((turn) => {
|
|
3419
|
-
if (typeof turn.turnFingerprint === "string" && turn.turnFingerprint.length > 0) {
|
|
3420
|
-
return `fp:${turn.turnFingerprint}`;
|
|
3421
|
-
}
|
|
3422
|
-
return `${turn.role}:${(turn.content ?? "").replace(/\s+/g, " ").trim().slice(0, this.config.extractionMaxTurnChars)}`;
|
|
3423
|
-
}).filter((value) => value.length > 0);
|
|
3424
|
-
}
|
|
3425
|
-
buildExtractionFingerprint(turns, bufferKey) {
|
|
3426
|
-
const normalized = this.normalizeExtractionFingerprintTurns(turns).join("\n");
|
|
3427
|
-
if (!normalized) return null;
|
|
3428
|
-
return createHash3("sha256").update(`${bufferKey}
|
|
3429
|
-
${normalized}`).digest("hex");
|
|
3430
|
-
}
|
|
3431
|
-
shouldQueueExtraction(turns, options = {}) {
|
|
3432
|
-
const lifecycleCaps = resolveMemoryLifecycleCapabilities(this.config);
|
|
3433
|
-
if (!lifecycleCaps.extractionDedupe) return true;
|
|
3434
|
-
if (!Array.isArray(turns) || turns.length === 0) return false;
|
|
3435
|
-
const bufferKey = options.bufferKey ?? turns[0]?.sessionKey ?? "default";
|
|
3436
|
-
const fingerprint = this.buildExtractionFingerprint(turns, bufferKey);
|
|
3437
|
-
if (!fingerprint) return false;
|
|
3438
|
-
const now = Date.now();
|
|
3439
|
-
const seenAt = this.recentExtractionFingerprints.get(fingerprint);
|
|
3440
|
-
if (seenAt && now - seenAt < this.config.extractionDedupeWindowMs) {
|
|
3441
|
-
log.debug("extraction dedupe: skipped duplicate buffered turn set");
|
|
3442
|
-
return false;
|
|
3443
|
-
}
|
|
3444
|
-
if (options.commit !== false) {
|
|
3445
|
-
this.recentExtractionFingerprints.set(fingerprint, now);
|
|
3446
|
-
}
|
|
3447
|
-
if (options.commit !== false && this.recentExtractionFingerprints.size > 200) {
|
|
3448
|
-
const entries = Array.from(this.recentExtractionFingerprints.entries()).sort((a, b) => a[1] - b[1]);
|
|
3449
|
-
for (const [key] of entries.slice(0, entries.length - 200)) {
|
|
3450
|
-
this.recentExtractionFingerprints.delete(key);
|
|
3451
|
-
}
|
|
3452
|
-
}
|
|
3453
|
-
return true;
|
|
3454
|
-
}
|
|
3455
|
-
// -------------------------------------------------------------------------
|
|
3456
|
-
// Processed-fingerprint recording
|
|
3457
|
-
// -------------------------------------------------------------------------
|
|
3458
|
-
async recordProcessedExtractionFingerprint(storage, fingerprint, preloadedMeta) {
|
|
3459
|
-
const meta = preloadedMeta ?? await storage.loadMeta();
|
|
3460
|
-
const observedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
3461
|
-
const seen = new Map(
|
|
3462
|
-
(meta.processedExtractionFingerprints ?? []).map((entry) => [entry.fingerprint, entry.observedAt])
|
|
3463
|
-
);
|
|
3464
|
-
seen.set(fingerprint, observedAt);
|
|
3465
|
-
meta.processedExtractionFingerprints = Array.from(seen.entries()).map(([value, at2]) => ({ fingerprint: value, observedAt: at2 })).sort((left, right) => left.observedAt.localeCompare(right.observedAt)).slice(-500);
|
|
3466
|
-
if (!preloadedMeta) {
|
|
3467
|
-
await storage.saveMeta(meta);
|
|
3468
|
-
}
|
|
3469
|
-
}
|
|
3470
|
-
// -------------------------------------------------------------------------
|
|
3471
|
-
// Extraction retry/backoff + circuit breaker (extraction hot-loop hardening)
|
|
3472
|
-
// -------------------------------------------------------------------------
|
|
3473
|
-
/** Lazily hydrate the in-memory retry-state mirror for a namespace from meta.
|
|
3474
|
-
* One-time per namespace per coordinator; the hot path is then a Map lookup.
|
|
3475
|
-
* Cross-process coherence: a fresh coordinator hydrates from the shared
|
|
3476
|
-
* meta.json, so a failure persisted by another process is honored here. */
|
|
3477
|
-
hydrateRetryStateFromMeta(namespace, meta) {
|
|
3478
|
-
if (this.hydratedRetryNamespaces.has(namespace)) return;
|
|
3479
|
-
this.hydratedRetryNamespaces.add(namespace);
|
|
3480
|
-
const nsMap = this.extractionRetryState.get(namespace) ?? /* @__PURE__ */ new Map();
|
|
3481
|
-
for (const entry of meta.extractionRetryState ?? []) {
|
|
3482
|
-
const nextEligibleAtMs = Date.parse(entry.nextEligibleAt);
|
|
3483
|
-
const firstFailedAtMs = Date.parse(entry.firstFailedAt);
|
|
3484
|
-
nsMap.set(entry.fingerprint, {
|
|
3485
|
-
attempts: entry.attempts,
|
|
3486
|
-
nextEligibleAtMs: Number.isFinite(nextEligibleAtMs) ? nextEligibleAtMs : 0,
|
|
3487
|
-
firstFailedAtMs: Number.isFinite(firstFailedAtMs) ? firstFailedAtMs : Date.now(),
|
|
3488
|
-
lastFailureClass: entry.lastFailureClass
|
|
3489
|
-
});
|
|
3490
|
-
}
|
|
3491
|
-
this.extractionRetryState.set(namespace, nsMap);
|
|
3492
|
-
}
|
|
3493
|
-
logBreakerTransition(state) {
|
|
3494
|
-
log.warn("extraction: provider circuit breaker transition", {
|
|
3495
|
-
state,
|
|
3496
|
-
consecutiveFailures: this.providerBreaker.consecutiveFailures,
|
|
3497
|
-
lastReason: this.providerBreaker.lastReason,
|
|
3498
|
-
openUntilMs: this.providerBreaker.openUntilMs
|
|
3499
|
-
});
|
|
3500
|
-
}
|
|
3501
|
-
/** True while the breaker suppresses non-forced attempts. Flips an expired
|
|
3502
|
-
* `open` breaker to `half_open`, which allows exactly one probe (the next
|
|
3503
|
-
* non-forced attempt) because the extraction queue is a serial drain. */
|
|
3504
|
-
isProviderBreakerOpen(now) {
|
|
3505
|
-
if (now < this.providerBreaker.openUntilMs) return true;
|
|
3506
|
-
if (this.providerBreaker.state === "open") {
|
|
3507
|
-
this.providerBreaker.state = "half_open";
|
|
3508
|
-
this.logBreakerTransition("half_open");
|
|
3509
|
-
}
|
|
3510
|
-
return false;
|
|
3511
|
-
}
|
|
3512
|
-
onProviderFailure(cls, now) {
|
|
3513
|
-
this.providerBreaker.consecutiveFailures += 1;
|
|
3514
|
-
const trip = cls === "auth_config" || // A failed half-open probe re-opens immediately (standard breaker
|
|
3515
|
-
// semantics). Without this, an auth_config-opened breaker (which trips
|
|
3516
|
-
// below the threshold) would get stuck half_open after a transient
|
|
3517
|
-
// probe failure and stop suppressing (cursor review).
|
|
3518
|
-
this.providerBreaker.state === "half_open" || this.providerBreaker.consecutiveFailures >= this.config.extractionBreakerFailureThreshold;
|
|
3519
|
-
if (!trip) return;
|
|
3520
|
-
const cooldown = cls === "auth_config" ? this.config.extractionBreakerAuthCooldownMs : this.config.extractionBreakerCooldownMs;
|
|
3521
|
-
this.providerBreaker.openUntilMs = now + Math.max(0, cooldown);
|
|
3522
|
-
this.providerBreaker.lastReason = cls;
|
|
3523
|
-
if (this.providerBreaker.state !== "open") {
|
|
3524
|
-
this.providerBreaker.state = "open";
|
|
3525
|
-
this.logBreakerTransition("open");
|
|
3526
|
-
}
|
|
3527
|
-
}
|
|
3528
|
-
resetProviderBreakerOnSuccess() {
|
|
3529
|
-
const wasDisturbed = this.providerBreaker.state !== "closed" || this.providerBreaker.consecutiveFailures > 0 || this.providerBreaker.openUntilMs > 0;
|
|
3530
|
-
if (!wasDisturbed) return;
|
|
3531
|
-
const wasOpen = this.providerBreaker.state !== "closed";
|
|
3532
|
-
this.providerBreaker.consecutiveFailures = 0;
|
|
3533
|
-
this.providerBreaker.openUntilMs = 0;
|
|
3534
|
-
this.providerBreaker.lastReason = "";
|
|
3535
|
-
this.providerBreaker.state = "closed";
|
|
3536
|
-
if (wasOpen) this.logBreakerTransition("closed");
|
|
3537
|
-
}
|
|
3538
|
-
/** Rebuild `meta.extractionRetryState` from the in-memory namespace mirror,
|
|
3539
|
-
* bounded to the newest entries, and prune the mirror to match. */
|
|
3540
|
-
persistRetryStateToMeta(namespace, meta) {
|
|
3541
|
-
const nsMap = this.extractionRetryState.get(namespace);
|
|
3542
|
-
const entries = nsMap ? Array.from(nsMap.entries()).map(([fingerprint, st]) => ({
|
|
3543
|
-
fingerprint,
|
|
3544
|
-
attempts: st.attempts,
|
|
3545
|
-
nextEligibleAt: new Date(st.nextEligibleAtMs).toISOString(),
|
|
3546
|
-
firstFailedAt: new Date(st.firstFailedAtMs).toISOString(),
|
|
3547
|
-
lastFailureClass: st.lastFailureClass
|
|
3548
|
-
})) : [];
|
|
3549
|
-
const capped = capExtractionRetryStateEntries(entries, EXTRACTION_RETRY_STATE_MAX_ENTRIES);
|
|
3550
|
-
meta.extractionRetryState = capped;
|
|
3551
|
-
if (nsMap && capped.length < nsMap.size) {
|
|
3552
|
-
const kept = new Set(capped.map((e) => e.fingerprint));
|
|
3553
|
-
for (const key of Array.from(nsMap.keys())) {
|
|
3554
|
-
if (!kept.has(key)) nsMap.delete(key);
|
|
3555
|
-
}
|
|
3556
|
-
}
|
|
3557
|
-
}
|
|
3558
|
-
/** Record an extraction failure into per-fingerprint backoff state + breaker,
|
|
3559
|
-
* persisting to namespace meta. Fail-open: never throws upward. */
|
|
3560
|
-
async recordExtractionFailure(storage, namespace, fingerprint, cls, meta, now) {
|
|
3561
|
-
try {
|
|
3562
|
-
this.hydrateRetryStateFromMeta(namespace, meta);
|
|
3563
|
-
const nsMap = this.extractionRetryState.get(namespace) ?? /* @__PURE__ */ new Map();
|
|
3564
|
-
const prev = nsMap.get(fingerprint);
|
|
3565
|
-
const attempts = (prev?.attempts ?? 0) + 1;
|
|
3566
|
-
const firstFailedAtMs = prev?.firstFailedAtMs ?? now;
|
|
3567
|
-
let nextEligibleAtMs;
|
|
3568
|
-
if (cls === "parse_empty" && attempts > this.config.extractionParseEmptyMaxAttempts) {
|
|
3569
|
-
nextEligibleAtMs = now + Math.max(0, this.config.extractionRetryMaxBackoffMs);
|
|
3570
|
-
} else {
|
|
3571
|
-
nextEligibleAtMs = computeExtractionRetryNextEligibleMs(
|
|
3572
|
-
attempts,
|
|
3573
|
-
this.config.extractionRetryScheduleMs,
|
|
3574
|
-
this.config.extractionRetryMaxBackoffMs,
|
|
3575
|
-
this.config.extractionRetryJitterRatio,
|
|
3576
|
-
now
|
|
3577
|
-
);
|
|
3578
|
-
}
|
|
3579
|
-
nsMap.set(fingerprint, { attempts, nextEligibleAtMs, firstFailedAtMs, lastFailureClass: cls });
|
|
3580
|
-
this.extractionRetryState.set(namespace, nsMap);
|
|
3581
|
-
this.onProviderFailure(cls, now);
|
|
3582
|
-
this.persistRetryStateToMeta(namespace, meta);
|
|
3583
|
-
await storage.saveMeta(meta);
|
|
3584
|
-
} catch (err) {
|
|
3585
|
-
log.warn("runExtraction: failed to record extraction retry state (non-fatal)", err);
|
|
3586
|
-
}
|
|
3587
|
-
}
|
|
3588
|
-
/** Delete a fingerprint's retry entry from the mirror + meta. Returns whether
|
|
3589
|
-
* meta changed (so the caller can decide to persist). Does not touch the
|
|
3590
|
-
* breaker — callers pair this with `resetProviderBreakerOnSuccess`. */
|
|
3591
|
-
clearExtractionRetryEntry(namespace, fingerprint, meta) {
|
|
3592
|
-
const nsMap = this.extractionRetryState.get(namespace);
|
|
3593
|
-
if (!nsMap?.has(fingerprint)) return false;
|
|
3594
|
-
nsMap.delete(fingerprint);
|
|
3595
|
-
this.persistRetryStateToMeta(namespace, meta);
|
|
3596
|
-
return true;
|
|
3597
|
-
}
|
|
3598
|
-
/** Live in-process resilience snapshot (breaker + backoff population). */
|
|
3599
|
-
getExtractionResilienceStatus() {
|
|
3600
|
-
let backoffFingerprintCount = 0;
|
|
3601
|
-
for (const nsMap of this.extractionRetryState.values()) {
|
|
3602
|
-
backoffFingerprintCount += nsMap.size;
|
|
3603
|
-
}
|
|
3604
|
-
return {
|
|
3605
|
-
breaker: {
|
|
3606
|
-
state: this.providerBreaker.state,
|
|
3607
|
-
openUntilMs: this.providerBreaker.openUntilMs,
|
|
3608
|
-
consecutiveFailures: this.providerBreaker.consecutiveFailures,
|
|
3609
|
-
lastReason: this.providerBreaker.lastReason
|
|
3610
|
-
},
|
|
3611
|
-
backoffFingerprintCount
|
|
3612
|
-
};
|
|
3613
|
-
}
|
|
3614
|
-
// -------------------------------------------------------------------------
|
|
3615
|
-
// Main extraction pipeline
|
|
3616
|
-
// -------------------------------------------------------------------------
|
|
3617
|
-
async runExtraction(turns, options = {}) {
|
|
3618
|
-
log.debug(`running extraction on ${turns.length} turns`);
|
|
3619
|
-
const clearBufferAfterExtraction = options.clearBufferAfterExtraction ?? true;
|
|
3620
|
-
const skipCharThreshold = options.skipCharThreshold ?? false;
|
|
3621
|
-
const skipUserTurnThreshold = options.skipUserTurnThreshold ?? false;
|
|
3622
|
-
const deadlineMs = typeof options.deadlineMs === "number" && Number.isFinite(options.deadlineMs) ? options.deadlineMs : void 0;
|
|
3623
|
-
const bufferKey = options.bufferKey ?? turns[0]?.sessionKey ?? "default";
|
|
3624
|
-
const throwIfDeadlineExceeded = (stage) => {
|
|
3625
|
-
if (typeof deadlineMs === "number" && Date.now() > deadlineMs) {
|
|
3626
|
-
throw new Error(`replay extraction deadline exceeded (${stage})`);
|
|
3627
|
-
}
|
|
3628
|
-
};
|
|
3629
|
-
const throwIfAborted2 = (stage) => {
|
|
3630
|
-
throwIfRecallAborted(options.abortSignal, `extraction aborted (${stage})`);
|
|
3631
|
-
};
|
|
3632
|
-
const clearBuffer = async (options2) => {
|
|
3633
|
-
if (options2?.ignoreAbort !== true) {
|
|
3634
|
-
throwIfAborted2("before_clear_buffer");
|
|
3635
|
-
}
|
|
3636
|
-
if (clearBufferAfterExtraction) {
|
|
3637
|
-
await this.deps.getBuffer().clearAfterExtraction(bufferKey, turns);
|
|
3638
|
-
}
|
|
3639
|
-
};
|
|
3640
|
-
const sessionKey = turns[0]?.sessionKey ?? "";
|
|
3641
|
-
if (sessionKey.includes(":cron:")) {
|
|
3642
|
-
log.debug(`skipping extraction for cron session: ${sessionKey}`);
|
|
3643
|
-
await clearBuffer();
|
|
3644
|
-
return {
|
|
3645
|
-
status: "skipped",
|
|
3646
|
-
reason: "cron_session",
|
|
3647
|
-
persistedCount: 0,
|
|
3648
|
-
durableOutputCount: 0
|
|
3649
|
-
};
|
|
3650
|
-
}
|
|
3651
|
-
const normalizedTurns = turns.filter((t) => (t.role === "user" || t.role === "assistant") && typeof t.content === "string").map((t) => ({
|
|
3652
|
-
...t,
|
|
3653
|
-
content: t.content.trim().slice(0, this.config.extractionMaxTurnChars)
|
|
3654
|
-
})).filter((t) => t.content.length > 0);
|
|
3655
|
-
const targetTurns = normalizedTurns.filter((turn) => turn.extractionContextOnly !== true);
|
|
3656
|
-
if (targetTurns.length === 0) {
|
|
3657
|
-
log.debug("skipping extraction: no non-context turns after normalization");
|
|
3658
|
-
if (normalizedTurns.length > 0) {
|
|
3659
|
-
await this.deps.maybeCapturePassiveCorrections(normalizedTurns, {
|
|
3660
|
-
sessionKey,
|
|
3661
|
-
principal: resolvePrincipal(sessionKey, this.config),
|
|
3662
|
-
namespace: this.deps.resolveSelfNamespace(sessionKey),
|
|
3663
|
-
bufferKey,
|
|
3664
|
-
isLiveSession: clearBufferAfterExtraction
|
|
3665
|
-
});
|
|
3666
|
-
}
|
|
3667
|
-
await clearBuffer();
|
|
3668
|
-
return { status: "skipped", reason: "empty_normalized_turns", persistedCount: 0, durableOutputCount: 0 };
|
|
3669
|
-
}
|
|
3670
|
-
const sourceValidAt = this.latestSourceValidAtFromTurns(targetTurns);
|
|
3671
|
-
throwIfDeadlineExceeded("before_extract");
|
|
3672
|
-
throwIfAborted2("before_extract");
|
|
3673
|
-
const userTurns = targetTurns.filter((t) => t.role === "user");
|
|
3674
|
-
const totalChars = targetTurns.reduce((sum, t) => sum + t.content.length, 0);
|
|
3675
|
-
const belowCharThreshold = totalChars < this.config.extractionMinChars;
|
|
3676
|
-
const belowUserTurnThreshold = !skipUserTurnThreshold && userTurns.length < this.config.extractionMinUserTurns;
|
|
3677
|
-
if (!skipCharThreshold && belowCharThreshold || belowUserTurnThreshold) {
|
|
3678
|
-
log.debug(`skipping extraction: below threshold (totalChars=${totalChars}, userTurns=${userTurns.length})`);
|
|
3679
|
-
await clearBuffer();
|
|
3680
|
-
{
|
|
3681
|
-
const capturePrincipal = typeof options.principalOverride === "string" && options.principalOverride.length > 0 ? options.principalOverride : resolvePrincipal(sessionKey, this.config);
|
|
3682
|
-
const captureWO = typeof options.writeNamespaceOverride === "string" && options.writeNamespaceOverride.length > 0 ? options.writeNamespaceOverride : void 0;
|
|
3683
|
-
const captureCodingCtx = sessionKey ? this.deps.getCodingContextForSession(sessionKey) : null;
|
|
3684
|
-
const captureCodingOv = resolveCodingNamespaceOverlay(
|
|
3685
|
-
captureCodingCtx,
|
|
3686
|
-
this.config.codingMode,
|
|
3687
|
-
this.config.defaultNamespace
|
|
3688
|
-
);
|
|
3689
|
-
const captureScopePlan = resolveScopeProfilePlan({
|
|
3690
|
-
config: this.config,
|
|
3691
|
-
principal: capturePrincipal,
|
|
3692
|
-
codingContext: captureCodingCtx,
|
|
3693
|
-
codingOverlay: captureCodingOv
|
|
3694
|
-
});
|
|
3695
|
-
const captureNamespace = captureWO ?? captureScopePlan?.writeNamespace ?? this.deps.resolveSelfNamespace(sessionKey);
|
|
3696
|
-
await this.deps.maybeCapturePassiveCorrections(normalizedTurns, {
|
|
3697
|
-
sessionKey,
|
|
3698
|
-
principal: capturePrincipal,
|
|
3699
|
-
namespace: captureNamespace,
|
|
3700
|
-
bufferKey,
|
|
3701
|
-
isLiveSession: clearBufferAfterExtraction
|
|
3702
|
-
});
|
|
3703
|
-
}
|
|
3704
|
-
return {
|
|
3705
|
-
status: "skipped",
|
|
3706
|
-
reason: "below_threshold",
|
|
3707
|
-
persistedCount: 0,
|
|
3708
|
-
durableOutputCount: 0
|
|
3709
|
-
};
|
|
3710
|
-
}
|
|
3711
|
-
const principal = typeof options.principalOverride === "string" && options.principalOverride.length > 0 ? options.principalOverride : resolvePrincipal(sessionKey, this.config);
|
|
3712
|
-
const explicitWriteNamespace = typeof options.writeNamespaceOverride === "string" && options.writeNamespaceOverride.length > 0 ? options.writeNamespaceOverride : void 0;
|
|
3713
|
-
const codingContextForWrite = sessionKey ? this.deps.getCodingContextForSession(sessionKey) : null;
|
|
3714
|
-
const codingOverlayForWrite = resolveCodingNamespaceOverlay(
|
|
3715
|
-
codingContextForWrite,
|
|
3716
|
-
this.config.codingMode,
|
|
3717
|
-
this.config.defaultNamespace
|
|
3718
|
-
);
|
|
3719
|
-
const scopeProfileGatePlan = resolveScopeProfilePlan({
|
|
3720
|
-
config: this.config,
|
|
3721
|
-
principal,
|
|
3722
|
-
codingContext: codingContextForWrite,
|
|
3723
|
-
codingOverlay: codingOverlayForWrite
|
|
3724
|
-
});
|
|
3725
|
-
const scopeProfileWritePlan = explicitWriteNamespace ? null : scopeProfileGatePlan;
|
|
3726
|
-
if (scopeProfileWritePlan) {
|
|
3727
|
-
const selectedLayer = scopeProfileWritePlan.layers.find((layer) => layer.id === scopeProfileWritePlan.writeLayer);
|
|
3728
|
-
const writeNamespaceReadable = scopeProfileWritePlan.readNamespaces.includes(
|
|
3729
|
-
scopeProfileWritePlan.writeNamespace
|
|
3730
|
-
);
|
|
3731
|
-
if (!selectedLayer?.writable || !writeNamespaceReadable) {
|
|
3732
|
-
log.warn(
|
|
3733
|
-
`runExtraction: skipping scope profile ${scopeProfileWritePlan.profileId} because write layer ${scopeProfileWritePlan.writeLayer} is not writable inside the profile read stack`
|
|
3734
|
-
);
|
|
3735
|
-
await clearBuffer();
|
|
3736
|
-
return {
|
|
3737
|
-
status: "skipped",
|
|
3738
|
-
reason: "scope_profile_no_writable_layer",
|
|
3739
|
-
persistedCount: 0,
|
|
3740
|
-
durableOutputCount: 0
|
|
3741
|
-
};
|
|
3742
|
-
}
|
|
3743
|
-
}
|
|
3744
|
-
const selfNamespace = explicitWriteNamespace ?? scopeProfileWritePlan?.writeNamespace ?? this.deps.applyCodingNamespaceOverlay(sessionKey, defaultNamespaceForPrincipal(principal, this.config));
|
|
3745
|
-
const storage = await this.deps.getStorageRouter().storageFor(selfNamespace);
|
|
3746
|
-
const shouldPersistProcessedFingerprint = targetTurns.some((turn) => turn.persistProcessedFingerprint === true);
|
|
3747
|
-
const extractionFingerprint = this.buildExtractionFingerprint(targetTurns, bufferKey);
|
|
3748
|
-
let meta = extractionFingerprint && shouldPersistProcessedFingerprint ? await storage.loadMeta() : null;
|
|
3749
|
-
if (extractionFingerprint && shouldPersistProcessedFingerprint && (meta?.processedExtractionFingerprints ?? []).some((entry) => entry.fingerprint === extractionFingerprint)) {
|
|
3750
|
-
log.debug(`runExtraction: skipping already-processed extraction fingerprint for ${bufferKey}`);
|
|
3751
|
-
await clearBuffer();
|
|
3752
|
-
return {
|
|
3753
|
-
status: "skipped",
|
|
3754
|
-
reason: "processed_fingerprint",
|
|
3755
|
-
persistedCount: 0,
|
|
3756
|
-
durableOutputCount: 0
|
|
3757
|
-
};
|
|
3758
|
-
}
|
|
3759
|
-
const forcedExtractionAttempt = options.failOnExtractionFailure === true || options.forceExtractionAttempt === true;
|
|
3760
|
-
const extractionRetryEnabled = resolveMemoryLifecycleCapabilities(this.config).extractionRetry;
|
|
3761
|
-
if (extractionFingerprint && !forcedExtractionAttempt && extractionRetryEnabled) {
|
|
3762
|
-
try {
|
|
3763
|
-
meta ??= await storage.loadMeta();
|
|
3764
|
-
this.hydrateRetryStateFromMeta(selfNamespace, meta);
|
|
3765
|
-
const nowMs = Date.now();
|
|
3766
|
-
let suppressReason = null;
|
|
3767
|
-
if (this.isProviderBreakerOpen(nowMs)) {
|
|
3768
|
-
suppressReason = "provider_circuit_open";
|
|
3769
|
-
} else {
|
|
3770
|
-
const st = this.extractionRetryState.get(selfNamespace)?.get(extractionFingerprint);
|
|
3771
|
-
if (st && nowMs < st.nextEligibleAtMs) suppressReason = "extraction_backoff";
|
|
3772
|
-
}
|
|
3773
|
-
if (suppressReason) {
|
|
3774
|
-
try {
|
|
3775
|
-
await this.deps.maybeCapturePassiveCorrections(normalizedTurns, {
|
|
3776
|
-
sessionKey,
|
|
3777
|
-
principal,
|
|
3778
|
-
namespace: selfNamespace,
|
|
3779
|
-
bufferKey,
|
|
3780
|
-
isLiveSession: clearBufferAfterExtraction
|
|
3781
|
-
});
|
|
3782
|
-
} catch (captureErr) {
|
|
3783
|
-
log.warn("runExtraction: passive correction capture failed on suppressed attempt (non-fatal)", captureErr);
|
|
3784
|
-
}
|
|
3785
|
-
return { status: "skipped", reason: suppressReason, persistedCount: 0, durableOutputCount: 0 };
|
|
3786
|
-
}
|
|
3787
|
-
} catch (err) {
|
|
3788
|
-
log.warn("runExtraction: extraction retry gate check failed; proceeding (fail-open)", err);
|
|
3789
|
-
}
|
|
3790
|
-
}
|
|
3791
|
-
const existingEntities = await storage.listEntityNames();
|
|
3792
|
-
const result = await raceRecallAbort(
|
|
3793
|
-
this.deps.getExtraction().extract(normalizedTurns, existingEntities),
|
|
3794
|
-
options.abortSignal,
|
|
3795
|
-
"extraction aborted (during_extract)"
|
|
3796
|
-
);
|
|
3797
|
-
throwIfDeadlineExceeded("before_persist");
|
|
3798
|
-
throwIfAborted2("before_persist");
|
|
3799
|
-
if (!result) {
|
|
3800
|
-
log.warn("runExtraction: extraction returned null/undefined");
|
|
3801
|
-
if (options.failOnExtractionFailure) {
|
|
3802
|
-
throw new Error("extraction failed: invalid_extraction_result");
|
|
3803
|
-
}
|
|
3804
|
-
await clearBuffer();
|
|
3805
|
-
return {
|
|
3806
|
-
status: "skipped",
|
|
3807
|
-
reason: "invalid_extraction_result",
|
|
3808
|
-
persistedCount: 0,
|
|
3809
|
-
durableOutputCount: 0
|
|
3810
|
-
};
|
|
3811
|
-
}
|
|
3812
|
-
const invalidExtractionResultFields = [
|
|
3813
|
-
["facts", result.facts],
|
|
3814
|
-
["entities", result.entities],
|
|
3815
|
-
["questions", result.questions],
|
|
3816
|
-
["profileUpdates", result.profileUpdates]
|
|
3817
|
-
].filter(([, value]) => !Array.isArray(value)).map(([field]) => field);
|
|
3818
|
-
if (invalidExtractionResultFields.length > 0) {
|
|
3819
|
-
log.warn("runExtraction: extraction returned invalid collection fields", {
|
|
3820
|
-
invalidFields: invalidExtractionResultFields,
|
|
3821
|
-
resultKeys: typeof result === "object" && result !== null ? Object.keys(result) : []
|
|
3822
|
-
});
|
|
3823
|
-
if (options.failOnExtractionFailure) {
|
|
3824
|
-
throw new Error("extraction failed: invalid_extraction_result");
|
|
3825
|
-
}
|
|
3826
|
-
await clearBuffer();
|
|
3827
|
-
return {
|
|
3828
|
-
status: "skipped",
|
|
3829
|
-
reason: "invalid_extraction_result",
|
|
3830
|
-
persistedCount: 0,
|
|
3831
|
-
durableOutputCount: 0
|
|
3832
|
-
};
|
|
3833
|
-
}
|
|
3834
|
-
const extractionFailure = typeof result.extractionFailure === "string" && result.extractionFailure.trim().length > 0 ? result.extractionFailure : void 0;
|
|
3835
|
-
let recordedRetryFailure = false;
|
|
3836
|
-
if (extractionFingerprint && extractionRetryEnabled) {
|
|
3837
|
-
if (extractionFailure) {
|
|
3838
|
-
try {
|
|
3839
|
-
meta ??= await storage.loadMeta();
|
|
3840
|
-
await this.recordExtractionFailure(
|
|
3841
|
-
storage,
|
|
3842
|
-
selfNamespace,
|
|
3843
|
-
extractionFingerprint,
|
|
3844
|
-
result.extractionFailureClass ?? "provider_retryable",
|
|
3845
|
-
meta,
|
|
3846
|
-
Date.now()
|
|
3847
|
-
);
|
|
3848
|
-
recordedRetryFailure = true;
|
|
3849
|
-
} catch (err) {
|
|
3850
|
-
log.warn("runExtraction: failed to load meta for retry bookkeeping (non-fatal)", err);
|
|
3851
|
-
}
|
|
3852
|
-
} else {
|
|
3853
|
-
this.resetProviderBreakerOnSuccess();
|
|
3854
|
-
try {
|
|
3855
|
-
meta ??= await storage.loadMeta();
|
|
3856
|
-
this.hydrateRetryStateFromMeta(selfNamespace, meta);
|
|
3857
|
-
if (this.clearExtractionRetryEntry(selfNamespace, extractionFingerprint, meta)) {
|
|
3858
|
-
await storage.saveMeta(meta);
|
|
3859
|
-
}
|
|
3860
|
-
} catch (err) {
|
|
3861
|
-
log.warn("runExtraction: failed to persist cleared retry state (non-fatal)", err);
|
|
3862
|
-
}
|
|
3863
|
-
}
|
|
3864
|
-
}
|
|
3865
|
-
if (options.failOnExtractionFailure && extractionFailure) {
|
|
3866
|
-
throw new Error(`extraction failed: ${extractionFailure}`);
|
|
3867
|
-
}
|
|
3868
|
-
if (result.facts.length === 0 && result.entities.length === 0 && result.questions.length === 0 && result.profileUpdates.length === 0) {
|
|
3869
|
-
log.debug("runExtraction: extraction produced no durable outputs; skipping persistence");
|
|
3870
|
-
if (extractionFailure) {
|
|
3871
|
-
log.warn(
|
|
3872
|
-
"runExtraction: extraction reported failure with no durable outputs; not marking fingerprint processed",
|
|
3873
|
-
{ extractionFailure }
|
|
3874
|
-
);
|
|
3875
|
-
}
|
|
3876
|
-
if (extractionFingerprint && shouldPersistProcessedFingerprint && !extractionFailure) {
|
|
3877
|
-
meta ??= await storage.loadMeta();
|
|
3878
|
-
await this.deps.recordProcessedExtractionFingerprint(storage, extractionFingerprint, meta);
|
|
3879
|
-
meta.extractionCount += 1;
|
|
3880
|
-
meta.lastExtractionAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
3881
|
-
await storage.saveMeta(meta);
|
|
3882
|
-
}
|
|
3883
|
-
await this.deps.maybeCapturePassiveCorrections(normalizedTurns, {
|
|
3884
|
-
sessionKey,
|
|
3885
|
-
principal,
|
|
3886
|
-
namespace: selfNamespace,
|
|
3887
|
-
bufferKey,
|
|
3888
|
-
isLiveSession: clearBufferAfterExtraction
|
|
3889
|
-
});
|
|
3890
|
-
if (recordedRetryFailure) {
|
|
3891
|
-
log.debug("runExtraction: retaining buffer for backoff retry after failure");
|
|
3892
|
-
} else {
|
|
3893
|
-
await clearBuffer();
|
|
3894
|
-
}
|
|
3895
|
-
return { status: "skipped", reason: "empty_extraction_result", persistedCount: 0, durableOutputCount: 0 };
|
|
3896
|
-
}
|
|
3897
|
-
let threadIdForExtraction = null;
|
|
3898
|
-
if (resolvePresentationCapabilities(this.config).threading && turns.length > 0) {
|
|
3899
|
-
const lastTurn = turns[turns.length - 1];
|
|
3900
|
-
try {
|
|
3901
|
-
threadIdForExtraction = await this.deps.getThreading().processTurn(lastTurn, []);
|
|
3902
|
-
} catch (err) {
|
|
3903
|
-
log.warn("[threading] processTurn failed before persistence (non-fatal)", err);
|
|
3904
|
-
}
|
|
3905
|
-
}
|
|
3906
|
-
const { persistedIds } = await this.deps.persistExtraction(
|
|
3907
|
-
result,
|
|
3908
|
-
storage,
|
|
3909
|
-
threadIdForExtraction,
|
|
3910
|
-
{ sessionKey, principal, validAt: sourceValidAt, sourceConnector: deriveSourceConnector(targetTurns) },
|
|
3911
|
-
// Pass the KNOWN base namespace (NHIdx) so the catalog write touch records the
|
|
3912
|
-
// real namespace rather than a guess decoded from the storage dir.
|
|
3913
|
-
selfNamespace,
|
|
3914
|
-
scopeProfileGatePlan,
|
|
3915
|
-
// Verbatim source turns for the faithfulness gate (#1576) so it can
|
|
3916
|
-
// locate a quote per fact when #1575 spans are absent.
|
|
3917
|
-
normalizedTurns.map((t) => t.content).join("\n\n")
|
|
3918
|
-
);
|
|
3919
|
-
let postPersistMetadataFailed = false;
|
|
3920
|
-
meta ??= await storage.loadMeta();
|
|
3921
|
-
if (extractionFingerprint && shouldPersistProcessedFingerprint) {
|
|
3922
|
-
try {
|
|
3923
|
-
await this.deps.recordProcessedExtractionFingerprint(storage, extractionFingerprint, meta);
|
|
3924
|
-
} catch (error) {
|
|
3925
|
-
log.warn(
|
|
3926
|
-
"runExtraction: failed to persist processed extraction fingerprint; continuing with buffer clear",
|
|
3927
|
-
error
|
|
3928
|
-
);
|
|
3929
|
-
postPersistMetadataFailed = true;
|
|
3930
|
-
}
|
|
3931
|
-
}
|
|
3932
|
-
meta.extractionCount += 1;
|
|
3933
|
-
meta.lastExtractionAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
3934
|
-
meta.totalMemories += Array.isArray(result?.facts) ? result.facts.length : 0;
|
|
3935
|
-
meta.totalEntities += Array.isArray(result?.entities) ? result.entities.length : 0;
|
|
3936
|
-
try {
|
|
3937
|
-
await storage.saveMeta(meta);
|
|
3938
|
-
} catch (error) {
|
|
3939
|
-
log.warn(
|
|
3940
|
-
"runExtraction: failed to save extraction metadata after durable persistence; continuing with buffer clear",
|
|
3941
|
-
error
|
|
3942
|
-
);
|
|
3943
|
-
postPersistMetadataFailed = true;
|
|
3944
|
-
}
|
|
3945
|
-
const durableOutputCount = result.facts.length + result.entities.length + result.questions.length + result.profileUpdates.length;
|
|
3946
|
-
try {
|
|
3947
|
-
if (clearBufferAfterExtraction && !this.config.extractionJudgeShadow) {
|
|
3948
|
-
const deferredCount = this.deps.getLastPersistExtractionDeferredCount();
|
|
3949
|
-
if (deferredCount > 0 && normalizedTurns.length > 0) {
|
|
3950
|
-
await this.deps.getBuffer().retainDeferredTurns(bufferKey, normalizedTurns, 10);
|
|
3951
|
-
} else {
|
|
3952
|
-
await this.deps.getBuffer().retainDeferredTurns(bufferKey, [], 0);
|
|
3953
|
-
}
|
|
3954
|
-
}
|
|
3955
|
-
} catch (err) {
|
|
3956
|
-
log.debug(
|
|
3957
|
-
`extraction-judge: defer retention failed (non-fatal): ${err instanceof Error ? err.message : String(err)}`
|
|
3958
|
-
);
|
|
3959
|
-
}
|
|
3960
|
-
await clearBuffer({ ignoreAbort: true });
|
|
3961
|
-
await this.deps.maybeCapturePassiveCorrections(normalizedTurns, {
|
|
3962
|
-
sessionKey,
|
|
3963
|
-
principal,
|
|
3964
|
-
namespace: selfNamespace,
|
|
3965
|
-
bufferKey,
|
|
3966
|
-
isLiveSession: clearBufferAfterExtraction
|
|
3967
|
-
});
|
|
3968
|
-
if (resolvePresentationCapabilities(this.config).memoryBoxes && persistedIds.length > 0) {
|
|
3969
|
-
const extractionTopics = deriveTopicsFromExtraction(result);
|
|
3970
|
-
const firstUserTurn = turns.find((t) => t.role === "user");
|
|
3971
|
-
const boxGoal = firstUserTurn?.content?.slice(0, 100)?.trim() || void 0;
|
|
3972
|
-
await this.deps.boxBuilderFor(storage).onExtraction({
|
|
3973
|
-
topics: extractionTopics,
|
|
3974
|
-
memoryIds: persistedIds,
|
|
3975
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3976
|
-
goal: boxGoal
|
|
3977
|
-
}).catch((err) => log.warn("[boxes] onExtraction failed (non-fatal)", err));
|
|
3978
|
-
}
|
|
3979
|
-
if (resolvePresentationCapabilities(this.config).threading && threadIdForExtraction && persistedIds.length > 0) {
|
|
3980
|
-
await this.deps.appendPersistedThreadEpisodes(threadIdForExtraction, persistedIds);
|
|
3981
|
-
}
|
|
3982
|
-
if (resolvePresentationCapabilities(this.config).threading && threadIdForExtraction) {
|
|
3983
|
-
const conversationContent = turns.map((t) => t.content).join(" ");
|
|
3984
|
-
try {
|
|
3985
|
-
await this.deps.getThreading().updateThreadTitle(threadIdForExtraction, conversationContent);
|
|
3986
|
-
} catch (err) {
|
|
3987
|
-
log.warn("[threading] updateThreadTitle failed after persistence (non-fatal)", err);
|
|
3988
|
-
}
|
|
3989
|
-
}
|
|
3990
|
-
const nonZeroExtraction = durableOutputCount > 0;
|
|
3991
|
-
try {
|
|
3992
|
-
this.deps.maybeScheduleConsolidation(nonZeroExtraction);
|
|
3993
|
-
} catch (err) {
|
|
3994
|
-
log.warn("runExtraction: consolidation scheduling failed after persistence (non-fatal)", err);
|
|
3995
|
-
}
|
|
3996
|
-
try {
|
|
3997
|
-
this.deps.requestQmdMaintenance();
|
|
3998
|
-
} catch (err) {
|
|
3999
|
-
log.warn("runExtraction: QMD maintenance scheduling failed after persistence (non-fatal)", err);
|
|
4000
|
-
}
|
|
4001
|
-
try {
|
|
4002
|
-
await this.deps.runTierMigrationCycle(storage, "extraction");
|
|
2751
|
+
}
|
|
4003
2752
|
} catch (err) {
|
|
4004
|
-
log.warn(
|
|
2753
|
+
log.warn(
|
|
2754
|
+
`contradiction auto-resolve supersede failed for ${contradiction.supersededId}: ${err}`
|
|
2755
|
+
);
|
|
4005
2756
|
}
|
|
4006
|
-
return {
|
|
4007
|
-
status: "completed",
|
|
4008
|
-
persistedCount: persistedIds.length,
|
|
4009
|
-
durableOutputCount,
|
|
4010
|
-
postPersistMetadataFailed
|
|
4011
|
-
};
|
|
4012
2757
|
}
|
|
4013
|
-
|
|
4014
|
-
|
|
4015
|
-
|
|
4016
|
-
|
|
4017
|
-
|
|
4018
|
-
|
|
4019
|
-
|
|
4020
|
-
|
|
4021
|
-
|
|
4022
|
-
|
|
2758
|
+
// ---------------------------------------------------------------------------
|
|
2759
|
+
// Memory Linking (Phase 3A)
|
|
2760
|
+
// ---------------------------------------------------------------------------
|
|
2761
|
+
/**
|
|
2762
|
+
* Suggest links for a new memory based on similar existing memories.
|
|
2763
|
+
*/
|
|
2764
|
+
async suggestLinksForMemory(content, category, namespaceScope) {
|
|
2765
|
+
if (!this.isSearchAvailable()) return [];
|
|
2766
|
+
const results = await this.searchAcrossNamespaces({
|
|
2767
|
+
query: content,
|
|
2768
|
+
namespaces: [namespaceScope],
|
|
2769
|
+
maxResults: 5,
|
|
2770
|
+
mode: "search"
|
|
2771
|
+
});
|
|
2772
|
+
if (results.length === 0) return [];
|
|
2773
|
+
const candidates = [];
|
|
2774
|
+
for (const result of results) {
|
|
2775
|
+
const memoryId = this.extractMemoryIdsFromResults([result])[0];
|
|
2776
|
+
if (!memoryId) continue;
|
|
2777
|
+
const resultNamespace = this.namespaceFromPath(result.path);
|
|
2778
|
+
if (resultNamespace !== namespaceScope) continue;
|
|
2779
|
+
const resultStorage = await this.storageForNamespace(resultNamespace);
|
|
2780
|
+
const memory = await resultStorage.getMemoryById(memoryId);
|
|
2781
|
+
if (memory && memory.frontmatter.status !== "superseded" && memory.frontmatter.status !== "forgotten") {
|
|
2782
|
+
candidates.push({
|
|
2783
|
+
id: memory.frontmatter.id,
|
|
2784
|
+
content: memory.content,
|
|
2785
|
+
category: memory.frontmatter.category
|
|
2786
|
+
});
|
|
2787
|
+
}
|
|
4023
2788
|
}
|
|
2789
|
+
if (candidates.length === 0) return [];
|
|
2790
|
+
const extraction = this.getExtraction();
|
|
2791
|
+
const suggestions = await extraction.suggestLinks(
|
|
2792
|
+
{ content, category },
|
|
2793
|
+
candidates
|
|
2794
|
+
);
|
|
2795
|
+
if (!suggestions || suggestions.links.length === 0) return [];
|
|
2796
|
+
return suggestions.links.map((link) => ({
|
|
2797
|
+
targetId: link.targetId,
|
|
2798
|
+
linkType: link.linkType,
|
|
2799
|
+
strength: link.strength,
|
|
2800
|
+
reason: link.reason || void 0
|
|
2801
|
+
}));
|
|
4024
2802
|
}
|
|
4025
|
-
|
|
4026
|
-
return connectors.size === 1 ? [...connectors][0] : void 0;
|
|
4027
|
-
}
|
|
2803
|
+
};
|
|
4028
2804
|
|
|
4029
2805
|
// src/orchestration/consolidation-run.ts
|
|
4030
|
-
import
|
|
2806
|
+
import path4 from "path";
|
|
4031
2807
|
import { mkdir as mkdir2, readFile, writeFile as writeFile2 } from "fs/promises";
|
|
4032
2808
|
var ConsolidationRunCoordinator = class {
|
|
4033
2809
|
constructor(deps) {
|
|
@@ -4258,7 +3034,7 @@ var ConsolidationRunCoordinator = class {
|
|
|
4258
3034
|
}
|
|
4259
3035
|
if (resolveConsolidationCapabilities(config).semanticConsolidation) {
|
|
4260
3036
|
try {
|
|
4261
|
-
const stateFilePath =
|
|
3037
|
+
const stateFilePath = path4.join(
|
|
4262
3038
|
config.memoryDir,
|
|
4263
3039
|
"state",
|
|
4264
3040
|
"semantic-consolidation-last-run.json"
|
|
@@ -4306,7 +3082,7 @@ var ConsolidationRunCoordinator = class {
|
|
|
4306
3082
|
);
|
|
4307
3083
|
}
|
|
4308
3084
|
if (semResult.errors === 0 || semResult.memoriesArchived > 0) {
|
|
4309
|
-
const stateDir =
|
|
3085
|
+
const stateDir = path4.join(config.memoryDir, "state");
|
|
4310
3086
|
await mkdir2(stateDir, { recursive: true });
|
|
4311
3087
|
await writeFile2(
|
|
4312
3088
|
stateFilePath,
|
|
@@ -6229,14 +5005,14 @@ var ExtractionPersistCoordinator = class {
|
|
|
6229
5005
|
};
|
|
6230
5006
|
|
|
6231
5007
|
// src/orchestration/recall-internal.ts
|
|
6232
|
-
import { createHash as
|
|
5008
|
+
import { createHash as createHash3 } from "crypto";
|
|
6233
5009
|
import { readFile as readFile2, stat, unlink } from "fs/promises";
|
|
6234
|
-
import
|
|
5010
|
+
import path7 from "path";
|
|
6235
5011
|
|
|
6236
5012
|
// src/orchestration/graph-recall-coordinator.ts
|
|
6237
|
-
import { createHash as
|
|
5013
|
+
import { createHash as createHash2 } from "crypto";
|
|
6238
5014
|
import { mkdir as mkdir3, writeFile as writeFile3 } from "fs/promises";
|
|
6239
|
-
import
|
|
5015
|
+
import path5 from "path";
|
|
6240
5016
|
function mergeGraphExpandedResults(primary, expanded) {
|
|
6241
5017
|
const mergedByNamespaceAndPath = /* @__PURE__ */ new Map();
|
|
6242
5018
|
for (const item of [...primary, ...expanded]) {
|
|
@@ -6253,11 +5029,11 @@ function mergeGraphExpandedResults(primary, expanded) {
|
|
|
6253
5029
|
return Array.from(mergedByNamespaceAndPath.values());
|
|
6254
5030
|
}
|
|
6255
5031
|
function graphPathRelativeToStorage(storageDir, candidatePath) {
|
|
6256
|
-
const absolutePath =
|
|
6257
|
-
const rel =
|
|
5032
|
+
const absolutePath = path5.isAbsolute(candidatePath) ? candidatePath : path5.resolve(storageDir, candidatePath);
|
|
5033
|
+
const rel = path5.relative(storageDir, absolutePath);
|
|
6258
5034
|
if (!rel || rel === ".") return null;
|
|
6259
5035
|
if (rel.startsWith("..")) return null;
|
|
6260
|
-
return rel.split(
|
|
5036
|
+
return rel.split(path5.sep).join("/");
|
|
6261
5037
|
}
|
|
6262
5038
|
function normalizeGraphActivationScore(score) {
|
|
6263
5039
|
const bounded = Number.isFinite(score) && score > 0 ? score : 0;
|
|
@@ -6328,7 +5104,7 @@ var GraphRecallCoordinator = class {
|
|
|
6328
5104
|
resolvedPath = resolvedCold.result.path;
|
|
6329
5105
|
resolvedResult = resolvedCold.result;
|
|
6330
5106
|
}
|
|
6331
|
-
if (!
|
|
5107
|
+
if (!path5.isAbsolute(resolvedPath)) {
|
|
6332
5108
|
resolvedAmbiguousSeeds.set(result.path, null);
|
|
6333
5109
|
return null;
|
|
6334
5110
|
}
|
|
@@ -6353,7 +5129,7 @@ var GraphRecallCoordinator = class {
|
|
|
6353
5129
|
}
|
|
6354
5130
|
continue;
|
|
6355
5131
|
}
|
|
6356
|
-
if (
|
|
5132
|
+
if (path5.isAbsolute(result.path)) {
|
|
6357
5133
|
const resolved = await resolveAmbiguousSeedOwner(result, null);
|
|
6358
5134
|
if (resolved) {
|
|
6359
5135
|
addResultForNamespace(resolved.namespace, resolved.result);
|
|
@@ -6396,7 +5172,7 @@ var GraphRecallCoordinator = class {
|
|
|
6396
5172
|
0
|
|
6397
5173
|
);
|
|
6398
5174
|
seedPaths.push(
|
|
6399
|
-
...seedRelativePaths.map((rel) =>
|
|
5175
|
+
...seedRelativePaths.map((rel) => path5.join(storage.dir, rel))
|
|
6400
5176
|
);
|
|
6401
5177
|
const seedSet = new Set(seedRelativePaths);
|
|
6402
5178
|
const expanded = await this.graphIndexFor(storage).spreadingActivation(
|
|
@@ -6412,7 +5188,7 @@ var GraphRecallCoordinator = class {
|
|
|
6412
5188
|
for (const candidate of expanded.slice(0, perNamespaceExpandedCap)) {
|
|
6413
5189
|
if (deadlineExpired()) break;
|
|
6414
5190
|
if (seedSet.has(candidate.path)) continue;
|
|
6415
|
-
const memoryPath =
|
|
5191
|
+
const memoryPath = path5.resolve(storage.dir, candidate.path);
|
|
6416
5192
|
const memory = await storage.readMemoryByPath(memoryPath);
|
|
6417
5193
|
if (deadlineExpired()) break;
|
|
6418
5194
|
if (!memory) continue;
|
|
@@ -6440,7 +5216,7 @@ var GraphRecallCoordinator = class {
|
|
|
6440
5216
|
path: memory.path,
|
|
6441
5217
|
score,
|
|
6442
5218
|
namespace,
|
|
6443
|
-
seed:
|
|
5219
|
+
seed: path5.resolve(storage.dir, candidate.seed),
|
|
6444
5220
|
hopDepth: candidate.hopDepth,
|
|
6445
5221
|
decayedWeight: candidate.decayedWeight,
|
|
6446
5222
|
graphType: candidate.graphType,
|
|
@@ -6464,12 +5240,12 @@ var GraphRecallCoordinator = class {
|
|
|
6464
5240
|
}
|
|
6465
5241
|
async recordLastGraphRecallSnapshot(options) {
|
|
6466
5242
|
try {
|
|
6467
|
-
const snapshotPath =
|
|
5243
|
+
const snapshotPath = path5.join(
|
|
6468
5244
|
options.storage.dir,
|
|
6469
5245
|
"state",
|
|
6470
5246
|
"last_graph_recall.json"
|
|
6471
5247
|
);
|
|
6472
|
-
await mkdir3(
|
|
5248
|
+
await mkdir3(path5.dirname(snapshotPath), { recursive: true });
|
|
6473
5249
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
6474
5250
|
const totalSeedCount = options.seedPaths.length;
|
|
6475
5251
|
const totalExpandedCount = options.expandedPaths.length;
|
|
@@ -6481,7 +5257,7 @@ var GraphRecallCoordinator = class {
|
|
|
6481
5257
|
const payload = {
|
|
6482
5258
|
recordedAt: now,
|
|
6483
5259
|
mode: options.recallMode,
|
|
6484
|
-
queryHash:
|
|
5260
|
+
queryHash: createHash2("sha256").update(options.prompt).digest("hex"),
|
|
6485
5261
|
queryLength: options.prompt.length,
|
|
6486
5262
|
namespaces: options.recallNamespaces,
|
|
6487
5263
|
seedCount: totalSeedCount,
|
|
@@ -6584,7 +5360,7 @@ ${blocks.join("\n\n")}`;
|
|
|
6584
5360
|
}
|
|
6585
5361
|
|
|
6586
5362
|
// src/orchestration/generic-recall-paths.ts
|
|
6587
|
-
import
|
|
5363
|
+
import path6 from "path";
|
|
6588
5364
|
var CATEGORY_MEMORY_ROOTS = Object.fromEntries(
|
|
6589
5365
|
ALL_CATEGORY_DIRS.map((directory) => [directory, true])
|
|
6590
5366
|
);
|
|
@@ -6609,7 +5385,7 @@ function normalizeQmdUriPath(relativePath, source) {
|
|
|
6609
5385
|
}
|
|
6610
5386
|
}
|
|
6611
5387
|
function stripQmdCollectionPrefix(relativePath, policy, source) {
|
|
6612
|
-
const normalized =
|
|
5388
|
+
const normalized = path6.posix.normalize(normalizeQmdUriPath(relativePath, source).replace(/\\/g, "/"));
|
|
6613
5389
|
const slashIndex = normalized.indexOf("/");
|
|
6614
5390
|
if (slashIndex <= 0 || slashIndex >= normalized.length - 1) return normalized;
|
|
6615
5391
|
const prefix = normalized.slice(0, slashIndex);
|
|
@@ -6618,8 +5394,8 @@ function stripQmdCollectionPrefix(relativePath, policy, source) {
|
|
|
6618
5394
|
return matchesHotCollection || matchesColdCollection ? normalized.slice(slashIndex + 1) : normalized;
|
|
6619
5395
|
}
|
|
6620
5396
|
function isTopLevelArchivePath(filePath, policy = {}, source = "filesystem") {
|
|
6621
|
-
const isAbsolutePath =
|
|
6622
|
-
const relative = policy.memoryDir && isAbsolutePath ?
|
|
5397
|
+
const isAbsolutePath = path6.isAbsolute(filePath);
|
|
5398
|
+
const relative = policy.memoryDir && isAbsolutePath ? path6.relative(policy.memoryDir, path6.resolve(filePath)) : filePath;
|
|
6623
5399
|
const normalized = !isAbsolutePath ? stripQmdCollectionPrefix(relative, policy, source) : relative;
|
|
6624
5400
|
return /^(?:archive|namespaces[\\/][^\\/]+[\\/]archive)(?:[\\/]|$)/i.test(normalized);
|
|
6625
5401
|
}
|
|
@@ -6705,8 +5481,8 @@ var RecallInternalCoordinator = class {
|
|
|
6705
5481
|
timings,
|
|
6706
5482
|
logger: log
|
|
6707
5483
|
});
|
|
6708
|
-
const promptHash =
|
|
6709
|
-
const traceId =
|
|
5484
|
+
const promptHash = createHash3("sha256").update(prompt).digest("hex");
|
|
5485
|
+
const traceId = createHash3("sha256").update(`${sessionKey ?? "default"}:${recallStart}:${promptHash}`).digest("hex").slice(0, 16);
|
|
6710
5486
|
const sectionBuckets = /* @__PURE__ */ new Map();
|
|
6711
5487
|
const queryPolicy = buildRecallQueryPolicy(prompt, sessionKey, {
|
|
6712
5488
|
cronRecallPolicyEnabled: resolveRecallAuxiliaryCapabilities(this.deps.config).cronRecallPolicy,
|
|
@@ -6715,7 +5491,7 @@ var RecallInternalCoordinator = class {
|
|
|
6715
5491
|
cronConversationRecallMode: this.deps.config.cronConversationRecallMode
|
|
6716
5492
|
});
|
|
6717
5493
|
const retrievalQuery = queryPolicy.retrievalQuery || prompt;
|
|
6718
|
-
const retrievalQueryHash =
|
|
5494
|
+
const retrievalQueryHash = createHash3("sha256").update(retrievalQuery).digest("hex");
|
|
6719
5495
|
const policyVersion = this.deps.currentPolicyVersion();
|
|
6720
5496
|
let recallSource = "none";
|
|
6721
5497
|
let recalledMemoryCount = 0;
|
|
@@ -6855,7 +5631,7 @@ var RecallInternalCoordinator = class {
|
|
|
6855
5631
|
const graphExpandedResultPaths = /* @__PURE__ */ new Set();
|
|
6856
5632
|
const graphSourceLabelsForPath = (resultPath) => {
|
|
6857
5633
|
const labels = [];
|
|
6858
|
-
const normalizedPath = resultPath.split(
|
|
5634
|
+
const normalizedPath = resultPath.split(path7.sep).join("/");
|
|
6859
5635
|
const isEntityPath = normalizedPath.startsWith("entities/") || normalizedPath.includes("/entities/");
|
|
6860
5636
|
if (graphBaselinePaths.has(resultPath)) labels.push("baseline");
|
|
6861
5637
|
if (graphExpandedResultPaths.has(resultPath))
|
|
@@ -7016,7 +5792,7 @@ var RecallInternalCoordinator = class {
|
|
|
7016
5792
|
profileStorageNamespaces.map((namespace) => this.deps.storageRouter.storageFor(namespace))
|
|
7017
5793
|
);
|
|
7018
5794
|
const emptyProfileStorage = new Proxy(
|
|
7019
|
-
{ dir:
|
|
5795
|
+
{ dir: path7.join(this.deps.config.memoryDir, ".empty-scope-profile") },
|
|
7020
5796
|
{
|
|
7021
5797
|
get(target, prop) {
|
|
7022
5798
|
if (prop in target) return target[prop];
|
|
@@ -8498,11 +7274,11 @@ ${formatted}`;
|
|
|
8498
7274
|
if (!resolveRecallAuxiliaryCapabilities(this.deps.config).compactionReset) return null;
|
|
8499
7275
|
const workspaceDir = compactionWorkspaceDir || this.deps.config.workspaceDir || defaultWorkspaceDir();
|
|
8500
7276
|
const safeSessionKey = sanitizeSessionKeyForFilename(effectiveSessionKey);
|
|
8501
|
-
const signalPath =
|
|
7277
|
+
const signalPath = path7.join(
|
|
8502
7278
|
workspaceDir,
|
|
8503
7279
|
`.compaction-reset-signal-${safeSessionKey}`
|
|
8504
7280
|
);
|
|
8505
|
-
const bootPath =
|
|
7281
|
+
const bootPath = path7.join(workspaceDir, "BOOT.md");
|
|
8506
7282
|
try {
|
|
8507
7283
|
const signalStat = await stat(signalPath).catch(() => null);
|
|
8508
7284
|
if (!signalStat) return null;
|
|
@@ -10655,8 +9431,8 @@ ${tmtNode.summary}`
|
|
|
10655
9431
|
};
|
|
10656
9432
|
|
|
10657
9433
|
// src/orchestration/recall-search-pipeline.ts
|
|
10658
|
-
import { createHash as
|
|
10659
|
-
import
|
|
9434
|
+
import { createHash as createHash4 } from "crypto";
|
|
9435
|
+
import path8 from "path";
|
|
10660
9436
|
var RecallSearchPipelineCoordinator = class {
|
|
10661
9437
|
constructor(deps) {
|
|
10662
9438
|
this.deps = deps;
|
|
@@ -10821,7 +9597,7 @@ var RecallSearchPipelineCoordinator = class {
|
|
|
10821
9597
|
if (!options.onDebugSnapshot) return;
|
|
10822
9598
|
await options.onDebugSnapshot({
|
|
10823
9599
|
recordedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
10824
|
-
queryHash:
|
|
9600
|
+
queryHash: createHash4("sha256").update(prompt).digest("hex"),
|
|
10825
9601
|
queryLength: prompt.length,
|
|
10826
9602
|
collection: options.collection,
|
|
10827
9603
|
namespaces: options.recallNamespaces,
|
|
@@ -10964,7 +9740,7 @@ var RecallSearchPipelineCoordinator = class {
|
|
|
10964
9740
|
if (hits.length === 0) return [];
|
|
10965
9741
|
const results = [];
|
|
10966
9742
|
for (const hit of hits) {
|
|
10967
|
-
const fullPath =
|
|
9743
|
+
const fullPath = path8.isAbsolute(hit.path) ? hit.path : path8.join(this.deps.config.memoryDir, hit.path);
|
|
10968
9744
|
const memory = await this.deps.storage.readMemoryByPath(fullPath);
|
|
10969
9745
|
if (!memory) continue;
|
|
10970
9746
|
results.push({
|
|
@@ -11127,7 +9903,7 @@ var RecallSearchPipelineCoordinator = class {
|
|
|
11127
9903
|
const storage = await this.deps.storageRouter.storageFor(namespace);
|
|
11128
9904
|
const storageDir = typeof storage.dir === "string" && storage.dir ? storage.dir : null;
|
|
11129
9905
|
if (!storageDir) continue;
|
|
11130
|
-
const recallRoot =
|
|
9906
|
+
const recallRoot = path8.resolve(storageDir);
|
|
11131
9907
|
if (seenRecallRoots.has(recallRoot)) continue;
|
|
11132
9908
|
seenRecallRoots.add(recallRoot);
|
|
11133
9909
|
recallRoots.push(recallRoot);
|
|
@@ -11151,8 +9927,8 @@ var RecallSearchPipelineCoordinator = class {
|
|
|
11151
9927
|
if (resolvedCold) scopedResults.push(resolvedCold.result);
|
|
11152
9928
|
continue;
|
|
11153
9929
|
}
|
|
11154
|
-
if (
|
|
11155
|
-
if (recallRoots.some((recallRoot) => isPathInsideStorageRoot(recallRoot,
|
|
9930
|
+
if (path8.isAbsolute(result.path)) {
|
|
9931
|
+
if (recallRoots.some((recallRoot) => isPathInsideStorageRoot(recallRoot, path8.resolve(result.path)))) {
|
|
11156
9932
|
scopedResults.push(result);
|
|
11157
9933
|
}
|
|
11158
9934
|
continue;
|
|
@@ -11679,7 +10455,7 @@ var RecallSearchPipelineCoordinator = class {
|
|
|
11679
10455
|
};
|
|
11680
10456
|
|
|
11681
10457
|
// src/orchestration/turn-ingestion.ts
|
|
11682
|
-
import { createHash as
|
|
10458
|
+
import { createHash as createHash5, randomBytes } from "crypto";
|
|
11683
10459
|
var TurnIngestionCoordinator = class {
|
|
11684
10460
|
constructor(deps) {
|
|
11685
10461
|
this.deps = deps;
|
|
@@ -11742,6 +10518,7 @@ var TurnIngestionCoordinator = class {
|
|
|
11742
10518
|
timestamp: turn.timestamp,
|
|
11743
10519
|
sourceValidAt: turn.sourceValidAt,
|
|
11744
10520
|
sessionKey: key,
|
|
10521
|
+
...options.sessionOwnerPrincipal ? { sessionOwnerPrincipal: options.sessionOwnerPrincipal } : {},
|
|
11745
10522
|
parts: turn.parts,
|
|
11746
10523
|
rawContent: turn.rawContent,
|
|
11747
10524
|
sourceFormat: turn.sourceFormat,
|
|
@@ -11863,7 +10640,7 @@ var TurnIngestionCoordinator = class {
|
|
|
11863
10640
|
const shouldUseStableBatchKey = turns.some(
|
|
11864
10641
|
(turn) => turn.persistProcessedFingerprint === true || typeof turn.turnFingerprint === "string" && turn.turnFingerprint.length > 0
|
|
11865
10642
|
);
|
|
11866
|
-
const stableBatchFingerprint = shouldUseStableBatchKey ?
|
|
10643
|
+
const stableBatchFingerprint = shouldUseStableBatchKey ? createHash5("sha256").update(
|
|
11867
10644
|
turns.map(
|
|
11868
10645
|
(turn) => [
|
|
11869
10646
|
turn.role,
|
|
@@ -12058,41 +10835,70 @@ var TurnIngestionCoordinator = class {
|
|
|
12058
10835
|
timeout = void 0;
|
|
12059
10836
|
}
|
|
12060
10837
|
};
|
|
10838
|
+
let abortHandler;
|
|
10839
|
+
const clearAbortListener = () => {
|
|
10840
|
+
if (abortHandler && options.abortSignal) {
|
|
10841
|
+
options.abortSignal.removeEventListener("abort", abortHandler);
|
|
10842
|
+
abortHandler = void 0;
|
|
10843
|
+
}
|
|
10844
|
+
};
|
|
12061
10845
|
const settleTask = (error, result) => {
|
|
12062
10846
|
if (settled) return false;
|
|
12063
10847
|
settled = true;
|
|
12064
10848
|
clearQueueWaitTimer();
|
|
10849
|
+
clearAbortListener();
|
|
12065
10850
|
options.onTaskSettled?.(error, result);
|
|
12066
10851
|
return true;
|
|
12067
10852
|
};
|
|
12068
|
-
if (
|
|
12069
|
-
const
|
|
12070
|
-
|
|
12071
|
-
|
|
10853
|
+
if (options.abortSignal) {
|
|
10854
|
+
const signal = options.abortSignal;
|
|
10855
|
+
abortHandler = () => settleTask(signal.reason ?? abortError("extraction aborted (queue_wait)"));
|
|
10856
|
+
signal.addEventListener("abort", abortHandler, { once: true });
|
|
10857
|
+
if (signal.aborted) {
|
|
10858
|
+
settleTask(signal.reason ?? abortError("extraction aborted (queue_wait)"));
|
|
12072
10859
|
return;
|
|
12073
10860
|
}
|
|
12074
|
-
|
|
12075
|
-
|
|
12076
|
-
|
|
10861
|
+
}
|
|
10862
|
+
if (typeof extractionDeadlineMs === "number") {
|
|
10863
|
+
const deadline = extractionDeadlineMs;
|
|
10864
|
+
const maxTimerDelayMs = 2147483647;
|
|
10865
|
+
const scheduleQueueWaitTimeout = () => {
|
|
10866
|
+
const remainingMs = deadline - Date.now();
|
|
10867
|
+
if (remainingMs <= 0) {
|
|
10868
|
+
settleTask(new ExtractionDeadlineError("queue_wait"));
|
|
10869
|
+
return;
|
|
10870
|
+
}
|
|
10871
|
+
timeout = setTimeout(() => {
|
|
10872
|
+
if (Date.now() >= deadline) {
|
|
10873
|
+
settleTask(new ExtractionDeadlineError("queue_wait"));
|
|
10874
|
+
} else {
|
|
10875
|
+
scheduleQueueWaitTimeout();
|
|
10876
|
+
}
|
|
10877
|
+
}, Math.min(remainingMs, maxTimerDelayMs));
|
|
10878
|
+
};
|
|
10879
|
+
scheduleQueueWaitTimeout();
|
|
12077
10880
|
}
|
|
12078
10881
|
this.deps.extractionQueueCoordinator.enqueue(async () => {
|
|
12079
10882
|
if (settled) return;
|
|
12080
10883
|
if (typeof extractionDeadlineMs === "number" && extractionDeadlineMs <= Date.now()) {
|
|
12081
|
-
settleTask(new
|
|
10884
|
+
settleTask(new ExtractionDeadlineError("queue_wait"));
|
|
12082
10885
|
return;
|
|
12083
10886
|
}
|
|
12084
10887
|
clearQueueWaitTimer();
|
|
12085
10888
|
try {
|
|
12086
10889
|
const result = await this.deps.runExtraction(turnsToExtract, {
|
|
12087
10890
|
clearBufferAfterExtraction: options.clearBufferAfterExtraction ?? true,
|
|
10891
|
+
clearMatchingTurns: options.clearMatchingTurns === true,
|
|
12088
10892
|
skipCharThreshold: options.skipCharThreshold ?? false,
|
|
12089
10893
|
skipUserTurnThreshold: options.skipUserTurnThreshold ?? false,
|
|
12090
10894
|
deadlineMs: extractionDeadlineMs,
|
|
12091
10895
|
bufferKey,
|
|
10896
|
+
onDurableCommit: options.onDurableCommit,
|
|
12092
10897
|
abortSignal: options.abortSignal,
|
|
12093
10898
|
failOnExtractionFailure: options.failOnExtractionFailure === true,
|
|
12094
10899
|
writeNamespaceOverride: options.writeNamespaceOverride,
|
|
12095
10900
|
principalOverride: options.principalOverride,
|
|
10901
|
+
scopeProfileWritePlan: options.scopeProfileWritePlan,
|
|
12096
10902
|
forceExtractionAttempt: options.forceExtractionAttempt === true
|
|
12097
10903
|
});
|
|
12098
10904
|
settleTask(void 0, result);
|
|
@@ -12138,11 +10944,12 @@ var TurnIngestionCoordinator = class {
|
|
|
12138
10944
|
bufferKey: opts.bufferKey,
|
|
12139
10945
|
sessionKey: opts.sessionKey,
|
|
12140
10946
|
principal: opts.principal,
|
|
12141
|
-
namespace: opts.namespace
|
|
10947
|
+
namespace: opts.namespace,
|
|
10948
|
+
abortSignal: opts.abortSignal
|
|
12142
10949
|
},
|
|
12143
10950
|
captureConfig,
|
|
12144
10951
|
{
|
|
12145
|
-
planCorrection: (req) => service.plan(req),
|
|
10952
|
+
planCorrection: (req, planOpts) => service.plan(req, planOpts),
|
|
12146
10953
|
applyCorrection: (planId, applyOpts) => service.apply(planId, applyOpts),
|
|
12147
10954
|
storageDir: async (ns) => (await this.deps.getStorage(ns)).dir,
|
|
12148
10955
|
// Resolve `[m:xxxx]` handles to concrete memory ids via the single
|
|
@@ -12175,7 +10982,7 @@ var TurnIngestionCoordinator = class {
|
|
|
12175
10982
|
|
|
12176
10983
|
// src/orchestration/recall-introspection.ts
|
|
12177
10984
|
import { mkdir as mkdir5, readFile as readFile4, writeFile as writeFile5 } from "fs/promises";
|
|
12178
|
-
import
|
|
10985
|
+
import path10 from "path";
|
|
12179
10986
|
|
|
12180
10987
|
// src/taxonomy/default-taxonomy.ts
|
|
12181
10988
|
var DEFAULT_TAXONOMY = {
|
|
@@ -12298,7 +11105,7 @@ function generateResolverDocument(taxonomy) {
|
|
|
12298
11105
|
|
|
12299
11106
|
// src/taxonomy/taxonomy-loader.ts
|
|
12300
11107
|
import { readFile as readFile3, mkdir as mkdir4, writeFile as writeFile4 } from "fs/promises";
|
|
12301
|
-
import
|
|
11108
|
+
import path9 from "path";
|
|
12302
11109
|
var TAXONOMY_DIR = ".taxonomy";
|
|
12303
11110
|
var TAXONOMY_FILE = "taxonomy.json";
|
|
12304
11111
|
var MAX_SLUG_LENGTH = 32;
|
|
@@ -12396,7 +11203,7 @@ function validateTaxonomy(taxonomy) {
|
|
|
12396
11203
|
}
|
|
12397
11204
|
}
|
|
12398
11205
|
async function loadTaxonomy(memoryDir) {
|
|
12399
|
-
const taxonomyPath =
|
|
11206
|
+
const taxonomyPath = path9.join(memoryDir, TAXONOMY_DIR, TAXONOMY_FILE);
|
|
12400
11207
|
let raw;
|
|
12401
11208
|
try {
|
|
12402
11209
|
raw = await readFile3(taxonomyPath, "utf-8");
|
|
@@ -12446,16 +11253,16 @@ async function loadTaxonomy(memoryDir) {
|
|
|
12446
11253
|
}
|
|
12447
11254
|
async function saveTaxonomy(memoryDir, taxonomy) {
|
|
12448
11255
|
validateTaxonomy(taxonomy);
|
|
12449
|
-
const dir =
|
|
11256
|
+
const dir = path9.join(memoryDir, TAXONOMY_DIR);
|
|
12450
11257
|
await mkdir4(dir, { recursive: true });
|
|
12451
|
-
const filePath =
|
|
11258
|
+
const filePath = path9.join(dir, TAXONOMY_FILE);
|
|
12452
11259
|
await writeFile4(filePath, JSON.stringify(taxonomy, null, 2) + "\n", "utf-8");
|
|
12453
11260
|
}
|
|
12454
11261
|
function getTaxonomyDir(memoryDir) {
|
|
12455
|
-
return
|
|
11262
|
+
return path9.join(memoryDir, TAXONOMY_DIR);
|
|
12456
11263
|
}
|
|
12457
11264
|
function getTaxonomyFilePath(memoryDir) {
|
|
12458
|
-
return
|
|
11265
|
+
return path9.join(memoryDir, TAXONOMY_DIR, TAXONOMY_FILE);
|
|
12459
11266
|
}
|
|
12460
11267
|
|
|
12461
11268
|
// src/orchestration/recall-introspection.ts
|
|
@@ -12479,7 +11286,7 @@ var RecallIntrospectionCoordinator = class {
|
|
|
12479
11286
|
}
|
|
12480
11287
|
async getLastGraphRecallSnapshot(namespace) {
|
|
12481
11288
|
const storage = await this.deps.getStorage(namespace);
|
|
12482
|
-
const snapshotPath =
|
|
11289
|
+
const snapshotPath = path10.join(
|
|
12483
11290
|
storage.dir,
|
|
12484
11291
|
"state",
|
|
12485
11292
|
"last_graph_recall.json"
|
|
@@ -12518,7 +11325,7 @@ var RecallIntrospectionCoordinator = class {
|
|
|
12518
11325
|
}
|
|
12519
11326
|
async getLastIntentSnapshot(namespace) {
|
|
12520
11327
|
const storage = await this.deps.getStorage(namespace);
|
|
12521
|
-
const snapshotPath =
|
|
11328
|
+
const snapshotPath = path10.join(storage.dir, "state", "last_intent.json");
|
|
12522
11329
|
try {
|
|
12523
11330
|
const raw = await readFile4(snapshotPath, "utf-8");
|
|
12524
11331
|
const parsed = JSON.parse(raw);
|
|
@@ -12551,7 +11358,7 @@ var RecallIntrospectionCoordinator = class {
|
|
|
12551
11358
|
}
|
|
12552
11359
|
async getLastQmdRecallSnapshot(namespace) {
|
|
12553
11360
|
const storage = await this.deps.getStorage(namespace);
|
|
12554
|
-
const snapshotPath =
|
|
11361
|
+
const snapshotPath = path10.join(
|
|
12555
11362
|
storage.dir,
|
|
12556
11363
|
"state",
|
|
12557
11364
|
"last_qmd_recall.json"
|
|
@@ -12841,12 +11648,12 @@ var RecallIntrospectionCoordinator = class {
|
|
|
12841
11648
|
}
|
|
12842
11649
|
async recordLastIntentSnapshot(options) {
|
|
12843
11650
|
try {
|
|
12844
|
-
const snapshotPath =
|
|
11651
|
+
const snapshotPath = path10.join(
|
|
12845
11652
|
options.storage.dir,
|
|
12846
11653
|
"state",
|
|
12847
11654
|
"last_intent.json"
|
|
12848
11655
|
);
|
|
12849
|
-
await mkdir5(
|
|
11656
|
+
await mkdir5(path10.dirname(snapshotPath), { recursive: true });
|
|
12850
11657
|
await writeFile5(
|
|
12851
11658
|
snapshotPath,
|
|
12852
11659
|
JSON.stringify(options.snapshot, null, 2),
|
|
@@ -12858,12 +11665,12 @@ var RecallIntrospectionCoordinator = class {
|
|
|
12858
11665
|
}
|
|
12859
11666
|
async recordLastQmdRecallSnapshot(options) {
|
|
12860
11667
|
try {
|
|
12861
|
-
const snapshotPath =
|
|
11668
|
+
const snapshotPath = path10.join(
|
|
12862
11669
|
options.storage.dir,
|
|
12863
11670
|
"state",
|
|
12864
11671
|
"last_qmd_recall.json"
|
|
12865
11672
|
);
|
|
12866
|
-
await mkdir5(
|
|
11673
|
+
await mkdir5(path10.dirname(snapshotPath), { recursive: true });
|
|
12867
11674
|
await writeFile5(
|
|
12868
11675
|
snapshotPath,
|
|
12869
11676
|
JSON.stringify(options.snapshot, null, 2),
|
|
@@ -12878,8 +11685,8 @@ var RecallIntrospectionCoordinator = class {
|
|
|
12878
11685
|
const stateDir = await this.deps.resolveStateDirForNamespace(
|
|
12879
11686
|
options.namespace
|
|
12880
11687
|
);
|
|
12881
|
-
const snapshotPath =
|
|
12882
|
-
await mkdir5(
|
|
11688
|
+
const snapshotPath = path10.join(stateDir, "last_intent.json");
|
|
11689
|
+
await mkdir5(path10.dirname(snapshotPath), { recursive: true });
|
|
12883
11690
|
await writeFile5(
|
|
12884
11691
|
snapshotPath,
|
|
12885
11692
|
JSON.stringify(options.snapshot, null, 2),
|
|
@@ -12893,7 +11700,7 @@ var RecallIntrospectionCoordinator = class {
|
|
|
12893
11700
|
|
|
12894
11701
|
// src/orchestration/orchestrator-init.ts
|
|
12895
11702
|
import { readdir as readdir2, stat as stat2, unlink as unlink2 } from "fs/promises";
|
|
12896
|
-
import
|
|
11703
|
+
import path11 from "path";
|
|
12897
11704
|
var OrchestratorInitCoordinator = class {
|
|
12898
11705
|
constructor(deps) {
|
|
12899
11706
|
this.deps = deps;
|
|
@@ -12989,7 +11796,7 @@ var OrchestratorInitCoordinator = class {
|
|
|
12989
11796
|
const files = await readdir2(wsDir).catch(() => []);
|
|
12990
11797
|
for (const f of files) {
|
|
12991
11798
|
if (!f.startsWith(".compaction-reset-signal-")) continue;
|
|
12992
|
-
const fp =
|
|
11799
|
+
const fp = path11.join(wsDir, f);
|
|
12993
11800
|
const s = await stat2(fp).catch(() => null);
|
|
12994
11801
|
if (s && Date.now() - s.mtimeMs >= COMPACTION_SIGNAL_MAX_AGE_MS) {
|
|
12995
11802
|
await unlink2(fp).catch(() => {
|
|
@@ -13341,7 +12148,7 @@ var OrchestratorInitCoordinator = class {
|
|
|
13341
12148
|
};
|
|
13342
12149
|
|
|
13343
12150
|
// src/orchestration/persistence-index.ts
|
|
13344
|
-
import
|
|
12151
|
+
import path12 from "path";
|
|
13345
12152
|
var PersistenceIndexCoordinator = class {
|
|
13346
12153
|
constructor(deps) {
|
|
13347
12154
|
this.deps = deps;
|
|
@@ -13527,7 +12334,7 @@ var PersistenceIndexCoordinator = class {
|
|
|
13527
12334
|
const allMems = allMemsForGraph ?? [];
|
|
13528
12335
|
for (const m of allMems) {
|
|
13529
12336
|
if (m.frontmatter.entityRef === entityRef) {
|
|
13530
|
-
const rel =
|
|
12337
|
+
const rel = path12.relative(storage.dir, m.path);
|
|
13531
12338
|
if (rel !== memoryRelPath) entitySiblings.push(rel);
|
|
13532
12339
|
}
|
|
13533
12340
|
}
|
|
@@ -13676,7 +12483,7 @@ var PersistenceIndexCoordinator = class {
|
|
|
13676
12483
|
|
|
13677
12484
|
// src/orchestration/workspace-ops.ts
|
|
13678
12485
|
import { lstat, mkdir as mkdir6, readFile as readFile5, readdir as readdir3, realpath, writeFile as writeFile6 } from "fs/promises";
|
|
13679
|
-
import
|
|
12486
|
+
import path13 from "path";
|
|
13680
12487
|
|
|
13681
12488
|
// src/maintenance/pattern-reinforcement.ts
|
|
13682
12489
|
function patternReinforcementKey(content) {
|
|
@@ -15575,8 +14382,8 @@ var MeetingsService = class {
|
|
|
15575
14382
|
// src/orchestration/workspace-ops.ts
|
|
15576
14383
|
var MEETINGS_BUILD_DEBOUNCE_MS = 5e3;
|
|
15577
14384
|
function matchesMemoryPath(candidatePath, requestedPath, memoryDir) {
|
|
15578
|
-
const normalizedCandidate =
|
|
15579
|
-
return normalizedCandidate ===
|
|
14385
|
+
const normalizedCandidate = path13.resolve(candidatePath);
|
|
14386
|
+
return normalizedCandidate === path13.resolve(requestedPath) || normalizedCandidate === path13.resolve(memoryDir, requestedPath);
|
|
15580
14387
|
}
|
|
15581
14388
|
function accessTrackingPathCandidates(storageDir, memoryPath) {
|
|
15582
14389
|
const candidates = qmdResultPathCandidates(storageDir, memoryPath);
|
|
@@ -15584,12 +14391,12 @@ function accessTrackingPathCandidates(storageDir, memoryPath) {
|
|
|
15584
14391
|
if (!parts) return candidates;
|
|
15585
14392
|
candidates.push(
|
|
15586
14393
|
...qmdResultPathCandidates(storageDir, parts.relativePath),
|
|
15587
|
-
...qmdResultPathCandidates(
|
|
14394
|
+
...qmdResultPathCandidates(path13.join(storageDir, "cold"), parts.relativePath)
|
|
15588
14395
|
);
|
|
15589
14396
|
return [...new Set(candidates)];
|
|
15590
14397
|
}
|
|
15591
14398
|
function canonicalMemoryPath(memoryPath, memoryDir) {
|
|
15592
|
-
return
|
|
14399
|
+
return path13.resolve(path13.isAbsolute(memoryPath) ? memoryPath : path13.resolve(memoryDir, memoryPath));
|
|
15593
14400
|
}
|
|
15594
14401
|
var WorkspaceOpsCoordinator = class {
|
|
15595
14402
|
constructor(deps) {
|
|
@@ -15671,15 +14478,15 @@ var WorkspaceOpsCoordinator = class {
|
|
|
15671
14478
|
this.deps.lastFileHygieneRunAtMs = now;
|
|
15672
14479
|
if (hygiene.rotateEnabled) {
|
|
15673
14480
|
for (const rel of hygiene.rotatePaths) {
|
|
15674
|
-
const abs =
|
|
14481
|
+
const abs = path13.isAbsolute(rel) ? rel : path13.join(this.deps.config.workspaceDir, rel);
|
|
15675
14482
|
try {
|
|
15676
14483
|
const raw = await readFile5(abs, "utf-8");
|
|
15677
14484
|
if (raw.length > hygiene.rotateMaxBytes) {
|
|
15678
|
-
const archiveDir =
|
|
14485
|
+
const archiveDir = path13.join(
|
|
15679
14486
|
this.deps.config.workspaceDir,
|
|
15680
14487
|
hygiene.archiveDir
|
|
15681
14488
|
);
|
|
15682
|
-
const base =
|
|
14489
|
+
const base = path13.basename(abs);
|
|
15683
14490
|
const prefix = base.toUpperCase().replace(/\.MD$/i, "").replace(/[^A-Z0-9]+/g, "-") || "FILE";
|
|
15684
14491
|
const { newContent } = await rotateMarkdownFileToArchive({
|
|
15685
14492
|
filePath: abs,
|
|
@@ -15704,8 +14511,8 @@ var WorkspaceOpsCoordinator = class {
|
|
|
15704
14511
|
log.warn(w.message);
|
|
15705
14512
|
}
|
|
15706
14513
|
if (hygiene.warningsLogEnabled && warnings.length > 0) {
|
|
15707
|
-
const fp =
|
|
15708
|
-
await mkdir6(
|
|
14514
|
+
const fp = path13.join(this.deps.config.memoryDir, hygiene.warningsLogPath);
|
|
14515
|
+
await mkdir6(path13.dirname(fp), { recursive: true });
|
|
15709
14516
|
const stamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
15710
14517
|
const block = `
|
|
15711
14518
|
|
|
@@ -15745,7 +14552,7 @@ var WorkspaceOpsCoordinator = class {
|
|
|
15745
14552
|
for (const categoryDir of RECALL_FALLBACK_DIRS) {
|
|
15746
14553
|
if (memoryRootReal === null) break;
|
|
15747
14554
|
for (const date of datesToScan) {
|
|
15748
|
-
const dateDir =
|
|
14555
|
+
const dateDir = path13.join(storage.dir, categoryDir, date);
|
|
15749
14556
|
try {
|
|
15750
14557
|
const dirStat = await lstat(dateDir);
|
|
15751
14558
|
if (dirStat.isSymbolicLink() || !dirStat.isDirectory()) continue;
|
|
@@ -15754,7 +14561,7 @@ var WorkspaceOpsCoordinator = class {
|
|
|
15754
14561
|
for (const entry of entries) {
|
|
15755
14562
|
if (entry.isSymbolicLink()) continue;
|
|
15756
14563
|
if (!entry.name.endsWith(".md")) continue;
|
|
15757
|
-
const fullPath =
|
|
14564
|
+
const fullPath = path13.join(dateDir, entry.name);
|
|
15758
14565
|
try {
|
|
15759
14566
|
assertPathInsideRoot(memoryRootReal, await realpath(fullPath), fullPath);
|
|
15760
14567
|
const raw = await readFile5(fullPath, "utf-8");
|
|
@@ -15776,7 +14583,7 @@ var WorkspaceOpsCoordinator = class {
|
|
|
15776
14583
|
facts.push({
|
|
15777
14584
|
path: fullPath,
|
|
15778
14585
|
frontmatter: {
|
|
15779
|
-
id: fm.id ||
|
|
14586
|
+
id: fm.id || path13.basename(entry.name, ".md"),
|
|
15780
14587
|
category: fm.category || "fact",
|
|
15781
14588
|
created,
|
|
15782
14589
|
updated: fm.updated || created,
|
|
@@ -15799,13 +14606,13 @@ var WorkspaceOpsCoordinator = class {
|
|
|
15799
14606
|
return a.frontmatter.created < b.frontmatter.created ? -1 : 1;
|
|
15800
14607
|
});
|
|
15801
14608
|
const hourlySummaries = [];
|
|
15802
|
-
const hourlyBaseDir =
|
|
14609
|
+
const hourlyBaseDir = path13.join(storage.dir, "summaries", "hourly");
|
|
15803
14610
|
try {
|
|
15804
14611
|
const sessionKeys = await readdir3(hourlyBaseDir, { withFileTypes: true });
|
|
15805
14612
|
for (const sk of sessionKeys) {
|
|
15806
14613
|
if (!sk.isDirectory()) continue;
|
|
15807
14614
|
for (const date of datesToScan) {
|
|
15808
|
-
const summaryFile =
|
|
14615
|
+
const summaryFile = path13.join(hourlyBaseDir, sk.name, `${date}.md`);
|
|
15809
14616
|
try {
|
|
15810
14617
|
const raw = await readFile5(summaryFile, "utf-8");
|
|
15811
14618
|
const filtered = filterHourlySummaryMarkdownForLocalDay(
|
|
@@ -16269,18 +15076,18 @@ ${reflectionsContent.trim()}
|
|
|
16269
15076
|
// src/orchestration/namespace-read-fanout.ts
|
|
16270
15077
|
import { existsSync, readFileSync } from "fs";
|
|
16271
15078
|
import { stat as stat3 } from "fs/promises";
|
|
16272
|
-
import
|
|
15079
|
+
import path15 from "path";
|
|
16273
15080
|
|
|
16274
15081
|
// src/orchestration/orchestrator-namespace-scope.ts
|
|
16275
|
-
import
|
|
15082
|
+
import path14 from "path";
|
|
16276
15083
|
function computeSemanticDedupScope(targetStorage, config) {
|
|
16277
15084
|
if (!resolveNamespaceCapabilities(config).namespaces) return {};
|
|
16278
|
-
const memoryDir =
|
|
16279
|
-
const storageDir =
|
|
15085
|
+
const memoryDir = path14.resolve(config.memoryDir);
|
|
15086
|
+
const storageDir = path14.resolve(targetStorage.dir);
|
|
16280
15087
|
if (storageDir === memoryDir) {
|
|
16281
15088
|
return { pathExcludePrefixes: ["namespaces/"] };
|
|
16282
15089
|
}
|
|
16283
|
-
let rel =
|
|
15090
|
+
let rel = path14.relative(memoryDir, storageDir);
|
|
16284
15091
|
if (!rel || rel.startsWith("..")) {
|
|
16285
15092
|
log.debug(
|
|
16286
15093
|
`semantic dedup: target storage dir ${storageDir} is outside memoryDir ${memoryDir}; scoping lookup to absolute path prefix`
|
|
@@ -16333,7 +15140,7 @@ var NamespaceReadFanoutCoordinator = class {
|
|
|
16333
15140
|
loadNamespaceStorageDirHintsFromCatalog() {
|
|
16334
15141
|
if (this.deps.namespaceStorageDirHintsLoaded || !this.deps.namespaceCatalog.enabled) return;
|
|
16335
15142
|
this.deps.namespaceStorageDirHintsLoaded = true;
|
|
16336
|
-
const catalogPath =
|
|
15143
|
+
const catalogPath = path15.join(this.deps.config.memoryDir, "state", "namespaces.jsonl");
|
|
16337
15144
|
if (!existsSync(catalogPath)) return;
|
|
16338
15145
|
let body;
|
|
16339
15146
|
try {
|
|
@@ -16370,7 +15177,7 @@ var NamespaceReadFanoutCoordinator = class {
|
|
|
16370
15177
|
if (!this.deps.storageDirMatchesNamespaceHint(record.namespace, record.storageDir)) {
|
|
16371
15178
|
continue;
|
|
16372
15179
|
}
|
|
16373
|
-
const resolvedStorageDir =
|
|
15180
|
+
const resolvedStorageDir = path15.resolve(record.storageDir);
|
|
16374
15181
|
const current = preferredByStorageDir.get(resolvedStorageDir);
|
|
16375
15182
|
preferredByStorageDir.set(
|
|
16376
15183
|
resolvedStorageDir,
|
|
@@ -16551,12 +15358,12 @@ var NamespaceReadFanoutCoordinator = class {
|
|
|
16551
15358
|
}
|
|
16552
15359
|
async resolveStateDirForNamespace(namespace) {
|
|
16553
15360
|
if (!resolveNamespaceCapabilities(this.deps.config).namespaces) {
|
|
16554
|
-
return
|
|
15361
|
+
return path15.join(this.deps.config.memoryDir, "state");
|
|
16555
15362
|
}
|
|
16556
15363
|
if (namespace !== this.deps.config.defaultNamespace) {
|
|
16557
|
-
return
|
|
15364
|
+
return path15.join(this.deps.config.memoryDir, "namespaces", namespace, "state");
|
|
16558
15365
|
}
|
|
16559
|
-
const candidate =
|
|
15366
|
+
const candidate = path15.join(
|
|
16560
15367
|
this.deps.config.memoryDir,
|
|
16561
15368
|
"namespaces",
|
|
16562
15369
|
this.deps.config.defaultNamespace
|
|
@@ -16564,11 +15371,11 @@ var NamespaceReadFanoutCoordinator = class {
|
|
|
16564
15371
|
try {
|
|
16565
15372
|
const candidateStat = await stat3(candidate);
|
|
16566
15373
|
if (candidateStat.isDirectory()) {
|
|
16567
|
-
return
|
|
15374
|
+
return path15.join(candidate, "state");
|
|
16568
15375
|
}
|
|
16569
15376
|
} catch {
|
|
16570
15377
|
}
|
|
16571
|
-
return
|
|
15378
|
+
return path15.join(this.deps.config.memoryDir, "state");
|
|
16572
15379
|
}
|
|
16573
15380
|
namespaceFromPath(p) {
|
|
16574
15381
|
if (!resolveNamespaceCapabilities(this.deps.config).namespaces) return this.deps.config.defaultNamespace;
|
|
@@ -16781,270 +15588,6 @@ var RecallEntryCoordinator = class {
|
|
|
16781
15588
|
}
|
|
16782
15589
|
};
|
|
16783
15590
|
|
|
16784
|
-
// src/orchestration/session-context.ts
|
|
16785
|
-
var SessionContextCoordinator = class {
|
|
16786
|
-
constructor(deps) {
|
|
16787
|
-
this.deps = deps;
|
|
16788
|
-
}
|
|
16789
|
-
deps;
|
|
16790
|
-
/**
|
|
16791
|
-
* Effective namespace a same-session LCM/structured-history READER must use
|
|
16792
|
-
* to find what the access `observe` surface WROTE (#1495 thread 2).
|
|
16793
|
-
*
|
|
16794
|
-
* This MUST mirror the `observe` scope plan's write-namespace resolution, NOT
|
|
16795
|
-
* `resolveSelfNamespace`: when no coding overlay applies, `observe` archives
|
|
16796
|
-
* under `config.defaultNamespace` (an unqualified observed turn is NOT moved
|
|
16797
|
-
* to the principal self namespace — identical to
|
|
16798
|
-
* `resolveCodingScopedWriteNamespace`/`memory_store`, rule 39). Only when a
|
|
16799
|
-
* coding overlay actually changes the namespace does the writer (and so the
|
|
16800
|
-
* reader) use the overlaid `project-*` namespace. Returning the self base for
|
|
16801
|
-
* the no-overlay case would prefix the read key with a namespace the writer
|
|
16802
|
-
* never used, so the reader would miss its own evidence.
|
|
16803
|
-
*
|
|
16804
|
-
* Honours the access-surface `principalOverride` (#1505 thread 2, codex): when
|
|
16805
|
-
* a recall supplies an authenticated principal NOT encoded in the raw
|
|
16806
|
-
* `sessionKey`, `observe` archived LCM under THAT principal's base namespace.
|
|
16807
|
-
* Deriving the base from `resolvePrincipal(sessionKey)` alone could fall back
|
|
16808
|
-
* to `default`, so principal `alice` observing `sess-1` would write under
|
|
16809
|
-
* `alice` but READ under `default`. Threading the override here keeps the read
|
|
16810
|
-
* base identical to the write base.
|
|
16811
|
-
*
|
|
16812
|
-
* READ-AUTHORIZATION gate (#1505 round 3, codex P2 "Gate LCM recall keys by
|
|
16813
|
-
* readable namespaces"): the overlay LCM read key is a `<principal>-project-*`
|
|
16814
|
-
* sub-namespace of the principal SELF base. The normal recall namespace set
|
|
16815
|
-
* below only substitutes the coding overlay when the principal SELF base is
|
|
16816
|
-
* actually in the readable recall set (`recallNamespacesForPrincipal` — gated
|
|
16817
|
-
* by `defaultRecallNamespaces.includes("self")` AND `canReadNamespace`). If a
|
|
16818
|
-
* principal can WRITE but not READ its self namespace (or `defaultRecall-
|
|
16819
|
-
* Namespaces` omits `self`), QMD/file recall never touches those overlay rows,
|
|
16820
|
-
* so neither may the LCM read key. When the self base is NOT readable, fall
|
|
16821
|
-
* back to the default store — exactly what an unqualified, unauthorized recall
|
|
16822
|
-
* resolves to — rather than injecting overlay rows the rest of recall excludes
|
|
16823
|
-
* (rule 42 read/write parity; rule 48 least-privilege).
|
|
16824
|
-
*/
|
|
16825
|
-
lcmReadNamespaceForSession(sessionKey, principalOverride) {
|
|
16826
|
-
const principal = typeof principalOverride === "string" && principalOverride.length > 0 ? principalOverride : this.deps.resolvePrincipal(sessionKey);
|
|
16827
|
-
const base = defaultNamespaceForPrincipal(principal, this.deps.config);
|
|
16828
|
-
const overlaid = this.deps.applyCodingNamespaceOverlay(sessionKey, base);
|
|
16829
|
-
if (overlaid === base) return this.deps.config.defaultNamespace;
|
|
16830
|
-
const selfReadableInRecall = recallNamespacesForPrincipal(
|
|
16831
|
-
principal,
|
|
16832
|
-
this.deps.config
|
|
16833
|
-
).includes(base);
|
|
16834
|
-
return selfReadableInRecall ? overlaid : this.deps.config.defaultNamespace;
|
|
16835
|
-
}
|
|
16836
|
-
/**
|
|
16837
|
-
* Attach a coding-agent context to a session (issue #569). Called by the
|
|
16838
|
-
* Claude Code / Codex / Cursor connectors at session start after
|
|
16839
|
-
* `resolveGitContext(cwd)`. The context is consulted by the recall path
|
|
16840
|
-
* and the write path so that memories route to a project- (and optionally
|
|
16841
|
-
* branch-) scoped namespace.
|
|
16842
|
-
*
|
|
16843
|
-
* Pass `null` to clear.
|
|
16844
|
-
*/
|
|
16845
|
-
setCodingContextForSession(sessionKey, codingContext) {
|
|
16846
|
-
if (typeof sessionKey !== "string" || sessionKey.length === 0) return;
|
|
16847
|
-
this.deps.ensureSessionBindingMaps();
|
|
16848
|
-
if (codingContext === null) {
|
|
16849
|
-
this.deps._codingContextBySession.delete(sessionKey);
|
|
16850
|
-
return;
|
|
16851
|
-
}
|
|
16852
|
-
this.deps._codingContextBySession.set(sessionKey, codingContext);
|
|
16853
|
-
}
|
|
16854
|
-
/**
|
|
16855
|
-
* Read-only accessor for the coding context attached to a session. Returns
|
|
16856
|
-
* `null` when none is set. Used by `remnic doctor` and by tests.
|
|
16857
|
-
*
|
|
16858
|
-
* Defensive `_codingContextBySession` lookup — legacy orchestrator-flush
|
|
16859
|
-
* tests use `Object.create(Orchestrator.prototype)` which does not run
|
|
16860
|
-
* class-field initializers, so the Map may be undefined on stubs.
|
|
16861
|
-
*/
|
|
16862
|
-
getCodingContextForSession(sessionKey) {
|
|
16863
|
-
if (typeof sessionKey !== "string" || sessionKey.length === 0) return null;
|
|
16864
|
-
return this.deps._codingContextBySession?.get(sessionKey) ?? null;
|
|
16865
|
-
}
|
|
16866
|
-
/**
|
|
16867
|
-
* Shared helper used by both the recall path and the write path (rule 42).
|
|
16868
|
-
*
|
|
16869
|
-
* Given a base namespace computed from the principal, returns the overlaid
|
|
16870
|
-
* coding namespace when the session has a coding context AND
|
|
16871
|
-
* `codingMode.projectScope` is true AND `namespacesEnabled` is true.
|
|
16872
|
-
* Otherwise returns `baseNamespace` unchanged — CLAUDE.md #30 escape hatch.
|
|
16873
|
-
*
|
|
16874
|
-
* Principal isolation (CLAUDE.md rule 42): the overlay is COMBINED with
|
|
16875
|
-
* the principal-derived `baseNamespace` rather than replacing it, so two
|
|
16876
|
-
* principals working in the same repository do not share memories through
|
|
16877
|
-
* a common `project-*` namespace.
|
|
16878
|
-
*
|
|
16879
|
-
* Namespaces-disabled gate: when `namespacesEnabled` is false, the
|
|
16880
|
-
* storage router maps every namespace to the same `memoryDir`. Returning
|
|
16881
|
-
* `project-*` in that mode would create apparent route separation with
|
|
16882
|
-
* no actual storage isolation — a false-isolation trap. In that mode we
|
|
16883
|
-
* return `baseNamespace` unchanged so coding mode degrades to the existing
|
|
16884
|
-
* unscoped behavior.
|
|
16885
|
-
*
|
|
16886
|
-
* @internal
|
|
16887
|
-
*/
|
|
16888
|
-
applyCodingNamespaceOverlay(sessionKey, baseNamespace) {
|
|
16889
|
-
if (!resolveNamespaceCapabilities(this.deps.config).namespaces) return baseNamespace;
|
|
16890
|
-
const codingContext = this.deps.getCodingContextForSession(sessionKey);
|
|
16891
|
-
const overlay = resolveCodingNamespaceOverlay(codingContext, this.deps.config.codingMode, this.deps.config.defaultNamespace);
|
|
16892
|
-
if (!overlay) return baseNamespace;
|
|
16893
|
-
return combineNamespaces(baseNamespace, overlay.namespace);
|
|
16894
|
-
}
|
|
16895
|
-
/**
|
|
16896
|
-
* Register a peer ID for a session so recall can inject the peer's
|
|
16897
|
-
* profile into context (issue #679 PR 3/5). Pass `null` to clear.
|
|
16898
|
-
*
|
|
16899
|
-
* Connectors and the `before_agent_start` hook call this when the
|
|
16900
|
-
* session's counter-party is known. The ID is validated against
|
|
16901
|
-
* `PEER_ID_PATTERN` before storing.
|
|
16902
|
-
*
|
|
16903
|
-
* Fail-closed (Codex P1 review): an invalid peerId clears any
|
|
16904
|
-
* previously registered mapping for the session rather than silently
|
|
16905
|
-
* keeping stale data. This prevents a malformed metadata update from
|
|
16906
|
-
* mixing one peer's profile context into another session.
|
|
16907
|
-
*
|
|
16908
|
-
* Defensive init (Cursor review + rule 16): `Object.create(
|
|
16909
|
-
* Orchestrator.prototype)` stubs in legacy tests skip class-field
|
|
16910
|
-
* initializers, so `_peerIdBySession` may be undefined. Mirror the
|
|
16911
|
-
* same guard used by `setCodingContextForSession`.
|
|
16912
|
-
*/
|
|
16913
|
-
setPeerIdForSession(sessionKey, peerId) {
|
|
16914
|
-
if (typeof sessionKey !== "string" || sessionKey.length === 0) return;
|
|
16915
|
-
this.deps.ensureSessionBindingMaps();
|
|
16916
|
-
if (peerId === null) {
|
|
16917
|
-
this.deps._peerIdBySession.delete(sessionKey);
|
|
16918
|
-
return;
|
|
16919
|
-
}
|
|
16920
|
-
if (typeof peerId !== "string" || peerId.length === 0 || peerId.length > 64 || !/^[A-Za-z0-9]+(?:[._-][A-Za-z0-9]+)*$/.test(peerId)) {
|
|
16921
|
-
log.warn(`setPeerIdForSession: invalid peerId \u2014 clearing session mapping`);
|
|
16922
|
-
this.deps._peerIdBySession.delete(sessionKey);
|
|
16923
|
-
return;
|
|
16924
|
-
}
|
|
16925
|
-
this.deps._peerIdBySession.set(sessionKey, peerId);
|
|
16926
|
-
}
|
|
16927
|
-
/**
|
|
16928
|
-
* Return the peer ID registered for a session, or `null` when none
|
|
16929
|
-
* is set. Used by `recallInternal` to inject the peer profile section.
|
|
16930
|
-
* Defensive `_peerIdBySession` lookup — legacy orchestrator-flush tests
|
|
16931
|
-
* use `Object.create(Orchestrator.prototype)` which skips class-field
|
|
16932
|
-
* initializers, so the Map may be undefined on stubs.
|
|
16933
|
-
*/
|
|
16934
|
-
getPeerIdForSession(sessionKey) {
|
|
16935
|
-
if (typeof sessionKey !== "string" || sessionKey.length === 0) return null;
|
|
16936
|
-
return this.deps._peerIdBySession?.get(sessionKey) ?? null;
|
|
16937
|
-
}
|
|
16938
|
-
async runDeepSleepGovernanceNow(options) {
|
|
16939
|
-
const targetStorage = options?.storage ?? this.deps.storage;
|
|
16940
|
-
const { runMemoryGovernance } = await import("./maintenance/memory-governance.js");
|
|
16941
|
-
const { summarizeGovernanceResultForDreams } = await import("./dreams-ledger-567VKVOU.js");
|
|
16942
|
-
const govResult = await runMemoryGovernance({
|
|
16943
|
-
memoryDir: targetStorage.dir,
|
|
16944
|
-
mode: options?.dryRun === true ? "shadow" : "apply"
|
|
16945
|
-
});
|
|
16946
|
-
if (options?.dryRun !== true) {
|
|
16947
|
-
try {
|
|
16948
|
-
await this.deps.entitySynthesisCoordinator.processQueue(
|
|
16949
|
-
this.deps.storageDirNamespace(targetStorage.dir),
|
|
16950
|
-
5
|
|
16951
|
-
);
|
|
16952
|
-
} catch (error) {
|
|
16953
|
-
log.debug(`deep-sleep governance: entity synthesis refresh failed after apply: ${error}`);
|
|
16954
|
-
}
|
|
16955
|
-
}
|
|
16956
|
-
return summarizeGovernanceResultForDreams(govResult, options?.dryRun === true);
|
|
16957
|
-
}
|
|
16958
|
-
async generateDaySummary(memories) {
|
|
16959
|
-
if (this.deps.initPromise) {
|
|
16960
|
-
let initGateTimeoutHandle;
|
|
16961
|
-
try {
|
|
16962
|
-
await Promise.race([
|
|
16963
|
-
this.deps.initPromise.catch(() => void 0),
|
|
16964
|
-
new Promise((resolve) => {
|
|
16965
|
-
initGateTimeoutHandle = setTimeout(
|
|
16966
|
-
resolve,
|
|
16967
|
-
this.deps.config.initGateTimeoutMs
|
|
16968
|
-
);
|
|
16969
|
-
})
|
|
16970
|
-
]);
|
|
16971
|
-
} finally {
|
|
16972
|
-
if (initGateTimeoutHandle) clearTimeout(initGateTimeoutHandle);
|
|
16973
|
-
}
|
|
16974
|
-
}
|
|
16975
|
-
return this.deps.extraction.generateDaySummary(memories);
|
|
16976
|
-
}
|
|
16977
|
-
async flushSession(sessionKey, options) {
|
|
16978
|
-
if (typeof this.deps.buffer.flushPendingSave === "function") {
|
|
16979
|
-
await this.deps.buffer.flushPendingSave({ throwOnFailure: true });
|
|
16980
|
-
}
|
|
16981
|
-
const explicitBufferKey = typeof options.bufferKey === "string" && options.bufferKey.length > 0 ? options.bufferKey : null;
|
|
16982
|
-
const discoveredBufferKeys = explicitBufferKey || typeof sessionKey !== "string" || sessionKey.length === 0 || typeof this.deps.buffer.findBufferKeysForSession !== "function" ? [] : await this.deps.buffer.findBufferKeysForSession(sessionKey);
|
|
16983
|
-
const bufferKeys = explicitBufferKey ? [explicitBufferKey] : discoveredBufferKeys.length > 0 ? discoveredBufferKeys : typeof sessionKey === "string" && sessionKey.length > 0 ? [sessionKey] : ["default"];
|
|
16984
|
-
for (const bufferKey of bufferKeys) {
|
|
16985
|
-
const turns = this.deps.buffer.getTurns(bufferKey);
|
|
16986
|
-
if (turns.length === 0) continue;
|
|
16987
|
-
await new Promise((resolve, reject) => {
|
|
16988
|
-
void this.deps.queueBufferedExtraction(turns, "trigger_mode", {
|
|
16989
|
-
bufferKey,
|
|
16990
|
-
clearBufferAfterExtraction: true,
|
|
16991
|
-
skipDedupeCheck: true,
|
|
16992
|
-
forceExtractionAttempt: true,
|
|
16993
|
-
abortSignal: options.abortSignal,
|
|
16994
|
-
onTaskSettled: (error) => error ? reject(error) : resolve()
|
|
16995
|
-
}).catch(reject);
|
|
16996
|
-
});
|
|
16997
|
-
}
|
|
16998
|
-
}
|
|
16999
|
-
/** Lazily construct the CorrectionService for passive capture. Stateless
|
|
17000
|
-
* across requests (per #1580 design); cached for the orchestrator's life. */
|
|
17001
|
-
passiveCorrectionService() {
|
|
17002
|
-
if (this.deps._passiveCorrectionService) return this.deps._passiveCorrectionService;
|
|
17003
|
-
this.deps._passiveCorrectionService = createCorrectionService({
|
|
17004
|
-
orchestrator: this.deps.orchestratorSelf,
|
|
17005
|
-
// Session-scoped write ACL (review: "passive capture bypasses write
|
|
17006
|
-
// ACL"). A correction detected in session S plans only against S readable
|
|
17007
|
-
// namespaces and applies only to writable ones (rule 42) — passive
|
|
17008
|
-
// capture never becomes a cross-tenant mutation vector. Mirrors the
|
|
17009
|
-
// access-service createCorrectionService wiring rather than bypassing it.
|
|
17010
|
-
resolveAuthorizedNamespace: async (req) => {
|
|
17011
|
-
const principal = req.principal || resolvePrincipal(req.sessionKey, this.deps.config);
|
|
17012
|
-
const ns = req.namespace ?? defaultNamespaceForPrincipal(principal, this.deps.config);
|
|
17013
|
-
if (!canWriteNamespace(principal, ns, this.deps.config)) {
|
|
17014
|
-
throw new Error(
|
|
17015
|
-
`passive correction: namespace "${ns}" is not writable for principal ${principal ?? "(none)"}`
|
|
17016
|
-
);
|
|
17017
|
-
}
|
|
17018
|
-
return ns;
|
|
17019
|
-
},
|
|
17020
|
-
resolveReadableNamespaces: (req) => {
|
|
17021
|
-
const principal = req.principal || resolvePrincipal(req.sessionKey, this.deps.config);
|
|
17022
|
-
return recallNamespacesForPrincipal(principal, this.deps.config);
|
|
17023
|
-
},
|
|
17024
|
-
canWriteNamespace: async (req) => {
|
|
17025
|
-
const principal = req.principal || resolvePrincipal(req.sessionKey, this.deps.config);
|
|
17026
|
-
return canWriteNamespace(principal, req.namespace, this.deps.config);
|
|
17027
|
-
},
|
|
17028
|
-
llmComplete: async ({ system, user }) => {
|
|
17029
|
-
const llmResult = await this.deps.localLlm.chatCompletion(
|
|
17030
|
-
[
|
|
17031
|
-
{ role: "system", content: system },
|
|
17032
|
-
{ role: "user", content: user }
|
|
17033
|
-
],
|
|
17034
|
-
{ operation: "correction-classify", priority: "background" }
|
|
17035
|
-
);
|
|
17036
|
-
if (!llmResult) {
|
|
17037
|
-
throw new Error(
|
|
17038
|
-
"passive correction classify+draft: local LLM unavailable (disabled or in cooldown)"
|
|
17039
|
-
);
|
|
17040
|
-
}
|
|
17041
|
-
return llmResult.content;
|
|
17042
|
-
}
|
|
17043
|
-
});
|
|
17044
|
-
return this.deps._passiveCorrectionService;
|
|
17045
|
-
}
|
|
17046
|
-
};
|
|
17047
|
-
|
|
17048
15591
|
// src/orchestration/recall-background-writes.ts
|
|
17049
15592
|
var pendingWritesByOwner = /* @__PURE__ */ new WeakMap();
|
|
17050
15593
|
function trackRecallWrite(owner, promise, label) {
|
|
@@ -17611,7 +16154,7 @@ var Orchestrator = class {
|
|
|
17611
16154
|
const defaultNs = normalizeNamespaceIdentity(this.config.defaultNamespace);
|
|
17612
16155
|
if (ns !== defaultNs && !isSafeRouteNamespace(ns)) return;
|
|
17613
16156
|
if (!this.storageDirMatchesNamespaceHint(ns, storageDir)) return;
|
|
17614
|
-
const resolvedStorageDir =
|
|
16157
|
+
const resolvedStorageDir = path16.resolve(storageDir);
|
|
17615
16158
|
let hints = this.namespaceStorageDirHints.get(resolvedStorageDir);
|
|
17616
16159
|
if (!hints) {
|
|
17617
16160
|
hints = /* @__PURE__ */ new Set();
|
|
@@ -17622,21 +16165,21 @@ var Orchestrator = class {
|
|
|
17622
16165
|
storageDirMatchesNamespaceHint(namespace, storageDir) {
|
|
17623
16166
|
const ns = normalizeNamespaceIdentity(namespace);
|
|
17624
16167
|
if (!ns) return false;
|
|
17625
|
-
const resolvedStorageDir =
|
|
17626
|
-
const resolvedMemoryDir =
|
|
16168
|
+
const resolvedStorageDir = path16.resolve(storageDir);
|
|
16169
|
+
const resolvedMemoryDir = path16.resolve(this.config.memoryDir);
|
|
17627
16170
|
const defaultNs = normalizeNamespaceIdentity(this.config.defaultNamespace);
|
|
17628
16171
|
if (resolvedStorageDir === resolvedMemoryDir) return ns === defaultNs;
|
|
17629
|
-
const resolvedNamespacesDir =
|
|
16172
|
+
const resolvedNamespacesDir = path16.join(resolvedMemoryDir, "namespaces");
|
|
17630
16173
|
if (!isPathInsideStorageRoot(resolvedNamespacesDir, resolvedStorageDir)) return false;
|
|
17631
|
-
const rawRoot =
|
|
17632
|
-
const tokenRoot =
|
|
16174
|
+
const rawRoot = path16.resolve(resolvedNamespacesDir, ns);
|
|
16175
|
+
const tokenRoot = path16.resolve(resolvedNamespacesDir, namespaceIdentityToken(ns));
|
|
17633
16176
|
return resolvedStorageDir === rawRoot || resolvedStorageDir === tokenRoot;
|
|
17634
16177
|
}
|
|
17635
16178
|
namespaceStorageDirHintOwnershipRank(record, resolvedStorageDir, configured) {
|
|
17636
|
-
if (resolvedStorageDir ===
|
|
16179
|
+
if (resolvedStorageDir === path16.resolve(this.config.memoryDir)) {
|
|
17637
16180
|
return record.namespace === normalizeNamespaceIdentity(this.config.defaultNamespace) ? 0 : 3;
|
|
17638
16181
|
}
|
|
17639
|
-
const leaf =
|
|
16182
|
+
const leaf = path16.basename(resolvedStorageDir);
|
|
17640
16183
|
const tokenOwnsRoot = namespaceIdentityToken(record.namespace) === leaf;
|
|
17641
16184
|
if (tokenOwnsRoot && configured.has(record.namespace)) return 0;
|
|
17642
16185
|
if (record.namespace === leaf) return 1;
|
|
@@ -17772,7 +16315,7 @@ var Orchestrator = class {
|
|
|
17772
16315
|
StorageManager.setScopedCacheInvalidationDefault(config.memoryDir, scopedCacheInvalidationEnabled);
|
|
17773
16316
|
this.profiler = new ProfilingCollector({
|
|
17774
16317
|
enabled: resolvePipelineProcessingCapabilities(this.config).profiling,
|
|
17775
|
-
storageDir: config.profilingStorageDir ||
|
|
16318
|
+
storageDir: config.profilingStorageDir || path16.join(config.memoryDir, "profiling"),
|
|
17776
16319
|
maxTraces: config.profilingMaxTraces
|
|
17777
16320
|
});
|
|
17778
16321
|
this.namespaceCatalog = new NamespaceCatalog(config);
|
|
@@ -17859,7 +16402,7 @@ var Orchestrator = class {
|
|
|
17859
16402
|
this.compounding = resolveConsolidationCapabilities(config).compounding ? new CompoundingEngine(config, this.storage) : void 0;
|
|
17860
16403
|
this.buffer = new SmartBuffer(config, this.storage);
|
|
17861
16404
|
this.transcript = new TranscriptManager(config);
|
|
17862
|
-
this.conversationIndexDir =
|
|
16405
|
+
this.conversationIndexDir = path16.join(
|
|
17863
16406
|
config.memoryDir,
|
|
17864
16407
|
"conversation-index",
|
|
17865
16408
|
"chunks"
|
|
@@ -18006,7 +16549,7 @@ var Orchestrator = class {
|
|
|
18006
16549
|
saveContentHashIndexes: () => this.saveContentHashIndexes()
|
|
18007
16550
|
});
|
|
18008
16551
|
this.threading = new ThreadingManager(
|
|
18009
|
-
|
|
16552
|
+
path16.join(config.memoryDir, "threads"),
|
|
18010
16553
|
config.threadingGapMinutes
|
|
18011
16554
|
);
|
|
18012
16555
|
const lifecycleCaps = resolveMemoryLifecycleCapabilities(config);
|
|
@@ -18086,7 +16629,7 @@ var Orchestrator = class {
|
|
|
18086
16629
|
utilityPromoteThresholdDelta: this.utilityRuntimeValues?.promoteThresholdDelta ?? 0,
|
|
18087
16630
|
utilityDemoteThresholdDelta: this.utilityRuntimeValues?.demoteThresholdDelta ?? 0
|
|
18088
16631
|
};
|
|
18089
|
-
return
|
|
16632
|
+
return createHash6("sha256").update(JSON.stringify(payload)).digest("hex").slice(0, 12);
|
|
18090
16633
|
}
|
|
18091
16634
|
effectiveLifecycleThresholds() {
|
|
18092
16635
|
const archiveDecayThreshold = this.config.lifecycleArchiveDecayThreshold;
|
|
@@ -20112,9 +18655,9 @@ function readStructuralSymbol(entry) {
|
|
|
20112
18655
|
const rec = entry;
|
|
20113
18656
|
const symbol = typeof rec.symbol === "string" ? rec.symbol.trim() : "";
|
|
20114
18657
|
if (!symbol) return null;
|
|
20115
|
-
const
|
|
18658
|
+
const path31 = typeof rec.path === "string" && rec.path.length > 0 ? rec.path : void 0;
|
|
20116
18659
|
const kind = typeof rec.kind === "string" && rec.kind.length > 0 ? rec.kind : void 0;
|
|
20117
|
-
const item =
|
|
18660
|
+
const item = path31 !== void 0 && kind !== void 0 ? { symbol, path: path31, kind } : path31 !== void 0 ? { symbol, path: path31 } : kind !== void 0 ? { symbol, kind } : { symbol };
|
|
20118
18661
|
return item;
|
|
20119
18662
|
}
|
|
20120
18663
|
function classifySpawnError(err) {
|
|
@@ -20188,7 +18731,7 @@ var DEFAULT_GRACE_PERIOD_DAYS = 7;
|
|
|
20188
18731
|
|
|
20189
18732
|
// src/binary-lifecycle/backend.ts
|
|
20190
18733
|
import fsp from "fs/promises";
|
|
20191
|
-
import
|
|
18734
|
+
import path17 from "path";
|
|
20192
18735
|
var FilesystemBackend = class {
|
|
20193
18736
|
type = "filesystem";
|
|
20194
18737
|
basePath;
|
|
@@ -20196,19 +18739,19 @@ var FilesystemBackend = class {
|
|
|
20196
18739
|
if (!basePath || basePath.trim().length === 0) {
|
|
20197
18740
|
throw new Error("FilesystemBackend requires a non-empty basePath");
|
|
20198
18741
|
}
|
|
20199
|
-
this.basePath =
|
|
18742
|
+
this.basePath = path17.resolve(basePath);
|
|
20200
18743
|
}
|
|
20201
18744
|
resolveRemotePath(remotePath) {
|
|
20202
|
-
const resolved =
|
|
20203
|
-
const relative =
|
|
20204
|
-
if (relative === ".." || relative.startsWith(`..${
|
|
18745
|
+
const resolved = path17.isAbsolute(remotePath) ? path17.resolve(remotePath) : path17.resolve(this.basePath, remotePath);
|
|
18746
|
+
const relative = path17.relative(this.basePath, resolved);
|
|
18747
|
+
if (relative === ".." || relative.startsWith(`..${path17.sep}`) || path17.isAbsolute(relative)) {
|
|
20205
18748
|
throw new Error(`FilesystemBackend remotePath escapes basePath: ${JSON.stringify(remotePath)}`);
|
|
20206
18749
|
}
|
|
20207
18750
|
return resolved;
|
|
20208
18751
|
}
|
|
20209
18752
|
isInsideBase(candidate, realBase) {
|
|
20210
|
-
const relative =
|
|
20211
|
-
return relative === "" || relative !== ".." && !relative.startsWith(`..${
|
|
18753
|
+
const relative = path17.relative(realBase, candidate);
|
|
18754
|
+
return relative === "" || relative !== ".." && !relative.startsWith(`..${path17.sep}`) && !path17.isAbsolute(relative);
|
|
20212
18755
|
}
|
|
20213
18756
|
async realBasePathIfExists() {
|
|
20214
18757
|
try {
|
|
@@ -20237,13 +18780,13 @@ var FilesystemBackend = class {
|
|
|
20237
18780
|
}
|
|
20238
18781
|
async ensureSafeParentDirectory(dest) {
|
|
20239
18782
|
const realBase = await this.ensureBaseDirectory();
|
|
20240
|
-
const destDir =
|
|
20241
|
-
const relativeDir =
|
|
20242
|
-
const segments = relativeDir === "" ? [] : relativeDir.split(
|
|
18783
|
+
const destDir = path17.dirname(dest);
|
|
18784
|
+
const relativeDir = path17.relative(this.basePath, destDir);
|
|
18785
|
+
const segments = relativeDir === "" ? [] : relativeDir.split(path17.sep);
|
|
20243
18786
|
let current = this.basePath;
|
|
20244
18787
|
for (const segment of segments) {
|
|
20245
18788
|
if (segment === "." || segment === "") continue;
|
|
20246
|
-
current =
|
|
18789
|
+
current = path17.join(current, segment);
|
|
20247
18790
|
try {
|
|
20248
18791
|
const stat5 = await fsp.lstat(current);
|
|
20249
18792
|
if (stat5.isSymbolicLink()) {
|
|
@@ -20271,13 +18814,13 @@ var FilesystemBackend = class {
|
|
|
20271
18814
|
if (realBase === null) {
|
|
20272
18815
|
return null;
|
|
20273
18816
|
}
|
|
20274
|
-
const destDir =
|
|
20275
|
-
const relativeDir =
|
|
20276
|
-
const segments = relativeDir === "" ? [] : relativeDir.split(
|
|
18817
|
+
const destDir = path17.dirname(dest);
|
|
18818
|
+
const relativeDir = path17.relative(this.basePath, destDir);
|
|
18819
|
+
const segments = relativeDir === "" ? [] : relativeDir.split(path17.sep);
|
|
20277
18820
|
let current = this.basePath;
|
|
20278
18821
|
for (const segment of segments) {
|
|
20279
18822
|
if (segment === "." || segment === "") continue;
|
|
20280
|
-
current =
|
|
18823
|
+
current = path17.join(current, segment);
|
|
20281
18824
|
let stat5;
|
|
20282
18825
|
try {
|
|
20283
18826
|
stat5 = await fsp.lstat(current);
|
|
@@ -20325,7 +18868,7 @@ var FilesystemBackend = class {
|
|
|
20325
18868
|
return dest;
|
|
20326
18869
|
}
|
|
20327
18870
|
async upload(localPath, remotePath) {
|
|
20328
|
-
if (
|
|
18871
|
+
if (path17.isAbsolute(remotePath)) {
|
|
20329
18872
|
throw new Error(`FilesystemBackend upload remotePath must be relative: ${JSON.stringify(remotePath)}`);
|
|
20330
18873
|
}
|
|
20331
18874
|
const dest = this.resolveRemotePath(remotePath);
|
|
@@ -20398,7 +18941,7 @@ function createBackend(cfg) {
|
|
|
20398
18941
|
|
|
20399
18942
|
// src/binary-lifecycle/scanner.ts
|
|
20400
18943
|
import fsp2 from "fs/promises";
|
|
20401
|
-
import
|
|
18944
|
+
import path18 from "path";
|
|
20402
18945
|
import crypto from "crypto";
|
|
20403
18946
|
function matchesPatterns(filename, patterns) {
|
|
20404
18947
|
const lower = filename.toLowerCase();
|
|
@@ -20423,8 +18966,8 @@ async function scanForBinaries(memoryDir, config, manifest) {
|
|
|
20423
18966
|
return;
|
|
20424
18967
|
}
|
|
20425
18968
|
for (const entry of entries) {
|
|
20426
|
-
const fullPath =
|
|
20427
|
-
const relativePath =
|
|
18969
|
+
const fullPath = path18.join(dir, entry.name);
|
|
18970
|
+
const relativePath = path18.relative(memoryDir, fullPath).split(path18.sep).join("/");
|
|
20428
18971
|
if (entry.isDirectory()) {
|
|
20429
18972
|
if (entry.name === ".binary-lifecycle") continue;
|
|
20430
18973
|
await walk(fullPath);
|
|
@@ -20464,15 +19007,15 @@ async function hashFile(filePath) {
|
|
|
20464
19007
|
|
|
20465
19008
|
// src/binary-lifecycle/manifest.ts
|
|
20466
19009
|
import fsp3 from "fs/promises";
|
|
20467
|
-
import
|
|
19010
|
+
import path19 from "path";
|
|
20468
19011
|
import crypto2 from "crypto";
|
|
20469
19012
|
var MANIFEST_DIR = ".binary-lifecycle";
|
|
20470
19013
|
var MANIFEST_FILE = "manifest.json";
|
|
20471
19014
|
function manifestDir(memoryDir) {
|
|
20472
|
-
return
|
|
19015
|
+
return path19.join(memoryDir, MANIFEST_DIR);
|
|
20473
19016
|
}
|
|
20474
19017
|
function manifestPath(memoryDir) {
|
|
20475
|
-
return
|
|
19018
|
+
return path19.join(memoryDir, MANIFEST_DIR, MANIFEST_FILE);
|
|
20476
19019
|
}
|
|
20477
19020
|
async function readManifest(memoryDir) {
|
|
20478
19021
|
const filePath = manifestPath(memoryDir);
|
|
@@ -20524,12 +19067,12 @@ function emptyManifest() {
|
|
|
20524
19067
|
|
|
20525
19068
|
// src/binary-lifecycle/pipeline.ts
|
|
20526
19069
|
import fsp4 from "fs/promises";
|
|
20527
|
-
import
|
|
19070
|
+
import path20 from "path";
|
|
20528
19071
|
import crypto3 from "crypto";
|
|
20529
19072
|
function isRecallCorpusMarkdown(mdPath, memoryDir) {
|
|
20530
|
-
const rel =
|
|
20531
|
-
if (rel.startsWith("..") ||
|
|
20532
|
-
const top = rel.split(
|
|
19073
|
+
const rel = path20.relative(memoryDir, mdPath);
|
|
19074
|
+
if (rel.startsWith("..") || path20.isAbsolute(rel)) return false;
|
|
19075
|
+
const top = rel.split(path20.sep)[0];
|
|
20533
19076
|
return RECALL_FALLBACK_DIRS.includes(top);
|
|
20534
19077
|
}
|
|
20535
19078
|
async function hashFile2(filePath) {
|
|
@@ -20553,13 +19096,13 @@ function escapeRegex(s) {
|
|
|
20553
19096
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
20554
19097
|
}
|
|
20555
19098
|
function resolveManifestAssetPath(memoryDir, originalPath) {
|
|
20556
|
-
if (originalPath.length === 0 || originalPath.includes("\0") || originalPath.includes("\\") ||
|
|
19099
|
+
if (originalPath.length === 0 || originalPath.includes("\0") || originalPath.includes("\\") || path20.isAbsolute(originalPath) || path20.win32.isAbsolute(originalPath)) {
|
|
20557
19100
|
return null;
|
|
20558
19101
|
}
|
|
20559
|
-
const memoryRoot =
|
|
20560
|
-
const fullPath =
|
|
20561
|
-
const relative =
|
|
20562
|
-
if (relative === "" || relative === ".." || relative.startsWith(`..${
|
|
19102
|
+
const memoryRoot = path20.resolve(memoryDir);
|
|
19103
|
+
const fullPath = path20.resolve(memoryRoot, originalPath);
|
|
19104
|
+
const relative = path20.relative(memoryRoot, fullPath);
|
|
19105
|
+
if (relative === "" || relative === ".." || relative.startsWith(`..${path20.sep}`) || path20.isAbsolute(relative)) {
|
|
20563
19106
|
return null;
|
|
20564
19107
|
}
|
|
20565
19108
|
return fullPath;
|
|
@@ -20570,7 +19113,7 @@ function validateBinaryLifecycleConfig(config) {
|
|
|
20570
19113
|
}
|
|
20571
19114
|
}
|
|
20572
19115
|
function remotePathForAsset(backend, relPath) {
|
|
20573
|
-
const normalized = relPath.split(
|
|
19116
|
+
const normalized = relPath.split(path20.sep).join("/");
|
|
20574
19117
|
if (backend.type === "filesystem") {
|
|
20575
19118
|
return `.binary-lifecycle/mirrors/${normalized}`;
|
|
20576
19119
|
}
|
|
@@ -20583,11 +19126,11 @@ async function stageMirror(memoryDir, newPaths, backend, assets, log2, dryRun) {
|
|
|
20583
19126
|
let mirrored = 0;
|
|
20584
19127
|
const errors = [];
|
|
20585
19128
|
for (const relPath of newPaths) {
|
|
20586
|
-
const fullPath =
|
|
19129
|
+
const fullPath = path20.join(memoryDir, relPath);
|
|
20587
19130
|
try {
|
|
20588
19131
|
const stat5 = await fsp4.stat(fullPath);
|
|
20589
19132
|
const contentHash = await hashFile2(fullPath);
|
|
20590
|
-
const ext =
|
|
19133
|
+
const ext = path20.extname(relPath);
|
|
20591
19134
|
const mimeType = guessMimeType(ext);
|
|
20592
19135
|
const remotePath = remotePathForAsset(backend, relPath);
|
|
20593
19136
|
let backendLocation = remotePath;
|
|
@@ -20790,10 +19333,10 @@ async function countRemainingLocalReferences(memoryDir, asset, assetAbsolute, md
|
|
|
20790
19333
|
return { remaining, errors };
|
|
20791
19334
|
}
|
|
20792
19335
|
function markdownReferencePattern(asset, assetAbsolute, mdPath) {
|
|
20793
|
-
const mdDir =
|
|
19336
|
+
const mdDir = path20.dirname(mdPath);
|
|
20794
19337
|
const candidates = /* @__PURE__ */ new Set();
|
|
20795
19338
|
const addCandidate = (candidate) => {
|
|
20796
|
-
const normalized = candidate.split(
|
|
19339
|
+
const normalized = candidate.split(path20.sep).join("/");
|
|
20797
19340
|
if (normalized.length === 0) return;
|
|
20798
19341
|
candidates.add(normalized);
|
|
20799
19342
|
const isParentTraversal = normalized === ".." || normalized.startsWith("../");
|
|
@@ -20801,10 +19344,10 @@ function markdownReferencePattern(asset, assetAbsolute, mdPath) {
|
|
|
20801
19344
|
candidates.add(`./${normalized}`);
|
|
20802
19345
|
}
|
|
20803
19346
|
};
|
|
20804
|
-
addCandidate(
|
|
20805
|
-
const originalPath = asset.originalPath.split(
|
|
20806
|
-
const originalAsFileRelative =
|
|
20807
|
-
if (
|
|
19347
|
+
addCandidate(path20.relative(mdDir, assetAbsolute));
|
|
19348
|
+
const originalPath = asset.originalPath.split(path20.sep).join("/");
|
|
19349
|
+
const originalAsFileRelative = path20.resolve(mdDir, ...originalPath.split("/"));
|
|
19350
|
+
if (path20.resolve(originalAsFileRelative) === path20.resolve(assetAbsolute)) {
|
|
20808
19351
|
addCandidate(originalPath);
|
|
20809
19352
|
}
|
|
20810
19353
|
addCandidate(`/${originalPath}`);
|
|
@@ -20900,7 +19443,7 @@ async function findMarkdownFiles(dir) {
|
|
|
20900
19443
|
return;
|
|
20901
19444
|
}
|
|
20902
19445
|
for (const entry of entries) {
|
|
20903
|
-
const full =
|
|
19446
|
+
const full = path20.join(current, entry.name);
|
|
20904
19447
|
if (entry.isDirectory()) {
|
|
20905
19448
|
if (entry.name === ".binary-lifecycle") continue;
|
|
20906
19449
|
await walk(full);
|
|
@@ -20975,7 +19518,7 @@ async function runBinaryLifecyclePipeline(memoryDir, config, backend, log2, opts
|
|
|
20975
19518
|
|
|
20976
19519
|
// src/projection/index.ts
|
|
20977
19520
|
import fs from "fs";
|
|
20978
|
-
import
|
|
19521
|
+
import path21 from "path";
|
|
20979
19522
|
var VALID_PROJECTION_CATEGORIES = new Set(ALL_CATEGORY_KEYS);
|
|
20980
19523
|
async function generateContextTree(options) {
|
|
20981
19524
|
const startTime = Date.now();
|
|
@@ -20990,8 +19533,8 @@ async function generateContextTree(options) {
|
|
|
20990
19533
|
let nodesGenerated = 0;
|
|
20991
19534
|
let nodesSkipped = 0;
|
|
20992
19535
|
const categoryCounts = {};
|
|
20993
|
-
const resolvedMemoryDir =
|
|
20994
|
-
const resolvedOutputDir =
|
|
19536
|
+
const resolvedMemoryDir = path21.resolve(memoryDir);
|
|
19537
|
+
const resolvedOutputDir = path21.resolve(outputDir);
|
|
20995
19538
|
const requestedCategories = validateProjectionCategories(filterCategories);
|
|
20996
19539
|
const realMemoryDir = assertSafeMemoryRoot(resolvedMemoryDir);
|
|
20997
19540
|
assertNotSymlink(resolvedOutputDir, "context tree outputDir");
|
|
@@ -21029,7 +19572,7 @@ async function generateContextTree(options) {
|
|
|
21029
19572
|
}
|
|
21030
19573
|
}
|
|
21031
19574
|
if (includeEntities) {
|
|
21032
|
-
const entitiesDir =
|
|
19575
|
+
const entitiesDir = path21.join(memoryDir, "entities");
|
|
21033
19576
|
if (fs.existsSync(entitiesDir)) {
|
|
21034
19577
|
assertSafeInputRoot(realMemoryDir, entitiesDir, "entities root");
|
|
21035
19578
|
categoryCounts["entity"] = 0;
|
|
@@ -21041,7 +19584,7 @@ async function generateContextTree(options) {
|
|
|
21041
19584
|
continue;
|
|
21042
19585
|
}
|
|
21043
19586
|
const content = fs.readFileSync(filePath, "utf8");
|
|
21044
|
-
const fileName =
|
|
19587
|
+
const fileName = path21.basename(filePath, ".md");
|
|
21045
19588
|
const node = projectEntityNode(fileName, content);
|
|
21046
19589
|
const outputPath = resolveContainedOutputPath(realOutputDir, "entities", `${fileName}.md`);
|
|
21047
19590
|
writeProjectedContent(realOutputDir, outputPath, node.content);
|
|
@@ -21053,7 +19596,7 @@ async function generateContextTree(options) {
|
|
|
21053
19596
|
}
|
|
21054
19597
|
const shouldIncludeQuestions = includeQuestions && (requestedCategories === void 0 || requestedCategories.includes("question"));
|
|
21055
19598
|
if (shouldIncludeQuestions) {
|
|
21056
|
-
const questionsDir =
|
|
19599
|
+
const questionsDir = path21.join(memoryDir, "questions");
|
|
21057
19600
|
if (fs.existsSync(questionsDir)) {
|
|
21058
19601
|
assertSafeInputRoot(realMemoryDir, questionsDir, "questions root");
|
|
21059
19602
|
categoryCounts["question"] = 0;
|
|
@@ -21094,8 +19637,8 @@ async function generateContextTree(options) {
|
|
|
21094
19637
|
};
|
|
21095
19638
|
}
|
|
21096
19639
|
function isPathInside(root, candidate) {
|
|
21097
|
-
const relative =
|
|
21098
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
19640
|
+
const relative = path21.relative(root, candidate);
|
|
19641
|
+
return relative === "" || !relative.startsWith("..") && !path21.isAbsolute(relative);
|
|
21099
19642
|
}
|
|
21100
19643
|
function assertNotSymlink(targetPath, label) {
|
|
21101
19644
|
try {
|
|
@@ -21132,12 +19675,12 @@ function assertSafeInputRoot(realMemoryDir, targetPath, label) {
|
|
|
21132
19675
|
}
|
|
21133
19676
|
function assertSafeOutputTarget(realOutputDir, outputPath) {
|
|
21134
19677
|
let current = realOutputDir;
|
|
21135
|
-
const relative =
|
|
21136
|
-
if (relative.startsWith("..") ||
|
|
19678
|
+
const relative = path21.relative(realOutputDir, outputPath);
|
|
19679
|
+
if (relative.startsWith("..") || path21.isAbsolute(relative)) {
|
|
21137
19680
|
throw new Error(`context tree output path escapes outputDir: ${outputPath}`);
|
|
21138
19681
|
}
|
|
21139
|
-
for (const segment of relative.split(
|
|
21140
|
-
current =
|
|
19682
|
+
for (const segment of relative.split(path21.sep).filter(Boolean)) {
|
|
19683
|
+
current = path21.join(current, segment);
|
|
21141
19684
|
try {
|
|
21142
19685
|
const stat5 = fs.lstatSync(current);
|
|
21143
19686
|
if (stat5.isSymbolicLink()) {
|
|
@@ -21167,17 +19710,17 @@ function validateProjectionCategories(categories) {
|
|
|
21167
19710
|
return validated;
|
|
21168
19711
|
}
|
|
21169
19712
|
function resolveContainedOutputPath(outputRoot, ...segments) {
|
|
21170
|
-
const resolved =
|
|
21171
|
-
const relative =
|
|
21172
|
-
if (relative === "" || !relative.startsWith("..") && !
|
|
19713
|
+
const resolved = path21.resolve(outputRoot, ...segments);
|
|
19714
|
+
const relative = path21.relative(outputRoot, resolved);
|
|
19715
|
+
if (relative === "" || !relative.startsWith("..") && !path21.isAbsolute(relative)) {
|
|
21173
19716
|
return resolved;
|
|
21174
19717
|
}
|
|
21175
19718
|
throw new Error(`context tree output path escapes outputDir: ${segments.join("/")}`);
|
|
21176
19719
|
}
|
|
21177
19720
|
function writeProjectedContent(realOutputDir, outputPath, generatedContent) {
|
|
21178
19721
|
assertSafeOutputTarget(realOutputDir, outputPath);
|
|
21179
|
-
fs.mkdirSync(
|
|
21180
|
-
const realParent = fs.realpathSync(
|
|
19722
|
+
fs.mkdirSync(path21.dirname(outputPath), { recursive: true });
|
|
19723
|
+
const realParent = fs.realpathSync(path21.dirname(outputPath));
|
|
21181
19724
|
if (!isPathInside(realOutputDir, realParent)) {
|
|
21182
19725
|
throw new Error(`context tree output path escapes outputDir: ${outputPath}`);
|
|
21183
19726
|
}
|
|
@@ -21216,7 +19759,7 @@ function walkR(dir, realMemoryDir) {
|
|
|
21216
19759
|
const results = [];
|
|
21217
19760
|
function walk(directory) {
|
|
21218
19761
|
for (const entry of fs.readdirSync(directory, { withFileTypes: true })) {
|
|
21219
|
-
const fullPath =
|
|
19762
|
+
const fullPath = path21.join(directory, entry.name);
|
|
21220
19763
|
if (entry.isSymbolicLink()) {
|
|
21221
19764
|
throw new Error(`context tree input path contains symlink: ${fullPath}`);
|
|
21222
19765
|
}
|
|
@@ -21269,13 +19812,13 @@ function extractBody(content) {
|
|
|
21269
19812
|
}
|
|
21270
19813
|
function projectNode(filePath, category, fm, rawContent) {
|
|
21271
19814
|
const body = extractBody(rawContent);
|
|
21272
|
-
const fileName =
|
|
21273
|
-
const dateDir =
|
|
19815
|
+
const fileName = path21.basename(filePath, ".md");
|
|
19816
|
+
const dateDir = path21.basename(path21.dirname(filePath));
|
|
21274
19817
|
let relPath;
|
|
21275
19818
|
if (/^\d{4}-\d{2}-\d{2}$/.test(dateDir)) {
|
|
21276
|
-
relPath =
|
|
19819
|
+
relPath = path21.join(category, dateDir, `${fileName}.md`);
|
|
21277
19820
|
} else {
|
|
21278
|
-
relPath =
|
|
19821
|
+
relPath = path21.join(category, `${fileName}.md`);
|
|
21279
19822
|
}
|
|
21280
19823
|
const generatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
21281
19824
|
const md = `# ${fm.id}
|
|
@@ -21321,7 +19864,7 @@ function projectEntityNode(fileName, content) {
|
|
|
21321
19864
|
${content}
|
|
21322
19865
|
`;
|
|
21323
19866
|
return {
|
|
21324
|
-
path:
|
|
19867
|
+
path: path21.join("entities", `${fileName}.md`),
|
|
21325
19868
|
category: "entity",
|
|
21326
19869
|
title: fileName,
|
|
21327
19870
|
content: md,
|
|
@@ -21374,7 +19917,7 @@ function generateIndex(categoryCounts, outputDir) {
|
|
|
21374
19917
|
|
|
21375
19918
|
// src/onboarding/index.ts
|
|
21376
19919
|
import fs2 from "fs";
|
|
21377
|
-
import
|
|
19920
|
+
import path22 from "path";
|
|
21378
19921
|
var LANGUAGE_RULES = [
|
|
21379
19922
|
{
|
|
21380
19923
|
language: "TypeScript",
|
|
@@ -21476,7 +20019,7 @@ function onboard(options) {
|
|
|
21476
20019
|
maxDepth = 6,
|
|
21477
20020
|
excludeDirs = []
|
|
21478
20021
|
} = options;
|
|
21479
|
-
const directory =
|
|
20022
|
+
const directory = path22.resolve(options.directory ?? process.cwd());
|
|
21480
20023
|
let rootStat;
|
|
21481
20024
|
try {
|
|
21482
20025
|
rootStat = fs2.statSync(directory);
|
|
@@ -21518,7 +20061,7 @@ function walkDir(root, exclude, maxDepth) {
|
|
|
21518
20061
|
}
|
|
21519
20062
|
for (const entry of entries) {
|
|
21520
20063
|
if (exclude.has(entry.name)) continue;
|
|
21521
|
-
const fullPath =
|
|
20064
|
+
const fullPath = path22.join(dir, entry.name);
|
|
21522
20065
|
if (entry.isDirectory()) {
|
|
21523
20066
|
walk(fullPath, depth + 1);
|
|
21524
20067
|
} else if (entry.isFile()) {
|
|
@@ -21533,11 +20076,11 @@ function detectLanguages(files, root) {
|
|
|
21533
20076
|
const results = [];
|
|
21534
20077
|
const extCounts = /* @__PURE__ */ new Map();
|
|
21535
20078
|
for (const f of files) {
|
|
21536
|
-
const ext =
|
|
20079
|
+
const ext = path22.extname(f).toLowerCase();
|
|
21537
20080
|
if (ext) extCounts.set(ext, (extCounts.get(ext) ?? 0) + 1);
|
|
21538
20081
|
}
|
|
21539
20082
|
const rootFiles = new Set(
|
|
21540
|
-
files.filter((f) =>
|
|
20083
|
+
files.filter((f) => path22.dirname(f) === root).map((f) => path22.basename(f))
|
|
21541
20084
|
);
|
|
21542
20085
|
for (const rule of LANGUAGE_RULES) {
|
|
21543
20086
|
const evidence = [];
|
|
@@ -21581,7 +20124,7 @@ function detectLanguages(files, root) {
|
|
|
21581
20124
|
}
|
|
21582
20125
|
function detectShape(files, root) {
|
|
21583
20126
|
const rootFiles = new Set(
|
|
21584
|
-
files.filter((f) =>
|
|
20127
|
+
files.filter((f) => path22.dirname(f) === root).map((f) => path22.basename(f))
|
|
21585
20128
|
);
|
|
21586
20129
|
const rootDirs = /* @__PURE__ */ new Set();
|
|
21587
20130
|
try {
|
|
@@ -21592,7 +20135,7 @@ function detectShape(files, root) {
|
|
|
21592
20135
|
}
|
|
21593
20136
|
const evidence = [];
|
|
21594
20137
|
if (rootFiles.has("package.json")) {
|
|
21595
|
-
const pkg = readJsonSafe(
|
|
20138
|
+
const pkg = readJsonSafe(path22.join(root, "package.json"));
|
|
21596
20139
|
if (pkg?.workspaces) {
|
|
21597
20140
|
evidence.push("package.json has workspaces");
|
|
21598
20141
|
return { shape: "monorepo", evidence };
|
|
@@ -21606,13 +20149,13 @@ function detectShape(files, root) {
|
|
|
21606
20149
|
evidence.push("workspace manifest found");
|
|
21607
20150
|
return { shape: "workspace", evidence };
|
|
21608
20151
|
}
|
|
21609
|
-
const cargoToml = readTomlWorkspace(
|
|
20152
|
+
const cargoToml = readTomlWorkspace(path22.join(root, "Cargo.toml"));
|
|
21610
20153
|
if (cargoToml) {
|
|
21611
20154
|
evidence.push("Cargo.toml has workspace");
|
|
21612
20155
|
return { shape: "workspace", evidence };
|
|
21613
20156
|
}
|
|
21614
20157
|
if (rootFiles.has("package.json")) {
|
|
21615
|
-
const pkg = readJsonSafe(
|
|
20158
|
+
const pkg = readJsonSafe(path22.join(root, "package.json"));
|
|
21616
20159
|
if (pkg?.exports || pkg?.main) {
|
|
21617
20160
|
if (pkg?.bin) {
|
|
21618
20161
|
evidence.push("package.json has bin");
|
|
@@ -21646,8 +20189,8 @@ function discoverDocs(files, root) {
|
|
|
21646
20189
|
{ pattern: /^\.editorconfig$/i, kind: "config" }
|
|
21647
20190
|
];
|
|
21648
20191
|
for (const filePath of files) {
|
|
21649
|
-
const basename =
|
|
21650
|
-
const relPath =
|
|
20192
|
+
const basename = path22.basename(filePath).toLowerCase();
|
|
20193
|
+
const relPath = path22.relative(root, filePath);
|
|
21651
20194
|
let kind;
|
|
21652
20195
|
for (const { pattern, kind: k } of docPatterns) {
|
|
21653
20196
|
if (pattern.test(basename)) {
|
|
@@ -21659,7 +20202,7 @@ function discoverDocs(files, root) {
|
|
|
21659
20202
|
kind = "docs";
|
|
21660
20203
|
}
|
|
21661
20204
|
if (!kind && (basename.endsWith(".md") || basename.endsWith(".mdx"))) {
|
|
21662
|
-
if (
|
|
20205
|
+
if (path22.dirname(relPath) === "." || isUnderDocsDir(relPath)) {
|
|
21663
20206
|
kind = "docs";
|
|
21664
20207
|
}
|
|
21665
20208
|
}
|
|
@@ -21680,7 +20223,7 @@ function discoverDocs(files, root) {
|
|
|
21680
20223
|
return docs;
|
|
21681
20224
|
}
|
|
21682
20225
|
function isUnderDocsDir(relPath) {
|
|
21683
|
-
const parts = relPath.split(
|
|
20226
|
+
const parts = relPath.split(path22.sep);
|
|
21684
20227
|
return parts[0] === "docs" || parts[0] === "doc" || parts[0] === "documentation";
|
|
21685
20228
|
}
|
|
21686
20229
|
function buildPlan(languages, shape, docs, _root) {
|
|
@@ -21724,7 +20267,7 @@ function readTomlWorkspace(filePath) {
|
|
|
21724
20267
|
|
|
21725
20268
|
// src/curation/index.ts
|
|
21726
20269
|
import fs3 from "fs";
|
|
21727
|
-
import
|
|
20270
|
+
import path23 from "path";
|
|
21728
20271
|
import crypto4 from "crypto";
|
|
21729
20272
|
async function curate(options) {
|
|
21730
20273
|
const startTime = Date.now();
|
|
@@ -21815,12 +20358,12 @@ function resolveTargets(targetPath) {
|
|
|
21815
20358
|
const extensions = /* @__PURE__ */ new Set([".md", ".txt", ".mdx", ".rst"]);
|
|
21816
20359
|
function walk(dir) {
|
|
21817
20360
|
for (const entry of fs3.readdirSync(dir, { withFileTypes: true })) {
|
|
21818
|
-
const fullPath =
|
|
20361
|
+
const fullPath = path23.join(dir, entry.name);
|
|
21819
20362
|
if (entry.isDirectory()) {
|
|
21820
20363
|
if (entry.name !== "node_modules" && entry.name !== ".git") {
|
|
21821
20364
|
walk(fullPath);
|
|
21822
20365
|
}
|
|
21823
|
-
} else if (extensions.has(
|
|
20366
|
+
} else if (extensions.has(path23.extname(entry.name).toLowerCase())) {
|
|
21824
20367
|
results.push(fullPath);
|
|
21825
20368
|
}
|
|
21826
20369
|
}
|
|
@@ -21829,12 +20372,12 @@ function resolveTargets(targetPath) {
|
|
|
21829
20372
|
return results;
|
|
21830
20373
|
}
|
|
21831
20374
|
function resolveProvenanceRoot(targetPath) {
|
|
21832
|
-
const resolvedTarget =
|
|
20375
|
+
const resolvedTarget = path23.resolve(targetPath);
|
|
21833
20376
|
const stat5 = fs3.statSync(resolvedTarget);
|
|
21834
|
-
return stat5.isFile() ?
|
|
20377
|
+
return stat5.isFile() ? path23.dirname(resolvedTarget) : resolvedTarget;
|
|
21835
20378
|
}
|
|
21836
20379
|
function extractStatements(content, filePath, projectRoot, source, sourceFileHash, categoryOverride, confidence, entityRef, tags) {
|
|
21837
|
-
const relativePath =
|
|
20380
|
+
const relativePath = path23.relative(projectRoot, path23.resolve(filePath)) || path23.basename(filePath);
|
|
21838
20381
|
const statements = [];
|
|
21839
20382
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
21840
20383
|
const paragraphs = content.split(/\n{2,}/).map((p) => p.trim()).filter((p) => p.length > 20 && p.length < 2e3);
|
|
@@ -21928,7 +20471,7 @@ function loadExistingMemories(memoryDir) {
|
|
|
21928
20471
|
if (!fs3.existsSync(memoryDir)) return result;
|
|
21929
20472
|
const dirs = ALL_CATEGORY_DIRS;
|
|
21930
20473
|
for (const dir of dirs) {
|
|
21931
|
-
const fullDir =
|
|
20474
|
+
const fullDir = path23.join(memoryDir, dir);
|
|
21932
20475
|
if (!fs3.existsSync(fullDir)) continue;
|
|
21933
20476
|
walkFiles(fullDir, (filePath) => {
|
|
21934
20477
|
const content = readFileSafe(filePath);
|
|
@@ -21950,10 +20493,10 @@ function writeStatement(stmt, memoryDir) {
|
|
|
21950
20493
|
const now = /* @__PURE__ */ new Date();
|
|
21951
20494
|
const dateDir = now.toISOString().split("T")[0];
|
|
21952
20495
|
const categoryDir = getCategoryDir(memoryDir, stmt.category);
|
|
21953
|
-
const dir =
|
|
20496
|
+
const dir = path23.join(categoryDir, dateDir);
|
|
21954
20497
|
fs3.mkdirSync(dir, { recursive: true });
|
|
21955
20498
|
const fileName = `${stmt.category}-${Date.now()}-${stmt.id.slice(0, 8)}.md`;
|
|
21956
|
-
const filePath =
|
|
20499
|
+
const filePath = path23.join(dir, fileName);
|
|
21957
20500
|
const frontmatter = [
|
|
21958
20501
|
"---",
|
|
21959
20502
|
`id: ${stmt.id}`,
|
|
@@ -22021,7 +20564,7 @@ function extractBody2(content) {
|
|
|
22021
20564
|
}
|
|
22022
20565
|
function walkFiles(dir, callback) {
|
|
22023
20566
|
for (const entry of fs3.readdirSync(dir, { withFileTypes: true })) {
|
|
22024
|
-
const fullPath =
|
|
20567
|
+
const fullPath = path23.join(dir, entry.name);
|
|
22025
20568
|
if (entry.isDirectory()) {
|
|
22026
20569
|
walkFiles(fullPath, callback);
|
|
22027
20570
|
} else if (entry.name.endsWith(".md")) {
|
|
@@ -22032,7 +20575,7 @@ function walkFiles(dir, callback) {
|
|
|
22032
20575
|
|
|
22033
20576
|
// src/dedup/index.ts
|
|
22034
20577
|
import fs4 from "fs";
|
|
22035
|
-
import
|
|
20578
|
+
import path24 from "path";
|
|
22036
20579
|
import crypto5 from "crypto";
|
|
22037
20580
|
var DEFAULT_DEDUP_THRESHOLD = 0.85;
|
|
22038
20581
|
var DEFAULT_MAX_LOAD = 1e4;
|
|
@@ -22174,7 +20717,7 @@ function loadMemories(memoryDir, categories, maxLoad = 1e4) {
|
|
|
22174
20717
|
const memoryRootReal = fs4.realpathSync(memoryDir);
|
|
22175
20718
|
for (const category of allCategories) {
|
|
22176
20719
|
if (result.length >= maxLoad) break;
|
|
22177
|
-
const dir =
|
|
20720
|
+
const dir = path24.join(memoryDir, category);
|
|
22178
20721
|
if (!fs4.existsSync(dir)) continue;
|
|
22179
20722
|
const categoryStat = fs4.lstatSync(dir);
|
|
22180
20723
|
if (categoryStat.isSymbolicLink()) {
|
|
@@ -22235,15 +20778,15 @@ function extractBody3(content) {
|
|
|
22235
20778
|
return match ? match[1].trim() : content.trim();
|
|
22236
20779
|
}
|
|
22237
20780
|
function assertPathInsideRoot2(rootReal, targetReal, sourcePath) {
|
|
22238
|
-
const rel =
|
|
22239
|
-
if (rel === "" || !rel.startsWith("..") && !
|
|
20781
|
+
const rel = path24.relative(rootReal, targetReal);
|
|
20782
|
+
if (rel === "" || !rel.startsWith("..") && !path24.isAbsolute(rel)) {
|
|
22240
20783
|
return;
|
|
22241
20784
|
}
|
|
22242
20785
|
throw new Error(`Refusing to scan memory path outside root: ${sourcePath}`);
|
|
22243
20786
|
}
|
|
22244
20787
|
function walkMdFiles(dir, memoryRootReal, categoryRootReal, callback) {
|
|
22245
20788
|
for (const entry of fs4.readdirSync(dir, { withFileTypes: true })) {
|
|
22246
|
-
const fullPath =
|
|
20789
|
+
const fullPath = path24.join(dir, entry.name);
|
|
22247
20790
|
const entryStat = fs4.lstatSync(fullPath);
|
|
22248
20791
|
if (entryStat.isSymbolicLink()) {
|
|
22249
20792
|
throw new Error(`Refusing to scan symlinked memory path: ${fullPath}`);
|
|
@@ -22261,7 +20804,7 @@ function walkMdFiles(dir, memoryRootReal, categoryRootReal, callback) {
|
|
|
22261
20804
|
|
|
22262
20805
|
// src/review/index.ts
|
|
22263
20806
|
import fs5 from "fs";
|
|
22264
|
-
import
|
|
20807
|
+
import path25 from "path";
|
|
22265
20808
|
var DEFAULT_CONFIDENCE_THRESHOLD = 0.7;
|
|
22266
20809
|
function realMemoryRoot(memoryDir) {
|
|
22267
20810
|
try {
|
|
@@ -22273,8 +20816,8 @@ function realMemoryRoot(memoryDir) {
|
|
|
22273
20816
|
}
|
|
22274
20817
|
}
|
|
22275
20818
|
function isPathInside2(rootReal, candidateReal) {
|
|
22276
|
-
const relative =
|
|
22277
|
-
return relative === "" || !!relative && !relative.startsWith("..") && !
|
|
20819
|
+
const relative = path25.relative(rootReal, candidateReal);
|
|
20820
|
+
return relative === "" || !!relative && !relative.startsWith("..") && !path25.isAbsolute(relative);
|
|
22278
20821
|
}
|
|
22279
20822
|
function isSafeDirectory(rootReal, dir) {
|
|
22280
20823
|
try {
|
|
@@ -22317,7 +20860,7 @@ function listReviewItems(options) {
|
|
|
22317
20860
|
if (filterReason && item.reviewReason !== filterReason) return;
|
|
22318
20861
|
items.push(item);
|
|
22319
20862
|
};
|
|
22320
|
-
const suggestionsDir =
|
|
20863
|
+
const suggestionsDir = path25.join(memoryDir, "suggestions");
|
|
22321
20864
|
if (!isLimitReached() && fs5.existsSync(suggestionsDir) && isSafeDirectory(rootReal, suggestionsDir)) {
|
|
22322
20865
|
walkMd(rootReal, suggestionsDir, (filePath, content) => {
|
|
22323
20866
|
if (isLimitReached()) return true;
|
|
@@ -22338,7 +20881,7 @@ function listReviewItems(options) {
|
|
|
22338
20881
|
return isLimitReached();
|
|
22339
20882
|
});
|
|
22340
20883
|
}
|
|
22341
|
-
const reviewDir =
|
|
20884
|
+
const reviewDir = path25.join(memoryDir, "review");
|
|
22342
20885
|
if (!isLimitReached() && fs5.existsSync(reviewDir) && isSafeDirectory(rootReal, reviewDir)) {
|
|
22343
20886
|
walkMd(rootReal, reviewDir, (filePath, content) => {
|
|
22344
20887
|
if (isLimitReached()) return true;
|
|
@@ -22363,7 +20906,7 @@ function listReviewItems(options) {
|
|
|
22363
20906
|
const categories = ALL_CATEGORY_DIRS;
|
|
22364
20907
|
for (const category of categories) {
|
|
22365
20908
|
if (isLimitReached()) break;
|
|
22366
|
-
const dir =
|
|
20909
|
+
const dir = path25.join(memoryDir, category);
|
|
22367
20910
|
if (!fs5.existsSync(dir) || !isSafeDirectory(rootReal, dir)) continue;
|
|
22368
20911
|
walkMd(rootReal, dir, (filePath, content) => {
|
|
22369
20912
|
if (isLimitReached()) return true;
|
|
@@ -22443,8 +20986,8 @@ function approveItem(memoryDir, itemId, options) {
|
|
|
22443
20986
|
const targetDir = getCategoryDir(memoryDir, category);
|
|
22444
20987
|
const dateDir = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
22445
20988
|
ensureSafeDirectory(rootReal, targetDir);
|
|
22446
|
-
const outputPath =
|
|
22447
|
-
ensureSafeDirectory(rootReal,
|
|
20989
|
+
const outputPath = path25.join(targetDir, dateDir, path25.basename(found.filePath));
|
|
20990
|
+
ensureSafeDirectory(rootReal, path25.dirname(outputPath));
|
|
22448
20991
|
const promotedPath = writeFileWithoutClobber(outputPath, updatedContent, itemId);
|
|
22449
20992
|
fs5.unlinkSync(found.filePath);
|
|
22450
20993
|
return {
|
|
@@ -22502,13 +21045,13 @@ function findReviewFileById(memoryDir, id, options = {}) {
|
|
|
22502
21045
|
const rootReal = realMemoryRoot(memoryDir);
|
|
22503
21046
|
if (!rootReal) return null;
|
|
22504
21047
|
for (const loc of ["suggestions", "review"]) {
|
|
22505
|
-
const dir =
|
|
21048
|
+
const dir = path25.join(memoryDir, loc);
|
|
22506
21049
|
if (!fs5.existsSync(dir) || !isSafeDirectory(rootReal, dir)) continue;
|
|
22507
21050
|
const found = findFileById(rootReal, dir, id);
|
|
22508
21051
|
if (found) return { filePath: found, location: "queue" };
|
|
22509
21052
|
}
|
|
22510
21053
|
for (const category of ALL_CATEGORY_DIRS) {
|
|
22511
|
-
const dir =
|
|
21054
|
+
const dir = path25.join(memoryDir, category);
|
|
22512
21055
|
if (!fs5.existsSync(dir) || !isSafeDirectory(rootReal, dir)) continue;
|
|
22513
21056
|
const found = findFileById(rootReal, dir, id, (fm) => isLowConfidenceReviewCandidate(fm, options));
|
|
22514
21057
|
if (found) return { filePath: found, location: "category" };
|
|
@@ -22584,10 +21127,10 @@ function readFileSafe3(filePath) {
|
|
|
22584
21127
|
}
|
|
22585
21128
|
}
|
|
22586
21129
|
function writeFileWithoutClobber(basePath, content, discriminator) {
|
|
22587
|
-
const parsed =
|
|
21130
|
+
const parsed = path25.parse(basePath);
|
|
22588
21131
|
const safeDiscriminator = sanitizeFilePart(discriminator);
|
|
22589
21132
|
for (let attempt = 0; attempt < 1e3; attempt++) {
|
|
22590
|
-
const candidate = attempt === 0 ? basePath :
|
|
21133
|
+
const candidate = attempt === 0 ? basePath : path25.join(
|
|
22591
21134
|
parsed.dir,
|
|
22592
21135
|
`${parsed.name}-${safeDiscriminator}${attempt === 1 ? "" : `-${attempt}`}${parsed.ext || ".md"}`
|
|
22593
21136
|
);
|
|
@@ -22643,7 +21186,7 @@ function extractBody4(content) {
|
|
|
22643
21186
|
function walkMd(rootReal, dir, callback) {
|
|
22644
21187
|
if (!isSafeDirectory(rootReal, dir)) return false;
|
|
22645
21188
|
for (const entry of fs5.readdirSync(dir, { withFileTypes: true })) {
|
|
22646
|
-
const fullPath =
|
|
21189
|
+
const fullPath = path25.join(dir, entry.name);
|
|
22647
21190
|
if (entry.isSymbolicLink()) continue;
|
|
22648
21191
|
if (entry.isDirectory()) {
|
|
22649
21192
|
if (walkMd(rootReal, fullPath, callback)) return true;
|
|
@@ -22658,7 +21201,7 @@ function walkMdPaths(rootReal, dir) {
|
|
|
22658
21201
|
const results = [];
|
|
22659
21202
|
if (!isSafeDirectory(rootReal, dir)) return results;
|
|
22660
21203
|
for (const entry of fs5.readdirSync(dir, { withFileTypes: true })) {
|
|
22661
|
-
const fullPath =
|
|
21204
|
+
const fullPath = path25.join(dir, entry.name);
|
|
22662
21205
|
if (entry.isSymbolicLink()) continue;
|
|
22663
21206
|
if (entry.isDirectory()) {
|
|
22664
21207
|
results.push(...walkMdPaths(rootReal, fullPath));
|
|
@@ -22671,7 +21214,7 @@ function walkMdPaths(rootReal, dir) {
|
|
|
22671
21214
|
|
|
22672
21215
|
// src/sync/index.ts
|
|
22673
21216
|
import fs6 from "fs";
|
|
22674
|
-
import
|
|
21217
|
+
import path26 from "path";
|
|
22675
21218
|
import crypto6 from "crypto";
|
|
22676
21219
|
var DEFAULT_EXTENSIONS = /* @__PURE__ */ new Set([".md", ".txt", ".mdx", ".rst"]);
|
|
22677
21220
|
var DEFAULT_EXCLUDE2 = /* @__PURE__ */ new Set([
|
|
@@ -22693,7 +21236,7 @@ function syncChanges(options) {
|
|
|
22693
21236
|
} = options;
|
|
22694
21237
|
const extSet = new Set(extensions);
|
|
22695
21238
|
const excludeSet = /* @__PURE__ */ new Set([...DEFAULT_EXCLUDE2, ...excludeDirs]);
|
|
22696
|
-
const stateFilePath = options.stateFile ??
|
|
21239
|
+
const stateFilePath = options.stateFile ?? path26.join(memoryDir, ".sync-state.json");
|
|
22697
21240
|
const prevState = loadState(stateFilePath);
|
|
22698
21241
|
const currentFiles = scanFiles(sourceDir, extSet, excludeSet);
|
|
22699
21242
|
const changes = computeDiff(currentFiles, prevState.fileHashes, sourceDir);
|
|
@@ -22709,7 +21252,7 @@ function syncChanges(options) {
|
|
|
22709
21252
|
for (const [relPath, hash] of Object.entries(currentFiles)) {
|
|
22710
21253
|
newState.fileHashes[relPath] = hash;
|
|
22711
21254
|
}
|
|
22712
|
-
fs6.mkdirSync(
|
|
21255
|
+
fs6.mkdirSync(path26.dirname(stateFilePath), { recursive: true });
|
|
22713
21256
|
fs6.writeFileSync(stateFilePath, JSON.stringify(newState, null, 2));
|
|
22714
21257
|
}
|
|
22715
21258
|
return {
|
|
@@ -22775,13 +21318,13 @@ function scanFiles(root, extensions, exclude) {
|
|
|
22775
21318
|
}
|
|
22776
21319
|
for (const entry of entries) {
|
|
22777
21320
|
if (exclude.has(entry.name)) continue;
|
|
22778
|
-
const fullPath =
|
|
21321
|
+
const fullPath = path26.join(dir, entry.name);
|
|
22779
21322
|
if (entry.isDirectory()) {
|
|
22780
21323
|
walk(fullPath);
|
|
22781
21324
|
} else if (entry.isFile()) {
|
|
22782
|
-
const ext =
|
|
21325
|
+
const ext = path26.extname(entry.name).toLowerCase();
|
|
22783
21326
|
if (!extensions.has(ext)) continue;
|
|
22784
|
-
const relPath =
|
|
21327
|
+
const relPath = path26.relative(root, fullPath);
|
|
22785
21328
|
try {
|
|
22786
21329
|
const content = fs6.readFileSync(fullPath, "utf8");
|
|
22787
21330
|
result[relPath] = hashContent3(content);
|
|
@@ -22796,7 +21339,7 @@ function scanFiles(root, extensions, exclude) {
|
|
|
22796
21339
|
function computeDiff(current, previous, sourceDir) {
|
|
22797
21340
|
const changes = [];
|
|
22798
21341
|
for (const [relPath, hash] of Object.entries(current)) {
|
|
22799
|
-
const fullPath =
|
|
21342
|
+
const fullPath = path26.join(sourceDir, relPath);
|
|
22800
21343
|
if (!(relPath in previous)) {
|
|
22801
21344
|
let size = 0;
|
|
22802
21345
|
try {
|
|
@@ -22829,7 +21372,7 @@ function computeDiff(current, previous, sourceDir) {
|
|
|
22829
21372
|
for (const relPath of Object.keys(previous)) {
|
|
22830
21373
|
if (!(relPath in current)) {
|
|
22831
21374
|
changes.push({
|
|
22832
|
-
filePath:
|
|
21375
|
+
filePath: path26.join(sourceDir, relPath),
|
|
22833
21376
|
relativePath: relPath,
|
|
22834
21377
|
type: "deleted",
|
|
22835
21378
|
currentHash: "",
|
|
@@ -22859,20 +21402,20 @@ function hashContent3(content) {
|
|
|
22859
21402
|
import { spawnSync } from "child_process";
|
|
22860
21403
|
import crypto7 from "crypto";
|
|
22861
21404
|
import fs7 from "fs";
|
|
22862
|
-
import
|
|
21405
|
+
import path27 from "path";
|
|
22863
21406
|
var MANIFEST_VERSION = 1;
|
|
22864
21407
|
var MANIFEST_LOCK_STALE_MS = 3e4;
|
|
22865
21408
|
var MANIFEST_LOCK_TIMEOUT_MS = MANIFEST_LOCK_STALE_MS + 1e4;
|
|
22866
21409
|
var MANIFEST_LOCK_SLEEP_MS = 20;
|
|
22867
21410
|
function normalizeSpaceMemoryDir(memoryDir) {
|
|
22868
|
-
return
|
|
21411
|
+
return path27.resolve(memoryDir);
|
|
22869
21412
|
}
|
|
22870
21413
|
function getSpacesDir(baseDir) {
|
|
22871
21414
|
const homeDir = baseDir ?? resolveHomeDir();
|
|
22872
|
-
return
|
|
21415
|
+
return path27.join(homeDir, ".config", "engram", "spaces");
|
|
22873
21416
|
}
|
|
22874
21417
|
function getManifestPath(baseDir) {
|
|
22875
|
-
return
|
|
21418
|
+
return path27.join(getSpacesDir(baseDir), "manifest.json");
|
|
22876
21419
|
}
|
|
22877
21420
|
function loadManifest(baseDir, memoryDirOverride) {
|
|
22878
21421
|
if (fs7.existsSync(getManifestPath(baseDir))) {
|
|
@@ -22919,9 +21462,9 @@ function readManifestUnlocked(baseDir, memoryDirOverride, options = {}) {
|
|
|
22919
21462
|
}
|
|
22920
21463
|
function saveManifestUnlocked(manifest, baseDir) {
|
|
22921
21464
|
const manifestPath2 = getManifestPath(baseDir);
|
|
22922
|
-
const manifestDir2 =
|
|
21465
|
+
const manifestDir2 = path27.dirname(manifestPath2);
|
|
22923
21466
|
fs7.mkdirSync(manifestDir2, { recursive: true });
|
|
22924
|
-
const tempPath =
|
|
21467
|
+
const tempPath = path27.join(manifestDir2, `.manifest.${process.pid}.${Date.now()}.${crypto7.randomUUID()}.tmp`);
|
|
22925
21468
|
try {
|
|
22926
21469
|
fs7.writeFileSync(tempPath, `${JSON.stringify(manifest, null, 2)}
|
|
22927
21470
|
`, { flag: "wx" });
|
|
@@ -22936,7 +21479,7 @@ function saveManifestUnlocked(manifest, baseDir) {
|
|
|
22936
21479
|
}
|
|
22937
21480
|
function withManifestLock(baseDir, operation) {
|
|
22938
21481
|
const lockDir = `${getManifestPath(baseDir)}.lock`;
|
|
22939
|
-
fs7.mkdirSync(
|
|
21482
|
+
fs7.mkdirSync(path27.dirname(lockDir), { recursive: true });
|
|
22940
21483
|
const lockOwner = acquireManifestLock(lockDir);
|
|
22941
21484
|
try {
|
|
22942
21485
|
return operation();
|
|
@@ -22962,7 +21505,7 @@ function acquireManifestLock(lockDir) {
|
|
|
22962
21505
|
try {
|
|
22963
21506
|
fs7.mkdirSync(lockDir, { recursive: false });
|
|
22964
21507
|
try {
|
|
22965
|
-
fs7.writeFileSync(
|
|
21508
|
+
fs7.writeFileSync(path27.join(lockDir, "owner"), `${owner}
|
|
22966
21509
|
`, { flag: "wx" });
|
|
22967
21510
|
} catch (error) {
|
|
22968
21511
|
fs7.rmSync(lockDir, { recursive: true, force: true });
|
|
@@ -22992,7 +21535,7 @@ function acquireManifestLock(lockDir) {
|
|
|
22992
21535
|
}
|
|
22993
21536
|
function releaseManifestLock(lockDir, owner) {
|
|
22994
21537
|
try {
|
|
22995
|
-
const ownerPath =
|
|
21538
|
+
const ownerPath = path27.join(lockDir, "owner");
|
|
22996
21539
|
if (fs7.readFileSync(ownerPath, "utf8").trim() === owner) {
|
|
22997
21540
|
fs7.rmSync(lockDir, { recursive: true, force: true });
|
|
22998
21541
|
}
|
|
@@ -23008,7 +21551,7 @@ function removeStaleManifestLock(lockDir) {
|
|
|
23008
21551
|
try {
|
|
23009
21552
|
fs7.mkdirSync(reclaimDir, { recursive: false });
|
|
23010
21553
|
try {
|
|
23011
|
-
fs7.writeFileSync(
|
|
21554
|
+
fs7.writeFileSync(path27.join(reclaimDir, "owner"), `${reclaimOwner}
|
|
23012
21555
|
`, { flag: "wx" });
|
|
23013
21556
|
} catch (error) {
|
|
23014
21557
|
fs7.rmSync(reclaimDir, { recursive: true, force: true });
|
|
@@ -23083,7 +21626,7 @@ function readManifestLockSnapshot(lockDir) {
|
|
|
23083
21626
|
throw error;
|
|
23084
21627
|
}
|
|
23085
21628
|
try {
|
|
23086
|
-
const owner = fs7.readFileSync(
|
|
21629
|
+
const owner = fs7.readFileSync(path27.join(lockDir, "owner"), "utf8").trim();
|
|
23087
21630
|
return { mtimeMs: stat5.mtimeMs, owner };
|
|
23088
21631
|
} catch (error) {
|
|
23089
21632
|
if (error.code === "ENOENT") {
|
|
@@ -23155,8 +21698,8 @@ function sleepSync(ms) {
|
|
|
23155
21698
|
}
|
|
23156
21699
|
function createPersonalSpace(baseDir, memoryDirOverride) {
|
|
23157
21700
|
const homeDir = baseDir ?? resolveHomeDir();
|
|
23158
|
-
const standalonePath =
|
|
23159
|
-
const openclawPath =
|
|
21701
|
+
const standalonePath = path27.join(homeDir, ".engram", "memory");
|
|
21702
|
+
const openclawPath = path27.join(homeDir, ".openclaw", "workspace", "memory", "local");
|
|
23160
21703
|
const memoryDir = memoryDirOverride ?? readEnvVar("REMNIC_MEMORY_DIR") ?? readEnvVar("ENGRAM_MEMORY_DIR") ?? (fs7.existsSync(standalonePath) ? standalonePath : fs7.existsSync(openclawPath) ? openclawPath : standalonePath);
|
|
23161
21704
|
const normalizedMemoryDir = normalizeSpaceMemoryDir(memoryDir);
|
|
23162
21705
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -23185,7 +21728,7 @@ function createSpace(options) {
|
|
|
23185
21728
|
const id = options.name.toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/-+/g, "-");
|
|
23186
21729
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
23187
21730
|
const memoryDir = normalizeSpaceMemoryDir(
|
|
23188
|
-
options.memoryDir ??
|
|
21731
|
+
options.memoryDir ?? path27.join(getSpacesDir(options.baseDir), id, "memory")
|
|
23189
21732
|
);
|
|
23190
21733
|
const space = updateManifest(options.baseDir, (manifest) => {
|
|
23191
21734
|
if (manifest.spaces.some((s) => s.id === id)) {
|
|
@@ -23406,14 +21949,14 @@ function mergeSpaces(sourceSpaceId, targetSpaceId, options) {
|
|
|
23406
21949
|
};
|
|
23407
21950
|
}
|
|
23408
21951
|
function getAuditLog(baseDir) {
|
|
23409
|
-
const auditPath =
|
|
21952
|
+
const auditPath = path27.join(getSpacesDir(baseDir), "audit.jsonl");
|
|
23410
21953
|
if (!fs7.existsSync(auditPath)) return [];
|
|
23411
21954
|
const lines = fs7.readFileSync(auditPath, "utf8").trim().split("\n");
|
|
23412
21955
|
return lines.filter((l) => l.trim()).map((l) => JSON.parse(l));
|
|
23413
21956
|
}
|
|
23414
21957
|
function appendAudit(entry, baseDir) {
|
|
23415
|
-
const auditPath =
|
|
23416
|
-
fs7.mkdirSync(
|
|
21958
|
+
const auditPath = path27.join(getSpacesDir(baseDir), "audit.jsonl");
|
|
21959
|
+
fs7.mkdirSync(path27.dirname(auditPath), { recursive: true });
|
|
23417
21960
|
const full = {
|
|
23418
21961
|
id: crypto7.randomUUID(),
|
|
23419
21962
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -23445,8 +21988,8 @@ function copyMemories(sourceDir, targetDir, options) {
|
|
|
23445
21988
|
continue;
|
|
23446
21989
|
}
|
|
23447
21990
|
const content = fs7.readFileSync(sourcePath, "utf8");
|
|
23448
|
-
const relativePath =
|
|
23449
|
-
const targetPath =
|
|
21991
|
+
const relativePath = path27.relative(sourceRoot, sourceRealPath);
|
|
21992
|
+
const targetPath = path27.resolve(targetRoot, relativePath);
|
|
23450
21993
|
if (!isPathInsideRoot(targetPath, targetRoot)) {
|
|
23451
21994
|
skipped++;
|
|
23452
21995
|
continue;
|
|
@@ -23488,8 +22031,8 @@ function copyMemories(sourceDir, targetDir, options) {
|
|
|
23488
22031
|
skipped++;
|
|
23489
22032
|
continue;
|
|
23490
22033
|
}
|
|
23491
|
-
fs7.mkdirSync(
|
|
23492
|
-
const targetParentRealPath = safeRealpath(
|
|
22034
|
+
fs7.mkdirSync(path27.dirname(targetPath), { recursive: true });
|
|
22035
|
+
const targetParentRealPath = safeRealpath(path27.dirname(targetPath));
|
|
23493
22036
|
if (!targetParentRealPath || !isPathInsideRoot(targetParentRealPath, targetRoot)) {
|
|
23494
22037
|
skipped++;
|
|
23495
22038
|
continue;
|
|
@@ -23507,7 +22050,7 @@ function walkMd2(dir) {
|
|
|
23507
22050
|
const results = [];
|
|
23508
22051
|
function walk(d) {
|
|
23509
22052
|
for (const entry of fs7.readdirSync(d, { withFileTypes: true })) {
|
|
23510
|
-
const fullPath =
|
|
22053
|
+
const fullPath = path27.join(d, entry.name);
|
|
23511
22054
|
if (entry.isSymbolicLink()) {
|
|
23512
22055
|
continue;
|
|
23513
22056
|
}
|
|
@@ -23536,8 +22079,8 @@ function safeRealpath(filePath) {
|
|
|
23536
22079
|
}
|
|
23537
22080
|
}
|
|
23538
22081
|
function isPathInsideRoot(candidatePath, rootPath) {
|
|
23539
|
-
const relative =
|
|
23540
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
22082
|
+
const relative = path27.relative(rootPath, candidatePath);
|
|
22083
|
+
return relative === "" || !relative.startsWith("..") && !path27.isAbsolute(relative);
|
|
23541
22084
|
}
|
|
23542
22085
|
function parseSimpleFrontmatter(content) {
|
|
23543
22086
|
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
@@ -23657,22 +22200,22 @@ var REMNIC_RECALL_DECISION_RULES = `## When to Use Recall vs Direct Read
|
|
|
23657
22200
|
|
|
23658
22201
|
// src/memory-extension/codex-publisher.ts
|
|
23659
22202
|
import fs8 from "fs";
|
|
23660
|
-
import
|
|
23661
|
-
import
|
|
22203
|
+
import os from "os";
|
|
22204
|
+
import path28 from "path";
|
|
23662
22205
|
var REMNIC_EXTENSION_DIR_NAME = "remnic";
|
|
23663
22206
|
function resolveEnvHome(env) {
|
|
23664
22207
|
if (env === void 0) return resolveHomeDir();
|
|
23665
|
-
return env.HOME?.trim() || env.USERPROFILE?.trim() ||
|
|
22208
|
+
return env.HOME?.trim() || env.USERPROFILE?.trim() || os.homedir();
|
|
23666
22209
|
}
|
|
23667
22210
|
function expandTildeWithHome(input, homeDir) {
|
|
23668
22211
|
if (input === "~") return homeDir;
|
|
23669
22212
|
if (input.startsWith("~/") || input.startsWith("~\\")) {
|
|
23670
|
-
return
|
|
22213
|
+
return path28.join(homeDir, input.slice(2));
|
|
23671
22214
|
}
|
|
23672
22215
|
return input;
|
|
23673
22216
|
}
|
|
23674
22217
|
function normalizeHostRoot(input, homeDir) {
|
|
23675
|
-
return
|
|
22218
|
+
return path28.resolve(expandTildeWithHome(input.trim(), homeDir));
|
|
23676
22219
|
}
|
|
23677
22220
|
var CodexMemoryExtensionPublisher = class {
|
|
23678
22221
|
hostId = "codex";
|
|
@@ -23686,12 +22229,12 @@ var CodexMemoryExtensionPublisher = class {
|
|
|
23686
22229
|
async resolveExtensionRoot(env) {
|
|
23687
22230
|
const homeDir = resolveEnvHome(env);
|
|
23688
22231
|
const codexHomeInput = env === void 0 ? readEnvVar("CODEX_HOME")?.trim() : env.CODEX_HOME?.trim();
|
|
23689
|
-
const codexHome = codexHomeInput ? normalizeHostRoot(codexHomeInput, homeDir) :
|
|
23690
|
-
return
|
|
22232
|
+
const codexHome = codexHomeInput ? normalizeHostRoot(codexHomeInput, homeDir) : path28.resolve(homeDir, ".codex");
|
|
22233
|
+
return path28.join(codexHome, "memories_extensions", REMNIC_EXTENSION_DIR_NAME);
|
|
23691
22234
|
}
|
|
23692
22235
|
async isHostAvailable() {
|
|
23693
22236
|
try {
|
|
23694
|
-
const home = readEnvVar("CODEX_HOME")?.trim() ||
|
|
22237
|
+
const home = readEnvVar("CODEX_HOME")?.trim() || path28.join(resolveHomeDir(), ".codex");
|
|
23695
22238
|
return fs8.existsSync(home);
|
|
23696
22239
|
} catch {
|
|
23697
22240
|
return false;
|
|
@@ -23742,7 +22285,7 @@ When running inside the Codex phase-2 consolidation sandbox:
|
|
|
23742
22285
|
}
|
|
23743
22286
|
async publish(ctx) {
|
|
23744
22287
|
const extensionRoot = await this.resolveExtensionRoot();
|
|
23745
|
-
const instructionsPath =
|
|
22288
|
+
const instructionsPath = path28.join(extensionRoot, "instructions.md");
|
|
23746
22289
|
const filesWritten = [];
|
|
23747
22290
|
const skipped = [];
|
|
23748
22291
|
ctx.log.info(`Publishing Codex memory extension to ${extensionRoot}`);
|
|
@@ -24116,9 +22659,9 @@ async function generateActivityMemories(date, digestBody, config, deps) {
|
|
|
24116
22659
|
}
|
|
24117
22660
|
|
|
24118
22661
|
// src/session-summaries/index.ts
|
|
24119
|
-
import { createHash as
|
|
22662
|
+
import { createHash as createHash7 } from "crypto";
|
|
24120
22663
|
import { lstat as lstat2, mkdir as mkdir7, readFile as readFile6, readdir as readdir4, rename, rm, stat as stat4, writeFile as writeFile7 } from "fs/promises";
|
|
24121
|
-
import
|
|
22664
|
+
import path29 from "path";
|
|
24122
22665
|
|
|
24123
22666
|
// src/session-summaries/adapters.ts
|
|
24124
22667
|
var VALID_ROLES = /* @__PURE__ */ new Set(["user", "assistant", "tool", "system", "other"]);
|
|
@@ -24618,12 +23161,12 @@ var DEFAULT_MAX_FILES = 5e3;
|
|
|
24618
23161
|
var DEFAULT_MAX_SESSIONS = 500;
|
|
24619
23162
|
var SUPPORTED_EXTENSIONS = /* @__PURE__ */ new Set([".json", ".jsonl"]);
|
|
24620
23163
|
function shortHash(value, length = 16) {
|
|
24621
|
-
return
|
|
23164
|
+
return createHash7("sha256").update(value).digest("hex").slice(0, length);
|
|
24622
23165
|
}
|
|
24623
23166
|
async function listTranscriptFiles(root, maxFiles) {
|
|
24624
23167
|
const out = [];
|
|
24625
23168
|
let truncated = false;
|
|
24626
|
-
const entrySortKey = (entryName, isDirectory) => isDirectory ? `${entryName}${
|
|
23169
|
+
const entrySortKey = (entryName, isDirectory) => isDirectory ? `${entryName}${path29.sep}` : entryName;
|
|
24627
23170
|
async function visit(dir) {
|
|
24628
23171
|
if (truncated) return;
|
|
24629
23172
|
const entries = (await readdir4(dir, { withFileTypes: true })).sort(
|
|
@@ -24633,13 +23176,13 @@ async function listTranscriptFiles(root, maxFiles) {
|
|
|
24633
23176
|
if (truncated) return;
|
|
24634
23177
|
if (entry.name.startsWith(".")) continue;
|
|
24635
23178
|
if (entry.isSymbolicLink()) continue;
|
|
24636
|
-
const fullPath =
|
|
23179
|
+
const fullPath = path29.join(dir, entry.name);
|
|
24637
23180
|
if (entry.isDirectory()) {
|
|
24638
23181
|
await visit(fullPath);
|
|
24639
23182
|
continue;
|
|
24640
23183
|
}
|
|
24641
23184
|
if (!entry.isFile()) continue;
|
|
24642
|
-
const ext =
|
|
23185
|
+
const ext = path29.extname(entry.name).toLowerCase();
|
|
24643
23186
|
if (!SUPPORTED_EXTENSIONS.has(ext)) continue;
|
|
24644
23187
|
out.push(fullPath);
|
|
24645
23188
|
if (out.length > maxFiles) {
|
|
@@ -24666,7 +23209,7 @@ function normalizeInputDir(inputDir) {
|
|
|
24666
23209
|
if (typeof inputDir !== "string" || inputDir.trim().length === 0) {
|
|
24667
23210
|
throw new Error("inputDir must be a non-empty string");
|
|
24668
23211
|
}
|
|
24669
|
-
return
|
|
23212
|
+
return path29.resolve(expandTildePath(inputDir.trim()));
|
|
24670
23213
|
}
|
|
24671
23214
|
function initRoleCounts() {
|
|
24672
23215
|
return {
|
|
@@ -24823,11 +23366,11 @@ async function collectLocalSessionSummaries(options) {
|
|
|
24823
23366
|
continue;
|
|
24824
23367
|
}
|
|
24825
23368
|
seenFileHashes.add(fileHash);
|
|
24826
|
-
const fileExtension =
|
|
23369
|
+
const fileExtension = path29.extname(filePath).toLowerCase();
|
|
24827
23370
|
const parsed = await adapter.parseFile(
|
|
24828
23371
|
{
|
|
24829
23372
|
content,
|
|
24830
|
-
fileName:
|
|
23373
|
+
fileName: path29.basename(filePath),
|
|
24831
23374
|
fileExtension,
|
|
24832
23375
|
fileRef: fileHash
|
|
24833
23376
|
},
|
|
@@ -24883,7 +23426,7 @@ async function collectLocalSessionSummaries(options) {
|
|
|
24883
23426
|
}
|
|
24884
23427
|
async function readRedactionConfig(pathLike) {
|
|
24885
23428
|
if (!pathLike) return void 0;
|
|
24886
|
-
const raw = await readFile6(
|
|
23429
|
+
const raw = await readFile6(path29.resolve(expandTildePath(pathLike)), "utf-8");
|
|
24887
23430
|
const parsed = JSON.parse(raw);
|
|
24888
23431
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
24889
23432
|
throw new Error("redaction config must be a JSON object");
|
|
@@ -24896,15 +23439,15 @@ function toJsonl(drafts) {
|
|
|
24896
23439
|
}
|
|
24897
23440
|
function defaultDraftOutputPath(memoryDir, generatedAt) {
|
|
24898
23441
|
const stamp = generatedAt.replace(/[:.]/g, "-");
|
|
24899
|
-
return
|
|
24900
|
-
|
|
23442
|
+
return path29.join(
|
|
23443
|
+
path29.resolve(expandTildePath(memoryDir)),
|
|
24901
23444
|
"state",
|
|
24902
23445
|
"session-summary-drafts",
|
|
24903
23446
|
`session-summaries-${stamp}.jsonl`
|
|
24904
23447
|
);
|
|
24905
23448
|
}
|
|
24906
23449
|
async function writeDrafts(filePath, drafts) {
|
|
24907
|
-
await mkdir7(
|
|
23450
|
+
await mkdir7(path29.dirname(filePath), { recursive: true });
|
|
24908
23451
|
const tempPath = `${filePath}.${process.pid}.${Date.now()}.tmp`;
|
|
24909
23452
|
try {
|
|
24910
23453
|
await writeFile7(tempPath, toJsonl(drafts), "utf-8");
|
|
@@ -24922,7 +23465,7 @@ async function runLocalSessionSummaryCliCommand(options) {
|
|
|
24922
23465
|
});
|
|
24923
23466
|
const wroteFiles = [];
|
|
24924
23467
|
if (options.output) {
|
|
24925
|
-
const outputPath =
|
|
23468
|
+
const outputPath = path29.resolve(expandTildePath(options.output));
|
|
24926
23469
|
await writeDrafts(outputPath, report.drafts);
|
|
24927
23470
|
wroteFiles.push(outputPath);
|
|
24928
23471
|
}
|
|
@@ -24957,19 +23500,19 @@ async function runLocalSessionSummaryCliCommand(options) {
|
|
|
24957
23500
|
|
|
24958
23501
|
// src/transfer/capsule-fork.ts
|
|
24959
23502
|
import { lstat as lstat3, mkdir as mkdir8, readFile as readFile7, realpath as realpath2, writeFile as writeFile8 } from "fs/promises";
|
|
24960
|
-
import
|
|
23503
|
+
import path30 from "path";
|
|
24961
23504
|
async function forkCapsule(opts) {
|
|
24962
23505
|
validateForkId(opts.forkId);
|
|
24963
|
-
const rootAbs =
|
|
23506
|
+
const rootAbs = path30.resolve(opts.targetRoot);
|
|
24964
23507
|
await assertIsDirectoryNotSymlink(rootAbs, "forkCapsule", "targetRoot");
|
|
24965
|
-
const forkDirAbs =
|
|
23508
|
+
const forkDirAbs = path30.join(rootAbs, "forks", opts.forkId);
|
|
24966
23509
|
const forkEntryExists = await pathEntryExists(forkDirAbs);
|
|
24967
23510
|
if (forkEntryExists) {
|
|
24968
23511
|
throw new Error(
|
|
24969
23512
|
`forkCapsule: fork path already exists \u2014 forkId "${opts.forkId}" is already in use at: ${forkDirAbs}`
|
|
24970
23513
|
);
|
|
24971
23514
|
}
|
|
24972
|
-
const archiveAbs =
|
|
23515
|
+
const archiveAbs = path30.resolve(opts.sourceArchive);
|
|
24973
23516
|
const importResult = await importCapsule({
|
|
24974
23517
|
archivePath: archiveAbs,
|
|
24975
23518
|
root: rootAbs,
|
|
@@ -24991,10 +23534,10 @@ async function forkCapsule(opts) {
|
|
|
24991
23534
|
importedRecords: importResult.imported.length,
|
|
24992
23535
|
skippedRecords: importResult.skipped.length
|
|
24993
23536
|
};
|
|
24994
|
-
const lineagePath =
|
|
23537
|
+
const lineagePath = path30.join(forkDirAbs, "lineage.json");
|
|
24995
23538
|
const rootReal = await realpath2(rootAbs);
|
|
24996
23539
|
await assertRealpathInsideRoot(rootReal, lineagePath, `forks/${opts.forkId}/lineage.json`, "forkCapsule");
|
|
24997
|
-
await mkdir8(
|
|
23540
|
+
await mkdir8(path30.dirname(lineagePath), { recursive: true });
|
|
24998
23541
|
await writeFile8(lineagePath, JSON.stringify(lineage, null, 2) + "\n", "utf-8");
|
|
24999
23542
|
return {
|
|
25000
23543
|
archivePath: archiveAbs,
|
|
@@ -25008,11 +23551,11 @@ async function readForkLineage(targetRoot, forkId) {
|
|
|
25008
23551
|
if (typeof forkId !== "string" || forkId.length === 0 || forkId.length > 64 || !CAPSULE_ID_PATTERN.test(forkId)) {
|
|
25009
23552
|
return null;
|
|
25010
23553
|
}
|
|
25011
|
-
const rootAbs =
|
|
23554
|
+
const rootAbs = path30.resolve(targetRoot);
|
|
25012
23555
|
const rootReal = await realpath2(rootAbs).catch(() => rootAbs);
|
|
25013
|
-
const lineagePath =
|
|
25014
|
-
const rel =
|
|
25015
|
-
if (rel.startsWith("..") ||
|
|
23556
|
+
const lineagePath = path30.join(rootReal, "forks", forkId, "lineage.json");
|
|
23557
|
+
const rel = path30.relative(rootReal, lineagePath);
|
|
23558
|
+
if (rel.startsWith("..") || path30.isAbsolute(rel)) {
|
|
25016
23559
|
return null;
|
|
25017
23560
|
}
|
|
25018
23561
|
if (!await isLineagePathContained(rootReal, lineagePath)) {
|
|
@@ -25053,60 +23596,23 @@ async function pathEntryExists(absPath) {
|
|
|
25053
23596
|
async function isLineagePathContained(rootReal, lineagePath) {
|
|
25054
23597
|
let existing = lineagePath;
|
|
25055
23598
|
const suffix = [];
|
|
25056
|
-
while (existing !==
|
|
23599
|
+
while (existing !== path30.dirname(existing)) {
|
|
25057
23600
|
const st = await lstat3(existing).catch(() => null);
|
|
25058
23601
|
if (st !== null) break;
|
|
25059
|
-
suffix.unshift(
|
|
25060
|
-
existing =
|
|
23602
|
+
suffix.unshift(path30.basename(existing));
|
|
23603
|
+
existing = path30.dirname(existing);
|
|
25061
23604
|
}
|
|
25062
23605
|
const existingReal = await realpath2(existing).catch(() => existing);
|
|
25063
|
-
const targetReal = suffix.length > 0 ?
|
|
25064
|
-
const rel =
|
|
23606
|
+
const targetReal = suffix.length > 0 ? path30.join(existingReal, ...suffix) : existingReal;
|
|
23607
|
+
const rel = path30.relative(rootReal, targetReal);
|
|
25065
23608
|
if (rel === "") return true;
|
|
25066
23609
|
if (rel === "..") return false;
|
|
25067
|
-
if (rel.startsWith(`..${
|
|
25068
|
-
if (
|
|
23610
|
+
if (rel.startsWith(`..${path30.sep}`)) return false;
|
|
23611
|
+
if (path30.isAbsolute(rel)) return false;
|
|
25069
23612
|
return true;
|
|
25070
23613
|
}
|
|
25071
23614
|
|
|
25072
23615
|
export {
|
|
25073
|
-
BulkImportBatchPartialFailureError,
|
|
25074
|
-
mapRecallSourceToXrayServedBy,
|
|
25075
|
-
throwIfRecallAborted,
|
|
25076
|
-
raceRecallAbort,
|
|
25077
|
-
COMPACTION_SIGNAL_MAX_AGE_MS,
|
|
25078
|
-
normalizeIanaTimeZone,
|
|
25079
|
-
formatDateInTimeZone,
|
|
25080
|
-
utcDateKeysForLocalDay,
|
|
25081
|
-
parseFiniteDate,
|
|
25082
|
-
filterHourlySummaryMarkdownForLocalDay,
|
|
25083
|
-
qmdStartupCollectionCheckWithTimeout,
|
|
25084
|
-
defaultWorkspaceDir,
|
|
25085
|
-
sanitizeSessionKeyForFilename,
|
|
25086
|
-
targetSourceValidAtSortMs,
|
|
25087
|
-
splitTurnsBySourceValidAt,
|
|
25088
|
-
isArtifactMemoryPath,
|
|
25089
|
-
buildCompressionGuidelinesMarkdown2 as buildCompressionGuidelinesMarkdown,
|
|
25090
|
-
applyQueryAwareCandidateFilter,
|
|
25091
|
-
tokenizeRecallQuery,
|
|
25092
|
-
shouldFilterLifecycleRecallCandidate,
|
|
25093
|
-
lifecycleRecallScoreAdjustment,
|
|
25094
|
-
computeArtifactRecallLimit,
|
|
25095
|
-
resolveEffectiveRecallMode,
|
|
25096
|
-
resolveRecallModeDecision,
|
|
25097
|
-
resolveRecallModeDecisionAsync,
|
|
25098
|
-
computeArtifactCandidateFetchLimit,
|
|
25099
|
-
computeQmdHybridFetchLimit,
|
|
25100
|
-
summarizeGraphShadowComparison,
|
|
25101
|
-
parseGraphRecallRankedResults,
|
|
25102
|
-
parseMemoryIntentSnapshot,
|
|
25103
|
-
parseQmdRecallResults,
|
|
25104
|
-
mergeArtifactRecallCandidates,
|
|
25105
|
-
resolveRecentThreadMemoryPaths,
|
|
25106
|
-
buildMemoryPathById,
|
|
25107
|
-
appendMemoryToGraphContext,
|
|
25108
|
-
resolvePersistedMemoryRelativePath,
|
|
25109
|
-
deriveTopicsFromExtraction,
|
|
25110
23616
|
buildProcedureRecallSection,
|
|
25111
23617
|
RELAY_DEMO_MISSION_ID,
|
|
25112
23618
|
RELAY_DEMO_NAMESPACE,
|
|
@@ -25222,4 +23728,4 @@ export {
|
|
|
25222
23728
|
filterRecallCandidates,
|
|
25223
23729
|
Orchestrator
|
|
25224
23730
|
};
|
|
25225
|
-
//# sourceMappingURL=chunk-
|
|
23731
|
+
//# sourceMappingURL=chunk-RUYJ7TWU.js.map
|