@remnic/core 1.1.12 → 1.1.13
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-cli.d.ts +2 -1
- package/dist/access-cli.js +263 -82
- package/dist/access-cli.js.map +1 -1
- package/dist/access-http.d.ts +26 -60
- package/dist/access-http.js +43 -29
- package/dist/access-mcp.d.ts +24 -6
- package/dist/access-mcp.js +35 -28
- package/dist/access-schema.d.ts +9 -6
- package/dist/access-schema.js +7 -5
- package/dist/access-service-DcCDmNYC.d.ts +1542 -0
- package/dist/access-service.d.ts +25 -7
- package/dist/access-service.js +33 -26
- package/dist/active-memory-bridge.js +2 -2
- package/dist/active-recall.js +11 -3
- package/dist/active-recall.js.map +1 -1
- package/dist/adapters/claude-code.d.ts +24 -0
- package/dist/adapters/claude-code.js +9 -0
- package/dist/adapters/codex.d.ts +25 -0
- package/dist/adapters/codex.js +9 -0
- package/dist/adapters/hermes.d.ts +35 -0
- package/dist/adapters/hermes.js +9 -0
- package/dist/adapters/index.d.ts +6 -0
- package/dist/adapters/index.js +26 -0
- package/dist/adapters/registry.d.ts +20 -0
- package/dist/adapters/registry.js +13 -0
- package/dist/adapters/replit.d.ts +28 -0
- package/dist/adapters/replit.js +9 -0
- package/dist/adapters/types.d.ts +43 -0
- package/dist/adapters/types.js +8 -0
- package/dist/bootstrap.d.ts +20 -5
- package/dist/boxes.d.ts +7 -0
- package/dist/boxes.js +1 -1
- package/dist/briefing.d.ts +5 -3
- package/dist/briefing.js +9 -6
- package/dist/buffer-surprise-report.js +1 -1
- package/dist/buffer.d.ts +18 -4
- package/dist/buffer.js +1 -1
- package/dist/calibration.js +4 -4
- package/dist/capsule-cli.d.ts +4 -4
- package/dist/capsule-cli.js +1 -1
- package/dist/capsule-crypto-5CYAGVC5.js +18 -0
- package/dist/capsule-merge-4MGKE7C5.js +189 -0
- package/dist/causal-behavior.d.ts +8 -28
- package/dist/causal-behavior.js +6 -3
- package/dist/causal-behavior.js.map +1 -1
- package/dist/causal-chain.js +3 -2
- package/dist/causal-consolidation.d.ts +1 -1
- package/dist/causal-consolidation.js +24 -13
- package/dist/causal-consolidation.js.map +1 -1
- package/dist/causal-retrieval.js +3 -3
- package/dist/causal-trajectory.js +1 -1
- package/dist/chunk-25MQ7IHJ.js +427 -0
- package/dist/chunk-25MQ7IHJ.js.map +1 -0
- package/dist/chunk-2F2W355T.js +256 -0
- package/dist/chunk-2F2W355T.js.map +1 -0
- package/dist/chunk-2KI4QFHU.js +228 -0
- package/dist/chunk-2KI4QFHU.js.map +1 -0
- package/dist/chunk-2PRQG7PV.js +86 -0
- package/dist/chunk-2PRQG7PV.js.map +1 -0
- package/dist/chunk-2QR3XXIC.js +2272 -0
- package/dist/chunk-2QR3XXIC.js.map +1 -0
- package/dist/chunk-2WWLHTZY.js +121 -0
- package/dist/chunk-326G7DJK.js +2185 -0
- package/dist/chunk-326G7DJK.js.map +1 -0
- package/dist/chunk-34DQE4KF.js +174 -0
- package/dist/chunk-34DQE4KF.js.map +1 -0
- package/dist/chunk-3APJ5EVB.js +601 -0
- package/dist/chunk-3APJ5EVB.js.map +1 -0
- package/dist/chunk-3HPAPHUK.js +51 -0
- package/dist/chunk-3HPAPHUK.js.map +1 -0
- package/dist/chunk-3JXBXXM2.js +69 -0
- package/dist/chunk-3JXBXXM2.js.map +1 -0
- package/dist/chunk-3KW65B36.js +681 -0
- package/dist/chunk-3KW65B36.js.map +1 -0
- package/dist/chunk-3UXOZBHV.js +20 -0
- package/dist/chunk-3UXOZBHV.js.map +1 -0
- package/dist/chunk-3VAL7ZL2.js +266 -0
- package/dist/chunk-3VAL7ZL2.js.map +1 -0
- package/dist/chunk-3Y4P7RXM.js +31 -0
- package/dist/chunk-3Y4P7RXM.js.map +1 -0
- package/dist/chunk-47VWKCAF.js +273 -0
- package/dist/chunk-47VWKCAF.js.map +1 -0
- package/dist/chunk-4CRG46BG.js +271 -0
- package/dist/chunk-5375UYTQ.js +914 -0
- package/dist/chunk-5375UYTQ.js.map +1 -0
- package/dist/chunk-56K5QLHX.js +506 -0
- package/dist/chunk-56K5QLHX.js.map +1 -0
- package/dist/chunk-5RGLBDQF.js +596 -0
- package/dist/chunk-5RGLBDQF.js.map +1 -0
- package/dist/chunk-5UZXUTVO.js +9 -0
- package/dist/chunk-5UZXUTVO.js.map +1 -0
- package/dist/chunk-65PG43EQ.js +105 -0
- package/dist/chunk-65PG43EQ.js.map +1 -0
- package/dist/chunk-66DHUKLO.js +57 -0
- package/dist/chunk-66DHUKLO.js.map +1 -0
- package/dist/chunk-6FC5EGNV.js +46 -0
- package/dist/chunk-6FC5EGNV.js.map +1 -0
- package/dist/chunk-6H2TESSP.js +62 -0
- package/dist/chunk-6H2TESSP.js.map +1 -0
- package/dist/chunk-6LVVDPJ4.js +32 -0
- package/dist/chunk-6LVVDPJ4.js.map +1 -0
- package/dist/chunk-6RVI47ZR.js +159 -0
- package/dist/chunk-6RVI47ZR.js.map +1 -0
- package/dist/chunk-7AAT6G4Q.js +5117 -0
- package/dist/chunk-7AAT6G4Q.js.map +1 -0
- package/dist/chunk-7DTASS5T.js +29 -0
- package/dist/chunk-7DTASS5T.js.map +1 -0
- package/dist/chunk-7IASACLB.js +596 -0
- package/dist/chunk-7MNMYOFP.js +32 -0
- package/dist/chunk-7MNMYOFP.js.map +1 -0
- package/dist/chunk-7N4KAIGN.js +133 -0
- package/dist/chunk-7N4KAIGN.js.map +1 -0
- package/dist/chunk-7OZ53EXP.js +101 -0
- package/dist/chunk-7OZ53EXP.js.map +1 -0
- package/dist/chunk-7XYTQGCC.js +134 -0
- package/dist/chunk-7XYTQGCC.js.map +1 -0
- package/dist/chunk-A2XUIMJ3.js +341 -0
- package/dist/chunk-A2XUIMJ3.js.map +1 -0
- package/dist/chunk-AGZQD76C.js +201 -0
- package/dist/chunk-AGZQD76C.js.map +1 -0
- package/dist/chunk-APO3DCMU.js +361 -0
- package/dist/chunk-APO3DCMU.js.map +1 -0
- package/dist/chunk-BFBF3XEF.js +283 -0
- package/dist/chunk-BFBF3XEF.js.map +1 -0
- package/dist/chunk-BJ3KMYTB.js +1974 -0
- package/dist/chunk-BJ3KMYTB.js.map +1 -0
- package/dist/chunk-CHEL3SKB.js +6758 -0
- package/dist/chunk-CHEL3SKB.js.map +1 -0
- package/dist/chunk-CQZRLNMV.js +1491 -0
- package/dist/chunk-CQZRLNMV.js.map +1 -0
- package/dist/chunk-D46YSIYX.js +892 -0
- package/dist/chunk-D46YSIYX.js.map +1 -0
- package/dist/chunk-DINWEURR.js +648 -0
- package/dist/chunk-DINWEURR.js.map +1 -0
- package/dist/chunk-DK5LDEQM.js +530 -0
- package/dist/chunk-DK5LDEQM.js.map +1 -0
- package/dist/chunk-DOM4GKSW.js +34 -0
- package/dist/chunk-DOM4GKSW.js.map +1 -0
- package/dist/chunk-EDTHC6UD.js +1075 -0
- package/dist/chunk-EFJ3MQ4V.js +721 -0
- package/dist/chunk-EHRTFRWW.js +89 -0
- package/dist/chunk-EHRTFRWW.js.map +1 -0
- package/dist/chunk-FAJ7FZYM.js +11 -0
- package/dist/chunk-FAJ7FZYM.js.map +1 -0
- package/dist/chunk-FBYESMQ2.js +570 -0
- package/dist/chunk-FDU6HUUL.js +147 -0
- package/dist/chunk-FF4KLI5W.js +99 -0
- package/dist/chunk-FF4KLI5W.js.map +1 -0
- package/dist/chunk-FIT6DMX6.js +310 -0
- package/dist/chunk-FIT6DMX6.js.map +1 -0
- package/dist/chunk-FJ43PRLT.js +272 -0
- package/dist/chunk-FJ43PRLT.js.map +1 -0
- package/dist/chunk-FKFMOY3N.js +32 -0
- package/dist/chunk-FKFMOY3N.js.map +1 -0
- package/dist/chunk-FLTNHQK6.js +262 -0
- package/dist/chunk-FLTNHQK6.js.map +1 -0
- package/dist/chunk-GA454ALV.js +12436 -0
- package/dist/chunk-GA454ALV.js.map +1 -0
- package/dist/chunk-GGKRUQOO.js +228 -0
- package/dist/chunk-GIF42EW3.js +63 -0
- package/dist/chunk-GIF42EW3.js.map +1 -0
- package/dist/chunk-GL6I6MEQ.js +647 -0
- package/dist/chunk-H3ME6L6D.js +709 -0
- package/dist/chunk-H3ME6L6D.js.map +1 -0
- package/dist/chunk-HHLLAQGZ.js +1 -0
- package/dist/chunk-HXXBL2KD.js +2040 -0
- package/dist/chunk-I5V2VDIW.js +219 -0
- package/dist/chunk-I5V2VDIW.js.map +1 -0
- package/dist/chunk-I6K5FBRQ.js +35 -0
- package/dist/chunk-I6K5FBRQ.js.map +1 -0
- package/dist/chunk-ICRIXAP2.js +121 -0
- package/dist/chunk-ICRIXAP2.js.map +1 -0
- package/dist/chunk-J4EB7DNW.js +11 -0
- package/dist/chunk-J4EB7DNW.js.map +1 -0
- package/dist/chunk-JLFA7DQG.js +62 -0
- package/dist/chunk-JLFA7DQG.js.map +1 -0
- package/dist/chunk-KJTKLXTH.js +9 -0
- package/dist/chunk-KJTKLXTH.js.map +1 -0
- package/dist/chunk-KLAO5DGL.js +917 -0
- package/dist/chunk-KLAO5DGL.js.map +1 -0
- package/dist/chunk-KNKUID7G.js +183 -0
- package/dist/chunk-KOSORCJG.js +624 -0
- package/dist/chunk-KOSORCJG.js.map +1 -0
- package/dist/chunk-KUJVMMZQ.js +1262 -0
- package/dist/chunk-KUJVMMZQ.js.map +1 -0
- package/dist/chunk-LCR46JY5.js +123 -0
- package/dist/chunk-LCR46JY5.js.map +1 -0
- package/dist/chunk-LLQ2LLWF.js +148 -0
- package/dist/chunk-LLQ2LLWF.js.map +1 -0
- package/dist/chunk-LPMVBPA3.js +236 -0
- package/dist/chunk-LT3NLYSI.js +50 -0
- package/dist/chunk-LT3NLYSI.js.map +1 -0
- package/dist/chunk-LUDTDZLK.js +287 -0
- package/dist/chunk-LUDTDZLK.js.map +1 -0
- package/dist/chunk-M23FSH32.js +3963 -0
- package/dist/chunk-M23FSH32.js.map +1 -0
- package/dist/chunk-MC26UJIM.js +118 -0
- package/dist/chunk-ME6ESPZU.js +119 -0
- package/dist/chunk-ME6ESPZU.js.map +1 -0
- package/dist/chunk-MGKYQQYF.js +272 -0
- package/dist/chunk-MJFNCJXV.js +66 -0
- package/dist/chunk-MJFNCJXV.js.map +1 -0
- package/dist/chunk-MSWG7JI6.js +237 -0
- package/dist/chunk-MSWG7JI6.js.map +1 -0
- package/dist/chunk-MT25YHYH.js +141 -0
- package/dist/chunk-MT25YHYH.js.map +1 -0
- package/dist/chunk-MT4HVDUZ.js +53 -0
- package/dist/chunk-MY6TPVXW.js +219 -0
- package/dist/chunk-N2D6GXBM.js +267 -0
- package/dist/chunk-N2D6GXBM.js.map +1 -0
- package/dist/chunk-NJ3MJQZX.js +46 -0
- package/dist/chunk-NJ3MJQZX.js.map +1 -0
- package/dist/chunk-NMZY542O.js +335 -0
- package/dist/chunk-NMZY542O.js.map +1 -0
- package/dist/chunk-NNVTUXEB.js +23 -0
- package/dist/chunk-NZL6GGQE.js +375 -0
- package/dist/chunk-NZL6GGQE.js.map +1 -0
- package/dist/chunk-P4NEIHUT.js +108 -0
- package/dist/chunk-P7FMDTKL.js +103 -0
- package/dist/chunk-P7FMDTKL.js.map +1 -0
- package/dist/chunk-PHK3HARR.js +32 -0
- package/dist/chunk-PHK3HARR.js.map +1 -0
- package/dist/chunk-PIRJPV5T.js +98 -0
- package/dist/chunk-PIRJPV5T.js.map +1 -0
- package/dist/chunk-PK7H5L6Y.js +159 -0
- package/dist/chunk-PK7H5L6Y.js.map +1 -0
- package/dist/chunk-PR5FBTFU.js +233 -0
- package/dist/chunk-PR5FBTFU.js.map +1 -0
- package/dist/chunk-PU63GXWS.js +174 -0
- package/dist/chunk-PU63GXWS.js.map +1 -0
- package/dist/chunk-PZIAX57I.js +124 -0
- package/dist/chunk-PZIAX57I.js.map +1 -0
- package/dist/chunk-Q7P4WJDP.js +26 -0
- package/dist/chunk-Q7P4WJDP.js.map +1 -0
- package/dist/chunk-QQUAB63I.js +63 -0
- package/dist/chunk-QQUAB63I.js.map +1 -0
- package/dist/chunk-QRNI5JBH.js +18 -0
- package/dist/chunk-RHY3HH7P.js +601 -0
- package/dist/chunk-RHY3HH7P.js.map +1 -0
- package/dist/chunk-RRF5UOBJ.js +91 -0
- package/dist/chunk-RXDLTSWT.js +124 -0
- package/dist/chunk-RXDLTSWT.js.map +1 -0
- package/dist/chunk-RYED3SPJ.js +42 -0
- package/dist/chunk-RYED3SPJ.js.map +1 -0
- package/dist/chunk-S7KDBTWT.js +106 -0
- package/dist/chunk-S7KDBTWT.js.map +1 -0
- package/dist/chunk-SEDEKFYQ.js +1 -0
- package/dist/chunk-TECVW3JP.js +36 -0
- package/dist/chunk-TECVW3JP.js.map +1 -0
- package/dist/chunk-TFO23QT4.js +88 -0
- package/dist/chunk-TFO23QT4.js.map +1 -0
- package/dist/chunk-TK4UEOSK.js +76 -0
- package/dist/chunk-TK4UEOSK.js.map +1 -0
- package/dist/chunk-TKWGAOLV.js +122 -0
- package/dist/chunk-TKWGAOLV.js.map +1 -0
- package/dist/chunk-TMM4S4IJ.js +597 -0
- package/dist/chunk-TMM4S4IJ.js.map +1 -0
- package/dist/chunk-TMQLARTH.js +188 -0
- package/dist/chunk-TMQLARTH.js.map +1 -0
- package/dist/chunk-TPDBFYEG.js +130 -0
- package/dist/chunk-TPDBFYEG.js.map +1 -0
- package/dist/chunk-TPMQ3G6Z.js +145 -0
- package/dist/chunk-TPMQ3G6Z.js.map +1 -0
- package/dist/chunk-TZOLIGIG.js +61 -0
- package/dist/chunk-TZOLIGIG.js.map +1 -0
- package/dist/chunk-U3PN77QT.js +113 -0
- package/dist/chunk-U3WSW6PZ.js +277 -0
- package/dist/chunk-U4SCL7B7.js +640 -0
- package/dist/chunk-U4SCL7B7.js.map +1 -0
- package/dist/chunk-UWK5OXUJ.js +156 -0
- package/dist/chunk-UWK5OXUJ.js.map +1 -0
- package/dist/chunk-UWVJF25J.js +74 -0
- package/dist/chunk-UXHQAFNA.js +1317 -0
- package/dist/chunk-UXHQAFNA.js.map +1 -0
- package/dist/chunk-V5OCT34X.js +1 -0
- package/dist/chunk-VLXA6PI2.js +304 -0
- package/dist/chunk-VLXA6PI2.js.map +1 -0
- package/dist/chunk-VNO6ZJ35.js +500 -0
- package/dist/chunk-VNO6ZJ35.js.map +1 -0
- package/dist/chunk-VW676BEI.js +827 -0
- package/dist/chunk-VW676BEI.js.map +1 -0
- package/dist/chunk-W3LR522O.js +2296 -0
- package/dist/chunk-W4L6CZKA.js +96 -0
- package/dist/chunk-W4L6CZKA.js.map +1 -0
- package/dist/chunk-W4RVMTHR.js +372 -0
- package/dist/chunk-W4RVMTHR.js.map +1 -0
- package/dist/chunk-WEHSQBFR.js +188 -0
- package/dist/chunk-WEHSQBFR.js.map +1 -0
- package/dist/chunk-WELDCG6C.js +380 -0
- package/dist/chunk-WELDCG6C.js.map +1 -0
- package/dist/chunk-WZYKANL3.js +2800 -0
- package/dist/chunk-WZYKANL3.js.map +1 -0
- package/dist/chunk-XIG5PDM7.js +48 -0
- package/dist/chunk-XJNBEDFE.js +193 -0
- package/dist/chunk-XJNBEDFE.js.map +1 -0
- package/dist/chunk-XVVIG67A.js +291 -0
- package/dist/chunk-XVVIG67A.js.map +1 -0
- package/dist/chunk-XVZ7B3HG.js +135 -0
- package/dist/chunk-YBPYIAA5.js +73 -0
- package/dist/chunk-YBPYIAA5.js.map +1 -0
- package/dist/chunk-Z734BLO3.js +21 -0
- package/dist/chunk-Z734BLO3.js.map +1 -0
- package/dist/chunk-ZKSK55RC.js +269 -0
- package/dist/chunk-ZKSK55RC.js.map +1 -0
- package/dist/chunk-ZTFCYYEZ.js +69 -0
- package/dist/chunk-ZTFCYYEZ.js.map +1 -0
- package/dist/chunk-ZY2MNJR6.js +329 -0
- package/dist/chunk-ZY2MNJR6.js.map +1 -0
- package/dist/cli-D3VpkVwB.d.ts +1136 -0
- package/dist/cli.d.ts +39 -10
- package/dist/cli.js +108 -49
- package/dist/commitment-ledger.js +1 -1
- package/dist/compat/checks.d.ts +5 -0
- package/dist/compat/checks.js +11 -0
- package/dist/compat/checks.js.map +1 -0
- package/dist/compat/types.d.ts +30 -0
- package/dist/compat/types.js +1 -0
- package/dist/compat/types.js.map +1 -0
- package/dist/compounding/engine.d.ts +221 -0
- package/dist/compounding/engine.js +32 -0
- package/dist/compounding/engine.js.map +1 -0
- package/dist/compounding/preference-consolidator.d.ts +92 -0
- package/dist/compounding/preference-consolidator.js +553 -0
- package/dist/compounding/preference-consolidator.js.map +1 -0
- package/dist/config.d.ts +4 -2
- package/dist/config.js +9 -4
- package/dist/conflict-policy-DyJ2wd-h.d.ts +4 -0
- package/dist/connectors/codex-materialize-runner.d.ts +64 -0
- package/dist/connectors/codex-materialize-runner.js +33 -0
- package/dist/connectors/codex-materialize-runner.js.map +1 -0
- package/dist/connectors/codex-materialize.d.ts +195 -0
- package/dist/connectors/codex-materialize.js +38 -0
- package/dist/connectors/codex-materialize.js.map +1 -0
- package/dist/connectors/index.d.ts +444 -0
- package/dist/connectors/index.js +115 -0
- package/dist/connectors/index.js.map +1 -0
- package/dist/connectors-cli-CwbyjGR7.d.ts +257 -0
- package/dist/connectors-cli.d.ts +1 -1
- package/dist/consolidation-provenance-check.d.ts +3 -1
- package/dist/consolidation-undo.d.ts +3 -1
- package/dist/contradiction/index.d.ts +258 -0
- package/dist/contradiction/index.js +43 -0
- package/dist/contradiction/index.js.map +1 -0
- package/dist/contradiction-review-ATP4S6IC.js +30 -0
- package/dist/contradiction-review-ATP4S6IC.js.map +1 -0
- package/dist/contradiction-scan-5A4IDZV5.js +13 -0
- package/dist/contradiction-scan-5A4IDZV5.js.map +1 -0
- package/dist/conversation-index/backend.d.ts +97 -0
- package/dist/conversation-index/backend.js +13 -0
- package/dist/conversation-index/backend.js.map +1 -0
- package/dist/conversation-index/chunker.d.ts +16 -0
- package/dist/conversation-index/chunker.js +8 -0
- package/dist/conversation-index/chunker.js.map +1 -0
- package/dist/conversation-index/cleanup.d.ts +11 -0
- package/dist/conversation-index/cleanup.js +9 -0
- package/dist/conversation-index/cleanup.js.map +1 -0
- package/dist/conversation-index/faiss-adapter.d.ts +6 -0
- package/dist/conversation-index/faiss-adapter.js +16 -0
- package/dist/conversation-index/faiss-adapter.js.map +1 -0
- package/dist/conversation-index/indexer.d.ts +23 -0
- package/dist/conversation-index/indexer.js +15 -0
- package/dist/conversation-index/indexer.js.map +1 -0
- package/dist/conversation-index/search.d.ts +6 -0
- package/dist/conversation-index/search.js +11 -0
- package/dist/conversation-index/search.js.map +1 -0
- package/dist/embedding-fallback.js +2 -2
- package/dist/enrichment/index.d.ts +163 -0
- package/dist/enrichment/index.js +18 -0
- package/dist/enrichment/index.js.map +1 -0
- package/dist/entity-retrieval.d.ts +4 -2
- package/dist/entity-retrieval.js +8 -5
- package/dist/evals.js +1 -1
- package/dist/explicit-capture.d.ts +20 -5
- package/dist/explicit-capture.js +2 -2
- package/dist/extraction-judge-training.js +1 -1
- package/dist/extraction.js +8 -8
- package/dist/faiss-adapter-CzPghc4C.d.ts +70 -0
- package/dist/fallback-llm.d.ts +2 -0
- package/dist/fallback-llm.js +4 -4
- package/dist/graph-edge-decay-5DI5GUNL.js +207 -0
- package/dist/index.d.ts +66 -711
- package/dist/index.js +556 -2680
- package/dist/index.js.map +1 -1
- package/dist/lcm/archive.d.ts +89 -0
- package/dist/lcm/archive.js +12 -0
- package/dist/lcm/archive.js.map +1 -0
- package/dist/lcm/dag.d.ts +48 -0
- package/dist/lcm/dag.js +8 -0
- package/dist/lcm/dag.js.map +1 -0
- package/dist/lcm/engine.d.ts +116 -0
- package/dist/lcm/engine.js +20 -0
- package/dist/lcm/engine.js.map +1 -0
- package/dist/lcm/index.d.ts +12 -0
- package/dist/lcm/index.js +44 -0
- package/dist/lcm/index.js.map +1 -0
- package/dist/lcm/queue.d.ts +62 -0
- package/dist/lcm/queue.js +8 -0
- package/dist/lcm/queue.js.map +1 -0
- package/dist/lcm/recall.d.ts +20 -0
- package/dist/lcm/recall.js +8 -0
- package/dist/lcm/recall.js.map +1 -0
- package/dist/lcm/schema.d.ts +16 -0
- package/dist/lcm/schema.js +14 -0
- package/dist/lcm/schema.js.map +1 -0
- package/dist/lcm/summarizer.d.ts +38 -0
- package/dist/lcm/summarizer.js +12 -0
- package/dist/lcm/summarizer.js.map +1 -0
- package/dist/lcm/tools.d.ts +29 -0
- package/dist/lcm/tools.js +8 -0
- package/dist/lcm/tools.js.map +1 -0
- package/dist/live-connectors-runner.js +5 -5
- package/dist/local-llm.js +3 -3
- package/dist/maintenance/archive-observations.d.ts +18 -0
- package/dist/maintenance/archive-observations.js +8 -0
- package/dist/maintenance/archive-observations.js.map +1 -0
- package/dist/maintenance/backup-stamp.d.ts +3 -0
- package/dist/maintenance/backup-stamp.js +8 -0
- package/dist/maintenance/backup-stamp.js.map +1 -0
- package/dist/maintenance/memory-governance-cron.d.ts +85 -0
- package/dist/maintenance/memory-governance-cron.js +22 -0
- package/dist/maintenance/memory-governance-cron.js.map +1 -0
- package/dist/maintenance/memory-governance.d.ts +137 -0
- package/dist/maintenance/memory-governance.js +40 -0
- package/dist/maintenance/memory-governance.js.map +1 -0
- package/dist/maintenance/migrate-observations.d.ts +18 -0
- package/dist/maintenance/migrate-observations.js +9 -0
- package/dist/maintenance/migrate-observations.js.map +1 -0
- package/dist/maintenance/observation-ledger-utils.d.ts +10 -0
- package/dist/maintenance/observation-ledger-utils.js +10 -0
- package/dist/maintenance/observation-ledger-utils.js.map +1 -0
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.d.ts +15 -0
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +28 -0
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js.map +1 -0
- package/dist/maintenance/rebuild-memory-projection.d.ts +77 -0
- package/dist/maintenance/rebuild-memory-projection.js +35 -0
- package/dist/maintenance/rebuild-memory-projection.js.map +1 -0
- package/dist/maintenance/rebuild-observations.d.ts +17 -0
- package/dist/maintenance/rebuild-observations.js +9 -0
- package/dist/maintenance/rebuild-observations.js.map +1 -0
- package/dist/mcp-memory-inspector-app.d.ts +24 -6
- package/dist/memory-projection-store.d.ts +108 -3
- package/dist/memory-projection-store.js +2 -1
- package/dist/memory-worth-outcomes.d.ts +4 -2
- package/dist/migrate/from-engram.d.ts +24 -0
- package/dist/migrate/from-engram.js +12 -0
- package/dist/migrate/from-engram.js.map +1 -0
- package/dist/namespaces/migrate.d.ts +50 -0
- package/dist/namespaces/migrate.js +50 -0
- package/dist/namespaces/migrate.js.map +1 -0
- package/dist/namespaces/principal.d.ts +17 -0
- package/dist/namespaces/principal.js +16 -0
- package/dist/namespaces/principal.js.map +1 -0
- package/dist/namespaces/search.d.ts +46 -0
- package/dist/namespaces/search.js +28 -0
- package/dist/namespaces/search.js.map +1 -0
- package/dist/namespaces/storage.d.ts +32 -0
- package/dist/namespaces/storage.js +28 -0
- package/dist/namespaces/storage.js.map +1 -0
- package/dist/network/tailscale.d.ts +41 -0
- package/dist/network/tailscale.js +9 -0
- package/dist/network/tailscale.js.map +1 -0
- package/dist/network/webdav.d.ts +39 -0
- package/dist/network/webdav.js +10 -0
- package/dist/network/webdav.js.map +1 -0
- package/dist/objective-state-writers.js +2 -2
- package/dist/operator-toolkit.d.ts +4 -2
- package/dist/operator-toolkit.js +32 -14
- package/dist/opik-exporter.js +2 -2
- package/dist/opik-exporter.js.map +1 -1
- package/dist/orchestrator-DuWl9Hwx.d.ts +1244 -0
- package/dist/orchestrator.d.ts +22 -7
- package/dist/orchestrator.js +79 -44
- package/dist/path-MR5JPYOP.js +9 -0
- package/dist/path-MR5JPYOP.js.map +1 -0
- package/dist/qmd-recall-cache.d.ts +1 -1
- package/dist/qmd.d.ts +102 -3
- package/dist/qmd.js +23 -5
- package/dist/recall-explain-renderer.js +3 -3
- package/dist/recall-xray-cli.js +4 -4
- package/dist/recall-xray-renderer.js +3 -3
- package/dist/recall-xray.js +2 -2
- package/dist/replay/normalizers/chatgpt.d.ts +6 -0
- package/dist/replay/normalizers/chatgpt.js +11 -0
- package/dist/replay/normalizers/chatgpt.js.map +1 -0
- package/dist/replay/normalizers/claude.d.ts +6 -0
- package/dist/replay/normalizers/claude.js +11 -0
- package/dist/replay/normalizers/claude.js.map +1 -0
- package/dist/replay/normalizers/openclaw.d.ts +6 -0
- package/dist/replay/normalizers/openclaw.js +11 -0
- package/dist/replay/normalizers/openclaw.js.map +1 -0
- package/dist/replay/normalizers/shared.d.ts +16 -0
- package/dist/replay/normalizers/shared.js +14 -0
- package/dist/replay/normalizers/shared.js.map +1 -0
- package/dist/replay/runner.d.ts +35 -0
- package/dist/replay/runner.js +16 -0
- package/dist/replay/runner.js.map +1 -0
- package/dist/replay/types.d.ts +57 -0
- package/dist/replay/types.js +19 -0
- package/dist/replay/types.js.map +1 -0
- package/dist/resolution-B7FNQSSP.js +12 -0
- package/dist/resolution-B7FNQSSP.js.map +1 -0
- package/dist/resolve-provider-secret.js +2 -2
- package/dist/resume-bundles.js +8 -6
- package/dist/retrieval-agents.d.ts +1 -1
- package/dist/routing/engine.d.ts +35 -0
- package/dist/routing/engine.js +16 -0
- package/dist/routing/engine.js.map +1 -0
- package/dist/routing/store.d.ts +27 -0
- package/dist/routing/store.js +10 -0
- package/dist/routing/store.js.map +1 -0
- package/dist/runtime/better-sqlite.d.ts +8 -0
- package/dist/runtime/better-sqlite.js +10 -0
- package/dist/runtime/better-sqlite.js.map +1 -0
- package/dist/runtime/child-process.d.ts +32 -0
- package/dist/runtime/child-process.js +10 -0
- package/dist/runtime/child-process.js.map +1 -0
- package/dist/runtime/env.d.ts +5 -0
- package/dist/runtime/env.js +12 -0
- package/dist/runtime/env.js.map +1 -0
- package/dist/schemas.d.ts +22 -22
- package/dist/sdk-compat.js +1 -1
- package/dist/search/document-scanner.d.ts +22 -0
- package/dist/search/document-scanner.js +8 -0
- package/dist/search/document-scanner.js.map +1 -0
- package/dist/search/embed-helper.d.ts +35 -0
- package/dist/search/embed-helper.js +9 -0
- package/dist/search/embed-helper.js.map +1 -0
- package/dist/search/factory.d.ts +32 -0
- package/dist/search/factory.js +29 -0
- package/dist/search/factory.js.map +1 -0
- package/dist/search/index.d.ts +15 -0
- package/dist/search/index.js +50 -0
- package/dist/search/index.js.map +1 -0
- package/dist/search/lancedb-backend.d.ts +51 -0
- package/dist/search/lancedb-backend.js +10 -0
- package/dist/search/lancedb-backend.js.map +1 -0
- package/dist/search/meilisearch-backend.d.ts +48 -0
- package/dist/search/meilisearch-backend.js +10 -0
- package/dist/search/meilisearch-backend.js.map +1 -0
- package/dist/search/noop-backend.d.ts +26 -0
- package/dist/search/noop-backend.js +8 -0
- package/dist/search/noop-backend.js.map +1 -0
- package/dist/search/orama-backend.d.ts +53 -0
- package/dist/search/orama-backend.js +10 -0
- package/dist/search/orama-backend.js.map +1 -0
- package/dist/search/port.d.ts +61 -0
- package/dist/search/port.js +1 -0
- package/dist/search/port.js.map +1 -0
- package/dist/search/remote-backend.d.ts +39 -0
- package/dist/search/remote-backend.js +9 -0
- package/dist/search/remote-backend.js.map +1 -0
- package/dist/secure-store/index.d.ts +890 -0
- package/dist/secure-store/index.js +156 -0
- package/dist/secure-store/index.js.map +1 -0
- package/dist/semantic-VwGI14Ok.d.ts +69 -0
- package/dist/semantic-consolidation-4HkHWgeI.d.ts +180 -0
- package/dist/semantic-consolidation.d.ts +2 -2
- package/dist/semantic-consolidation.js +13 -6
- package/dist/semantic-rule-promotion.js +8 -5
- package/dist/semantic-rule-verifier.js +8 -5
- package/dist/shared-context/manager.d.ts +131 -0
- package/dist/shared-context/manager.js +15 -0
- package/dist/shared-context/manager.js.map +1 -0
- package/dist/skills-registry.js +13 -1
- package/dist/skills-registry.js.map +1 -1
- package/dist/state-store-VZU2IA53.js +16 -0
- package/dist/state-store-VZU2IA53.js.map +1 -0
- package/dist/storage-paths.d.ts +9 -0
- package/dist/storage-paths.js +20 -0
- package/dist/storage-paths.js.map +1 -0
- package/dist/storage.d.ts +3 -1
- package/dist/storage.js +7 -4
- package/dist/summarizer.d.ts +5 -0
- package/dist/summarizer.js +9 -8
- package/dist/summary-snapshot.js +2 -1
- package/dist/surfaces/dreams.d.ts +16 -0
- package/dist/surfaces/dreams.js +282 -0
- package/dist/surfaces/dreams.js.map +1 -0
- package/dist/surfaces/heartbeat.d.ts +17 -0
- package/dist/surfaces/heartbeat.js +265 -0
- package/dist/surfaces/heartbeat.js.map +1 -0
- package/dist/temporal-supersession.d.ts +3 -1
- package/dist/threading.d.ts +5 -0
- package/dist/threading.js +2 -1
- package/dist/tier-migration.d.ts +4 -2
- package/dist/tokens.js +2 -2
- package/dist/transcript.d.ts +15 -1
- package/dist/transcript.js +2 -1
- package/dist/transfer/autodetect.d.ts +4 -0
- package/dist/transfer/autodetect.js +15 -0
- package/dist/transfer/autodetect.js.map +1 -0
- package/dist/transfer/backup.d.ts +21 -0
- package/dist/transfer/backup.js +17 -0
- package/dist/transfer/backup.js.map +1 -0
- package/dist/transfer/capsule-export.d.ts +113 -0
- package/dist/transfer/capsule-export.js +19 -0
- package/dist/transfer/capsule-export.js.map +1 -0
- package/dist/transfer/capsule-import.d.ts +124 -0
- package/dist/transfer/capsule-import.js +16 -0
- package/dist/transfer/capsule-import.js.map +1 -0
- package/dist/transfer/constants.d.ts +13 -0
- package/dist/transfer/constants.js +12 -0
- package/dist/transfer/constants.js.map +1 -0
- package/dist/transfer/export-json.d.ts +11 -0
- package/dist/transfer/export-json.js +11 -0
- package/dist/transfer/export-json.js.map +1 -0
- package/dist/transfer/export-md.d.ts +10 -0
- package/dist/transfer/export-md.js +13 -0
- package/dist/transfer/export-md.js.map +1 -0
- package/dist/transfer/export-sqlite.d.ts +9 -0
- package/dist/transfer/export-sqlite.js +12 -0
- package/dist/transfer/export-sqlite.js.map +1 -0
- package/dist/transfer/fs-utils.d.ts +61 -0
- package/dist/transfer/fs-utils.js +40 -0
- package/dist/transfer/fs-utils.js.map +1 -0
- package/dist/transfer/import-json.d.ts +16 -0
- package/dist/transfer/import-json.js +13 -0
- package/dist/transfer/import-json.js.map +1 -0
- package/dist/transfer/import-md.d.ts +14 -0
- package/dist/transfer/import-md.js +11 -0
- package/dist/transfer/import-md.js.map +1 -0
- package/dist/transfer/import-sqlite.d.ts +14 -0
- package/dist/transfer/import-sqlite.js +12 -0
- package/dist/transfer/import-sqlite.js.map +1 -0
- package/dist/transfer/sqlite-schema.d.ts +4 -0
- package/dist/transfer/sqlite-schema.js +10 -0
- package/dist/transfer/sqlite-schema.js.map +1 -0
- package/dist/transfer/types.d.ts +916 -0
- package/dist/transfer/types.js +30 -0
- package/dist/transfer/types.js.map +1 -0
- package/dist/types.d.ts +28 -1
- package/dist/types.js +1 -1
- package/dist/verified-recall.js +9 -6
- package/dist/work/board.d.ts +43 -0
- package/dist/work/board.js +14 -0
- package/dist/work/board.js.map +1 -0
- package/dist/work/boundary.d.ts +8 -0
- package/dist/work/boundary.js +14 -0
- package/dist/work/boundary.js.map +1 -0
- package/dist/work/storage.d.ts +39 -0
- package/dist/work/storage.js +11 -0
- package/dist/work/storage.js.map +1 -0
- package/dist/work/types.d.ts +75 -0
- package/dist/work/types.js +1 -0
- package/dist/work/types.js.map +1 -0
- package/package.json +2767 -6
- package/scripts/faiss_index.py +816 -0
- package/scripts/faiss_requirements.txt +3 -0
- package/skills/remnic-entities/SKILL.md +51 -0
- package/skills/remnic-memory-workflow/SKILL.md +61 -0
- package/skills/remnic-recall/SKILL.md +51 -0
- package/skills/remnic-remember/SKILL.md +56 -0
- package/skills/remnic-search/SKILL.md +51 -0
- package/skills/remnic-status/SKILL.md +51 -0
- package/src/abort-error.test.ts +49 -0
- package/src/abort-error.ts +46 -0
- package/src/abstraction-nodes.ts +162 -0
- package/src/access-audit.test.ts +178 -0
- package/src/access-audit.ts +125 -0
- package/src/access-cli.test.ts +439 -0
- package/src/access-cli.ts +438 -0
- package/src/access-http.test.ts +225 -0
- package/src/access-http.ts +1899 -0
- package/src/access-idempotency.ts +232 -0
- package/src/access-mcp.test.ts +568 -0
- package/src/access-mcp.ts +3056 -0
- package/src/access-schema-pi.test.ts +60 -0
- package/src/access-schema.ts +522 -0
- package/src/access-service-namespace.test.ts +123 -0
- package/src/access-service.ts +5629 -0
- package/src/action-confidence.test.ts +206 -0
- package/src/action-confidence.ts +466 -0
- package/src/active-memory-bridge.test.ts +285 -0
- package/src/active-memory-bridge.ts +217 -0
- package/src/active-recall.test.ts +484 -0
- package/src/active-recall.ts +459 -0
- package/src/adapters/claude-code.ts +56 -0
- package/src/adapters/codex.ts +57 -0
- package/src/adapters/hermes.ts +64 -0
- package/src/adapters/index.ts +6 -0
- package/src/adapters/registry.ts +41 -0
- package/src/adapters/replit.ts +55 -0
- package/src/adapters/types.ts +51 -0
- package/src/behavior-learner.ts +144 -0
- package/src/behavior-signals.ts +73 -0
- package/src/binary-lifecycle/backend.ts +117 -0
- package/src/binary-lifecycle/index.ts +35 -0
- package/src/binary-lifecycle/manifest.ts +79 -0
- package/src/binary-lifecycle/pipeline.ts +352 -0
- package/src/binary-lifecycle/scanner.ts +89 -0
- package/src/binary-lifecycle/types.ts +89 -0
- package/src/bootstrap.ts +178 -0
- package/src/boxes.ts +521 -0
- package/src/briefing.test.ts +1535 -0
- package/src/briefing.ts +1382 -0
- package/src/buffer-session.test.ts +443 -0
- package/src/buffer-surprise-report.ts +176 -0
- package/src/buffer-surprise-telemetry.test.ts +606 -0
- package/src/buffer-surprise-trigger.test.ts +766 -0
- package/src/buffer-surprise.test.ts +339 -0
- package/src/buffer-surprise.ts +203 -0
- package/src/buffer.ts +900 -0
- package/src/bulk-import/cli-command.test.ts +204 -0
- package/src/bulk-import/index.ts +34 -0
- package/src/bulk-import/pipeline.test.ts +445 -0
- package/src/bulk-import/pipeline.ts +178 -0
- package/src/bulk-import/registry.test.ts +151 -0
- package/src/bulk-import/registry.ts +72 -0
- package/src/bulk-import/types.test.ts +272 -0
- package/src/bulk-import/types.ts +145 -0
- package/src/calibration.ts +394 -0
- package/src/capsule-cli.test.ts +398 -0
- package/src/capsule-cli.ts +565 -0
- package/src/causal-behavior.ts +308 -0
- package/src/causal-chain.ts +419 -0
- package/src/causal-consolidation.ts +370 -0
- package/src/causal-retrieval.ts +286 -0
- package/src/causal-trajectory-graph.ts +60 -0
- package/src/causal-trajectory.ts +303 -0
- package/src/chunking.ts +220 -0
- package/src/citations.ts +232 -0
- package/src/cli.ts +9403 -0
- package/src/codex-cli-fallback.ts +162 -0
- package/src/codex-thread-key.ts +1 -0
- package/src/coding/access-coding-context.test.ts +197 -0
- package/src/coding/coding-branch-scope.test.ts +281 -0
- package/src/coding/coding-namespace.test.ts +360 -0
- package/src/coding/coding-namespace.ts +412 -0
- package/src/coding/coding-orchestrator.test.ts +249 -0
- package/src/coding/git-context.test.ts +507 -0
- package/src/coding/git-context.ts +336 -0
- package/src/coding/mcp-set-coding-context.test.ts +174 -0
- package/src/coding/review-context.test.ts +316 -0
- package/src/coding/review-context.ts +349 -0
- package/src/coding/wire-coding-context.test.ts +468 -0
- package/src/commitment-ledger.test.ts +78 -0
- package/src/commitment-ledger.ts +337 -0
- package/src/compat/checks.test.ts +206 -0
- package/src/compat/checks.ts +716 -0
- package/src/compat/types.ts +33 -0
- package/src/compounding/engine.ts +1686 -0
- package/src/compounding/preference-consolidator.ts +778 -0
- package/src/compression-optimizer.ts +312 -0
- package/src/config.test.ts +930 -0
- package/src/config.ts +3807 -0
- package/src/connectors/codex/instructions.md +160 -0
- package/src/connectors/codex/resources/namespace-cheatsheet.md +48 -0
- package/src/connectors/codex-marketplace.ts +500 -0
- package/src/connectors/codex-materialize-runner.ts +212 -0
- package/src/connectors/codex-materialize.ts +983 -0
- package/src/connectors/coerce.ts +62 -0
- package/src/connectors/index.test.ts +1570 -0
- package/src/connectors/index.ts +3222 -0
- package/src/connectors/live/framework.ts +164 -0
- package/src/connectors/live/github.test.ts +1218 -0
- package/src/connectors/live/github.ts +1068 -0
- package/src/connectors/live/gmail.test.ts +1706 -0
- package/src/connectors/live/gmail.ts +1293 -0
- package/src/connectors/live/google-drive.test.ts +696 -0
- package/src/connectors/live/google-drive.ts +724 -0
- package/src/connectors/live/index.ts +101 -0
- package/src/connectors/live/live-connectors.test.ts +689 -0
- package/src/connectors/live/notion.test.ts +1109 -0
- package/src/connectors/live/notion.ts +978 -0
- package/src/connectors/live/registry.ts +103 -0
- package/src/connectors/live/state-store.ts +399 -0
- package/src/connectors/live/transient-errors.ts +150 -0
- package/src/connectors/weclone-installer.test.ts +850 -0
- package/src/connectors-cli.ts +513 -0
- package/src/console/state.test.ts +224 -0
- package/src/console/state.ts +514 -0
- package/src/console/trace.test.ts +813 -0
- package/src/console/trace.ts +603 -0
- package/src/console/tui.test.ts +582 -0
- package/src/console/tui.ts +508 -0
- package/src/consolidation-operator.ts +182 -0
- package/src/consolidation-provenance-check.ts +551 -0
- package/src/consolidation-undo.ts +718 -0
- package/src/contradiction/contradiction-judge.test.ts +189 -0
- package/src/contradiction/contradiction-judge.ts +333 -0
- package/src/contradiction/contradiction-review.ts +574 -0
- package/src/contradiction/contradiction-scan.ts +504 -0
- package/src/contradiction/contradiction.test.ts +2230 -0
- package/src/contradiction/index.ts +37 -0
- package/src/contradiction/resolution.ts +383 -0
- package/src/conversation-index/backend.ts +323 -0
- package/src/conversation-index/chunker.ts +47 -0
- package/src/conversation-index/cleanup.ts +53 -0
- package/src/conversation-index/faiss-adapter.ts +384 -0
- package/src/conversation-index/indexer.test.ts +164 -0
- package/src/conversation-index/indexer.ts +192 -0
- package/src/conversation-index/search.ts +37 -0
- package/src/cross-namespace-budget.test.ts +275 -0
- package/src/cross-namespace-budget.ts +365 -0
- package/src/cue-anchors.ts +163 -0
- package/src/curation/index.ts +544 -0
- package/src/dashboard-runtime.ts +337 -0
- package/src/day-summary.ts +122 -0
- package/src/dedup/index.ts +330 -0
- package/src/dedup/semantic.test.ts +1577 -0
- package/src/dedup/semantic.ts +148 -0
- package/src/delinearize.ts +193 -0
- package/src/direct-answer-wiring.test.ts +473 -0
- package/src/direct-answer-wiring.ts +180 -0
- package/src/direct-answer.test.ts +484 -0
- package/src/direct-answer.ts +273 -0
- package/src/embedding-fallback.ts +565 -0
- package/src/enrichment/audit.ts +89 -0
- package/src/enrichment/index.ts +27 -0
- package/src/enrichment/pipeline.ts +197 -0
- package/src/enrichment/provider-registry.ts +85 -0
- package/src/enrichment/types.ts +100 -0
- package/src/enrichment/web-search-provider.ts +63 -0
- package/src/entity-retrieval.ts +774 -0
- package/src/entity-schema.ts +239 -0
- package/src/evals.ts +1312 -0
- package/src/event-order-recall.test.ts +4164 -0
- package/src/event-order-recall.ts +2802 -0
- package/src/evidence-pack.test.ts +89 -0
- package/src/evidence-pack.ts +388 -0
- package/src/explicit-capture.ts +530 -0
- package/src/explicit-cue-recall.test.ts +3019 -0
- package/src/explicit-cue-recall.ts +5545 -0
- package/src/extraction-judge-telemetry.ts +234 -0
- package/src/extraction-judge-training.ts +221 -0
- package/src/extraction-judge.ts +846 -0
- package/src/extraction-timeout.test.ts +265 -0
- package/src/extraction.ts +2719 -0
- package/src/fallback-llm.test.ts +1060 -0
- package/src/fallback-llm.ts +918 -0
- package/src/focused-list-recall.test.ts +734 -0
- package/src/focused-list-recall.ts +1160 -0
- package/src/graph-dashboard-diff.ts +35 -0
- package/src/graph-dashboard-key.ts +5 -0
- package/src/graph-dashboard-parser.ts +104 -0
- package/src/graph-edge-reinforcement.ts +192 -0
- package/src/graph-events.ts +151 -0
- package/src/graph-recall.test.ts +164 -0
- package/src/graph-recall.ts +189 -0
- package/src/graph-retrieval.test.ts +809 -0
- package/src/graph-retrieval.ts +823 -0
- package/src/graph-snapshot.ts +329 -0
- package/src/graph.ts +813 -0
- package/src/harmonic-retrieval.ts +223 -0
- package/src/himem.ts +154 -0
- package/src/hygiene.ts +87 -0
- package/src/identity-continuity.ts +333 -0
- package/src/importance.ts +328 -0
- package/src/importers/base.test.ts +294 -0
- package/src/importers/base.ts +436 -0
- package/src/importers/index.ts +21 -0
- package/src/index.ts +1204 -0
- package/src/intent.ts +154 -0
- package/src/json-extract.ts +85 -0
- package/src/json-store.ts +42 -0
- package/src/lcm/archive.ts +617 -0
- package/src/lcm/dag.ts +199 -0
- package/src/lcm/engine.ts +645 -0
- package/src/lcm/index.ts +7 -0
- package/src/lcm/queue.test.ts +178 -0
- package/src/lcm/queue.ts +200 -0
- package/src/lcm/recall.ts +117 -0
- package/src/lcm/schema.ts +154 -0
- package/src/lcm/summarizer.ts +235 -0
- package/src/lcm/tools.ts +191 -0
- package/src/lcm-engine.test.ts +660 -0
- package/src/legacy-hook-compat.test.ts +20 -0
- package/src/legacy-hook-compat.ts +45 -0
- package/src/lifecycle.ts +289 -0
- package/src/live-connectors-runner.ts +385 -0
- package/src/local-llm-qos.test.ts +303 -0
- package/src/local-llm-thinking.test.ts +292 -0
- package/src/local-llm.ts +1464 -0
- package/src/logger.ts +49 -0
- package/src/maintenance/archive-observations.ts +147 -0
- package/src/maintenance/backup-stamp.ts +3 -0
- package/src/maintenance/dreams-ledger.ts +516 -0
- package/src/maintenance/first-start-migration.ts +362 -0
- package/src/maintenance/forget.test.ts +206 -0
- package/src/maintenance/forget.ts +126 -0
- package/src/maintenance/graph-edge-decay.test.ts +409 -0
- package/src/maintenance/graph-edge-decay.ts +394 -0
- package/src/maintenance/memory-governance-cron.ts +447 -0
- package/src/maintenance/memory-governance.ts +1039 -0
- package/src/maintenance/migrate-observations.ts +216 -0
- package/src/maintenance/observation-ledger-utils.ts +54 -0
- package/src/maintenance/pattern-reinforcement.test.ts +875 -0
- package/src/maintenance/pattern-reinforcement.ts +369 -0
- package/src/maintenance/purge.ts +334 -0
- package/src/maintenance/rebuild-memory-lifecycle-ledger.ts +78 -0
- package/src/maintenance/rebuild-memory-projection.ts +1234 -0
- package/src/maintenance/rebuild-observations.ts +178 -0
- package/src/maintenance/tier-stats.test.ts +378 -0
- package/src/maintenance/tier-stats.ts +222 -0
- package/src/mcp-memory-inspector-app.ts +421 -0
- package/src/memory-action-policy.ts +80 -0
- package/src/memory-cache.ts +208 -0
- package/src/memory-extension/claude-code-publisher.ts +51 -0
- package/src/memory-extension/codex-publisher.ts +149 -0
- package/src/memory-extension/hermes-publisher.ts +51 -0
- package/src/memory-extension/index.ts +100 -0
- package/src/memory-extension/shared-instructions.ts +133 -0
- package/src/memory-extension/types.ts +86 -0
- package/src/memory-extension-host/host-discovery.ts +276 -0
- package/src/memory-extension-host/index.ts +14 -0
- package/src/memory-extension-host/render-extensions-block.ts +73 -0
- package/src/memory-extension-host/types.ts +21 -0
- package/src/memory-lifecycle-ledger-utils.ts +116 -0
- package/src/memory-projection-format.ts +11 -0
- package/src/memory-projection-store.ts +951 -0
- package/src/memory-provenance.test.ts +196 -0
- package/src/memory-provenance.ts +484 -0
- package/src/memory-worth-bench.test.ts +71 -0
- package/src/memory-worth-bench.ts +265 -0
- package/src/memory-worth-filter.test.ts +209 -0
- package/src/memory-worth-filter.ts +204 -0
- package/src/memory-worth-frontmatter.test.ts +311 -0
- package/src/memory-worth-outcomes.test.ts +316 -0
- package/src/memory-worth-outcomes.ts +286 -0
- package/src/memory-worth.test.ts +317 -0
- package/src/memory-worth.ts +215 -0
- package/src/message-parts/index.ts +806 -0
- package/src/message-parts/message-parts.test.ts +421 -0
- package/src/migrate/from-engram.ts +789 -0
- package/src/model-registry.ts +313 -0
- package/src/models-json.ts +76 -0
- package/src/namespaces/migrate.ts +187 -0
- package/src/namespaces/path.ts +25 -0
- package/src/namespaces/principal.test.ts +195 -0
- package/src/namespaces/principal.ts +86 -0
- package/src/namespaces/search.test.ts +105 -0
- package/src/namespaces/search.ts +233 -0
- package/src/namespaces/storage.ts +74 -0
- package/src/native-knowledge.ts +1823 -0
- package/src/negative.ts +72 -0
- package/src/network/tailscale.ts +179 -0
- package/src/network/webdav.ts +385 -0
- package/src/objective-state-writers.ts +951 -0
- package/src/objective-state.ts +320 -0
- package/src/onboarding/index.ts +529 -0
- package/src/openai-chat-compat.ts +56 -0
- package/src/operator-toolkit.ts +2132 -0
- package/src/opik-exporter.test.ts +72 -0
- package/src/opik-exporter.ts +587 -0
- package/src/orchestrator-extraction-queue.test.ts +197 -0
- package/src/orchestrator-flush.test.ts +1171 -0
- package/src/orchestrator-pattern-reinforcement.test.ts +128 -0
- package/src/orchestrator-source-attribution.test.ts +701 -0
- package/src/orchestrator.ts +16368 -0
- package/src/page-versioning.ts +450 -0
- package/src/patterns-cli.ts +574 -0
- package/src/peers/index.ts +54 -0
- package/src/peers/migrate-from-identity-anchor.test.ts +291 -0
- package/src/peers/migrate-from-identity-anchor.ts +350 -0
- package/src/peers/peers.test.ts +419 -0
- package/src/peers/profile-reasoner.ts +694 -0
- package/src/peers/storage.ts +1350 -0
- package/src/peers/types.ts +138 -0
- package/src/plugin-id.ts +84 -0
- package/src/policy-runtime.ts +209 -0
- package/src/procedural/procedure-miner.ts +150 -0
- package/src/procedural/procedure-recall.ts +93 -0
- package/src/procedural/procedure-stats.ts +213 -0
- package/src/procedural/procedure-types.ts +132 -0
- package/src/procedural/reinforcement-core.test.ts +132 -0
- package/src/procedural/reinforcement-core.ts +73 -0
- package/src/profiling.test.ts +263 -0
- package/src/profiling.ts +435 -0
- package/src/projection/index.ts +398 -0
- package/src/qmd-recall-cache.test.ts +138 -0
- package/src/qmd-recall-cache.ts +111 -0
- package/src/qmd.test.ts +257 -0
- package/src/qmd.ts +2614 -0
- package/src/reasoning-trace-recall.ts +201 -0
- package/src/reasoning-trace-types.ts +235 -0
- package/src/recall-audit-anomaly.test.ts +246 -0
- package/src/recall-audit-anomaly.ts +297 -0
- package/src/recall-audit.test.ts +51 -0
- package/src/recall-audit.ts +72 -0
- package/src/recall-budget-config.test.ts +87 -0
- package/src/recall-disclosure-escalation.test.ts +196 -0
- package/src/recall-disclosure-escalation.ts +158 -0
- package/src/recall-disclosure-shaping.test.ts +146 -0
- package/src/recall-disclosure.test.ts +214 -0
- package/src/recall-explain-renderer.test.ts +140 -0
- package/src/recall-explain-renderer.ts +356 -0
- package/src/recall-mmr.test.ts +808 -0
- package/src/recall-mmr.ts +607 -0
- package/src/recall-qos.test.ts +85 -0
- package/src/recall-qos.ts +82 -0
- package/src/recall-query-policy.ts +221 -0
- package/src/recall-state.test.ts +233 -0
- package/src/recall-state.ts +456 -0
- package/src/recall-tag-filter.ts +143 -0
- package/src/recall-tokenization.ts +35 -0
- package/src/recall-xray-cli.test.ts +118 -0
- package/src/recall-xray-cli.ts +100 -0
- package/src/recall-xray-disclosure-telemetry.test.ts +183 -0
- package/src/recall-xray-renderer.test.ts +539 -0
- package/src/recall-xray-renderer.ts +487 -0
- package/src/recall-xray.test.ts +503 -0
- package/src/recall-xray.ts +621 -0
- package/src/reconstruct.ts +41 -0
- package/src/release-changelog.ts +35 -0
- package/src/relevance.ts +67 -0
- package/src/replay/normalizers/chatgpt.ts +133 -0
- package/src/replay/normalizers/claude.ts +102 -0
- package/src/replay/normalizers/openclaw.ts +119 -0
- package/src/replay/normalizers/shared.ts +69 -0
- package/src/replay/runner.ts +197 -0
- package/src/replay/types.ts +143 -0
- package/src/rerank.test.ts +48 -0
- package/src/rerank.ts +176 -0
- package/src/resolve-auth-token.test.ts +226 -0
- package/src/resolve-auth-token.ts +151 -0
- package/src/resolve-provider-secret.test.ts +187 -0
- package/src/resolve-provider-secret.ts +410 -0
- package/src/response-guidance-recall.test.ts +3952 -0
- package/src/response-guidance-recall.ts +4431 -0
- package/src/resume-bundles.ts +415 -0
- package/src/retrieval-agents.ts +623 -0
- package/src/retrieval-tiers.ts +25 -0
- package/src/retrieval.ts +104 -0
- package/src/review/index.test.ts +201 -0
- package/src/review/index.ts +536 -0
- package/src/routing/engine.ts +162 -0
- package/src/routing/store.ts +321 -0
- package/src/runtime/better-sqlite.test.ts +32 -0
- package/src/runtime/better-sqlite.ts +76 -0
- package/src/runtime/child-process.ts +67 -0
- package/src/runtime/env.ts +48 -0
- package/src/sanitize.ts +58 -0
- package/src/schemas.ts +449 -0
- package/src/sdk-compat.ts +87 -0
- package/src/search/document-scanner.ts +96 -0
- package/src/search/embed-helper.ts +142 -0
- package/src/search/factory.ts +189 -0
- package/src/search/index.ts +10 -0
- package/src/search/lancedb-backend.ts +342 -0
- package/src/search/meilisearch-backend.ts +232 -0
- package/src/search/noop-backend.ts +57 -0
- package/src/search/orama-backend.ts +358 -0
- package/src/search/port.ts +86 -0
- package/src/search/remote-backend.ts +124 -0
- package/src/secure-store/cipher.ts +271 -0
- package/src/secure-store/cli-handlers.ts +355 -0
- package/src/secure-store/cli-renderer.ts +131 -0
- package/src/secure-store/header.ts +373 -0
- package/src/secure-store/index.ts +137 -0
- package/src/secure-store/kdf.ts +263 -0
- package/src/secure-store/keyring.ts +106 -0
- package/src/secure-store/metadata.ts +394 -0
- package/src/secure-store/passphrase-reader.ts +252 -0
- package/src/secure-store/secure-fs.ts +571 -0
- package/src/secure-store/secure-store.test.ts +755 -0
- package/src/semantic-chunking.ts +545 -0
- package/src/semantic-consolidation.test.ts +182 -0
- package/src/semantic-consolidation.ts +432 -0
- package/src/semantic-rule-promotion.ts +183 -0
- package/src/semantic-rule-verifier.ts +160 -0
- package/src/session-integrity.ts +569 -0
- package/src/session-observer-bands.ts +11 -0
- package/src/session-observer-state.ts +346 -0
- package/src/session-toggles.test.ts +96 -0
- package/src/session-toggles.ts +159 -0
- package/src/shared-context/manager.ts +810 -0
- package/src/signal.ts +84 -0
- package/src/skills-registry.test.ts +277 -0
- package/src/skills-registry.ts +120 -0
- package/src/source-attribution-roundtrip.test.ts +215 -0
- package/src/source-attribution.test.ts +1425 -0
- package/src/source-attribution.ts +639 -0
- package/src/spaces/index.ts +627 -0
- package/src/storage-paths.ts +117 -0
- package/src/storage.ts +6657 -0
- package/src/store-contract.ts +55 -0
- package/src/summarizer.ts +844 -0
- package/src/summary-snapshot.test.ts +681 -0
- package/src/summary-snapshot.ts +238 -0
- package/src/surfaces/dreams.test.ts +394 -0
- package/src/surfaces/dreams.ts +346 -0
- package/src/surfaces/heartbeat.test.ts +415 -0
- package/src/surfaces/heartbeat.ts +325 -0
- package/src/sync/index.ts +308 -0
- package/src/targeted-fact-recall.test.ts +1694 -0
- package/src/targeted-fact-recall.ts +2905 -0
- package/src/taxonomy/default-taxonomy.ts +87 -0
- package/src/taxonomy/index.ts +26 -0
- package/src/taxonomy/resolver-doc-generator.ts +57 -0
- package/src/taxonomy/resolver.ts +184 -0
- package/src/taxonomy/taxonomy-loader.ts +186 -0
- package/src/taxonomy/types.ts +48 -0
- package/src/telemetry-transcript.ts +70 -0
- package/src/temporal-index.ts +890 -0
- package/src/temporal-supersession.test.ts +2703 -0
- package/src/temporal-supersession.ts +493 -0
- package/src/temporal-validity.test.ts +448 -0
- package/src/temporal-validity.ts +123 -0
- package/src/threading.ts +395 -0
- package/src/tier-migration.ts +124 -0
- package/src/tier-routing.ts +102 -0
- package/src/tmt.ts +462 -0
- package/src/tokens.test.ts +178 -0
- package/src/tokens.ts +279 -0
- package/src/topics.ts +147 -0
- package/src/training-export/cli-date-validation.test.ts +258 -0
- package/src/training-export/converter.test.ts +452 -0
- package/src/training-export/converter.ts +319 -0
- package/src/training-export/date-parse.ts +117 -0
- package/src/training-export/index.ts +26 -0
- package/src/training-export/registry.test.ts +85 -0
- package/src/training-export/registry.ts +57 -0
- package/src/training-export/types.ts +31 -0
- package/src/transcript.ts +1179 -0
- package/src/transfer/autodetect.ts +30 -0
- package/src/transfer/backup.ts +138 -0
- package/src/transfer/capsule-crypto.ts +485 -0
- package/src/transfer/capsule-encrypt.test.ts +690 -0
- package/src/transfer/capsule-export.ts +543 -0
- package/src/transfer/capsule-fork.ts +375 -0
- package/src/transfer/capsule-import.ts +564 -0
- package/src/transfer/capsule-merge.ts +433 -0
- package/src/transfer/conflict-policy.ts +16 -0
- package/src/transfer/constants.ts +13 -0
- package/src/transfer/exclusions.ts +37 -0
- package/src/transfer/export-json.ts +65 -0
- package/src/transfer/export-md.ts +59 -0
- package/src/transfer/export-sqlite.ts +52 -0
- package/src/transfer/fs-utils.ts +269 -0
- package/src/transfer/import-json.ts +108 -0
- package/src/transfer/import-md.ts +84 -0
- package/src/transfer/import-sqlite.ts +100 -0
- package/src/transfer/integrity.ts +71 -0
- package/src/transfer/sqlite-schema.ts +16 -0
- package/src/transfer/types.ts +297 -0
- package/src/trust-zones.ts +1186 -0
- package/src/types.ts +3074 -0
- package/src/user-model.test.ts +124 -0
- package/src/user-model.ts +162 -0
- package/src/utility-learner.ts +353 -0
- package/src/utility-runtime.ts +88 -0
- package/src/utility-telemetry.ts +215 -0
- package/src/utils/category-dir.ts +44 -0
- package/src/utils/errno.ts +6 -0
- package/src/utils/iso-timestamp.test.ts +37 -0
- package/src/utils/iso-timestamp.ts +164 -0
- package/src/utils/path.ts +26 -0
- package/src/verified-recall.ts +138 -0
- package/src/version-utils.test.ts +10 -0
- package/src/version-utils.ts +9 -0
- package/src/whitespace.ts +10 -0
- package/src/work/board.ts +359 -0
- package/src/work/boundary.ts +107 -0
- package/src/work/storage.ts +436 -0
- package/src/work/types.ts +82 -0
- package/src/work-product-ledger.ts +265 -0
- package/dist/access-service-DDjzFALq.d.ts +0 -2088
- package/dist/capsule-crypto-SJS5VVAP.js +0 -18
- package/dist/capsule-export-7QNCBZOQ.js +0 -17
- package/dist/capsule-import-EPBHD2EN.js +0 -16
- package/dist/capsule-merge-DI7PNQ2H.js +0 -189
- package/dist/chunk-23ZZK64Y.js +0 -26
- package/dist/chunk-23ZZK64Y.js.map +0 -1
- package/dist/chunk-242S3I2A.js +0 -647
- package/dist/chunk-2LGMW3DJ.js +0 -111
- package/dist/chunk-3B6KIRBH.js +0 -5213
- package/dist/chunk-3B6KIRBH.js.map +0 -1
- package/dist/chunk-457A4P3L.js +0 -119
- package/dist/chunk-457A4P3L.js.map +0 -1
- package/dist/chunk-4IS4SXIQ.js +0 -2040
- package/dist/chunk-4YM32CRU.js +0 -721
- package/dist/chunk-6TBWYBJ3.js +0 -236
- package/dist/chunk-74EMIVE4.js +0 -329
- package/dist/chunk-74EMIVE4.js.map +0 -1
- package/dist/chunk-767ODGE6.js +0 -183
- package/dist/chunk-7V22HTMD.js +0 -623
- package/dist/chunk-7V22HTMD.js.map +0 -1
- package/dist/chunk-7ZM3BFKK.js +0 -9705
- package/dist/chunk-7ZM3BFKK.js.map +0 -1
- package/dist/chunk-AQJNPMOA.js +0 -643
- package/dist/chunk-AQJNPMOA.js.map +0 -1
- package/dist/chunk-ASAITVLA.js +0 -64
- package/dist/chunk-ASAITVLA.js.map +0 -1
- package/dist/chunk-BBE34QBJ.js +0 -275
- package/dist/chunk-BBE34QBJ.js.map +0 -1
- package/dist/chunk-BZSQEPRW.js +0 -14710
- package/dist/chunk-BZSQEPRW.js.map +0 -1
- package/dist/chunk-CPKTBRS2.js +0 -891
- package/dist/chunk-CPKTBRS2.js.map +0 -1
- package/dist/chunk-D4GAOFF6.js +0 -562
- package/dist/chunk-D4GAOFF6.js.map +0 -1
- package/dist/chunk-D54LZC5L.js +0 -147
- package/dist/chunk-DF3RVK3X.js +0 -119
- package/dist/chunk-DF3RVK3X.js.map +0 -1
- package/dist/chunk-DZZPC36E.js +0 -1451
- package/dist/chunk-DZZPC36E.js.map +0 -1
- package/dist/chunk-E2UCDP5S.js +0 -570
- package/dist/chunk-E6K4NIEU.js +0 -747
- package/dist/chunk-E6K4NIEU.js.map +0 -1
- package/dist/chunk-EEQLFRUM.js +0 -89
- package/dist/chunk-ETOW6ACV.js +0 -158
- package/dist/chunk-ETOW6ACV.js.map +0 -1
- package/dist/chunk-FMEBPEAO.js +0 -347
- package/dist/chunk-FMEBPEAO.js.map +0 -1
- package/dist/chunk-FQDPCE3I.js +0 -1837
- package/dist/chunk-FQDPCE3I.js.map +0 -1
- package/dist/chunk-FYIYMQ5N.js +0 -221
- package/dist/chunk-FYIYMQ5N.js.map +0 -1
- package/dist/chunk-G2WADRQ3.js +0 -219
- package/dist/chunk-G4SK7DSQ.js +0 -121
- package/dist/chunk-GVPWB7EY.js +0 -390
- package/dist/chunk-GVPWB7EY.js.map +0 -1
- package/dist/chunk-HELQZFZO.js +0 -1075
- package/dist/chunk-HL5LRPNA.js +0 -1914
- package/dist/chunk-HL5LRPNA.js.map +0 -1
- package/dist/chunk-HQZVVSVB.js +0 -147
- package/dist/chunk-HQZVVSVB.js.map +0 -1
- package/dist/chunk-HY3L4WKC.js +0 -2195
- package/dist/chunk-HY3L4WKC.js.map +0 -1
- package/dist/chunk-IB3BFHGN.js +0 -228
- package/dist/chunk-IXEJRKCZ.js +0 -18
- package/dist/chunk-JBMSGZEQ.js +0 -441
- package/dist/chunk-JBMSGZEQ.js.map +0 -1
- package/dist/chunk-JESOB2HO.js +0 -108
- package/dist/chunk-JKDVIE52.js +0 -272
- package/dist/chunk-JRNQ3RNA.js +0 -284
- package/dist/chunk-JRNQ3RNA.js.map +0 -1
- package/dist/chunk-K6WK37A6.js +0 -865
- package/dist/chunk-K6WK37A6.js.map +0 -1
- package/dist/chunk-MARWOCVP.js +0 -48
- package/dist/chunk-MNU6ZBWT.js +0 -4454
- package/dist/chunk-MNU6ZBWT.js.map +0 -1
- package/dist/chunk-N5AKDXAI.js +0 -74
- package/dist/chunk-OA3L7BFR.js +0 -183
- package/dist/chunk-OA3L7BFR.js.map +0 -1
- package/dist/chunk-OR64ZGRZ.js +0 -23
- package/dist/chunk-P77UEOU2.js +0 -1521
- package/dist/chunk-P77UEOU2.js.map +0 -1
- package/dist/chunk-PH4C2U43.js +0 -239
- package/dist/chunk-PH4C2U43.js.map +0 -1
- package/dist/chunk-RVPLBATS.js +0 -1586
- package/dist/chunk-RVPLBATS.js.map +0 -1
- package/dist/chunk-U5JMRGKX.js +0 -340
- package/dist/chunk-U5JMRGKX.js.map +0 -1
- package/dist/chunk-URB2WSKZ.js +0 -350
- package/dist/chunk-URB2WSKZ.js.map +0 -1
- package/dist/chunk-UVMUAWVT.js +0 -596
- package/dist/chunk-WEJG4TB5.js +0 -118
- package/dist/chunk-X7HPGUVG.js +0 -271
- package/dist/chunk-XAMBKFQS.js +0 -2777
- package/dist/chunk-XAMBKFQS.js.map +0 -1
- package/dist/chunk-XJKFSSDW.js +0 -726
- package/dist/chunk-XJKFSSDW.js.map +0 -1
- package/dist/chunk-XMHBH5H6.js +0 -283
- package/dist/chunk-XMHBH5H6.js.map +0 -1
- package/dist/chunk-XMVFHBHT.js +0 -277
- package/dist/chunk-Y3VMVTYX.js +0 -53
- package/dist/chunk-YNB73F22.js +0 -137
- package/dist/chunk-YNB73F22.js.map +0 -1
- package/dist/chunk-Z2E7VW55.js +0 -335
- package/dist/chunk-Z2E7VW55.js.map +0 -1
- package/dist/chunk-ZG7PTKBK.js +0 -2296
- package/dist/chunk-ZNQN6ZTA.js +0 -135
- package/dist/chunk-ZVTKDVVM.js +0 -827
- package/dist/chunk-ZVTKDVVM.js.map +0 -1
- package/dist/cli-BR8KpIU0.d.ts +0 -1259
- package/dist/codex-materialize-CQlLTzke.d.ts +0 -139
- package/dist/connectors-cli-DFGtY2DB.d.ts +0 -257
- package/dist/contradiction-review-5LTTVDQV.js +0 -22
- package/dist/contradiction-scan-QTXAMBUA.js +0 -414
- package/dist/contradiction-scan-QTXAMBUA.js.map +0 -1
- package/dist/engine-35M5BKQ7.js +0 -28
- package/dist/fs-utils-IRVUFB6G.js +0 -30
- package/dist/graph-edge-decay-PWB63GRE.js +0 -207
- package/dist/memory-governance-IMPQZXFC.js +0 -37
- package/dist/memory-projection-store-CY8TU40w.d.ts +0 -222
- package/dist/orchestrator-DDMPqU6R.d.ts +0 -1792
- package/dist/path-RMTY5Y5A.js +0 -9
- package/dist/port-B6VEDIkC.d.ts +0 -53
- package/dist/resolution-YGIBORXI.js +0 -101
- package/dist/resolution-YGIBORXI.js.map +0 -1
- package/dist/secure-store-4R2GSO7S.js +0 -156
- package/dist/semantic-consolidation-ByBXb-sf.d.ts +0 -180
- package/dist/state-store-3EH7HYIN.js +0 -16
- package/dist/types-V3FJ26TF.js +0 -30
- /package/dist/{capsule-crypto-SJS5VVAP.js.map → adapters/claude-code.js.map} +0 -0
- /package/dist/{capsule-export-7QNCBZOQ.js.map → adapters/codex.js.map} +0 -0
- /package/dist/{capsule-import-EPBHD2EN.js.map → adapters/hermes.js.map} +0 -0
- /package/dist/{contradiction-review-5LTTVDQV.js.map → adapters/index.js.map} +0 -0
- /package/dist/{engine-35M5BKQ7.js.map → adapters/registry.js.map} +0 -0
- /package/dist/{fs-utils-IRVUFB6G.js.map → adapters/replit.js.map} +0 -0
- /package/dist/{memory-governance-IMPQZXFC.js.map → adapters/types.js.map} +0 -0
- /package/dist/{path-RMTY5Y5A.js.map → capsule-crypto-5CYAGVC5.js.map} +0 -0
- /package/dist/{capsule-merge-DI7PNQ2H.js.map → capsule-merge-4MGKE7C5.js.map} +0 -0
- /package/dist/{chunk-G4SK7DSQ.js.map → chunk-2WWLHTZY.js.map} +0 -0
- /package/dist/{chunk-X7HPGUVG.js.map → chunk-4CRG46BG.js.map} +0 -0
- /package/dist/{chunk-UVMUAWVT.js.map → chunk-7IASACLB.js.map} +0 -0
- /package/dist/{chunk-HELQZFZO.js.map → chunk-EDTHC6UD.js.map} +0 -0
- /package/dist/{chunk-4YM32CRU.js.map → chunk-EFJ3MQ4V.js.map} +0 -0
- /package/dist/{chunk-E2UCDP5S.js.map → chunk-FBYESMQ2.js.map} +0 -0
- /package/dist/{chunk-D54LZC5L.js.map → chunk-FDU6HUUL.js.map} +0 -0
- /package/dist/{chunk-IB3BFHGN.js.map → chunk-GGKRUQOO.js.map} +0 -0
- /package/dist/{chunk-242S3I2A.js.map → chunk-GL6I6MEQ.js.map} +0 -0
- /package/dist/{secure-store-4R2GSO7S.js.map → chunk-HHLLAQGZ.js.map} +0 -0
- /package/dist/{chunk-4IS4SXIQ.js.map → chunk-HXXBL2KD.js.map} +0 -0
- /package/dist/{chunk-767ODGE6.js.map → chunk-KNKUID7G.js.map} +0 -0
- /package/dist/{chunk-6TBWYBJ3.js.map → chunk-LPMVBPA3.js.map} +0 -0
- /package/dist/{chunk-WEJG4TB5.js.map → chunk-MC26UJIM.js.map} +0 -0
- /package/dist/{chunk-JKDVIE52.js.map → chunk-MGKYQQYF.js.map} +0 -0
- /package/dist/{chunk-Y3VMVTYX.js.map → chunk-MT4HVDUZ.js.map} +0 -0
- /package/dist/{chunk-G2WADRQ3.js.map → chunk-MY6TPVXW.js.map} +0 -0
- /package/dist/{chunk-OR64ZGRZ.js.map → chunk-NNVTUXEB.js.map} +0 -0
- /package/dist/{chunk-JESOB2HO.js.map → chunk-P4NEIHUT.js.map} +0 -0
- /package/dist/{chunk-IXEJRKCZ.js.map → chunk-QRNI5JBH.js.map} +0 -0
- /package/dist/{chunk-EEQLFRUM.js.map → chunk-RRF5UOBJ.js.map} +0 -0
- /package/dist/{state-store-3EH7HYIN.js.map → chunk-SEDEKFYQ.js.map} +0 -0
- /package/dist/{chunk-2LGMW3DJ.js.map → chunk-U3PN77QT.js.map} +0 -0
- /package/dist/{chunk-XMVFHBHT.js.map → chunk-U3WSW6PZ.js.map} +0 -0
- /package/dist/{chunk-N5AKDXAI.js.map → chunk-UWVJF25J.js.map} +0 -0
- /package/dist/{types-V3FJ26TF.js.map → chunk-V5OCT34X.js.map} +0 -0
- /package/dist/{chunk-ZG7PTKBK.js.map → chunk-W3LR522O.js.map} +0 -0
- /package/dist/{chunk-MARWOCVP.js.map → chunk-XIG5PDM7.js.map} +0 -0
- /package/dist/{chunk-ZNQN6ZTA.js.map → chunk-XVZ7B3HG.js.map} +0 -0
- /package/dist/{graph-edge-decay-PWB63GRE.js.map → graph-edge-decay-5DI5GUNL.js.map} +0 -0
package/dist/chunk-MNU6ZBWT.js
DELETED
|
@@ -1,4454 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
importCapsule
|
|
3
|
-
} from "./chunk-IB3BFHGN.js";
|
|
4
|
-
import {
|
|
5
|
-
applyTagFilter,
|
|
6
|
-
normalizeTags,
|
|
7
|
-
parseTagMatch
|
|
8
|
-
} from "./chunk-BT7NVCML.js";
|
|
9
|
-
import {
|
|
10
|
-
decideDisclosureEscalation
|
|
11
|
-
} from "./chunk-H7XKCNR6.js";
|
|
12
|
-
import {
|
|
13
|
-
toRecallExplainJson
|
|
14
|
-
} from "./chunk-E2UCDP5S.js";
|
|
15
|
-
import {
|
|
16
|
-
clusterByKey,
|
|
17
|
-
resolveGitContext
|
|
18
|
-
} from "./chunk-D54LZC5L.js";
|
|
19
|
-
import {
|
|
20
|
-
getTrustZoneStoreStatus,
|
|
21
|
-
isTrustZoneName,
|
|
22
|
-
listTrustZoneRecords,
|
|
23
|
-
promoteTrustZoneRecord,
|
|
24
|
-
scoreTrustZoneProvenance,
|
|
25
|
-
seedTrustZoneDemoDataset,
|
|
26
|
-
summarizeTrustZonePromotionReadiness
|
|
27
|
-
} from "./chunk-QDZ2RLEC.js";
|
|
28
|
-
import {
|
|
29
|
-
estimateRecallTokens
|
|
30
|
-
} from "./chunk-JKDVIE52.js";
|
|
31
|
-
import {
|
|
32
|
-
recordObjectiveStateSnapshotsFromObservedMessages
|
|
33
|
-
} from "./chunk-242S3I2A.js";
|
|
34
|
-
import {
|
|
35
|
-
objectiveStateStoreOverrideForNamespace
|
|
36
|
-
} from "./chunk-5UM2VJ6D.js";
|
|
37
|
-
import {
|
|
38
|
-
buildProposedActions,
|
|
39
|
-
buildQualityScore,
|
|
40
|
-
groupActionsByStatus,
|
|
41
|
-
listMemoryGovernanceRuns,
|
|
42
|
-
readMemoryGovernanceRunArtifact,
|
|
43
|
-
runMemoryGovernance
|
|
44
|
-
} from "./chunk-4YM32CRU.js";
|
|
45
|
-
import {
|
|
46
|
-
recordMemoryOutcome
|
|
47
|
-
} from "./chunk-EIR5VLIH.js";
|
|
48
|
-
import {
|
|
49
|
-
buildGraphSnapshot
|
|
50
|
-
} from "./chunk-PCUKNJAZ.js";
|
|
51
|
-
import {
|
|
52
|
-
wrapWorkLayerContext
|
|
53
|
-
} from "./chunk-EEQLFRUM.js";
|
|
54
|
-
import {
|
|
55
|
-
formatProfileTraceAscii
|
|
56
|
-
} from "./chunk-NBNN5GOB.js";
|
|
57
|
-
import {
|
|
58
|
-
buildProcedurePersistBody,
|
|
59
|
-
normalizeProcedureSteps
|
|
60
|
-
} from "./chunk-QDW3E4RD.js";
|
|
61
|
-
import {
|
|
62
|
-
persistExplicitCapture,
|
|
63
|
-
queueExplicitCaptureForReview,
|
|
64
|
-
validateExplicitCaptureInput
|
|
65
|
-
} from "./chunk-GVPWB7EY.js";
|
|
66
|
-
import {
|
|
67
|
-
CrossNamespaceBudget
|
|
68
|
-
} from "./chunk-GDFS42HT.js";
|
|
69
|
-
import {
|
|
70
|
-
filterTrajectoriesByLookbackDays,
|
|
71
|
-
readCausalTrajectoryRecords
|
|
72
|
-
} from "./chunk-G2WADRQ3.js";
|
|
73
|
-
import {
|
|
74
|
-
FileCalendarSource,
|
|
75
|
-
buildBriefing,
|
|
76
|
-
parseBriefingFocus,
|
|
77
|
-
parseBriefingWindow
|
|
78
|
-
} from "./chunk-ZVTKDVVM.js";
|
|
79
|
-
import {
|
|
80
|
-
parseEntityFile
|
|
81
|
-
} from "./chunk-3B6KIRBH.js";
|
|
82
|
-
import {
|
|
83
|
-
DEFAULT_RECALL_DISCLOSURE,
|
|
84
|
-
isRecallDisclosure
|
|
85
|
-
} from "./chunk-23ZZK64Y.js";
|
|
86
|
-
import {
|
|
87
|
-
normalizeProjectionPreview,
|
|
88
|
-
normalizeProjectionTags
|
|
89
|
-
} from "./chunk-SCU65EZI.js";
|
|
90
|
-
import {
|
|
91
|
-
getMemoryProjectionPath
|
|
92
|
-
} from "./chunk-XJKFSSDW.js";
|
|
93
|
-
import {
|
|
94
|
-
inferMemoryStatus,
|
|
95
|
-
toMemoryPathRel
|
|
96
|
-
} from "./chunk-RULE4VG5.js";
|
|
97
|
-
import {
|
|
98
|
-
defaultCapsulesDir
|
|
99
|
-
} from "./chunk-74EMIVE4.js";
|
|
100
|
-
import {
|
|
101
|
-
canReadNamespace,
|
|
102
|
-
canWriteNamespace,
|
|
103
|
-
defaultNamespaceForPrincipal,
|
|
104
|
-
recallNamespacesForPrincipal,
|
|
105
|
-
resolvePrincipal
|
|
106
|
-
} from "./chunk-N5AKDXAI.js";
|
|
107
|
-
import {
|
|
108
|
-
log
|
|
109
|
-
} from "./chunk-2ODBA7MQ.js";
|
|
110
|
-
import {
|
|
111
|
-
AccessAuditAdapter
|
|
112
|
-
} from "./chunk-TVVEYCNW.js";
|
|
113
|
-
import {
|
|
114
|
-
AccessIdempotencyStore,
|
|
115
|
-
hashAccessIdempotencyPayload
|
|
116
|
-
} from "./chunk-XKECPATV.js";
|
|
117
|
-
import {
|
|
118
|
-
exportCapsule
|
|
119
|
-
} from "./chunk-BBE34QBJ.js";
|
|
120
|
-
import {
|
|
121
|
-
evaluateActionConfidence
|
|
122
|
-
} from "./chunk-AH2JUU6X.js";
|
|
123
|
-
|
|
124
|
-
// src/access-service.ts
|
|
125
|
-
import { stat } from "fs/promises";
|
|
126
|
-
import * as nodeFs from "fs/promises";
|
|
127
|
-
import { constants as fsConstants } from "fs";
|
|
128
|
-
import { createHash } from "crypto";
|
|
129
|
-
import { ZodError } from "zod";
|
|
130
|
-
|
|
131
|
-
// src/work/storage.ts
|
|
132
|
-
import path from "path";
|
|
133
|
-
import { randomUUID } from "crypto";
|
|
134
|
-
import { mkdir, readdir, readFile, rm, writeFile } from "fs/promises";
|
|
135
|
-
var TASK_TRANSITIONS = {
|
|
136
|
-
todo: /* @__PURE__ */ new Set(["in_progress", "blocked", "cancelled"]),
|
|
137
|
-
in_progress: /* @__PURE__ */ new Set(["todo", "blocked", "done", "cancelled"]),
|
|
138
|
-
blocked: /* @__PURE__ */ new Set(["todo", "in_progress", "cancelled"]),
|
|
139
|
-
done: /* @__PURE__ */ new Set(),
|
|
140
|
-
cancelled: /* @__PURE__ */ new Set()
|
|
141
|
-
};
|
|
142
|
-
function serializeFrontmatter(values) {
|
|
143
|
-
const lines = Object.entries(values).map(([k, v]) => `${k}: ${JSON.stringify(v)}`);
|
|
144
|
-
return `---
|
|
145
|
-
${lines.join("\n")}
|
|
146
|
-
---`;
|
|
147
|
-
}
|
|
148
|
-
function parseFrontmatter(raw) {
|
|
149
|
-
const match = raw.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);
|
|
150
|
-
if (!match) return null;
|
|
151
|
-
const fm = match[1] ?? "";
|
|
152
|
-
const body = match[2] ?? "";
|
|
153
|
-
const data = {};
|
|
154
|
-
for (const line of fm.split("\n")) {
|
|
155
|
-
if (!line.trim()) continue;
|
|
156
|
-
const idx = line.indexOf(":");
|
|
157
|
-
if (idx <= 0) continue;
|
|
158
|
-
const key = line.slice(0, idx).trim();
|
|
159
|
-
const rawValue = line.slice(idx + 1).trim();
|
|
160
|
-
try {
|
|
161
|
-
data[key] = JSON.parse(rawValue);
|
|
162
|
-
} catch {
|
|
163
|
-
data[key] = rawValue;
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
return { data, body };
|
|
167
|
-
}
|
|
168
|
-
function toSafeSlug(value) {
|
|
169
|
-
let slug = value.toLowerCase().trim().replace(/[^a-z0-9]+/g, "-");
|
|
170
|
-
let start = 0;
|
|
171
|
-
while (start < slug.length && slug[start] === "-") start++;
|
|
172
|
-
let end = slug.length;
|
|
173
|
-
while (end > start && slug[end - 1] === "-") end--;
|
|
174
|
-
return slug.slice(start, end).slice(0, 80);
|
|
175
|
-
}
|
|
176
|
-
var WORK_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9-]{0,127}$/;
|
|
177
|
-
function makeId(prefix, titleOrName, now) {
|
|
178
|
-
const slug = toSafeSlug(titleOrName) || "item";
|
|
179
|
-
const nonce = randomUUID().slice(0, 8);
|
|
180
|
-
return `${prefix}-${now.getTime()}-${slug}-${nonce}`;
|
|
181
|
-
}
|
|
182
|
-
function assertValidWorkId(id, kind) {
|
|
183
|
-
if (!WORK_ID_PATTERN.test(id)) {
|
|
184
|
-
throw new Error(`invalid ${kind} id: ${id}`);
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
function ensureString(value, fallback = "") {
|
|
188
|
-
return typeof value === "string" ? value : fallback;
|
|
189
|
-
}
|
|
190
|
-
function ensureStringArray(value) {
|
|
191
|
-
if (!Array.isArray(value)) return [];
|
|
192
|
-
return value.filter((entry) => typeof entry === "string");
|
|
193
|
-
}
|
|
194
|
-
function ensureNullableString(value) {
|
|
195
|
-
return typeof value === "string" ? value : null;
|
|
196
|
-
}
|
|
197
|
-
function ensureTaskStatus(value) {
|
|
198
|
-
if (value === "todo" || value === "in_progress" || value === "blocked" || value === "done" || value === "cancelled") {
|
|
199
|
-
return value;
|
|
200
|
-
}
|
|
201
|
-
return "todo";
|
|
202
|
-
}
|
|
203
|
-
function ensureTaskPriority(value) {
|
|
204
|
-
if (value === "low" || value === "medium" || value === "high") return value;
|
|
205
|
-
return "medium";
|
|
206
|
-
}
|
|
207
|
-
function ensureProjectStatus(value) {
|
|
208
|
-
if (value === "active" || value === "on_hold" || value === "completed" || value === "archived") return value;
|
|
209
|
-
return "active";
|
|
210
|
-
}
|
|
211
|
-
var WorkStorage = class {
|
|
212
|
-
constructor(memoryDir) {
|
|
213
|
-
this.memoryDir = memoryDir;
|
|
214
|
-
this.tasksDir = path.join(memoryDir, "work", "tasks");
|
|
215
|
-
this.projectsDir = path.join(memoryDir, "work", "projects");
|
|
216
|
-
}
|
|
217
|
-
memoryDir;
|
|
218
|
-
tasksDir;
|
|
219
|
-
projectsDir;
|
|
220
|
-
async ensureDirectories() {
|
|
221
|
-
await mkdir(this.tasksDir, { recursive: true });
|
|
222
|
-
await mkdir(this.projectsDir, { recursive: true });
|
|
223
|
-
}
|
|
224
|
-
taskPath(id) {
|
|
225
|
-
assertValidWorkId(id, "task");
|
|
226
|
-
return path.join(this.tasksDir, `${id}.md`);
|
|
227
|
-
}
|
|
228
|
-
projectPath(id) {
|
|
229
|
-
assertValidWorkId(id, "project");
|
|
230
|
-
return path.join(this.projectsDir, `${id}.md`);
|
|
231
|
-
}
|
|
232
|
-
serializeTask(task) {
|
|
233
|
-
return `${serializeFrontmatter(task)}
|
|
234
|
-
|
|
235
|
-
${task.description}
|
|
236
|
-
`;
|
|
237
|
-
}
|
|
238
|
-
serializeProject(project) {
|
|
239
|
-
return `${serializeFrontmatter(project)}
|
|
240
|
-
|
|
241
|
-
${project.description}
|
|
242
|
-
`;
|
|
243
|
-
}
|
|
244
|
-
parseTask(raw) {
|
|
245
|
-
const parsed = parseFrontmatter(raw);
|
|
246
|
-
if (!parsed) return null;
|
|
247
|
-
const d = parsed.data;
|
|
248
|
-
return {
|
|
249
|
-
id: ensureString(d.id),
|
|
250
|
-
title: ensureString(d.title),
|
|
251
|
-
description: ensureString(d.description, parsed.body.trim()),
|
|
252
|
-
status: ensureTaskStatus(d.status),
|
|
253
|
-
priority: ensureTaskPriority(d.priority),
|
|
254
|
-
owner: ensureNullableString(d.owner),
|
|
255
|
-
assignee: ensureNullableString(d.assignee),
|
|
256
|
-
projectId: ensureNullableString(d.projectId),
|
|
257
|
-
tags: ensureStringArray(d.tags),
|
|
258
|
-
dueAt: ensureNullableString(d.dueAt),
|
|
259
|
-
createdAt: ensureString(d.createdAt),
|
|
260
|
-
updatedAt: ensureString(d.updatedAt)
|
|
261
|
-
};
|
|
262
|
-
}
|
|
263
|
-
parseProject(raw) {
|
|
264
|
-
const parsed = parseFrontmatter(raw);
|
|
265
|
-
if (!parsed) return null;
|
|
266
|
-
const d = parsed.data;
|
|
267
|
-
return {
|
|
268
|
-
id: ensureString(d.id),
|
|
269
|
-
name: ensureString(d.name),
|
|
270
|
-
description: ensureString(d.description, parsed.body.trim()),
|
|
271
|
-
status: ensureProjectStatus(d.status),
|
|
272
|
-
owner: ensureNullableString(d.owner),
|
|
273
|
-
tags: ensureStringArray(d.tags),
|
|
274
|
-
taskIds: ensureStringArray(d.taskIds),
|
|
275
|
-
createdAt: ensureString(d.createdAt),
|
|
276
|
-
updatedAt: ensureString(d.updatedAt)
|
|
277
|
-
};
|
|
278
|
-
}
|
|
279
|
-
async createTask(input, now = /* @__PURE__ */ new Date()) {
|
|
280
|
-
await this.ensureDirectories();
|
|
281
|
-
const timestamp = now.toISOString();
|
|
282
|
-
const task = {
|
|
283
|
-
id: input.id ?? makeId("task", input.title, now),
|
|
284
|
-
title: input.title,
|
|
285
|
-
description: input.description ?? "",
|
|
286
|
-
status: input.status ?? "todo",
|
|
287
|
-
priority: input.priority ?? "medium",
|
|
288
|
-
owner: input.owner ?? null,
|
|
289
|
-
assignee: input.assignee ?? null,
|
|
290
|
-
projectId: input.projectId ?? null,
|
|
291
|
-
tags: input.tags ?? [],
|
|
292
|
-
dueAt: input.dueAt ?? null,
|
|
293
|
-
createdAt: timestamp,
|
|
294
|
-
updatedAt: timestamp
|
|
295
|
-
};
|
|
296
|
-
if (task.projectId) {
|
|
297
|
-
const project = await this.getProject(task.projectId);
|
|
298
|
-
if (!project) {
|
|
299
|
-
throw new Error(`project not found: ${task.projectId}`);
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
await writeFile(this.taskPath(task.id), this.serializeTask(task), "utf-8");
|
|
303
|
-
if (task.projectId) {
|
|
304
|
-
await this.addTaskIdToProject(task.projectId, task.id, now);
|
|
305
|
-
}
|
|
306
|
-
return task;
|
|
307
|
-
}
|
|
308
|
-
async getTask(id) {
|
|
309
|
-
try {
|
|
310
|
-
const raw = await readFile(this.taskPath(id), "utf-8");
|
|
311
|
-
return this.parseTask(raw);
|
|
312
|
-
} catch {
|
|
313
|
-
return null;
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
async listTasks(filter) {
|
|
317
|
-
await this.ensureDirectories();
|
|
318
|
-
const entries = await readdir(this.tasksDir, { withFileTypes: true });
|
|
319
|
-
const out = [];
|
|
320
|
-
for (const entry of entries) {
|
|
321
|
-
if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
|
|
322
|
-
const raw = await readFile(path.join(this.tasksDir, entry.name), "utf-8");
|
|
323
|
-
const task = this.parseTask(raw);
|
|
324
|
-
if (!task) continue;
|
|
325
|
-
if (filter?.status && task.status !== filter.status) continue;
|
|
326
|
-
if (filter?.owner && task.owner !== filter.owner) continue;
|
|
327
|
-
if (filter?.assignee && task.assignee !== filter.assignee) continue;
|
|
328
|
-
if (filter?.projectId && task.projectId !== filter.projectId) continue;
|
|
329
|
-
out.push(task);
|
|
330
|
-
}
|
|
331
|
-
out.sort((a, b) => a.createdAt.localeCompare(b.createdAt));
|
|
332
|
-
return out;
|
|
333
|
-
}
|
|
334
|
-
async updateTask(id, patch, now = /* @__PURE__ */ new Date(), options) {
|
|
335
|
-
const existing = await this.getTask(id);
|
|
336
|
-
if (!existing) return null;
|
|
337
|
-
const projectIdPatched = Object.prototype.hasOwnProperty.call(patch, "projectId");
|
|
338
|
-
const statusPatched = Object.prototype.hasOwnProperty.call(patch, "status");
|
|
339
|
-
const nextProjectId = projectIdPatched ? patch.projectId ?? null : existing.projectId;
|
|
340
|
-
if (statusPatched && patch.status && existing.status !== patch.status && options?.skipStatusTransitionValidation !== true && !TASK_TRANSITIONS[existing.status].has(patch.status)) {
|
|
341
|
-
throw new Error(`invalid task status transition: ${existing.status} -> ${patch.status}`);
|
|
342
|
-
}
|
|
343
|
-
if (projectIdPatched && nextProjectId) {
|
|
344
|
-
const nextProject = await this.getProject(nextProjectId);
|
|
345
|
-
if (!nextProject) {
|
|
346
|
-
throw new Error(`project not found: ${nextProjectId}`);
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
if (projectIdPatched && existing.projectId !== nextProjectId) {
|
|
350
|
-
if (existing.projectId) {
|
|
351
|
-
await this.removeTaskIdFromProject(existing.projectId, id, now);
|
|
352
|
-
}
|
|
353
|
-
if (nextProjectId) {
|
|
354
|
-
await this.addTaskIdToProject(nextProjectId, id, now);
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
const next = {
|
|
358
|
-
...existing,
|
|
359
|
-
...patch,
|
|
360
|
-
projectId: nextProjectId,
|
|
361
|
-
tags: patch.tags ?? existing.tags,
|
|
362
|
-
updatedAt: now.toISOString()
|
|
363
|
-
};
|
|
364
|
-
await writeFile(this.taskPath(id), this.serializeTask(next), "utf-8");
|
|
365
|
-
return next;
|
|
366
|
-
}
|
|
367
|
-
async transitionTask(id, nextStatus, now = /* @__PURE__ */ new Date()) {
|
|
368
|
-
const existing = await this.getTask(id);
|
|
369
|
-
if (!existing) throw new Error(`task not found: ${id}`);
|
|
370
|
-
if (existing.status === nextStatus) return existing;
|
|
371
|
-
if (!TASK_TRANSITIONS[existing.status].has(nextStatus)) {
|
|
372
|
-
throw new Error(`invalid task status transition: ${existing.status} -> ${nextStatus}`);
|
|
373
|
-
}
|
|
374
|
-
const updated = await this.updateTask(id, { status: nextStatus }, now);
|
|
375
|
-
if (!updated) throw new Error(`task not found after update: ${id}`);
|
|
376
|
-
return updated;
|
|
377
|
-
}
|
|
378
|
-
async deleteTask(id) {
|
|
379
|
-
try {
|
|
380
|
-
const existing = await this.getTask(id);
|
|
381
|
-
await rm(this.taskPath(id));
|
|
382
|
-
if (existing?.projectId) {
|
|
383
|
-
await this.removeTaskIdFromProject(existing.projectId, id);
|
|
384
|
-
}
|
|
385
|
-
return true;
|
|
386
|
-
} catch {
|
|
387
|
-
return false;
|
|
388
|
-
}
|
|
389
|
-
}
|
|
390
|
-
async createProject(input, now = /* @__PURE__ */ new Date()) {
|
|
391
|
-
await this.ensureDirectories();
|
|
392
|
-
const timestamp = now.toISOString();
|
|
393
|
-
const project = {
|
|
394
|
-
id: input.id ?? makeId("project", input.name, now),
|
|
395
|
-
name: input.name,
|
|
396
|
-
description: input.description ?? "",
|
|
397
|
-
status: input.status ?? "active",
|
|
398
|
-
owner: input.owner ?? null,
|
|
399
|
-
tags: input.tags ?? [],
|
|
400
|
-
taskIds: [],
|
|
401
|
-
createdAt: timestamp,
|
|
402
|
-
updatedAt: timestamp
|
|
403
|
-
};
|
|
404
|
-
await writeFile(this.projectPath(project.id), this.serializeProject(project), "utf-8");
|
|
405
|
-
return project;
|
|
406
|
-
}
|
|
407
|
-
async getProject(id) {
|
|
408
|
-
try {
|
|
409
|
-
const raw = await readFile(this.projectPath(id), "utf-8");
|
|
410
|
-
return this.parseProject(raw);
|
|
411
|
-
} catch {
|
|
412
|
-
return null;
|
|
413
|
-
}
|
|
414
|
-
}
|
|
415
|
-
async listProjects() {
|
|
416
|
-
await this.ensureDirectories();
|
|
417
|
-
const entries = await readdir(this.projectsDir, { withFileTypes: true });
|
|
418
|
-
const out = [];
|
|
419
|
-
for (const entry of entries) {
|
|
420
|
-
if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
|
|
421
|
-
const raw = await readFile(path.join(this.projectsDir, entry.name), "utf-8");
|
|
422
|
-
const project = this.parseProject(raw);
|
|
423
|
-
if (project) out.push(project);
|
|
424
|
-
}
|
|
425
|
-
out.sort((a, b) => a.createdAt.localeCompare(b.createdAt));
|
|
426
|
-
return out;
|
|
427
|
-
}
|
|
428
|
-
async updateProject(id, patch, now = /* @__PURE__ */ new Date()) {
|
|
429
|
-
const existing = await this.getProject(id);
|
|
430
|
-
if (!existing) return null;
|
|
431
|
-
const next = {
|
|
432
|
-
...existing,
|
|
433
|
-
...patch,
|
|
434
|
-
tags: patch.tags ?? existing.tags,
|
|
435
|
-
taskIds: patch.taskIds ? [...patch.taskIds].sort() : existing.taskIds,
|
|
436
|
-
updatedAt: now.toISOString()
|
|
437
|
-
};
|
|
438
|
-
await writeFile(this.projectPath(id), this.serializeProject(next), "utf-8");
|
|
439
|
-
return next;
|
|
440
|
-
}
|
|
441
|
-
async deleteProject(id) {
|
|
442
|
-
try {
|
|
443
|
-
const existing = await this.getProject(id);
|
|
444
|
-
if (existing) {
|
|
445
|
-
for (const taskId of existing.taskIds) {
|
|
446
|
-
await this.updateTask(taskId, { projectId: null });
|
|
447
|
-
}
|
|
448
|
-
}
|
|
449
|
-
await rm(this.projectPath(id));
|
|
450
|
-
return true;
|
|
451
|
-
} catch {
|
|
452
|
-
return false;
|
|
453
|
-
}
|
|
454
|
-
}
|
|
455
|
-
async linkTaskToProject(taskId, projectId, now = /* @__PURE__ */ new Date()) {
|
|
456
|
-
const task = await this.getTask(taskId);
|
|
457
|
-
if (!task) throw new Error(`task not found: ${taskId}`);
|
|
458
|
-
const project = await this.getProject(projectId);
|
|
459
|
-
if (!project) throw new Error(`project not found: ${projectId}`);
|
|
460
|
-
const updatedTask = await this.updateTask(taskId, { projectId }, now);
|
|
461
|
-
if (!updatedTask) throw new Error(`task not found after update: ${taskId}`);
|
|
462
|
-
const updatedProject = await this.getProject(projectId);
|
|
463
|
-
if (!updatedProject) throw new Error(`project not found after update: ${projectId}`);
|
|
464
|
-
return { task: updatedTask, project: updatedProject };
|
|
465
|
-
}
|
|
466
|
-
async removeTaskIdFromProject(projectId, taskId, now = /* @__PURE__ */ new Date()) {
|
|
467
|
-
const project = await this.getProject(projectId);
|
|
468
|
-
if (!project) return;
|
|
469
|
-
const filtered = project.taskIds.filter((id) => id !== taskId);
|
|
470
|
-
if (filtered.length === project.taskIds.length) return;
|
|
471
|
-
await this.updateProject(projectId, { taskIds: filtered }, now);
|
|
472
|
-
}
|
|
473
|
-
async addTaskIdToProject(projectId, taskId, now = /* @__PURE__ */ new Date()) {
|
|
474
|
-
const project = await this.getProject(projectId);
|
|
475
|
-
if (!project) return;
|
|
476
|
-
const taskIds = new Set(project.taskIds);
|
|
477
|
-
taskIds.add(taskId);
|
|
478
|
-
await this.updateProject(projectId, { taskIds: Array.from(taskIds) }, now);
|
|
479
|
-
}
|
|
480
|
-
};
|
|
481
|
-
|
|
482
|
-
// src/work/board.ts
|
|
483
|
-
var BOARD_STATUS_ORDER = [
|
|
484
|
-
"todo",
|
|
485
|
-
"in_progress",
|
|
486
|
-
"blocked",
|
|
487
|
-
"done",
|
|
488
|
-
"cancelled"
|
|
489
|
-
];
|
|
490
|
-
var BOARD_STATUS_LABEL = {
|
|
491
|
-
todo: "Todo",
|
|
492
|
-
in_progress: "In Progress",
|
|
493
|
-
blocked: "Blocked",
|
|
494
|
-
done: "Done",
|
|
495
|
-
cancelled: "Cancelled"
|
|
496
|
-
};
|
|
497
|
-
var PRIORITY_WEIGHT = {
|
|
498
|
-
high: 0,
|
|
499
|
-
medium: 1,
|
|
500
|
-
low: 2
|
|
501
|
-
};
|
|
502
|
-
function stableSortTasks(tasks) {
|
|
503
|
-
return [...tasks].sort((a, b) => {
|
|
504
|
-
const priorityCmp = PRIORITY_WEIGHT[a.priority] - PRIORITY_WEIGHT[b.priority];
|
|
505
|
-
if (priorityCmp !== 0) return priorityCmp;
|
|
506
|
-
const createdCmp = a.createdAt.localeCompare(b.createdAt);
|
|
507
|
-
if (createdCmp !== 0) return createdCmp;
|
|
508
|
-
return a.id.localeCompare(b.id);
|
|
509
|
-
});
|
|
510
|
-
}
|
|
511
|
-
function projectMatches(task, projectId) {
|
|
512
|
-
if (!projectId) return true;
|
|
513
|
-
return task.projectId === projectId;
|
|
514
|
-
}
|
|
515
|
-
function assertValidImportEnums(item) {
|
|
516
|
-
if (!["todo", "in_progress", "blocked", "done", "cancelled"].includes(item.status)) {
|
|
517
|
-
throw new Error(`invalid task status in snapshot for ${item.id}: ${item.status}`);
|
|
518
|
-
}
|
|
519
|
-
if (!["low", "medium", "high"].includes(item.priority)) {
|
|
520
|
-
throw new Error(`invalid task priority in snapshot for ${item.id}: ${item.priority}`);
|
|
521
|
-
}
|
|
522
|
-
}
|
|
523
|
-
function normalizeImportedProjectId(rawValue, taskId, fallbackForUndefined) {
|
|
524
|
-
if (rawValue === void 0) return fallbackForUndefined;
|
|
525
|
-
if (rawValue === null) return null;
|
|
526
|
-
if (typeof rawValue === "string") {
|
|
527
|
-
const trimmed = rawValue.trim();
|
|
528
|
-
return trimmed.length > 0 ? trimmed : null;
|
|
529
|
-
}
|
|
530
|
-
throw new Error(`invalid task projectId in snapshot for ${taskId}`);
|
|
531
|
-
}
|
|
532
|
-
function normalizeImportedTags(rawValue, taskId) {
|
|
533
|
-
if (rawValue === void 0 || rawValue === null) return [];
|
|
534
|
-
if (!Array.isArray(rawValue)) {
|
|
535
|
-
throw new Error(`invalid task tags in snapshot for ${taskId}`);
|
|
536
|
-
}
|
|
537
|
-
if (!rawValue.every((entry) => typeof entry === "string")) {
|
|
538
|
-
throw new Error(`invalid task tags in snapshot for ${taskId}`);
|
|
539
|
-
}
|
|
540
|
-
return [...rawValue];
|
|
541
|
-
}
|
|
542
|
-
function assertValidImportedTaskId(rawValue) {
|
|
543
|
-
if (typeof rawValue !== "string") {
|
|
544
|
-
throw new Error("invalid task id in snapshot");
|
|
545
|
-
}
|
|
546
|
-
const trimmed = rawValue.trim();
|
|
547
|
-
if (!WORK_ID_PATTERN.test(trimmed)) {
|
|
548
|
-
throw new Error(`invalid task id in snapshot: ${trimmed}`);
|
|
549
|
-
}
|
|
550
|
-
return trimmed;
|
|
551
|
-
}
|
|
552
|
-
function normalizeImportedNullableField(rawValue, taskId, fieldName, fallbackForUndefined) {
|
|
553
|
-
if (rawValue === void 0) return fallbackForUndefined;
|
|
554
|
-
if (rawValue === null) return null;
|
|
555
|
-
if (typeof rawValue === "string") return rawValue;
|
|
556
|
-
throw new Error(`invalid task ${fieldName} in snapshot for ${taskId}`);
|
|
557
|
-
}
|
|
558
|
-
function normalizeImportedTitle(rawValue, taskId) {
|
|
559
|
-
if (typeof rawValue !== "string") {
|
|
560
|
-
throw new Error(`invalid task title in snapshot for ${taskId}`);
|
|
561
|
-
}
|
|
562
|
-
const trimmed = rawValue.trim();
|
|
563
|
-
if (trimmed.length === 0) {
|
|
564
|
-
throw new Error(`invalid task title in snapshot for ${taskId}`);
|
|
565
|
-
}
|
|
566
|
-
return trimmed;
|
|
567
|
-
}
|
|
568
|
-
function normalizeImportedDescription(rawValue, taskId) {
|
|
569
|
-
if (typeof rawValue !== "string") {
|
|
570
|
-
throw new Error(`invalid task description in snapshot for ${taskId}`);
|
|
571
|
-
}
|
|
572
|
-
return rawValue;
|
|
573
|
-
}
|
|
574
|
-
function asBoardItem(task) {
|
|
575
|
-
return {
|
|
576
|
-
id: task.id,
|
|
577
|
-
title: task.title,
|
|
578
|
-
description: task.description,
|
|
579
|
-
status: task.status,
|
|
580
|
-
priority: task.priority,
|
|
581
|
-
owner: task.owner,
|
|
582
|
-
assignee: task.assignee,
|
|
583
|
-
projectId: task.projectId,
|
|
584
|
-
tags: [...task.tags],
|
|
585
|
-
dueAt: task.dueAt
|
|
586
|
-
};
|
|
587
|
-
}
|
|
588
|
-
function formatTaskLine(task) {
|
|
589
|
-
const bits = [`id:${task.id}`, `priority:${task.priority}`];
|
|
590
|
-
if (task.assignee) bits.push(`assignee:${task.assignee}`);
|
|
591
|
-
if (task.owner) bits.push(`owner:${task.owner}`);
|
|
592
|
-
if (task.dueAt) bits.push(`due:${task.dueAt}`);
|
|
593
|
-
if (task.tags.length > 0) bits.push(`tags:${task.tags.join(",")}`);
|
|
594
|
-
const checked = task.status === "done";
|
|
595
|
-
return `- [${checked ? "x" : " "}] ${task.title} \`[${bits.join(" ")}]\``;
|
|
596
|
-
}
|
|
597
|
-
async function exportWorkBoardSnapshot(options) {
|
|
598
|
-
const storage = new WorkStorage(options.memoryDir);
|
|
599
|
-
await storage.ensureDirectories();
|
|
600
|
-
const projectId = options.projectId?.trim() || void 0;
|
|
601
|
-
let project = null;
|
|
602
|
-
if (projectId) {
|
|
603
|
-
project = await storage.getProject(projectId);
|
|
604
|
-
if (!project) throw new Error(`project not found: ${projectId}`);
|
|
605
|
-
}
|
|
606
|
-
const allTasks = await storage.listTasks();
|
|
607
|
-
const filtered = stableSortTasks(allTasks.filter((task) => projectMatches(task, projectId)));
|
|
608
|
-
return {
|
|
609
|
-
version: 1,
|
|
610
|
-
generatedAt: (options.now ?? /* @__PURE__ */ new Date()).toISOString(),
|
|
611
|
-
projectId: projectId ?? null,
|
|
612
|
-
projectName: project?.name ?? null,
|
|
613
|
-
items: filtered.map(asBoardItem)
|
|
614
|
-
};
|
|
615
|
-
}
|
|
616
|
-
function renderWorkBoardMarkdown(snapshot) {
|
|
617
|
-
const lines = [];
|
|
618
|
-
lines.push("# Work Board");
|
|
619
|
-
lines.push("");
|
|
620
|
-
lines.push(`Generated: ${snapshot.generatedAt}`);
|
|
621
|
-
lines.push(`Project: ${snapshot.projectName ?? "all"} (${snapshot.projectId ?? "all"})`);
|
|
622
|
-
lines.push("");
|
|
623
|
-
for (const status of BOARD_STATUS_ORDER) {
|
|
624
|
-
const bucket = snapshot.items.filter((item) => item.status === status);
|
|
625
|
-
lines.push(`## ${BOARD_STATUS_LABEL[status]} (${bucket.length})`);
|
|
626
|
-
if (bucket.length === 0) {
|
|
627
|
-
lines.push("_none_");
|
|
628
|
-
} else {
|
|
629
|
-
for (const item of bucket) {
|
|
630
|
-
lines.push(formatTaskLine(item));
|
|
631
|
-
}
|
|
632
|
-
}
|
|
633
|
-
lines.push("");
|
|
634
|
-
}
|
|
635
|
-
return `${lines.join("\n").trim()}
|
|
636
|
-
`;
|
|
637
|
-
}
|
|
638
|
-
async function exportWorkBoardMarkdown(options) {
|
|
639
|
-
const snapshot = await exportWorkBoardSnapshot(options);
|
|
640
|
-
return renderWorkBoardMarkdown(snapshot);
|
|
641
|
-
}
|
|
642
|
-
async function importWorkBoardSnapshot(options) {
|
|
643
|
-
if (options.snapshot.version !== 1) {
|
|
644
|
-
throw new Error(`unsupported work board snapshot version: ${options.snapshot.version}`);
|
|
645
|
-
}
|
|
646
|
-
const storage = new WorkStorage(options.memoryDir);
|
|
647
|
-
await storage.ensureDirectories();
|
|
648
|
-
const forcedProjectId = options.projectId === void 0 ? void 0 : options.projectId?.trim() || null;
|
|
649
|
-
const snapshotProjectId = normalizeImportedProjectId(
|
|
650
|
-
options.snapshot.projectId,
|
|
651
|
-
"snapshot",
|
|
652
|
-
null
|
|
653
|
-
);
|
|
654
|
-
const preparedRows = [];
|
|
655
|
-
const seenItemIds = /* @__PURE__ */ new Set();
|
|
656
|
-
for (const item of options.snapshot.items) {
|
|
657
|
-
const id = assertValidImportedTaskId(item.id);
|
|
658
|
-
if (seenItemIds.has(id)) {
|
|
659
|
-
throw new Error(`duplicate task id in snapshot: ${id}`);
|
|
660
|
-
}
|
|
661
|
-
seenItemIds.add(id);
|
|
662
|
-
assertValidImportEnums(item);
|
|
663
|
-
const existing = await storage.getTask(id);
|
|
664
|
-
const title = normalizeImportedTitle(item.title, id);
|
|
665
|
-
const description = normalizeImportedDescription(item.description, id);
|
|
666
|
-
const fallbackProjectId = existing ? existing.projectId : snapshotProjectId;
|
|
667
|
-
const projectId = forcedProjectId === void 0 ? normalizeImportedProjectId(
|
|
668
|
-
item.projectId,
|
|
669
|
-
item.id,
|
|
670
|
-
fallbackProjectId
|
|
671
|
-
) : forcedProjectId;
|
|
672
|
-
const hasTagsField = Object.prototype.hasOwnProperty.call(
|
|
673
|
-
item,
|
|
674
|
-
"tags"
|
|
675
|
-
);
|
|
676
|
-
const tags = hasTagsField ? normalizeImportedTags(item.tags, item.id) : existing ? [...existing.tags] : [];
|
|
677
|
-
const owner = normalizeImportedNullableField(
|
|
678
|
-
item.owner,
|
|
679
|
-
id,
|
|
680
|
-
"owner",
|
|
681
|
-
existing?.owner ?? null
|
|
682
|
-
);
|
|
683
|
-
const assignee = normalizeImportedNullableField(
|
|
684
|
-
item.assignee,
|
|
685
|
-
id,
|
|
686
|
-
"assignee",
|
|
687
|
-
existing?.assignee ?? null
|
|
688
|
-
);
|
|
689
|
-
const dueAt = normalizeImportedNullableField(
|
|
690
|
-
item.dueAt,
|
|
691
|
-
id,
|
|
692
|
-
"dueAt",
|
|
693
|
-
existing?.dueAt ?? null
|
|
694
|
-
);
|
|
695
|
-
preparedRows.push({ item, existing, id, title, description, projectId, tags, owner, assignee, dueAt });
|
|
696
|
-
}
|
|
697
|
-
const projectIdsToValidate = new Set(
|
|
698
|
-
preparedRows.map((row) => row.projectId).filter((projectId) => typeof projectId === "string")
|
|
699
|
-
);
|
|
700
|
-
for (const projectId of projectIdsToValidate) {
|
|
701
|
-
const project = await storage.getProject(projectId);
|
|
702
|
-
if (!project) throw new Error(`project not found: ${projectId}`);
|
|
703
|
-
}
|
|
704
|
-
let created = 0;
|
|
705
|
-
let updated = 0;
|
|
706
|
-
for (const row of preparedRows) {
|
|
707
|
-
const { item, existing, id, title, description, projectId, tags, owner, assignee, dueAt } = row;
|
|
708
|
-
if (existing) {
|
|
709
|
-
await storage.updateTask(id, {
|
|
710
|
-
title,
|
|
711
|
-
description,
|
|
712
|
-
status: item.status,
|
|
713
|
-
priority: item.priority,
|
|
714
|
-
owner,
|
|
715
|
-
assignee,
|
|
716
|
-
projectId,
|
|
717
|
-
tags,
|
|
718
|
-
dueAt
|
|
719
|
-
}, options.now, { skipStatusTransitionValidation: true });
|
|
720
|
-
updated += 1;
|
|
721
|
-
continue;
|
|
722
|
-
}
|
|
723
|
-
await storage.createTask({
|
|
724
|
-
id,
|
|
725
|
-
title,
|
|
726
|
-
description,
|
|
727
|
-
status: item.status,
|
|
728
|
-
priority: item.priority,
|
|
729
|
-
owner,
|
|
730
|
-
assignee,
|
|
731
|
-
projectId,
|
|
732
|
-
tags,
|
|
733
|
-
dueAt
|
|
734
|
-
}, options.now);
|
|
735
|
-
created += 1;
|
|
736
|
-
}
|
|
737
|
-
return { created, updated };
|
|
738
|
-
}
|
|
739
|
-
|
|
740
|
-
// src/procedural/procedure-miner.ts
|
|
741
|
-
var PROCEDURE_CLUSTER_ATTR_MAX = 500;
|
|
742
|
-
function clusterKey(record) {
|
|
743
|
-
const goal = record.goal.trim().toLowerCase().replace(/\s+/g, " ").slice(0, 120);
|
|
744
|
-
const refs = [...record.entityRefs ?? []].map((r) => r.trim().toLowerCase()).sort();
|
|
745
|
-
return `${goal}|${refs.join(",")}`;
|
|
746
|
-
}
|
|
747
|
-
function successRate(group) {
|
|
748
|
-
if (group.length === 0) return 0;
|
|
749
|
-
const ok = group.filter((g) => g.outcomeKind === "success" || g.outcomeKind === "partial").length;
|
|
750
|
-
return ok / group.length;
|
|
751
|
-
}
|
|
752
|
-
function pseudoStepsFromCluster(group) {
|
|
753
|
-
const sentences = [];
|
|
754
|
-
const pushUnique = (raw) => {
|
|
755
|
-
const t = raw.trim();
|
|
756
|
-
if (t.length < 8) return;
|
|
757
|
-
if (!sentences.includes(t)) sentences.push(t);
|
|
758
|
-
};
|
|
759
|
-
for (const g of group) {
|
|
760
|
-
const parts = [g.actionSummary, g.observationSummary, g.outcomeSummary].join(" ").split(/[.!?]\s+|;|\n+/).map((s) => s.trim()).filter((s) => s.length > 12);
|
|
761
|
-
for (const p of parts) pushUnique(p);
|
|
762
|
-
if (sentences.length >= 5) break;
|
|
763
|
-
}
|
|
764
|
-
if (sentences.length < 2 && group[0]) {
|
|
765
|
-
pushUnique(`${group[0].goal.trim()} \u2014 confirm prerequisites and context.`);
|
|
766
|
-
pushUnique("Execute the planned actions, then record the outcome.");
|
|
767
|
-
}
|
|
768
|
-
return sentences.slice(0, 6).map((intent, i) => ({
|
|
769
|
-
order: i + 1,
|
|
770
|
-
intent
|
|
771
|
-
}));
|
|
772
|
-
}
|
|
773
|
-
async function hasExistingClusterWrite(storage, cluster) {
|
|
774
|
-
const clusterKey2 = cluster.slice(0, PROCEDURE_CLUSTER_ATTR_MAX);
|
|
775
|
-
const memories = await storage.readAllMemories();
|
|
776
|
-
for (const m of memories) {
|
|
777
|
-
if (m.frontmatter.category !== "procedure") continue;
|
|
778
|
-
const c = m.frontmatter.structuredAttributes?.procedure_cluster;
|
|
779
|
-
if (c === clusterKey2) return true;
|
|
780
|
-
}
|
|
781
|
-
return false;
|
|
782
|
-
}
|
|
783
|
-
async function runProcedureMining(options) {
|
|
784
|
-
const cfg = options.config.procedural;
|
|
785
|
-
if (!cfg?.enabled) {
|
|
786
|
-
return { clustersProcessed: 0, proceduresWritten: 0, skippedReason: "procedural_disabled" };
|
|
787
|
-
}
|
|
788
|
-
if (cfg.minOccurrences <= 0) {
|
|
789
|
-
return { clustersProcessed: 0, proceduresWritten: 0, skippedReason: "minOccurrences_zero" };
|
|
790
|
-
}
|
|
791
|
-
const trajectoryDir = typeof options.config.causalTrajectoryStoreDir === "string" && options.config.causalTrajectoryStoreDir.trim().length > 0 ? options.config.causalTrajectoryStoreDir.trim() : void 0;
|
|
792
|
-
const { trajectories } = await readCausalTrajectoryRecords({
|
|
793
|
-
memoryDir: options.memoryDir,
|
|
794
|
-
causalTrajectoryStoreDir: trajectoryDir
|
|
795
|
-
});
|
|
796
|
-
const recent = filterTrajectoriesByLookbackDays(trajectories, cfg.lookbackDays);
|
|
797
|
-
const clusters = clusterByKey(recent, clusterKey);
|
|
798
|
-
let clustersProcessed = 0;
|
|
799
|
-
let proceduresWritten = 0;
|
|
800
|
-
for (const [key, group] of clusters) {
|
|
801
|
-
if (group.length < cfg.minOccurrences) continue;
|
|
802
|
-
const rate = successRate(group);
|
|
803
|
-
if (rate < cfg.successFloor) continue;
|
|
804
|
-
clustersProcessed += 1;
|
|
805
|
-
if (await hasExistingClusterWrite(options.storage, key)) {
|
|
806
|
-
log.debug(`procedure-miner: skip duplicate cluster key=${key.slice(0, 40)}\u2026`);
|
|
807
|
-
continue;
|
|
808
|
-
}
|
|
809
|
-
const steps = normalizeProcedureSteps(pseudoStepsFromCluster(group));
|
|
810
|
-
if (steps.length < 2) continue;
|
|
811
|
-
const title = `When you work on goals like: ${group[0].goal.trim().slice(0, 140)}`;
|
|
812
|
-
const body = buildProcedurePersistBody(title, steps);
|
|
813
|
-
const promote = cfg.autoPromoteEnabled === true && group.length >= cfg.autoPromoteOccurrences && rate >= cfg.successFloor;
|
|
814
|
-
await options.storage.writeMemory("procedure", body, {
|
|
815
|
-
source: "procedure-miner",
|
|
816
|
-
status: promote ? "active" : "pending_review",
|
|
817
|
-
tags: ["procedure-miner", "causal-trajectory"],
|
|
818
|
-
structuredAttributes: {
|
|
819
|
-
procedure_cluster: key.slice(0, PROCEDURE_CLUSTER_ATTR_MAX),
|
|
820
|
-
trajectory_ids: group.map((g) => g.trajectoryId).join(",").slice(0, 1900),
|
|
821
|
-
trajectory_count: String(group.length),
|
|
822
|
-
success_rate: rate.toFixed(4)
|
|
823
|
-
}
|
|
824
|
-
});
|
|
825
|
-
proceduresWritten += 1;
|
|
826
|
-
}
|
|
827
|
-
return { clustersProcessed, proceduresWritten };
|
|
828
|
-
}
|
|
829
|
-
|
|
830
|
-
// src/procedural/procedure-stats.ts
|
|
831
|
-
function snapshotConfig(config) {
|
|
832
|
-
const p = config.procedural;
|
|
833
|
-
return {
|
|
834
|
-
enabled: p?.enabled === true,
|
|
835
|
-
minOccurrences: typeof p?.minOccurrences === "number" ? p.minOccurrences : 0,
|
|
836
|
-
successFloor: typeof p?.successFloor === "number" ? p.successFloor : 0,
|
|
837
|
-
autoPromoteOccurrences: typeof p?.autoPromoteOccurrences === "number" ? p.autoPromoteOccurrences : 0,
|
|
838
|
-
autoPromoteEnabled: p?.autoPromoteEnabled === true,
|
|
839
|
-
lookbackDays: typeof p?.lookbackDays === "number" ? p.lookbackDays : 0,
|
|
840
|
-
recallMaxProcedures: typeof p?.recallMaxProcedures === "number" ? p.recallMaxProcedures : 0
|
|
841
|
-
};
|
|
842
|
-
}
|
|
843
|
-
function tsMs(value) {
|
|
844
|
-
if (typeof value !== "string") return null;
|
|
845
|
-
const ms = Date.parse(value);
|
|
846
|
-
return Number.isFinite(ms) ? ms : null;
|
|
847
|
-
}
|
|
848
|
-
async function computeProcedureStats(options) {
|
|
849
|
-
const { storage, config } = options;
|
|
850
|
-
const nowMs = options.nowMs ?? Date.now();
|
|
851
|
-
const sevenDaysMs = 7 * 24 * 60 * 60 * 1e3;
|
|
852
|
-
const counts = {
|
|
853
|
-
total: 0,
|
|
854
|
-
active: 0,
|
|
855
|
-
pending_review: 0,
|
|
856
|
-
rejected: 0,
|
|
857
|
-
quarantined: 0,
|
|
858
|
-
superseded: 0,
|
|
859
|
-
archived: 0,
|
|
860
|
-
other: 0
|
|
861
|
-
};
|
|
862
|
-
let lastWriteMs = null;
|
|
863
|
-
let writesLast7Days = 0;
|
|
864
|
-
let minerSourced = 0;
|
|
865
|
-
const known = [
|
|
866
|
-
"active",
|
|
867
|
-
"pending_review",
|
|
868
|
-
"rejected",
|
|
869
|
-
"quarantined",
|
|
870
|
-
"superseded",
|
|
871
|
-
"archived"
|
|
872
|
-
];
|
|
873
|
-
const seen = /* @__PURE__ */ new Set();
|
|
874
|
-
const live = await storage.readAllMemories();
|
|
875
|
-
const archived = await storage.readArchivedMemories();
|
|
876
|
-
const pool = [...live, ...archived];
|
|
877
|
-
for (const m of pool) {
|
|
878
|
-
if (m.frontmatter.category !== "procedure") continue;
|
|
879
|
-
if (seen.has(m.frontmatter.id)) continue;
|
|
880
|
-
seen.add(m.frontmatter.id);
|
|
881
|
-
counts.total += 1;
|
|
882
|
-
const status = m.frontmatter.status ?? "active";
|
|
883
|
-
if (known.includes(status)) {
|
|
884
|
-
counts[status] += 1;
|
|
885
|
-
} else {
|
|
886
|
-
counts.other += 1;
|
|
887
|
-
}
|
|
888
|
-
const createdMs = tsMs(m.frontmatter.created);
|
|
889
|
-
const updatedMs = tsMs(m.frontmatter.updated);
|
|
890
|
-
const latestMs = createdMs !== null && updatedMs !== null ? Math.max(createdMs, updatedMs) : updatedMs ?? createdMs;
|
|
891
|
-
if (latestMs !== null) {
|
|
892
|
-
if (lastWriteMs === null || latestMs > lastWriteMs) {
|
|
893
|
-
lastWriteMs = latestMs;
|
|
894
|
-
}
|
|
895
|
-
if (latestMs >= nowMs - sevenDaysMs && latestMs < nowMs) {
|
|
896
|
-
writesLast7Days += 1;
|
|
897
|
-
}
|
|
898
|
-
}
|
|
899
|
-
if (m.frontmatter.source === "procedure-miner") {
|
|
900
|
-
minerSourced += 1;
|
|
901
|
-
}
|
|
902
|
-
}
|
|
903
|
-
return {
|
|
904
|
-
schemaVersion: 1,
|
|
905
|
-
generatedAt: new Date(nowMs).toISOString(),
|
|
906
|
-
counts,
|
|
907
|
-
recent: {
|
|
908
|
-
lastWriteAt: lastWriteMs !== null ? new Date(lastWriteMs).toISOString() : null,
|
|
909
|
-
writesLast7Days,
|
|
910
|
-
minerSourced
|
|
911
|
-
},
|
|
912
|
-
config: snapshotConfig(config)
|
|
913
|
-
};
|
|
914
|
-
}
|
|
915
|
-
function formatProcedureStatsText(report) {
|
|
916
|
-
const { counts, recent, config } = report;
|
|
917
|
-
const lines = [];
|
|
918
|
-
lines.push(`Procedural memory stats (schema v${report.schemaVersion})`);
|
|
919
|
-
lines.push(` generated: ${report.generatedAt}`);
|
|
920
|
-
lines.push("");
|
|
921
|
-
lines.push(` config:`);
|
|
922
|
-
lines.push(` enabled: ${config.enabled}`);
|
|
923
|
-
lines.push(` minOccurrences: ${config.minOccurrences}`);
|
|
924
|
-
lines.push(` successFloor: ${config.successFloor}`);
|
|
925
|
-
lines.push(` autoPromoteOccurrences: ${config.autoPromoteOccurrences}`);
|
|
926
|
-
lines.push(` autoPromoteEnabled: ${config.autoPromoteEnabled}`);
|
|
927
|
-
lines.push(` lookbackDays: ${config.lookbackDays}`);
|
|
928
|
-
lines.push(` recallMaxProcedures: ${config.recallMaxProcedures}`);
|
|
929
|
-
lines.push("");
|
|
930
|
-
lines.push(` counts:`);
|
|
931
|
-
lines.push(` total: ${counts.total}`);
|
|
932
|
-
lines.push(` active: ${counts.active}`);
|
|
933
|
-
lines.push(` pending_review: ${counts.pending_review}`);
|
|
934
|
-
lines.push(` rejected: ${counts.rejected}`);
|
|
935
|
-
lines.push(` quarantined: ${counts.quarantined}`);
|
|
936
|
-
lines.push(` superseded: ${counts.superseded}`);
|
|
937
|
-
lines.push(` archived: ${counts.archived}`);
|
|
938
|
-
if (counts.other > 0) {
|
|
939
|
-
lines.push(` other: ${counts.other}`);
|
|
940
|
-
}
|
|
941
|
-
lines.push("");
|
|
942
|
-
lines.push(` recent:`);
|
|
943
|
-
lines.push(` lastWriteAt: ${recent.lastWriteAt ?? "(none)"}`);
|
|
944
|
-
lines.push(` writesLast7Days: ${recent.writesLast7Days}`);
|
|
945
|
-
lines.push(` minerSourced: ${recent.minerSourced}`);
|
|
946
|
-
return lines.join("\n") + "\n";
|
|
947
|
-
}
|
|
948
|
-
|
|
949
|
-
// src/access-service.ts
|
|
950
|
-
import * as nodePath from "path";
|
|
951
|
-
var EngramAccessInputError = class extends Error {
|
|
952
|
-
};
|
|
953
|
-
var cachedPackageVersion = null;
|
|
954
|
-
async function getPackageVersion() {
|
|
955
|
-
if (cachedPackageVersion !== null) return cachedPackageVersion;
|
|
956
|
-
try {
|
|
957
|
-
const raw = await nodeFs.readFile(new URL("../package.json", import.meta.url), "utf-8");
|
|
958
|
-
const parsed = JSON.parse(raw);
|
|
959
|
-
cachedPackageVersion = typeof parsed.version === "string" && parsed.version.length > 0 ? parsed.version : "unknown";
|
|
960
|
-
} catch {
|
|
961
|
-
cachedPackageVersion = "unknown";
|
|
962
|
-
}
|
|
963
|
-
return cachedPackageVersion;
|
|
964
|
-
}
|
|
965
|
-
function normalizeTrustZoneInputError(error) {
|
|
966
|
-
const message = error instanceof Error ? error.message : null;
|
|
967
|
-
if (!message) {
|
|
968
|
-
return null;
|
|
969
|
-
}
|
|
970
|
-
if (/^sourceRecordId must /.test(message) || /^promotionReason must /.test(message) || /^recordedAt must /.test(message) || /^trust zone promotion requires /.test(message) || /^source trust-zone record not found: /.test(message) || /^trust-zone promotion denied: /.test(message) || /^trust zone demo seed requires /.test(message) || /^unsupported trust-zone demo scenario: /.test(message)) {
|
|
971
|
-
return new EngramAccessInputError(message);
|
|
972
|
-
}
|
|
973
|
-
return null;
|
|
974
|
-
}
|
|
975
|
-
var ENGRAM_ACCESS_WRITE_SCHEMA_VERSION = 1;
|
|
976
|
-
async function buildProjectedGovernanceProposedActions(storage, projected) {
|
|
977
|
-
const reviewQueue = projected.reviewQueueRows.map((row) => ({
|
|
978
|
-
entryId: row.entryId,
|
|
979
|
-
memoryId: row.memoryId,
|
|
980
|
-
path: row.path,
|
|
981
|
-
reasonCode: row.reasonCode,
|
|
982
|
-
severity: row.severity,
|
|
983
|
-
suggestedAction: row.suggestedAction,
|
|
984
|
-
suggestedStatus: row.suggestedStatus,
|
|
985
|
-
relatedMemoryIds: row.relatedMemoryIds
|
|
986
|
-
}));
|
|
987
|
-
const memories = (await Promise.all(projected.reviewQueueRows.map((row) => storage.getMemoryById(row.memoryId)))).filter((memory) => Boolean(memory));
|
|
988
|
-
return buildProposedActions(reviewQueue, memories);
|
|
989
|
-
}
|
|
990
|
-
function hasGroupedGovernanceActions(grouped) {
|
|
991
|
-
if (!grouped) return false;
|
|
992
|
-
return Object.values(grouped).some((actions) => Array.isArray(actions) && actions.length > 0);
|
|
993
|
-
}
|
|
994
|
-
function normalizePagination(limit, offset) {
|
|
995
|
-
const normalizedLimit = Number.isFinite(limit) ? Math.max(1, Math.min(200, Math.floor(limit ?? 50))) : 50;
|
|
996
|
-
const normalizedOffset = Number.isFinite(offset) ? Math.max(0, Math.floor(offset ?? 0)) : 0;
|
|
997
|
-
return { limit: normalizedLimit, offset: normalizedOffset };
|
|
998
|
-
}
|
|
999
|
-
function normalizeBrowseSort(sort) {
|
|
1000
|
-
switch (sort) {
|
|
1001
|
-
case "updated_asc":
|
|
1002
|
-
case "created_desc":
|
|
1003
|
-
case "created_asc":
|
|
1004
|
-
return sort;
|
|
1005
|
-
case "updated_desc":
|
|
1006
|
-
default:
|
|
1007
|
-
return "updated_desc";
|
|
1008
|
-
}
|
|
1009
|
-
}
|
|
1010
|
-
function bucketMemoryAge(referenceIso, nowMs) {
|
|
1011
|
-
const referenceMs = referenceIso ? Date.parse(referenceIso) : Number.NaN;
|
|
1012
|
-
if (!Number.isFinite(referenceMs)) return "unknown";
|
|
1013
|
-
const ageDays = Math.floor((nowMs - referenceMs) / 864e5);
|
|
1014
|
-
if (ageDays <= 7) return "0_7_days";
|
|
1015
|
-
if (ageDays <= 30) return "8_30_days";
|
|
1016
|
-
if (ageDays <= 90) return "31_90_days";
|
|
1017
|
-
return "91_plus_days";
|
|
1018
|
-
}
|
|
1019
|
-
function incrementCount(counts, key) {
|
|
1020
|
-
counts[key] = (counts[key] ?? 0) + 1;
|
|
1021
|
-
}
|
|
1022
|
-
function summarizeTrustZoneRecord(record, filePath, allRecords, poisoningDefenseEnabled, trustZonesEnabled, promotionEnabled) {
|
|
1023
|
-
const trustScore = poisoningDefenseEnabled ? scoreTrustZoneProvenance(record) : void 0;
|
|
1024
|
-
const readiness = summarizeTrustZonePromotionReadiness({
|
|
1025
|
-
record,
|
|
1026
|
-
allRecords,
|
|
1027
|
-
poisoningDefenseEnabled
|
|
1028
|
-
});
|
|
1029
|
-
const promotionReasons = [...readiness.reasons];
|
|
1030
|
-
const promotionAllowed = readiness.allowed && trustZonesEnabled === true && promotionEnabled === true;
|
|
1031
|
-
if (trustZonesEnabled !== true) {
|
|
1032
|
-
promotionReasons.push("trust zone promotion requires trustZonesEnabled=true");
|
|
1033
|
-
}
|
|
1034
|
-
if (promotionEnabled !== true) {
|
|
1035
|
-
promotionReasons.push("trust zone promotion requires quarantinePromotionEnabled=true");
|
|
1036
|
-
}
|
|
1037
|
-
return {
|
|
1038
|
-
recordId: record.recordId,
|
|
1039
|
-
filePath,
|
|
1040
|
-
zone: record.zone,
|
|
1041
|
-
recordedAt: record.recordedAt,
|
|
1042
|
-
kind: record.kind,
|
|
1043
|
-
summary: record.summary,
|
|
1044
|
-
sourceClass: record.provenance.sourceClass,
|
|
1045
|
-
sessionKey: record.provenance.sessionKey,
|
|
1046
|
-
sourceId: record.provenance.sourceId,
|
|
1047
|
-
evidenceHashPresent: typeof record.provenance.evidenceHash === "string",
|
|
1048
|
-
anchored: Boolean(record.provenance.sourceId && record.provenance.evidenceHash),
|
|
1049
|
-
entityRefs: [...record.entityRefs ?? []],
|
|
1050
|
-
tags: [...record.tags ?? []],
|
|
1051
|
-
metadata: record.metadata,
|
|
1052
|
-
trustScore,
|
|
1053
|
-
nextPromotionTarget: readiness.nextTargetZone,
|
|
1054
|
-
nextPromotionAllowed: promotionAllowed,
|
|
1055
|
-
nextPromotionReasons: promotionReasons,
|
|
1056
|
-
corroborationCount: readiness.requiresCorroboration ? readiness.corroborationCount : void 0,
|
|
1057
|
-
corroborationSourceClasses: readiness.requiresCorroboration ? readiness.corroborationSourceClasses : void 0
|
|
1058
|
-
};
|
|
1059
|
-
}
|
|
1060
|
-
function compareBrowseMemory(sort, left, right) {
|
|
1061
|
-
const leftUpdated = left.frontmatter.updated ?? left.frontmatter.created ?? "";
|
|
1062
|
-
const rightUpdated = right.frontmatter.updated ?? right.frontmatter.created ?? "";
|
|
1063
|
-
const leftCreated = left.frontmatter.created ?? "";
|
|
1064
|
-
const rightCreated = right.frontmatter.created ?? "";
|
|
1065
|
-
switch (sort) {
|
|
1066
|
-
case "updated_asc":
|
|
1067
|
-
return leftUpdated.localeCompare(rightUpdated) || leftCreated.localeCompare(rightCreated) || left.frontmatter.id.localeCompare(right.frontmatter.id);
|
|
1068
|
-
case "created_desc":
|
|
1069
|
-
return rightCreated.localeCompare(leftCreated) || rightUpdated.localeCompare(leftUpdated) || left.frontmatter.id.localeCompare(right.frontmatter.id);
|
|
1070
|
-
case "created_asc":
|
|
1071
|
-
return leftCreated.localeCompare(rightCreated) || leftUpdated.localeCompare(rightUpdated) || left.frontmatter.id.localeCompare(right.frontmatter.id);
|
|
1072
|
-
case "updated_desc":
|
|
1073
|
-
default:
|
|
1074
|
-
return rightUpdated.localeCompare(leftUpdated) || rightCreated.localeCompare(leftCreated) || left.frontmatter.id.localeCompare(right.frontmatter.id);
|
|
1075
|
-
}
|
|
1076
|
-
}
|
|
1077
|
-
function shapeMemorySummary(memory, baseDir, disclosure, rawExcerpts) {
|
|
1078
|
-
const includeFullContent = disclosure === "section" || disclosure === "raw";
|
|
1079
|
-
return {
|
|
1080
|
-
id: memory.frontmatter.id,
|
|
1081
|
-
path: memory.path,
|
|
1082
|
-
category: memory.frontmatter.category,
|
|
1083
|
-
status: inferMemoryStatus(memory.frontmatter, toMemoryPathRel(baseDir, memory.path)),
|
|
1084
|
-
created: memory.frontmatter.created,
|
|
1085
|
-
updated: memory.frontmatter.updated,
|
|
1086
|
-
tags: normalizeProjectionTags(memory.frontmatter.tags),
|
|
1087
|
-
entityRef: memory.frontmatter.entityRef,
|
|
1088
|
-
preview: normalizeProjectionPreview(memory.content),
|
|
1089
|
-
...disclosure !== void 0 ? { disclosure } : {},
|
|
1090
|
-
...includeFullContent ? { content: memory.content } : {},
|
|
1091
|
-
...disclosure === "raw" && rawExcerpts !== void 0 ? { rawExcerpts } : {}
|
|
1092
|
-
};
|
|
1093
|
-
}
|
|
1094
|
-
var EngramAccessService = class {
|
|
1095
|
-
constructor(orchestrator) {
|
|
1096
|
-
this.orchestrator = orchestrator;
|
|
1097
|
-
this.idempotency = new AccessIdempotencyStore(orchestrator.config.memoryDir);
|
|
1098
|
-
this.budget = new CrossNamespaceBudget({
|
|
1099
|
-
enabled: orchestrator.config.recallCrossNamespaceBudgetEnabled,
|
|
1100
|
-
windowMs: orchestrator.config.recallCrossNamespaceBudgetWindowMs,
|
|
1101
|
-
softLimit: orchestrator.config.recallCrossNamespaceBudgetSoftLimit,
|
|
1102
|
-
hardLimit: orchestrator.config.recallCrossNamespaceBudgetHardLimit
|
|
1103
|
-
});
|
|
1104
|
-
const auditEnabled = orchestrator.config.recallAuditAnomalyDetectionEnabled === true;
|
|
1105
|
-
const auditLogEnabled = false;
|
|
1106
|
-
if (auditEnabled || auditLogEnabled) {
|
|
1107
|
-
const auditConfig = {
|
|
1108
|
-
audit: {
|
|
1109
|
-
enabled: auditLogEnabled,
|
|
1110
|
-
rootDir: orchestrator.config.memoryDir
|
|
1111
|
-
},
|
|
1112
|
-
detection: {
|
|
1113
|
-
enabled: auditEnabled,
|
|
1114
|
-
windowMs: orchestrator.config.recallAuditAnomalyWindowMs,
|
|
1115
|
-
repeatQueryLimit: orchestrator.config.recallAuditAnomalyRepeatQueryLimit,
|
|
1116
|
-
namespaceWalkLimit: orchestrator.config.recallAuditAnomalyNamespaceWalkLimit,
|
|
1117
|
-
highCardinalityReturnLimit: orchestrator.config.recallAuditAnomalyHighCardinalityLimit,
|
|
1118
|
-
rapidFireLimit: orchestrator.config.recallAuditAnomalyRapidFireLimit
|
|
1119
|
-
}
|
|
1120
|
-
};
|
|
1121
|
-
this.auditAdapter = new AccessAuditAdapter(auditConfig);
|
|
1122
|
-
} else {
|
|
1123
|
-
this.auditAdapter = null;
|
|
1124
|
-
}
|
|
1125
|
-
}
|
|
1126
|
-
orchestrator;
|
|
1127
|
-
idempotency;
|
|
1128
|
-
idempotencyLocks = /* @__PURE__ */ new Map();
|
|
1129
|
-
budget;
|
|
1130
|
-
auditAdapter;
|
|
1131
|
-
get briefingEnabled() {
|
|
1132
|
-
return this.orchestrator.config.briefing?.enabled === true;
|
|
1133
|
-
}
|
|
1134
|
-
resolveNamespace(namespace) {
|
|
1135
|
-
const requested = namespace?.trim();
|
|
1136
|
-
if (!requested) return this.orchestrator.config.defaultNamespace;
|
|
1137
|
-
if (!this.orchestrator.config.namespacesEnabled && requested !== this.orchestrator.config.defaultNamespace) {
|
|
1138
|
-
throw new EngramAccessInputError(`unsupported namespace: ${requested}`);
|
|
1139
|
-
}
|
|
1140
|
-
return requested;
|
|
1141
|
-
}
|
|
1142
|
-
normalizeRecallMode(mode) {
|
|
1143
|
-
if (!mode || mode === "auto") return void 0;
|
|
1144
|
-
if (mode === "no_recall" || mode === "minimal" || mode === "full" || mode === "graph_mode") {
|
|
1145
|
-
return mode;
|
|
1146
|
-
}
|
|
1147
|
-
throw new EngramAccessInputError(`unsupported recall mode: ${mode}`);
|
|
1148
|
-
}
|
|
1149
|
-
resolveRecallNamespace(namespace, sessionKey, authenticatedPrincipal) {
|
|
1150
|
-
const requested = namespace?.trim();
|
|
1151
|
-
if (!requested) return void 0;
|
|
1152
|
-
const resolved = this.resolveNamespace(requested);
|
|
1153
|
-
const principal = this.resolveRequestPrincipal(sessionKey, authenticatedPrincipal);
|
|
1154
|
-
if (!canReadNamespace(principal, resolved, this.orchestrator.config)) {
|
|
1155
|
-
throw new EngramAccessInputError(`namespace override is not readable: ${resolved}`);
|
|
1156
|
-
}
|
|
1157
|
-
return resolved;
|
|
1158
|
-
}
|
|
1159
|
-
resolveRequestPrincipal(sessionKey, authenticatedPrincipal) {
|
|
1160
|
-
const trusted = authenticatedPrincipal?.trim();
|
|
1161
|
-
if (trusted) return trusted;
|
|
1162
|
-
return resolvePrincipal(sessionKey, this.orchestrator.config);
|
|
1163
|
-
}
|
|
1164
|
-
resolveWritableNamespace(namespace, sessionKey, authenticatedPrincipal) {
|
|
1165
|
-
const resolved = this.resolveNamespace(namespace);
|
|
1166
|
-
const principal = this.resolveRequestPrincipal(sessionKey, authenticatedPrincipal);
|
|
1167
|
-
if (!canWriteNamespace(principal, resolved, this.orchestrator.config)) {
|
|
1168
|
-
throw new EngramAccessInputError(`namespace is not writable: ${resolved}`);
|
|
1169
|
-
}
|
|
1170
|
-
return resolved;
|
|
1171
|
-
}
|
|
1172
|
-
async objectiveStateStoreLocationForNamespace(namespace) {
|
|
1173
|
-
if (!this.orchestrator.config.namespacesEnabled) {
|
|
1174
|
-
return {
|
|
1175
|
-
memoryDir: this.orchestrator.config.memoryDir,
|
|
1176
|
-
objectiveStateStoreDir: this.orchestrator.config.objectiveStateStoreDir
|
|
1177
|
-
};
|
|
1178
|
-
}
|
|
1179
|
-
const storage = await this.orchestrator.getStorage(namespace);
|
|
1180
|
-
return {
|
|
1181
|
-
memoryDir: storage.dir,
|
|
1182
|
-
objectiveStateStoreDir: objectiveStateStoreOverrideForNamespace({
|
|
1183
|
-
memoryDir: this.orchestrator.config.memoryDir,
|
|
1184
|
-
configuredStoreDir: this.orchestrator.config.objectiveStateStoreDir,
|
|
1185
|
-
namespacesEnabled: this.orchestrator.config.namespacesEnabled,
|
|
1186
|
-
namespace
|
|
1187
|
-
})
|
|
1188
|
-
};
|
|
1189
|
-
}
|
|
1190
|
-
resolveReadableNamespace(namespace, principal) {
|
|
1191
|
-
const resolved = this.resolveNamespace(namespace);
|
|
1192
|
-
const namespacesEnabled = this.orchestrator.config.namespacesEnabled;
|
|
1193
|
-
if (!namespacesEnabled) {
|
|
1194
|
-
return resolved;
|
|
1195
|
-
}
|
|
1196
|
-
if (!principal) {
|
|
1197
|
-
throw new EngramAccessInputError(
|
|
1198
|
-
"authentication required: namespaces are enabled and no principal was supplied"
|
|
1199
|
-
);
|
|
1200
|
-
}
|
|
1201
|
-
if (!canReadNamespace(principal, resolved, this.orchestrator.config)) {
|
|
1202
|
-
throw new EngramAccessInputError(`namespace is not readable: ${resolved}`);
|
|
1203
|
-
}
|
|
1204
|
-
return resolved;
|
|
1205
|
-
}
|
|
1206
|
-
async buildRecallDebug(snapshot, namespace, includeDebug, sessionKey) {
|
|
1207
|
-
if (!includeDebug) return void 0;
|
|
1208
|
-
if (!sessionKey?.trim()) return void 0;
|
|
1209
|
-
const [intent, graph] = await Promise.all([
|
|
1210
|
-
this.orchestrator.getLastIntentSnapshot(namespace),
|
|
1211
|
-
this.orchestrator.getLastGraphRecallSnapshot(namespace)
|
|
1212
|
-
]);
|
|
1213
|
-
return snapshot || intent || graph ? {
|
|
1214
|
-
snapshot: snapshot ?? void 0,
|
|
1215
|
-
intent,
|
|
1216
|
-
graph
|
|
1217
|
-
} : void 0;
|
|
1218
|
-
}
|
|
1219
|
-
async buildRecallResponseFromXraySnapshot(options) {
|
|
1220
|
-
const memoryIds = options.snapshot.results.map((result) => result.memoryId);
|
|
1221
|
-
const resultPaths = options.snapshot.results.map((result) => result.path);
|
|
1222
|
-
const namespace = options.snapshot.namespace ? this.resolveNamespace(options.snapshot.namespace) : this.orchestrator.config.defaultNamespace;
|
|
1223
|
-
const sourcesUsed = Array.from(
|
|
1224
|
-
new Set(options.snapshot.results.map((result) => result.servedBy))
|
|
1225
|
-
);
|
|
1226
|
-
const snapshotForSerialization = {
|
|
1227
|
-
sessionKey: options.sessionKey ?? "",
|
|
1228
|
-
recordedAt: new Date(options.snapshot.capturedAt).toISOString(),
|
|
1229
|
-
queryHash: createHash("sha256").update(options.query).digest("hex"),
|
|
1230
|
-
queryLen: options.query.length,
|
|
1231
|
-
memoryIds,
|
|
1232
|
-
namespace,
|
|
1233
|
-
traceId: options.snapshot.traceId,
|
|
1234
|
-
plannerMode: options.normalizedMode,
|
|
1235
|
-
requestedMode: options.requestedMode && options.requestedMode !== "auto" ? options.requestedMode : void 0,
|
|
1236
|
-
sourcesUsed,
|
|
1237
|
-
budgetsApplied: {
|
|
1238
|
-
appliedTopK: memoryIds.length,
|
|
1239
|
-
recallBudgetChars: options.snapshot.budget.chars,
|
|
1240
|
-
maxMemoryTokens: this.orchestrator.config.maxMemoryTokens,
|
|
1241
|
-
finalContextChars: options.snapshot.budget.used
|
|
1242
|
-
},
|
|
1243
|
-
latencyMs: Date.now() - options.startedAt,
|
|
1244
|
-
resultPaths
|
|
1245
|
-
};
|
|
1246
|
-
const results = await this.serializeRecallResults(
|
|
1247
|
-
snapshotForSerialization,
|
|
1248
|
-
options.disclosure,
|
|
1249
|
-
{
|
|
1250
|
-
query: options.query,
|
|
1251
|
-
...options.sessionKey ? { sessionKey: options.sessionKey } : {}
|
|
1252
|
-
}
|
|
1253
|
-
);
|
|
1254
|
-
const context = results.map((result) => {
|
|
1255
|
-
const content = typeof result.content === "string" && result.content.length > 0 ? result.content : "";
|
|
1256
|
-
return content || result.preview;
|
|
1257
|
-
}).filter((text) => text.length > 0).join("\n\n");
|
|
1258
|
-
return {
|
|
1259
|
-
query: options.query,
|
|
1260
|
-
...options.sessionKey ? { sessionKey: options.sessionKey } : {},
|
|
1261
|
-
namespace,
|
|
1262
|
-
context,
|
|
1263
|
-
count: memoryIds.length,
|
|
1264
|
-
memoryIds,
|
|
1265
|
-
results,
|
|
1266
|
-
recordedAt: snapshotForSerialization.recordedAt,
|
|
1267
|
-
traceId: options.snapshot.traceId,
|
|
1268
|
-
plannerMode: options.normalizedMode,
|
|
1269
|
-
fallbackUsed: sourcesUsed.some((source) => source !== "hybrid"),
|
|
1270
|
-
sourcesUsed,
|
|
1271
|
-
disclosure: options.disclosure,
|
|
1272
|
-
budgetsApplied: snapshotForSerialization.budgetsApplied,
|
|
1273
|
-
latencyMs: snapshotForSerialization.latencyMs
|
|
1274
|
-
};
|
|
1275
|
-
}
|
|
1276
|
-
async serializeRecallResults(snapshot, disclosure, rawContext = null) {
|
|
1277
|
-
if (!snapshot) return [];
|
|
1278
|
-
const namespace = snapshot.namespace ? this.resolveNamespace(snapshot.namespace) : this.orchestrator.config.defaultNamespace;
|
|
1279
|
-
const storage = await this.orchestrator.getStorage(namespace);
|
|
1280
|
-
const storageDir = storage.dir;
|
|
1281
|
-
const results = [];
|
|
1282
|
-
const seen = /* @__PURE__ */ new Set();
|
|
1283
|
-
const rawExcerptsResult = await this.fetchRawExcerpts(
|
|
1284
|
-
disclosure,
|
|
1285
|
-
rawContext ? { ...rawContext, namespace } : null
|
|
1286
|
-
);
|
|
1287
|
-
const rawExcerpts = rawExcerptsResult ?? void 0;
|
|
1288
|
-
for (const memoryPath of snapshot.resultPaths ?? []) {
|
|
1289
|
-
if (!memoryPath || seen.has(memoryPath)) continue;
|
|
1290
|
-
const memory = await storage.readMemoryByPath(memoryPath);
|
|
1291
|
-
if (!memory) continue;
|
|
1292
|
-
seen.add(memoryPath);
|
|
1293
|
-
results.push(
|
|
1294
|
-
this.serializeMemorySummary(
|
|
1295
|
-
memory,
|
|
1296
|
-
storageDir,
|
|
1297
|
-
disclosure,
|
|
1298
|
-
// Attach the (possibly empty) raw excerpts to the first raw
|
|
1299
|
-
// result; subsequent results do not duplicate the array.
|
|
1300
|
-
results.length === 0 ? rawExcerpts : void 0
|
|
1301
|
-
)
|
|
1302
|
-
);
|
|
1303
|
-
}
|
|
1304
|
-
if (results.length > 0) return results;
|
|
1305
|
-
for (const memoryId of snapshot.memoryIds) {
|
|
1306
|
-
const memory = await storage.getMemoryById(memoryId);
|
|
1307
|
-
if (!memory || seen.has(memory.path)) continue;
|
|
1308
|
-
seen.add(memory.path);
|
|
1309
|
-
results.push(
|
|
1310
|
-
this.serializeMemorySummary(
|
|
1311
|
-
memory,
|
|
1312
|
-
storageDir,
|
|
1313
|
-
disclosure,
|
|
1314
|
-
results.length === 0 ? rawExcerpts : void 0
|
|
1315
|
-
)
|
|
1316
|
-
);
|
|
1317
|
-
}
|
|
1318
|
-
return results;
|
|
1319
|
-
}
|
|
1320
|
-
/**
|
|
1321
|
-
* Fetch raw transcript excerpts from the LCM archive for `disclosure ===
|
|
1322
|
-
* "raw"` recalls (issue #677 PR 2/4). Returns `null` for non-raw recall
|
|
1323
|
-
* depths, an empty array when LCM is disabled / not initialized / has no
|
|
1324
|
-
* matches, and an array of LCM-side excerpts otherwise. Errors are
|
|
1325
|
-
* swallowed and treated as "no excerpts" so a failing LCM never breaks
|
|
1326
|
-
* the recall response.
|
|
1327
|
-
*
|
|
1328
|
-
* Namespace handling: LCM archival prefixes non-default-namespace
|
|
1329
|
-
* sessions with `${namespace}:${sessionKey}` (see `observe()` around
|
|
1330
|
-
* line 2498), so the lookup must mirror that prefix or raw recalls in
|
|
1331
|
-
* non-default namespaces miss their own excerpts.
|
|
1332
|
-
*/
|
|
1333
|
-
async fetchRawExcerpts(disclosure, context) {
|
|
1334
|
-
if (disclosure !== "raw") return null;
|
|
1335
|
-
if (!context || !context.query) return [];
|
|
1336
|
-
if (!context.sessionKey) return [];
|
|
1337
|
-
const lcm = this.orchestrator.lcmEngine;
|
|
1338
|
-
if (!lcm || !lcm.enabled) return [];
|
|
1339
|
-
try {
|
|
1340
|
-
const lcmSessionKey = context.namespace && context.namespace !== this.orchestrator.config.defaultNamespace ? `${context.namespace}:${context.sessionKey}` : context.sessionKey;
|
|
1341
|
-
const rows = await lcm.searchContextFull(
|
|
1342
|
-
context.query,
|
|
1343
|
-
// Cap the excerpt fanout so recall responses stay bounded. Five
|
|
1344
|
-
// matches is enough to anchor the model in the raw transcript
|
|
1345
|
-
// without ballooning token spend; raw is meant as the escape
|
|
1346
|
-
// hatch, not the default.
|
|
1347
|
-
5,
|
|
1348
|
-
lcmSessionKey
|
|
1349
|
-
);
|
|
1350
|
-
return rows.map((r) => ({
|
|
1351
|
-
turnIndex: r.turn_index,
|
|
1352
|
-
role: r.role,
|
|
1353
|
-
content: r.content,
|
|
1354
|
-
sessionId: r.session_id
|
|
1355
|
-
}));
|
|
1356
|
-
} catch {
|
|
1357
|
-
return [];
|
|
1358
|
-
}
|
|
1359
|
-
}
|
|
1360
|
-
async handleIdempotentWrite(options) {
|
|
1361
|
-
if (options.skip === true) {
|
|
1362
|
-
return options.execute();
|
|
1363
|
-
}
|
|
1364
|
-
const key = options.idempotencyKey?.trim();
|
|
1365
|
-
if (!key) {
|
|
1366
|
-
return options.execute();
|
|
1367
|
-
}
|
|
1368
|
-
return this.withIdempotencyLock(key, async () => {
|
|
1369
|
-
return this.idempotency.withKeyLock(key, async () => {
|
|
1370
|
-
const requestHash = hashAccessIdempotencyPayload({
|
|
1371
|
-
operation: options.operation,
|
|
1372
|
-
request: options.requestFingerprint
|
|
1373
|
-
});
|
|
1374
|
-
const existing = await this.idempotency.get(key, requestHash);
|
|
1375
|
-
if (existing.conflict) {
|
|
1376
|
-
throw new EngramAccessInputError(`idempotencyKey reuse conflict: ${key}`);
|
|
1377
|
-
}
|
|
1378
|
-
if (existing.response) {
|
|
1379
|
-
return {
|
|
1380
|
-
...existing.response,
|
|
1381
|
-
idempotencyReplay: true
|
|
1382
|
-
};
|
|
1383
|
-
}
|
|
1384
|
-
const response = await options.execute();
|
|
1385
|
-
await this.idempotency.put(key, requestHash, response);
|
|
1386
|
-
return response;
|
|
1387
|
-
});
|
|
1388
|
-
});
|
|
1389
|
-
}
|
|
1390
|
-
async peekIdempotentWrite(options) {
|
|
1391
|
-
if (options.skip === true) {
|
|
1392
|
-
return "miss";
|
|
1393
|
-
}
|
|
1394
|
-
const key = options.idempotencyKey?.trim();
|
|
1395
|
-
if (!key) {
|
|
1396
|
-
return "miss";
|
|
1397
|
-
}
|
|
1398
|
-
return this.withIdempotencyLock(key, async () => {
|
|
1399
|
-
return this.idempotency.withKeyLock(key, async () => {
|
|
1400
|
-
const requestHash = hashAccessIdempotencyPayload({
|
|
1401
|
-
operation: options.operation,
|
|
1402
|
-
request: options.requestFingerprint
|
|
1403
|
-
});
|
|
1404
|
-
const existing = await this.idempotency.get(key, requestHash);
|
|
1405
|
-
if (existing.conflict) {
|
|
1406
|
-
return "conflict";
|
|
1407
|
-
}
|
|
1408
|
-
return existing.response ? "replay" : "miss";
|
|
1409
|
-
});
|
|
1410
|
-
});
|
|
1411
|
-
}
|
|
1412
|
-
async withIdempotencyLock(key, fn) {
|
|
1413
|
-
const previous = this.idempotencyLocks.get(key) ?? Promise.resolve();
|
|
1414
|
-
let release;
|
|
1415
|
-
const current = new Promise((resolve2) => {
|
|
1416
|
-
release = resolve2;
|
|
1417
|
-
});
|
|
1418
|
-
const queued = previous.then(() => current, () => current);
|
|
1419
|
-
this.idempotencyLocks.set(key, queued);
|
|
1420
|
-
await previous.catch(() => {
|
|
1421
|
-
});
|
|
1422
|
-
try {
|
|
1423
|
-
return await fn();
|
|
1424
|
-
} finally {
|
|
1425
|
-
release();
|
|
1426
|
-
if (this.idempotencyLocks.get(key) === queued) {
|
|
1427
|
-
this.idempotencyLocks.delete(key);
|
|
1428
|
-
}
|
|
1429
|
-
}
|
|
1430
|
-
}
|
|
1431
|
-
async health(namespace) {
|
|
1432
|
-
const resolvedNamespace = this.resolveNamespace(namespace);
|
|
1433
|
-
const storage = await this.orchestrator.getStorage(resolvedNamespace);
|
|
1434
|
-
let projectionAvailable = false;
|
|
1435
|
-
try {
|
|
1436
|
-
await stat(getMemoryProjectionPath(storage.dir));
|
|
1437
|
-
projectionAvailable = true;
|
|
1438
|
-
} catch {
|
|
1439
|
-
projectionAvailable = false;
|
|
1440
|
-
}
|
|
1441
|
-
return {
|
|
1442
|
-
ok: true,
|
|
1443
|
-
memoryDir: storage.dir,
|
|
1444
|
-
namespacesEnabled: this.orchestrator.config.namespacesEnabled === true,
|
|
1445
|
-
defaultNamespace: this.orchestrator.config.defaultNamespace,
|
|
1446
|
-
searchBackend: this.orchestrator.config.searchBackend ?? "qmd",
|
|
1447
|
-
qmdEnabled: this.orchestrator.config.qmdEnabled === true,
|
|
1448
|
-
nativeKnowledgeEnabled: this.orchestrator.config.nativeKnowledge?.enabled === true,
|
|
1449
|
-
projectionAvailable
|
|
1450
|
-
};
|
|
1451
|
-
}
|
|
1452
|
-
async actionConfidence(request = {}) {
|
|
1453
|
-
return evaluateActionConfidence(request);
|
|
1454
|
-
}
|
|
1455
|
-
async daySummary(request) {
|
|
1456
|
-
if (!this.orchestrator.config.daySummaryEnabled) {
|
|
1457
|
-
throw new EngramAccessInputError("day summary is disabled");
|
|
1458
|
-
}
|
|
1459
|
-
const memories = (request.memories ?? "").trim();
|
|
1460
|
-
const namespace = this.resolveRecallNamespace(request.namespace, request.sessionKey);
|
|
1461
|
-
if (memories.length === 0) {
|
|
1462
|
-
return this.orchestrator.generateDaySummaryAuto(namespace);
|
|
1463
|
-
}
|
|
1464
|
-
return this.orchestrator.generateDaySummary(memories);
|
|
1465
|
-
}
|
|
1466
|
-
/**
|
|
1467
|
-
* Build a daily context briefing. Gracefully degrades when the OpenAI key
|
|
1468
|
-
* or Responses API is unavailable — never throws for LLM-related problems.
|
|
1469
|
-
*/
|
|
1470
|
-
async briefing(request) {
|
|
1471
|
-
const config = this.orchestrator.config;
|
|
1472
|
-
if (!config.briefing.enabled) {
|
|
1473
|
-
throw new EngramAccessInputError("briefing is disabled");
|
|
1474
|
-
}
|
|
1475
|
-
const namespace = this.resolveReadableNamespace(request.namespace, request.principal);
|
|
1476
|
-
const storage = await this.orchestrator.getStorage(namespace);
|
|
1477
|
-
const token = typeof request.since === "string" && request.since.trim().length > 0 ? request.since.trim() : config.briefing.defaultWindow;
|
|
1478
|
-
const window = parseBriefingWindow(token);
|
|
1479
|
-
if (!window) {
|
|
1480
|
-
throw new EngramAccessInputError(`invalid briefing window: ${token}`);
|
|
1481
|
-
}
|
|
1482
|
-
const rawFocus = typeof request.focus === "string" ? request.focus.trim() : "";
|
|
1483
|
-
let focus = null;
|
|
1484
|
-
if (rawFocus.length > 0) {
|
|
1485
|
-
focus = parseBriefingFocus(rawFocus);
|
|
1486
|
-
if (!focus) {
|
|
1487
|
-
throw new EngramAccessInputError(
|
|
1488
|
-
`invalid briefing focus filter: ${request.focus}`
|
|
1489
|
-
);
|
|
1490
|
-
}
|
|
1491
|
-
}
|
|
1492
|
-
const SUPPORTED_FORMATS = ["markdown", "json"];
|
|
1493
|
-
if (typeof request.format === "string" && !SUPPORTED_FORMATS.includes(request.format)) {
|
|
1494
|
-
throw new EngramAccessInputError(
|
|
1495
|
-
`unsupported briefing format: "${request.format}". Accepted: ${SUPPORTED_FORMATS.join(", ")}.`
|
|
1496
|
-
);
|
|
1497
|
-
}
|
|
1498
|
-
const format = request.format === "json" ? "json" : request.format === "markdown" ? "markdown" : config.briefing.defaultFormat;
|
|
1499
|
-
const maxFollowups = typeof request.maxFollowups === "number" && Number.isFinite(request.maxFollowups) ? Math.max(0, Math.min(10, Math.floor(request.maxFollowups))) : config.briefing.maxFollowups;
|
|
1500
|
-
const calendarSource = config.briefing.calendarSource ? new FileCalendarSource(config.briefing.calendarSource) : void 0;
|
|
1501
|
-
const result = await buildBriefing({
|
|
1502
|
-
storage,
|
|
1503
|
-
namespace,
|
|
1504
|
-
window,
|
|
1505
|
-
focus,
|
|
1506
|
-
calendarSource,
|
|
1507
|
-
maxFollowups,
|
|
1508
|
-
allowLlm: config.briefing.llmFollowups,
|
|
1509
|
-
openaiApiKey: config.openaiApiKey,
|
|
1510
|
-
openaiBaseUrl: config.openaiBaseUrl,
|
|
1511
|
-
model: config.model
|
|
1512
|
-
});
|
|
1513
|
-
return {
|
|
1514
|
-
format,
|
|
1515
|
-
window: result.window,
|
|
1516
|
-
namespace,
|
|
1517
|
-
markdown: result.markdown,
|
|
1518
|
-
json: result.json,
|
|
1519
|
-
followupsUnavailableReason: result.followupsUnavailableReason
|
|
1520
|
-
};
|
|
1521
|
-
}
|
|
1522
|
-
/**
|
|
1523
|
-
* Attach a coding context to a session (issue #569). Used by the Claude
|
|
1524
|
-
* Code / Codex / generic-MCP connectors at session start so that recall +
|
|
1525
|
-
* write paths can route to a project- / branch-scoped namespace.
|
|
1526
|
-
*
|
|
1527
|
-
* Validates the input shape and rejects malformed payloads rather than
|
|
1528
|
-
* silently accepting them (CLAUDE.md #51). Pass `codingContext: null` to
|
|
1529
|
-
* clear.
|
|
1530
|
-
*/
|
|
1531
|
-
setCodingContext(request) {
|
|
1532
|
-
const sessionKey = typeof request.sessionKey === "string" ? request.sessionKey.trim() : "";
|
|
1533
|
-
if (!sessionKey) {
|
|
1534
|
-
throw new EngramAccessInputError("sessionKey is required for setCodingContext");
|
|
1535
|
-
}
|
|
1536
|
-
if (request.codingContext === null) {
|
|
1537
|
-
this.orchestrator.setCodingContextForSession(sessionKey, null);
|
|
1538
|
-
return;
|
|
1539
|
-
}
|
|
1540
|
-
const ctx = request.codingContext;
|
|
1541
|
-
if (!ctx || typeof ctx !== "object") {
|
|
1542
|
-
throw new EngramAccessInputError("codingContext must be an object or null");
|
|
1543
|
-
}
|
|
1544
|
-
if (typeof ctx.projectId !== "string" || ctx.projectId.trim().length === 0) {
|
|
1545
|
-
throw new EngramAccessInputError("codingContext.projectId must be a non-empty string");
|
|
1546
|
-
}
|
|
1547
|
-
if (typeof ctx.rootPath !== "string" || ctx.rootPath.trim().length === 0) {
|
|
1548
|
-
throw new EngramAccessInputError("codingContext.rootPath must be a non-empty string");
|
|
1549
|
-
}
|
|
1550
|
-
if (ctx.branch !== null && typeof ctx.branch !== "string") {
|
|
1551
|
-
throw new EngramAccessInputError("codingContext.branch must be a string or null");
|
|
1552
|
-
}
|
|
1553
|
-
if (ctx.defaultBranch !== null && typeof ctx.defaultBranch !== "string") {
|
|
1554
|
-
throw new EngramAccessInputError("codingContext.defaultBranch must be a string or null");
|
|
1555
|
-
}
|
|
1556
|
-
this.orchestrator.setCodingContextForSession(sessionKey, {
|
|
1557
|
-
projectId: ctx.projectId,
|
|
1558
|
-
branch: ctx.branch,
|
|
1559
|
-
rootPath: ctx.rootPath,
|
|
1560
|
-
defaultBranch: ctx.defaultBranch
|
|
1561
|
-
});
|
|
1562
|
-
}
|
|
1563
|
-
/**
|
|
1564
|
-
* Auto-resolve and attach a coding context for a session when one is not
|
|
1565
|
-
* already present. Resolves from `projectTag` (highest priority after
|
|
1566
|
-
* explicit `codingContext`), then from `cwd` via git detection.
|
|
1567
|
-
*
|
|
1568
|
-
* This is a no-op when:
|
|
1569
|
-
* - `sessionKey` is missing
|
|
1570
|
-
* - the session already has a coding context attached
|
|
1571
|
-
* - codingMode.projectScope is disabled (CLAUDE.md #30)
|
|
1572
|
-
* - neither `cwd` nor `projectTag` is provided
|
|
1573
|
-
*
|
|
1574
|
-
* Never throws — git resolution failures are silently ignored because not
|
|
1575
|
-
* being in a repo is a normal runtime state.
|
|
1576
|
-
*/
|
|
1577
|
-
async maybeAttachCodingContext(sessionKey, options) {
|
|
1578
|
-
if (!sessionKey) return;
|
|
1579
|
-
if (!this.orchestrator.config.codingMode?.projectScope) return;
|
|
1580
|
-
if (this.orchestrator.getCodingContextForSession(sessionKey)) return;
|
|
1581
|
-
if (typeof options.projectTag === "string" && options.projectTag.trim().length > 0) {
|
|
1582
|
-
const tag = options.projectTag.trim();
|
|
1583
|
-
this.orchestrator.setCodingContextForSession(sessionKey, {
|
|
1584
|
-
projectId: `tag:${tag}`,
|
|
1585
|
-
branch: null,
|
|
1586
|
-
rootPath: `tag:${tag}`,
|
|
1587
|
-
defaultBranch: null
|
|
1588
|
-
});
|
|
1589
|
-
return;
|
|
1590
|
-
}
|
|
1591
|
-
if (typeof options.cwd === "string" && options.cwd.trim().length > 0) {
|
|
1592
|
-
try {
|
|
1593
|
-
const gitCtx = await resolveGitContext(options.cwd);
|
|
1594
|
-
if (gitCtx) {
|
|
1595
|
-
this.setCodingContext({
|
|
1596
|
-
sessionKey,
|
|
1597
|
-
codingContext: {
|
|
1598
|
-
projectId: gitCtx.projectId,
|
|
1599
|
-
branch: gitCtx.branch,
|
|
1600
|
-
rootPath: gitCtx.rootPath,
|
|
1601
|
-
defaultBranch: gitCtx.defaultBranch
|
|
1602
|
-
}
|
|
1603
|
-
});
|
|
1604
|
-
}
|
|
1605
|
-
} catch {
|
|
1606
|
-
}
|
|
1607
|
-
}
|
|
1608
|
-
}
|
|
1609
|
-
async recall(request) {
|
|
1610
|
-
const query = request.query.trim();
|
|
1611
|
-
if (query.length === 0) {
|
|
1612
|
-
throw new EngramAccessInputError("query is required");
|
|
1613
|
-
}
|
|
1614
|
-
const callerProvidedDisclosure = request.disclosure !== void 0 && request.disclosure !== null;
|
|
1615
|
-
const requestedDisclosure = (() => {
|
|
1616
|
-
if (!callerProvidedDisclosure) {
|
|
1617
|
-
return DEFAULT_RECALL_DISCLOSURE;
|
|
1618
|
-
}
|
|
1619
|
-
if (!isRecallDisclosure(request.disclosure)) {
|
|
1620
|
-
throw new EngramAccessInputError(
|
|
1621
|
-
`disclosure must be one of: chunk, section, raw (got: ${String(request.disclosure)})`
|
|
1622
|
-
);
|
|
1623
|
-
}
|
|
1624
|
-
return request.disclosure;
|
|
1625
|
-
})();
|
|
1626
|
-
if (request.codingContext !== void 0 && request.sessionKey) {
|
|
1627
|
-
this.setCodingContext({
|
|
1628
|
-
sessionKey: request.sessionKey,
|
|
1629
|
-
codingContext: request.codingContext
|
|
1630
|
-
});
|
|
1631
|
-
}
|
|
1632
|
-
if (request.codingContext === void 0 && request.sessionKey) {
|
|
1633
|
-
await this.maybeAttachCodingContext(request.sessionKey, {
|
|
1634
|
-
cwd: request.cwd,
|
|
1635
|
-
projectTag: request.projectTag
|
|
1636
|
-
});
|
|
1637
|
-
}
|
|
1638
|
-
const authenticatedPrincipal = request.authenticatedPrincipal?.trim();
|
|
1639
|
-
const namespaceOverride = this.resolveRecallNamespace(
|
|
1640
|
-
request.namespace,
|
|
1641
|
-
request.sessionKey,
|
|
1642
|
-
authenticatedPrincipal
|
|
1643
|
-
);
|
|
1644
|
-
const namespace = namespaceOverride ?? this.orchestrator.config.defaultNamespace;
|
|
1645
|
-
const mode = this.normalizeRecallMode(request.mode);
|
|
1646
|
-
const principal = this.resolveRequestPrincipal(request.sessionKey, authenticatedPrincipal);
|
|
1647
|
-
const principalNamespace = defaultNamespaceForPrincipal(principal, this.orchestrator.config);
|
|
1648
|
-
const modeSkipsBudget = mode === "no_recall";
|
|
1649
|
-
const effectiveNamespaces = namespaceOverride ? [namespaceOverride] : recallNamespacesForPrincipal(principal, this.orchestrator.config);
|
|
1650
|
-
let budgetDecision;
|
|
1651
|
-
if (modeSkipsBudget) {
|
|
1652
|
-
budgetDecision = {
|
|
1653
|
-
allowed: true,
|
|
1654
|
-
reason: "allowed-same-namespace",
|
|
1655
|
-
count: 0,
|
|
1656
|
-
limit: {
|
|
1657
|
-
softLimit: this.orchestrator.config.recallCrossNamespaceBudgetSoftLimit ?? 10,
|
|
1658
|
-
hardLimit: this.orchestrator.config.recallCrossNamespaceBudgetHardLimit ?? 30,
|
|
1659
|
-
windowMs: this.orchestrator.config.recallCrossNamespaceBudgetWindowMs ?? 6e4
|
|
1660
|
-
}
|
|
1661
|
-
};
|
|
1662
|
-
} else {
|
|
1663
|
-
let anyCrossNamespace = false;
|
|
1664
|
-
let denied = null;
|
|
1665
|
-
for (const ns of effectiveNamespaces) {
|
|
1666
|
-
const peek = this.budget.peek({
|
|
1667
|
-
principal,
|
|
1668
|
-
principalNamespace,
|
|
1669
|
-
queryNamespace: ns
|
|
1670
|
-
});
|
|
1671
|
-
if (peek.reason !== "allowed-same-namespace") {
|
|
1672
|
-
anyCrossNamespace = true;
|
|
1673
|
-
}
|
|
1674
|
-
if (!peek.allowed) {
|
|
1675
|
-
denied = peek;
|
|
1676
|
-
break;
|
|
1677
|
-
}
|
|
1678
|
-
}
|
|
1679
|
-
if (denied) {
|
|
1680
|
-
budgetDecision = denied;
|
|
1681
|
-
} else if (anyCrossNamespace) {
|
|
1682
|
-
budgetDecision = this.budget.record(principal);
|
|
1683
|
-
} else {
|
|
1684
|
-
budgetDecision = {
|
|
1685
|
-
allowed: true,
|
|
1686
|
-
reason: "allowed-same-namespace",
|
|
1687
|
-
count: 0,
|
|
1688
|
-
limit: {
|
|
1689
|
-
softLimit: this.orchestrator.config.recallCrossNamespaceBudgetSoftLimit ?? 10,
|
|
1690
|
-
hardLimit: this.orchestrator.config.recallCrossNamespaceBudgetHardLimit ?? 30,
|
|
1691
|
-
windowMs: this.orchestrator.config.recallCrossNamespaceBudgetWindowMs ?? 6e4
|
|
1692
|
-
}
|
|
1693
|
-
};
|
|
1694
|
-
}
|
|
1695
|
-
if (!budgetDecision.allowed) {
|
|
1696
|
-
throw new EngramAccessInputError(
|
|
1697
|
-
`recall denied: cross-namespace budget exceeded (${budgetDecision.count}/${budgetDecision.limit.hardLimit} in ${budgetDecision.limit.windowMs}ms window)`
|
|
1698
|
-
);
|
|
1699
|
-
}
|
|
1700
|
-
this.budget.gc();
|
|
1701
|
-
}
|
|
1702
|
-
const topK = Number.isFinite(request.topK) ? Math.max(0, Math.floor(request.topK ?? 0)) : void 0;
|
|
1703
|
-
let asOf;
|
|
1704
|
-
if (request.asOf !== void 0 && request.asOf !== null) {
|
|
1705
|
-
if (typeof request.asOf !== "string" || request.asOf.trim().length === 0) {
|
|
1706
|
-
throw new EngramAccessInputError(
|
|
1707
|
-
"asOf must be a non-empty ISO 8601 timestamp string"
|
|
1708
|
-
);
|
|
1709
|
-
}
|
|
1710
|
-
const parsed = Date.parse(request.asOf);
|
|
1711
|
-
if (!Number.isFinite(parsed)) {
|
|
1712
|
-
throw new EngramAccessInputError(
|
|
1713
|
-
`asOf must be a parseable ISO 8601 timestamp (got: "${request.asOf}")`
|
|
1714
|
-
);
|
|
1715
|
-
}
|
|
1716
|
-
asOf = request.asOf;
|
|
1717
|
-
}
|
|
1718
|
-
const recallOptions = {
|
|
1719
|
-
namespace: namespaceOverride,
|
|
1720
|
-
topK,
|
|
1721
|
-
mode,
|
|
1722
|
-
...authenticatedPrincipal ? { principalOverride: authenticatedPrincipal } : {},
|
|
1723
|
-
...asOf !== void 0 ? { asOf } : {},
|
|
1724
|
-
...request.includeLowConfidence === true ? { includeLowConfidence: true } : {}
|
|
1725
|
-
};
|
|
1726
|
-
const startedAt = Date.now();
|
|
1727
|
-
const context = await this.orchestrator.recall(query, request.sessionKey, recallOptions);
|
|
1728
|
-
const snapshot = request.sessionKey ? this.orchestrator.lastRecall.get(request.sessionKey) : null;
|
|
1729
|
-
const effectiveNamespace = snapshot?.namespace ? this.resolveNamespace(snapshot.namespace) : namespace;
|
|
1730
|
-
const resultsReturned = snapshot?.memoryIds?.length ?? 0;
|
|
1731
|
-
const appliedTopK = snapshot?.budgetsApplied?.appliedTopK;
|
|
1732
|
-
const configMaxResults = typeof this.orchestrator.config.qmdMaxResults === "number" && Number.isFinite(this.orchestrator.config.qmdMaxResults) && this.orchestrator.config.qmdMaxResults > 0 ? this.orchestrator.config.qmdMaxResults : 0;
|
|
1733
|
-
const topKDenominator = typeof appliedTopK === "number" && Number.isFinite(appliedTopK) && appliedTopK > 0 ? Math.max(appliedTopK, resultsReturned) : typeof topK === "number" && topK > 0 ? Math.max(topK, resultsReturned) : Math.max(configMaxResults, resultsReturned, 1);
|
|
1734
|
-
const topKConfidence = snapshot && topKDenominator > 0 ? Math.min(1, resultsReturned / topKDenominator) : void 0;
|
|
1735
|
-
const escalationDecision = decideDisclosureEscalation({
|
|
1736
|
-
mode: this.orchestrator.config.recallDisclosureEscalation,
|
|
1737
|
-
threshold: this.orchestrator.config.recallDisclosureEscalationThreshold,
|
|
1738
|
-
originalDisclosure: requestedDisclosure,
|
|
1739
|
-
callerProvidedDisclosure,
|
|
1740
|
-
topKConfidence
|
|
1741
|
-
});
|
|
1742
|
-
const disclosure = escalationDecision.effective;
|
|
1743
|
-
let results = await this.serializeRecallResults(snapshot, disclosure, {
|
|
1744
|
-
query,
|
|
1745
|
-
sessionKey: request.sessionKey
|
|
1746
|
-
});
|
|
1747
|
-
const filterTags = normalizeTags(request.tags);
|
|
1748
|
-
let tagMatchMode;
|
|
1749
|
-
try {
|
|
1750
|
-
tagMatchMode = parseTagMatch(request.tagMatch);
|
|
1751
|
-
} catch (err) {
|
|
1752
|
-
throw new EngramAccessInputError(
|
|
1753
|
-
err instanceof Error ? err.message : String(err)
|
|
1754
|
-
);
|
|
1755
|
-
}
|
|
1756
|
-
let effectiveContext = context;
|
|
1757
|
-
if (filterTags && filterTags.length > 0) {
|
|
1758
|
-
const beforeIds = results.map((r) => r.id);
|
|
1759
|
-
const { results: admitted } = applyTagFilter(results, {
|
|
1760
|
-
tags: filterTags,
|
|
1761
|
-
tagMatch: tagMatchMode
|
|
1762
|
-
});
|
|
1763
|
-
results = admitted;
|
|
1764
|
-
const admittedIds = new Set(results.map((r) => r.id));
|
|
1765
|
-
const droppedAny = beforeIds.some((id) => !admittedIds.has(id));
|
|
1766
|
-
if (droppedAny) {
|
|
1767
|
-
effectiveContext = results.map((r) => {
|
|
1768
|
-
const content = typeof r.content === "string" ? r.content ?? "" : "";
|
|
1769
|
-
const preview = typeof r.preview === "string" ? r.preview ?? "" : "";
|
|
1770
|
-
return content || preview;
|
|
1771
|
-
}).filter((s) => s.length > 0).join("\n\n");
|
|
1772
|
-
}
|
|
1773
|
-
}
|
|
1774
|
-
const filteredMemoryIds = filterTags && filterTags.length > 0 ? results.map((r) => r.id) : snapshot?.memoryIds ?? [];
|
|
1775
|
-
const debug = await this.buildRecallDebug(
|
|
1776
|
-
snapshot,
|
|
1777
|
-
effectiveNamespace,
|
|
1778
|
-
request.includeDebug === true,
|
|
1779
|
-
request.sessionKey
|
|
1780
|
-
);
|
|
1781
|
-
let auditAnomalies;
|
|
1782
|
-
if (this.auditAdapter) {
|
|
1783
|
-
try {
|
|
1784
|
-
const resolvedAgentId = principal;
|
|
1785
|
-
const auditEntry = {
|
|
1786
|
-
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1787
|
-
sessionKey: request.sessionKey ?? "",
|
|
1788
|
-
agentId: resolvedAgentId,
|
|
1789
|
-
trigger: "access-surface",
|
|
1790
|
-
queryText: query,
|
|
1791
|
-
candidateMemoryIds: snapshot?.memoryIds ?? [],
|
|
1792
|
-
// Audit must reflect what was actually injected, not what
|
|
1793
|
-
// recall produced before the tag filter. Using `context`
|
|
1794
|
-
// (pre-filter) overstates injectedChars and can leak content
|
|
1795
|
-
// from excluded memories into the audit summary (cursor
|
|
1796
|
-
// Medium on PR #712).
|
|
1797
|
-
summary: effectiveContext.slice(0, 200) || null,
|
|
1798
|
-
injectedChars: effectiveContext.length,
|
|
1799
|
-
toggleState: "enabled",
|
|
1800
|
-
latencyMs: Date.now() - startedAt,
|
|
1801
|
-
plannerMode: snapshot?.plannerMode ?? mode,
|
|
1802
|
-
requestedMode: mode,
|
|
1803
|
-
fallbackUsed: snapshot?.fallbackUsed ?? false
|
|
1804
|
-
};
|
|
1805
|
-
const auditResult = await this.auditAdapter.record(
|
|
1806
|
-
resolvedAgentId || "__anonymous__",
|
|
1807
|
-
auditEntry
|
|
1808
|
-
);
|
|
1809
|
-
auditAnomalies = auditResult.anomalies;
|
|
1810
|
-
} catch {
|
|
1811
|
-
}
|
|
1812
|
-
}
|
|
1813
|
-
return {
|
|
1814
|
-
query,
|
|
1815
|
-
sessionKey: request.sessionKey,
|
|
1816
|
-
namespace: effectiveNamespace,
|
|
1817
|
-
context: effectiveContext,
|
|
1818
|
-
count: filterTags && filterTags.length > 0 ? results.length : snapshot?.memoryIds.length ?? results.length,
|
|
1819
|
-
memoryIds: filteredMemoryIds,
|
|
1820
|
-
results,
|
|
1821
|
-
recordedAt: snapshot?.recordedAt,
|
|
1822
|
-
traceId: snapshot?.traceId,
|
|
1823
|
-
plannerMode: snapshot?.plannerMode ?? mode,
|
|
1824
|
-
fallbackUsed: snapshot?.fallbackUsed ?? false,
|
|
1825
|
-
sourcesUsed: snapshot?.sourcesUsed ?? [],
|
|
1826
|
-
disclosure,
|
|
1827
|
-
budgetsApplied: snapshot?.budgetsApplied,
|
|
1828
|
-
auditAnomalies,
|
|
1829
|
-
budgetWarning: budgetDecision.reason === "warn-over-soft" ? budgetDecision : void 0,
|
|
1830
|
-
latencyMs: snapshot?.latencyMs ?? Date.now() - startedAt,
|
|
1831
|
-
debug
|
|
1832
|
-
};
|
|
1833
|
-
}
|
|
1834
|
-
async recallExplain(request = {}) {
|
|
1835
|
-
const requestedNamespace = request.namespace?.trim() ? this.resolveNamespace(request.namespace) : void 0;
|
|
1836
|
-
if (requestedNamespace) {
|
|
1837
|
-
const principal = resolvePrincipal(request.sessionKey, this.orchestrator.config);
|
|
1838
|
-
if (!canReadNamespace(principal, requestedNamespace, this.orchestrator.config)) {
|
|
1839
|
-
return { found: false };
|
|
1840
|
-
}
|
|
1841
|
-
}
|
|
1842
|
-
const snapshot = request.sessionKey ? (() => {
|
|
1843
|
-
const candidate = this.orchestrator.lastRecall.get(request.sessionKey);
|
|
1844
|
-
if (!candidate) return null;
|
|
1845
|
-
if (!requestedNamespace) return candidate;
|
|
1846
|
-
return candidate.namespace === requestedNamespace ? candidate : null;
|
|
1847
|
-
})() : (() => {
|
|
1848
|
-
const candidate = this.orchestrator.lastRecall.getMostRecent();
|
|
1849
|
-
if (!candidate) return null;
|
|
1850
|
-
if (!requestedNamespace) return candidate;
|
|
1851
|
-
return candidate.namespace === requestedNamespace ? candidate : null;
|
|
1852
|
-
})();
|
|
1853
|
-
const namespace = requestedNamespace ?? snapshot?.namespace ?? this.orchestrator.config.defaultNamespace;
|
|
1854
|
-
const [intent, graph] = await Promise.all([
|
|
1855
|
-
this.orchestrator.getLastIntentSnapshot(namespace),
|
|
1856
|
-
this.orchestrator.getLastGraphRecallSnapshot(namespace)
|
|
1857
|
-
]);
|
|
1858
|
-
if (!snapshot && !intent && !graph) return { found: false };
|
|
1859
|
-
return { found: true, snapshot: snapshot ?? void 0, intent, graph };
|
|
1860
|
-
}
|
|
1861
|
-
async recallTierExplain(sessionKey, namespace, authenticatedPrincipal) {
|
|
1862
|
-
const namespacesEnabled = this.orchestrator.config.namespacesEnabled;
|
|
1863
|
-
const requestedNamespace = namespace?.trim() ? this.resolveNamespace(namespace) : void 0;
|
|
1864
|
-
const principal = authenticatedPrincipal?.trim() || resolvePrincipal(sessionKey, this.orchestrator.config);
|
|
1865
|
-
if (requestedNamespace) {
|
|
1866
|
-
if (!canReadNamespace(principal, requestedNamespace, this.orchestrator.config)) {
|
|
1867
|
-
return toRecallExplainJson(null);
|
|
1868
|
-
}
|
|
1869
|
-
} else if (namespacesEnabled && !authenticatedPrincipal?.trim() && !sessionKey?.trim()) {
|
|
1870
|
-
return toRecallExplainJson(null);
|
|
1871
|
-
}
|
|
1872
|
-
const candidate = sessionKey ? this.orchestrator.lastRecall.get(sessionKey) : this.orchestrator.lastRecall.getMostRecent();
|
|
1873
|
-
const snapshot = (() => {
|
|
1874
|
-
if (!candidate) return null;
|
|
1875
|
-
if (requestedNamespace) {
|
|
1876
|
-
return candidate.namespace === requestedNamespace ? candidate : null;
|
|
1877
|
-
}
|
|
1878
|
-
if (!namespacesEnabled) return candidate;
|
|
1879
|
-
const snapshotNs = candidate.namespace ?? this.orchestrator.config.defaultNamespace;
|
|
1880
|
-
return canReadNamespace(principal, snapshotNs, this.orchestrator.config) ? candidate : null;
|
|
1881
|
-
})();
|
|
1882
|
-
return toRecallExplainJson(snapshot);
|
|
1883
|
-
}
|
|
1884
|
-
/**
|
|
1885
|
-
* Recall X-ray (issue #570). Runs a recall with `xrayCapture: true`
|
|
1886
|
-
* and returns the resulting snapshot as structured JSON so every
|
|
1887
|
-
* surface (CLI / HTTP / MCP) gets the same payload. Namespace scope
|
|
1888
|
-
* is enforced before the recall fires (CLAUDE.md rule 42 — read and
|
|
1889
|
-
* write paths must resolve through the same namespace layer) so an
|
|
1890
|
-
* unauthorized principal cannot capture an x-ray for a namespace it
|
|
1891
|
-
* cannot read.
|
|
1892
|
-
*/
|
|
1893
|
-
async recallXray(request) {
|
|
1894
|
-
const query = typeof request.query === "string" ? request.query : "";
|
|
1895
|
-
if (query.trim().length === 0) {
|
|
1896
|
-
throw new Error("recallXray: query is required and must be non-empty");
|
|
1897
|
-
}
|
|
1898
|
-
if (request.disclosure !== void 0 && !isRecallDisclosure(request.disclosure)) {
|
|
1899
|
-
throw new EngramAccessInputError(
|
|
1900
|
-
`recallXray: disclosure must be one of: chunk, section, raw (got: ${String(request.disclosure)})`
|
|
1901
|
-
);
|
|
1902
|
-
}
|
|
1903
|
-
const namespacesEnabled = this.orchestrator.config.namespacesEnabled;
|
|
1904
|
-
const requestedNamespace = request.namespace?.trim() ? this.resolveNamespace(request.namespace) : void 0;
|
|
1905
|
-
const authenticatedPrincipal = request.authenticatedPrincipal?.trim();
|
|
1906
|
-
const principal = authenticatedPrincipal || resolvePrincipal(request.sessionKey, this.orchestrator.config);
|
|
1907
|
-
if (requestedNamespace) {
|
|
1908
|
-
if (!canReadNamespace(
|
|
1909
|
-
principal,
|
|
1910
|
-
requestedNamespace,
|
|
1911
|
-
this.orchestrator.config
|
|
1912
|
-
)) {
|
|
1913
|
-
return { snapshotFound: false };
|
|
1914
|
-
}
|
|
1915
|
-
} else if (namespacesEnabled && !authenticatedPrincipal && !request.sessionKey?.trim()) {
|
|
1916
|
-
return { snapshotFound: false };
|
|
1917
|
-
}
|
|
1918
|
-
let budgetOverride;
|
|
1919
|
-
if (request.budget !== void 0 && request.budget !== null) {
|
|
1920
|
-
const parsed = typeof request.budget === "number" ? request.budget : Number(request.budget);
|
|
1921
|
-
if (!Number.isFinite(parsed) || parsed <= 0 || !Number.isInteger(parsed)) {
|
|
1922
|
-
throw new Error(
|
|
1923
|
-
`recallXray: budget expects a positive integer; got ${JSON.stringify(request.budget)}`
|
|
1924
|
-
);
|
|
1925
|
-
}
|
|
1926
|
-
budgetOverride = parsed;
|
|
1927
|
-
}
|
|
1928
|
-
const mode = this.normalizeRecallMode(request.mode);
|
|
1929
|
-
const disclosure = request.disclosure ?? DEFAULT_RECALL_DISCLOSURE;
|
|
1930
|
-
const previousQueue = this.xrayQueue;
|
|
1931
|
-
let release = () => {
|
|
1932
|
-
};
|
|
1933
|
-
this.xrayQueue = new Promise((resolve2) => {
|
|
1934
|
-
release = resolve2;
|
|
1935
|
-
});
|
|
1936
|
-
await previousQueue;
|
|
1937
|
-
const recallStartedAt = Date.now();
|
|
1938
|
-
const recallSessionKey = request.sessionKey?.trim() || void 0;
|
|
1939
|
-
let xrayResponse = { snapshotFound: false };
|
|
1940
|
-
try {
|
|
1941
|
-
this.orchestrator.clearLastXraySnapshot();
|
|
1942
|
-
await this.orchestrator.recall(query, recallSessionKey, {
|
|
1943
|
-
xrayCapture: true,
|
|
1944
|
-
...requestedNamespace ? { namespace: requestedNamespace } : {},
|
|
1945
|
-
...budgetOverride !== void 0 ? { budgetCharsOverride: budgetOverride } : {},
|
|
1946
|
-
...mode !== void 0 ? { mode } : {},
|
|
1947
|
-
// When the caller supplies an authenticated principal, forward
|
|
1948
|
-
// it via the dedicated override channel so orchestrator-side
|
|
1949
|
-
// ACL decisions use the SAME principal the access-surface
|
|
1950
|
-
// pre-check above authorized. Threading an
|
|
1951
|
-
// `authenticatedPrincipal` through `sessionKey` would be wrong:
|
|
1952
|
-
// `resolvePrincipal(sessionKey)` only maps configured raw
|
|
1953
|
-
// session keys and otherwise collapses to `"default"`, which
|
|
1954
|
-
// in namespace-enabled deployments produces false denials /
|
|
1955
|
-
// wrong-scope serving despite the pre-check passing
|
|
1956
|
-
// (CLAUDE.md rule 42).
|
|
1957
|
-
...authenticatedPrincipal ? { principalOverride: authenticatedPrincipal } : {},
|
|
1958
|
-
...request.currentContextScopes !== void 0 ? { currentContextScopes: request.currentContextScopes } : {}
|
|
1959
|
-
});
|
|
1960
|
-
const rawSnapshot = this.orchestrator.getLastXraySnapshot();
|
|
1961
|
-
const namespaceMismatch = requestedNamespace !== void 0 && rawSnapshot?.namespace !== requestedNamespace;
|
|
1962
|
-
if (!rawSnapshot) {
|
|
1963
|
-
xrayResponse = { snapshotFound: false };
|
|
1964
|
-
} else if (namespaceMismatch) {
|
|
1965
|
-
xrayResponse = { snapshotFound: false };
|
|
1966
|
-
} else {
|
|
1967
|
-
let snapshot = rawSnapshot;
|
|
1968
|
-
const xrayFilterTags = normalizeTags(request.tags);
|
|
1969
|
-
let xrayTagMatch;
|
|
1970
|
-
try {
|
|
1971
|
-
xrayTagMatch = parseTagMatch(request.tagMatch);
|
|
1972
|
-
} catch (err) {
|
|
1973
|
-
throw new EngramAccessInputError(
|
|
1974
|
-
err instanceof Error ? err.message : String(err)
|
|
1975
|
-
);
|
|
1976
|
-
}
|
|
1977
|
-
if (xrayFilterTags && xrayFilterTags.length > 0) {
|
|
1978
|
-
const namespace = snapshot.namespace ? this.resolveNamespace(snapshot.namespace) : this.orchestrator.config.defaultNamespace;
|
|
1979
|
-
const tagsByIndex = await Promise.all(
|
|
1980
|
-
snapshot.results.map(async (result) => {
|
|
1981
|
-
try {
|
|
1982
|
-
const storage = await this.orchestrator.getStorage(namespace);
|
|
1983
|
-
const memory = await storage.readMemoryByPath(result.path);
|
|
1984
|
-
const t = memory?.frontmatter?.tags;
|
|
1985
|
-
return Array.isArray(t) ? normalizeProjectionTags(t) : [];
|
|
1986
|
-
} catch {
|
|
1987
|
-
return [];
|
|
1988
|
-
}
|
|
1989
|
-
})
|
|
1990
|
-
);
|
|
1991
|
-
const tagged = snapshot.results.map((result, index) => ({
|
|
1992
|
-
result,
|
|
1993
|
-
tags: tagsByIndex[index] ?? []
|
|
1994
|
-
}));
|
|
1995
|
-
const { results: admittedTagged, trace } = applyTagFilter(tagged, {
|
|
1996
|
-
tags: xrayFilterTags,
|
|
1997
|
-
tagMatch: xrayTagMatch
|
|
1998
|
-
});
|
|
1999
|
-
const admittedResults = admittedTagged.map((entry) => entry.result);
|
|
2000
|
-
const filters = trace ? [...snapshot.filters, trace] : snapshot.filters;
|
|
2001
|
-
snapshot = { ...snapshot, results: admittedResults, filters };
|
|
2002
|
-
}
|
|
2003
|
-
if (request.disclosure !== void 0) {
|
|
2004
|
-
const disclosure2 = request.disclosure;
|
|
2005
|
-
const namespace = snapshot.namespace ? this.resolveNamespace(snapshot.namespace) : this.orchestrator.config.defaultNamespace;
|
|
2006
|
-
const trimmedSessionKey = request.sessionKey?.trim() || void 0;
|
|
2007
|
-
const rawExcerpts = disclosure2 === "raw" ? await this.fetchRawExcerpts(disclosure2, {
|
|
2008
|
-
query,
|
|
2009
|
-
...trimmedSessionKey ? { sessionKey: trimmedSessionKey } : {},
|
|
2010
|
-
namespace
|
|
2011
|
-
}) : null;
|
|
2012
|
-
const rawExcerptText = rawExcerpts && rawExcerpts.length > 0 ? rawExcerpts.map((e) => e.content).join("\n") : "";
|
|
2013
|
-
const memoryByIndex = await Promise.all(
|
|
2014
|
-
snapshot.results.map(async (result) => {
|
|
2015
|
-
try {
|
|
2016
|
-
const storage = await this.orchestrator.getStorage(namespace);
|
|
2017
|
-
return await storage.readMemoryByPath(result.path);
|
|
2018
|
-
} catch {
|
|
2019
|
-
return null;
|
|
2020
|
-
}
|
|
2021
|
-
})
|
|
2022
|
-
);
|
|
2023
|
-
const firstReadableIndex = memoryByIndex.findIndex((m) => m !== null);
|
|
2024
|
-
const baseDir = (await this.orchestrator.getStorage(namespace)).dir;
|
|
2025
|
-
const decorated = snapshot.results.map((result, index) => {
|
|
2026
|
-
const memory = memoryByIndex[index];
|
|
2027
|
-
if (!memory) {
|
|
2028
|
-
return { ...result, disclosure: disclosure2 };
|
|
2029
|
-
}
|
|
2030
|
-
const shaped = shapeMemorySummary(
|
|
2031
|
-
memory,
|
|
2032
|
-
baseDir,
|
|
2033
|
-
disclosure2,
|
|
2034
|
-
disclosure2 === "raw" && index === firstReadableIndex && rawExcerpts && rawExcerpts.length > 0 ? rawExcerpts : void 0
|
|
2035
|
-
);
|
|
2036
|
-
return {
|
|
2037
|
-
...result,
|
|
2038
|
-
disclosure: disclosure2,
|
|
2039
|
-
estimatedTokens: estimateRecallTokens(JSON.stringify(shaped))
|
|
2040
|
-
};
|
|
2041
|
-
});
|
|
2042
|
-
if (disclosure2 === "raw" && firstReadableIndex === -1 && rawExcerptText.length > 0 && decorated.length > 0) {
|
|
2043
|
-
decorated[0] = {
|
|
2044
|
-
...decorated[0],
|
|
2045
|
-
disclosure: disclosure2,
|
|
2046
|
-
estimatedTokens: estimateRecallTokens(rawExcerptText)
|
|
2047
|
-
};
|
|
2048
|
-
}
|
|
2049
|
-
const decoratedSnapshot = { ...snapshot, results: decorated };
|
|
2050
|
-
xrayResponse = {
|
|
2051
|
-
snapshotFound: true,
|
|
2052
|
-
snapshot: decoratedSnapshot
|
|
2053
|
-
};
|
|
2054
|
-
} else {
|
|
2055
|
-
xrayResponse = {
|
|
2056
|
-
snapshotFound: true,
|
|
2057
|
-
snapshot
|
|
2058
|
-
};
|
|
2059
|
-
}
|
|
2060
|
-
}
|
|
2061
|
-
} finally {
|
|
2062
|
-
release();
|
|
2063
|
-
}
|
|
2064
|
-
if (request.includeRecall === true && xrayResponse.snapshotFound === true && xrayResponse.snapshot) {
|
|
2065
|
-
return {
|
|
2066
|
-
...xrayResponse,
|
|
2067
|
-
recall: await this.buildRecallResponseFromXraySnapshot({
|
|
2068
|
-
query,
|
|
2069
|
-
sessionKey: recallSessionKey,
|
|
2070
|
-
snapshot: xrayResponse.snapshot,
|
|
2071
|
-
disclosure,
|
|
2072
|
-
startedAt: recallStartedAt,
|
|
2073
|
-
requestedMode: request.mode,
|
|
2074
|
-
normalizedMode: mode
|
|
2075
|
-
})
|
|
2076
|
-
};
|
|
2077
|
-
}
|
|
2078
|
-
return xrayResponse;
|
|
2079
|
-
}
|
|
2080
|
-
// Sequence lock for `recallXray` — see comment inside the method.
|
|
2081
|
-
// Lives on the instance so every x-ray call on the same service
|
|
2082
|
-
// shares it, and so separate services in the same process (e.g.
|
|
2083
|
-
// per-tenant) do not block each other.
|
|
2084
|
-
xrayQueue = Promise.resolve();
|
|
2085
|
-
async memoryStore(request) {
|
|
2086
|
-
const namespace = this.resolveWritableNamespace(
|
|
2087
|
-
request.namespace,
|
|
2088
|
-
request.sessionKey,
|
|
2089
|
-
request.authenticatedPrincipal
|
|
2090
|
-
);
|
|
2091
|
-
const schemaVersion = request.schemaVersion ?? ENGRAM_ACCESS_WRITE_SCHEMA_VERSION;
|
|
2092
|
-
if (schemaVersion !== ENGRAM_ACCESS_WRITE_SCHEMA_VERSION) {
|
|
2093
|
-
throw new EngramAccessInputError(`unsupported schemaVersion: ${schemaVersion}`);
|
|
2094
|
-
}
|
|
2095
|
-
const execute = async () => {
|
|
2096
|
-
const candidate = this.validateWriteCandidate(request, namespace);
|
|
2097
|
-
if (request.dryRun === true) {
|
|
2098
|
-
return {
|
|
2099
|
-
schemaVersion: ENGRAM_ACCESS_WRITE_SCHEMA_VERSION,
|
|
2100
|
-
operation: "memory_store",
|
|
2101
|
-
namespace,
|
|
2102
|
-
dryRun: true,
|
|
2103
|
-
accepted: true,
|
|
2104
|
-
queued: false,
|
|
2105
|
-
status: "validated",
|
|
2106
|
-
idempotencyKey: request.idempotencyKey?.trim() || void 0
|
|
2107
|
-
};
|
|
2108
|
-
}
|
|
2109
|
-
const result = await persistExplicitCapture(this.orchestrator, candidate, "memory_store");
|
|
2110
|
-
const response = {
|
|
2111
|
-
schemaVersion: ENGRAM_ACCESS_WRITE_SCHEMA_VERSION,
|
|
2112
|
-
operation: "memory_store",
|
|
2113
|
-
namespace,
|
|
2114
|
-
dryRun: false,
|
|
2115
|
-
accepted: true,
|
|
2116
|
-
queued: false,
|
|
2117
|
-
status: result.duplicateOf ? "duplicate" : "stored",
|
|
2118
|
-
memoryId: result.id,
|
|
2119
|
-
duplicateOf: result.duplicateOf,
|
|
2120
|
-
idempotencyKey: request.idempotencyKey?.trim() || void 0
|
|
2121
|
-
};
|
|
2122
|
-
log.info(
|
|
2123
|
-
`access-write op=memory_store namespace=${namespace} dryRun=false status=${response.status} memoryId=${response.memoryId ?? "-"} idempotency=${response.idempotencyKey ? "yes" : "no"}`
|
|
2124
|
-
);
|
|
2125
|
-
return response;
|
|
2126
|
-
};
|
|
2127
|
-
return this.handleIdempotentWrite({
|
|
2128
|
-
operation: "memory_store",
|
|
2129
|
-
idempotencyKey: request.idempotencyKey,
|
|
2130
|
-
requestFingerprint: {
|
|
2131
|
-
schemaVersion,
|
|
2132
|
-
content: request.content,
|
|
2133
|
-
category: request.category,
|
|
2134
|
-
confidence: request.confidence,
|
|
2135
|
-
namespace,
|
|
2136
|
-
tags: request.tags,
|
|
2137
|
-
entityRef: request.entityRef,
|
|
2138
|
-
ttl: request.ttl,
|
|
2139
|
-
sourceReason: request.sourceReason
|
|
2140
|
-
},
|
|
2141
|
-
skip: request.dryRun === true,
|
|
2142
|
-
execute
|
|
2143
|
-
});
|
|
2144
|
-
}
|
|
2145
|
-
async peekMemoryStoreIdempotency(request) {
|
|
2146
|
-
const namespace = this.resolveWritableNamespace(
|
|
2147
|
-
request.namespace,
|
|
2148
|
-
request.sessionKey,
|
|
2149
|
-
request.authenticatedPrincipal
|
|
2150
|
-
);
|
|
2151
|
-
const schemaVersion = request.schemaVersion ?? ENGRAM_ACCESS_WRITE_SCHEMA_VERSION;
|
|
2152
|
-
if (schemaVersion !== ENGRAM_ACCESS_WRITE_SCHEMA_VERSION) {
|
|
2153
|
-
throw new EngramAccessInputError(`unsupported schemaVersion: ${schemaVersion}`);
|
|
2154
|
-
}
|
|
2155
|
-
return this.peekIdempotentWrite({
|
|
2156
|
-
operation: "memory_store",
|
|
2157
|
-
idempotencyKey: request.idempotencyKey,
|
|
2158
|
-
requestFingerprint: {
|
|
2159
|
-
schemaVersion,
|
|
2160
|
-
content: request.content,
|
|
2161
|
-
category: request.category,
|
|
2162
|
-
confidence: request.confidence,
|
|
2163
|
-
namespace,
|
|
2164
|
-
tags: request.tags,
|
|
2165
|
-
entityRef: request.entityRef,
|
|
2166
|
-
ttl: request.ttl,
|
|
2167
|
-
sourceReason: request.sourceReason
|
|
2168
|
-
},
|
|
2169
|
-
skip: request.dryRun === true
|
|
2170
|
-
});
|
|
2171
|
-
}
|
|
2172
|
-
async suggestionSubmit(request) {
|
|
2173
|
-
const namespace = this.resolveWritableNamespace(
|
|
2174
|
-
request.namespace,
|
|
2175
|
-
request.sessionKey,
|
|
2176
|
-
request.authenticatedPrincipal
|
|
2177
|
-
);
|
|
2178
|
-
const schemaVersion = request.schemaVersion ?? ENGRAM_ACCESS_WRITE_SCHEMA_VERSION;
|
|
2179
|
-
if (schemaVersion !== ENGRAM_ACCESS_WRITE_SCHEMA_VERSION) {
|
|
2180
|
-
throw new EngramAccessInputError(`unsupported schemaVersion: ${schemaVersion}`);
|
|
2181
|
-
}
|
|
2182
|
-
const execute = async () => {
|
|
2183
|
-
const candidate = this.validateWriteCandidate(request, namespace);
|
|
2184
|
-
if (request.dryRun === true) {
|
|
2185
|
-
return {
|
|
2186
|
-
schemaVersion: ENGRAM_ACCESS_WRITE_SCHEMA_VERSION,
|
|
2187
|
-
operation: "suggestion_submit",
|
|
2188
|
-
namespace,
|
|
2189
|
-
dryRun: true,
|
|
2190
|
-
accepted: true,
|
|
2191
|
-
queued: true,
|
|
2192
|
-
status: "validated",
|
|
2193
|
-
idempotencyKey: request.idempotencyKey?.trim() || void 0
|
|
2194
|
-
};
|
|
2195
|
-
}
|
|
2196
|
-
const result = await queueExplicitCaptureForReview(
|
|
2197
|
-
this.orchestrator,
|
|
2198
|
-
candidate,
|
|
2199
|
-
"suggestion_submit",
|
|
2200
|
-
new Error(request.sourceReason?.trim() || "submitted via engram suggestion_submit")
|
|
2201
|
-
);
|
|
2202
|
-
const response = {
|
|
2203
|
-
schemaVersion: ENGRAM_ACCESS_WRITE_SCHEMA_VERSION,
|
|
2204
|
-
operation: "suggestion_submit",
|
|
2205
|
-
namespace,
|
|
2206
|
-
dryRun: false,
|
|
2207
|
-
accepted: true,
|
|
2208
|
-
queued: true,
|
|
2209
|
-
status: "queued_for_review",
|
|
2210
|
-
memoryId: result.id,
|
|
2211
|
-
duplicateOf: result.duplicateOf,
|
|
2212
|
-
idempotencyKey: request.idempotencyKey?.trim() || void 0
|
|
2213
|
-
};
|
|
2214
|
-
log.info(
|
|
2215
|
-
`access-write op=suggestion_submit namespace=${namespace} dryRun=false status=${response.status} memoryId=${response.memoryId ?? "-"} idempotency=${response.idempotencyKey ? "yes" : "no"}`
|
|
2216
|
-
);
|
|
2217
|
-
return response;
|
|
2218
|
-
};
|
|
2219
|
-
return this.handleIdempotentWrite({
|
|
2220
|
-
operation: "suggestion_submit",
|
|
2221
|
-
idempotencyKey: request.idempotencyKey,
|
|
2222
|
-
requestFingerprint: {
|
|
2223
|
-
schemaVersion,
|
|
2224
|
-
content: request.content,
|
|
2225
|
-
category: request.category,
|
|
2226
|
-
confidence: request.confidence,
|
|
2227
|
-
namespace,
|
|
2228
|
-
tags: request.tags,
|
|
2229
|
-
entityRef: request.entityRef,
|
|
2230
|
-
ttl: request.ttl,
|
|
2231
|
-
sourceReason: request.sourceReason
|
|
2232
|
-
},
|
|
2233
|
-
skip: request.dryRun === true,
|
|
2234
|
-
execute
|
|
2235
|
-
});
|
|
2236
|
-
}
|
|
2237
|
-
async peekSuggestionSubmitIdempotency(request) {
|
|
2238
|
-
const namespace = this.resolveWritableNamespace(
|
|
2239
|
-
request.namespace,
|
|
2240
|
-
request.sessionKey,
|
|
2241
|
-
request.authenticatedPrincipal
|
|
2242
|
-
);
|
|
2243
|
-
const schemaVersion = request.schemaVersion ?? ENGRAM_ACCESS_WRITE_SCHEMA_VERSION;
|
|
2244
|
-
if (schemaVersion !== ENGRAM_ACCESS_WRITE_SCHEMA_VERSION) {
|
|
2245
|
-
throw new EngramAccessInputError(`unsupported schemaVersion: ${schemaVersion}`);
|
|
2246
|
-
}
|
|
2247
|
-
return this.peekIdempotentWrite({
|
|
2248
|
-
operation: "suggestion_submit",
|
|
2249
|
-
idempotencyKey: request.idempotencyKey,
|
|
2250
|
-
requestFingerprint: {
|
|
2251
|
-
schemaVersion,
|
|
2252
|
-
content: request.content,
|
|
2253
|
-
category: request.category,
|
|
2254
|
-
confidence: request.confidence,
|
|
2255
|
-
namespace,
|
|
2256
|
-
tags: request.tags,
|
|
2257
|
-
entityRef: request.entityRef,
|
|
2258
|
-
ttl: request.ttl,
|
|
2259
|
-
sourceReason: request.sourceReason
|
|
2260
|
-
},
|
|
2261
|
-
skip: request.dryRun === true
|
|
2262
|
-
});
|
|
2263
|
-
}
|
|
2264
|
-
validateWriteCandidate(request, namespace) {
|
|
2265
|
-
try {
|
|
2266
|
-
return validateExplicitCaptureInput(
|
|
2267
|
-
{
|
|
2268
|
-
...request,
|
|
2269
|
-
namespace
|
|
2270
|
-
},
|
|
2271
|
-
"legacy_tool"
|
|
2272
|
-
);
|
|
2273
|
-
} catch (error) {
|
|
2274
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
2275
|
-
throw new EngramAccessInputError(message);
|
|
2276
|
-
}
|
|
2277
|
-
}
|
|
2278
|
-
async memoryGet(memoryId, namespace, principal) {
|
|
2279
|
-
const resolvedNamespace = this.resolveReadableNamespace(namespace, principal);
|
|
2280
|
-
const storage = await this.orchestrator.getStorage(resolvedNamespace);
|
|
2281
|
-
const memory = await storage.getMemoryById(memoryId);
|
|
2282
|
-
if (!memory) {
|
|
2283
|
-
return { found: false, namespace: resolvedNamespace };
|
|
2284
|
-
}
|
|
2285
|
-
return {
|
|
2286
|
-
found: true,
|
|
2287
|
-
namespace: resolvedNamespace,
|
|
2288
|
-
memory: this.serializeMemory(memory)
|
|
2289
|
-
};
|
|
2290
|
-
}
|
|
2291
|
-
async memoryBrowse(request = {}) {
|
|
2292
|
-
const storage = await this.orchestrator.getStorage(request.namespace);
|
|
2293
|
-
const resolvedNamespace = request.namespace?.trim() || this.orchestrator.config.defaultNamespace;
|
|
2294
|
-
const { limit, offset } = normalizePagination(request.limit, request.offset);
|
|
2295
|
-
const sort = normalizeBrowseSort(request.sort);
|
|
2296
|
-
const query = request.query?.trim().toLowerCase() ?? "";
|
|
2297
|
-
const statusFilter = request.status?.trim().toLowerCase();
|
|
2298
|
-
const categoryFilter = request.category?.trim().toLowerCase();
|
|
2299
|
-
const projected = await storage.browseProjectedMemories({
|
|
2300
|
-
query,
|
|
2301
|
-
status: statusFilter,
|
|
2302
|
-
category: categoryFilter,
|
|
2303
|
-
sort,
|
|
2304
|
-
limit,
|
|
2305
|
-
offset
|
|
2306
|
-
});
|
|
2307
|
-
if (projected) {
|
|
2308
|
-
return {
|
|
2309
|
-
namespace: resolvedNamespace,
|
|
2310
|
-
sort,
|
|
2311
|
-
total: projected.total,
|
|
2312
|
-
count: projected.memories.length,
|
|
2313
|
-
limit,
|
|
2314
|
-
offset,
|
|
2315
|
-
memories: projected.memories.map((row) => ({ ...row }))
|
|
2316
|
-
};
|
|
2317
|
-
}
|
|
2318
|
-
let memories = [...await storage.readAllMemories(), ...await storage.readArchivedMemories()];
|
|
2319
|
-
memories = memories.filter((memory) => {
|
|
2320
|
-
const status = inferMemoryStatus(memory.frontmatter, toMemoryPathRel(storage.dir, memory.path)).toLowerCase();
|
|
2321
|
-
if (statusFilter && status !== statusFilter) return false;
|
|
2322
|
-
if (categoryFilter && memory.frontmatter.category.toLowerCase() !== categoryFilter) return false;
|
|
2323
|
-
if (!query) return true;
|
|
2324
|
-
const haystack = [
|
|
2325
|
-
memory.frontmatter.id,
|
|
2326
|
-
memory.path,
|
|
2327
|
-
memory.content,
|
|
2328
|
-
memory.frontmatter.entityRef ?? "",
|
|
2329
|
-
...memory.frontmatter.tags
|
|
2330
|
-
].join("\n").toLowerCase();
|
|
2331
|
-
return haystack.includes(query);
|
|
2332
|
-
});
|
|
2333
|
-
memories.sort((left, right) => compareBrowseMemory(sort, left, right));
|
|
2334
|
-
const page = memories.slice(offset, offset + limit).map((memory) => this.serializeMemorySummary(memory, storage.dir));
|
|
2335
|
-
return {
|
|
2336
|
-
namespace: resolvedNamespace,
|
|
2337
|
-
sort,
|
|
2338
|
-
total: memories.length,
|
|
2339
|
-
count: page.length,
|
|
2340
|
-
limit,
|
|
2341
|
-
offset,
|
|
2342
|
-
memories: page
|
|
2343
|
-
};
|
|
2344
|
-
}
|
|
2345
|
-
async memoryTimeline(memoryId, namespace, limit = 200, principal) {
|
|
2346
|
-
const resolvedNamespace = this.resolveReadableNamespace(namespace, principal);
|
|
2347
|
-
const storage = await this.orchestrator.getStorage(resolvedNamespace);
|
|
2348
|
-
const timeline = await storage.getMemoryTimeline(memoryId, limit);
|
|
2349
|
-
return {
|
|
2350
|
-
found: timeline.length > 0,
|
|
2351
|
-
namespace: resolvedNamespace,
|
|
2352
|
-
count: timeline.length,
|
|
2353
|
-
timeline
|
|
2354
|
-
};
|
|
2355
|
-
}
|
|
2356
|
-
async entityList(options = {}) {
|
|
2357
|
-
const storage = await this.orchestrator.getStorage(options.namespace);
|
|
2358
|
-
const resolvedNamespace = options.namespace?.trim() || this.orchestrator.config.defaultNamespace;
|
|
2359
|
-
const { limit, offset } = normalizePagination(options.limit, options.offset);
|
|
2360
|
-
const query = options.query?.trim().toLowerCase() ?? "";
|
|
2361
|
-
const names = await storage.listEntityNames();
|
|
2362
|
-
const entities = [];
|
|
2363
|
-
for (const name of names) {
|
|
2364
|
-
const raw = await storage.readEntity(name);
|
|
2365
|
-
if (!raw) continue;
|
|
2366
|
-
const entity = parseEntityFile(raw, this.orchestrator.config.entitySchemas);
|
|
2367
|
-
if (query) {
|
|
2368
|
-
const haystack = [
|
|
2369
|
-
entity.name,
|
|
2370
|
-
entity.type,
|
|
2371
|
-
entity.synthesis || entity.summary || "",
|
|
2372
|
-
...entity.aliases,
|
|
2373
|
-
...entity.facts,
|
|
2374
|
-
...(entity.structuredSections ?? []).flatMap((section) => [section.title, ...section.facts])
|
|
2375
|
-
].join("\n").toLowerCase();
|
|
2376
|
-
if (!haystack.includes(query)) continue;
|
|
2377
|
-
}
|
|
2378
|
-
entities.push({
|
|
2379
|
-
name: entity.name,
|
|
2380
|
-
type: entity.type,
|
|
2381
|
-
updated: entity.updated,
|
|
2382
|
-
summary: entity.synthesis || entity.summary,
|
|
2383
|
-
aliases: entity.aliases
|
|
2384
|
-
});
|
|
2385
|
-
}
|
|
2386
|
-
entities.sort((left, right) => left.name.localeCompare(right.name));
|
|
2387
|
-
const page = entities.slice(offset, offset + limit);
|
|
2388
|
-
return {
|
|
2389
|
-
namespace: resolvedNamespace,
|
|
2390
|
-
total: entities.length,
|
|
2391
|
-
count: page.length,
|
|
2392
|
-
limit,
|
|
2393
|
-
offset,
|
|
2394
|
-
entities: page
|
|
2395
|
-
};
|
|
2396
|
-
}
|
|
2397
|
-
async entityGet(name, namespace) {
|
|
2398
|
-
const storage = await this.orchestrator.getStorage(namespace);
|
|
2399
|
-
const resolvedNamespace = namespace?.trim() || this.orchestrator.config.defaultNamespace;
|
|
2400
|
-
const raw = await storage.readEntity(name);
|
|
2401
|
-
if (!raw) return { found: false, namespace: resolvedNamespace };
|
|
2402
|
-
return {
|
|
2403
|
-
found: true,
|
|
2404
|
-
namespace: resolvedNamespace,
|
|
2405
|
-
entity: parseEntityFile(raw, this.orchestrator.config.entitySchemas)
|
|
2406
|
-
};
|
|
2407
|
-
}
|
|
2408
|
-
async reviewQueue(runId, namespace, principal) {
|
|
2409
|
-
const resolvedNamespace = this.resolveReadableNamespace(namespace, principal);
|
|
2410
|
-
const storage = await this.orchestrator.getStorage(resolvedNamespace);
|
|
2411
|
-
const projected = await storage.getProjectedGovernanceRecord();
|
|
2412
|
-
if (projected && (!runId || projected.runId === runId.trim())) {
|
|
2413
|
-
const projectedAppliedActions = projected.appliedActionRows.map((row) => ({
|
|
2414
|
-
action: row.action,
|
|
2415
|
-
memoryId: row.memoryId,
|
|
2416
|
-
reasonCode: row.reasonCode,
|
|
2417
|
-
beforeStatus: row.beforeStatus,
|
|
2418
|
-
afterStatus: row.afterStatus,
|
|
2419
|
-
originalPath: row.originalPath,
|
|
2420
|
-
currentPath: row.currentPath
|
|
2421
|
-
}));
|
|
2422
|
-
const projectedProposedActions = await buildProjectedGovernanceProposedActions(storage, projected);
|
|
2423
|
-
const projectedArtifact = await (async () => {
|
|
2424
|
-
try {
|
|
2425
|
-
return await readMemoryGovernanceRunArtifact(storage.dir, projected.runId);
|
|
2426
|
-
} catch {
|
|
2427
|
-
return null;
|
|
2428
|
-
}
|
|
2429
|
-
})();
|
|
2430
|
-
const metrics = projected.metrics;
|
|
2431
|
-
const fallbackTransitionReport = {
|
|
2432
|
-
proposed: groupActionsByStatus(projectedProposedActions),
|
|
2433
|
-
applied: groupActionsByStatus(projectedAppliedActions)
|
|
2434
|
-
};
|
|
2435
|
-
const transitionReport = projectedArtifact?.transitionReport ? {
|
|
2436
|
-
proposed: hasGroupedGovernanceActions(projectedArtifact.transitionReport.proposed) || projectedProposedActions.length === 0 ? projectedArtifact.transitionReport.proposed : fallbackTransitionReport.proposed,
|
|
2437
|
-
applied: hasGroupedGovernanceActions(projectedArtifact.transitionReport.applied) || projectedAppliedActions.length === 0 ? projectedArtifact.transitionReport.applied : fallbackTransitionReport.applied
|
|
2438
|
-
} : fallbackTransitionReport;
|
|
2439
|
-
const qualityScore = projectedArtifact?.qualityScore ?? metrics?.qualityScore ?? buildQualityScore(metrics?.reviewReasons ?? {
|
|
2440
|
-
exact_duplicate: 0,
|
|
2441
|
-
semantic_duplicate_candidate: 0,
|
|
2442
|
-
disputed_memory: 0,
|
|
2443
|
-
speculative_low_confidence: 0,
|
|
2444
|
-
archive_candidate: 0,
|
|
2445
|
-
explicit_capture_review: 0,
|
|
2446
|
-
malformed_import: 0
|
|
2447
|
-
});
|
|
2448
|
-
const effectiveMetrics = metrics ? { ...metrics, qualityScore: metrics.qualityScore ?? qualityScore } : metrics;
|
|
2449
|
-
return {
|
|
2450
|
-
found: true,
|
|
2451
|
-
namespace: resolvedNamespace,
|
|
2452
|
-
runId: projected.runId,
|
|
2453
|
-
summary: projected.summary,
|
|
2454
|
-
metrics: effectiveMetrics,
|
|
2455
|
-
qualityScore,
|
|
2456
|
-
reviewQueue: projected.reviewQueueRows.map((row) => ({
|
|
2457
|
-
entryId: row.entryId,
|
|
2458
|
-
memoryId: row.memoryId,
|
|
2459
|
-
path: row.path,
|
|
2460
|
-
reasonCode: row.reasonCode,
|
|
2461
|
-
severity: row.severity,
|
|
2462
|
-
suggestedAction: row.suggestedAction,
|
|
2463
|
-
suggestedStatus: row.suggestedStatus,
|
|
2464
|
-
relatedMemoryIds: row.relatedMemoryIds
|
|
2465
|
-
})),
|
|
2466
|
-
appliedActions: projectedAppliedActions,
|
|
2467
|
-
transitionReport,
|
|
2468
|
-
report: projected.report
|
|
2469
|
-
};
|
|
2470
|
-
}
|
|
2471
|
-
const resolvedRunId = runId?.trim() || (await listMemoryGovernanceRuns(storage.dir))[0];
|
|
2472
|
-
if (!resolvedRunId) return { found: false, namespace: resolvedNamespace };
|
|
2473
|
-
const artifact = await readMemoryGovernanceRunArtifact(storage.dir, resolvedRunId);
|
|
2474
|
-
return {
|
|
2475
|
-
found: true,
|
|
2476
|
-
namespace: resolvedNamespace,
|
|
2477
|
-
runId: resolvedRunId,
|
|
2478
|
-
summary: artifact.summary,
|
|
2479
|
-
metrics: artifact.metrics,
|
|
2480
|
-
qualityScore: artifact.qualityScore,
|
|
2481
|
-
reviewQueue: artifact.reviewQueue,
|
|
2482
|
-
appliedActions: artifact.appliedActions,
|
|
2483
|
-
transitionReport: artifact.transitionReport,
|
|
2484
|
-
report: artifact.report
|
|
2485
|
-
};
|
|
2486
|
-
}
|
|
2487
|
-
async maintenance(namespace, principal) {
|
|
2488
|
-
const resolvedNamespace = this.resolveReadableNamespace(namespace, principal);
|
|
2489
|
-
return {
|
|
2490
|
-
namespace: resolvedNamespace,
|
|
2491
|
-
health: await this.health(resolvedNamespace),
|
|
2492
|
-
latestGovernanceRun: await this.reviewQueue(void 0, resolvedNamespace, principal)
|
|
2493
|
-
};
|
|
2494
|
-
}
|
|
2495
|
-
async quality(namespace, principal) {
|
|
2496
|
-
const resolvedNamespace = this.resolveReadableNamespace(namespace, principal);
|
|
2497
|
-
const storage = await this.orchestrator.getStorage(resolvedNamespace);
|
|
2498
|
-
const governance = await this.reviewQueue(void 0, resolvedNamespace, principal);
|
|
2499
|
-
const nowMs = Date.now();
|
|
2500
|
-
const statusCounts = {};
|
|
2501
|
-
const categoryCounts = {};
|
|
2502
|
-
const confidenceTierCounts = {};
|
|
2503
|
-
const ageBucketCounts = {};
|
|
2504
|
-
let staleActive = 0;
|
|
2505
|
-
let lowConfidenceActive = 0;
|
|
2506
|
-
const memories = [...await storage.readAllMemories(), ...await storage.readArchivedMemories()];
|
|
2507
|
-
for (const memory of memories) {
|
|
2508
|
-
const status = inferMemoryStatus(memory.frontmatter, toMemoryPathRel(storage.dir, memory.path)).toLowerCase();
|
|
2509
|
-
const confidenceTier = memory.frontmatter.confidenceTier ?? "unknown";
|
|
2510
|
-
const ageBucket = bucketMemoryAge(memory.frontmatter.updated ?? memory.frontmatter.created, nowMs);
|
|
2511
|
-
incrementCount(statusCounts, status);
|
|
2512
|
-
incrementCount(categoryCounts, memory.frontmatter.category);
|
|
2513
|
-
incrementCount(confidenceTierCounts, confidenceTier);
|
|
2514
|
-
incrementCount(ageBucketCounts, ageBucket);
|
|
2515
|
-
if (status === "active") {
|
|
2516
|
-
if (ageBucket === "91_plus_days") staleActive += 1;
|
|
2517
|
-
if ((memory.frontmatter.confidence ?? 0) < 0.6) lowConfidenceActive += 1;
|
|
2518
|
-
}
|
|
2519
|
-
}
|
|
2520
|
-
return {
|
|
2521
|
-
namespace: resolvedNamespace,
|
|
2522
|
-
totalMemories: memories.length,
|
|
2523
|
-
statusCounts,
|
|
2524
|
-
categoryCounts,
|
|
2525
|
-
confidenceTierCounts,
|
|
2526
|
-
ageBucketCounts,
|
|
2527
|
-
archivePressure: {
|
|
2528
|
-
pendingReview: statusCounts.pending_review ?? 0,
|
|
2529
|
-
quarantined: statusCounts.quarantined ?? 0,
|
|
2530
|
-
archived: statusCounts.archived ?? 0,
|
|
2531
|
-
staleActive,
|
|
2532
|
-
lowConfidenceActive
|
|
2533
|
-
},
|
|
2534
|
-
latestGovernanceRun: {
|
|
2535
|
-
found: governance.found,
|
|
2536
|
-
runId: governance.runId,
|
|
2537
|
-
qualityScore: governance.qualityScore ?? governance.metrics?.qualityScore,
|
|
2538
|
-
reviewQueueCount: governance.reviewQueue?.length ?? 0
|
|
2539
|
-
}
|
|
2540
|
-
};
|
|
2541
|
-
}
|
|
2542
|
-
async governanceRun(request, principal) {
|
|
2543
|
-
const deepSleep = this.orchestrator.config.dreamsPhases.deepSleep;
|
|
2544
|
-
if (deepSleep.enabled === false && deepSleep.enabledExplicitlySet === true) {
|
|
2545
|
-
throw new Error("memory governance is disabled by dreams.phases.deepSleep.enabled=false");
|
|
2546
|
-
}
|
|
2547
|
-
const resolvedNamespace = this.resolveWritableNamespace(
|
|
2548
|
-
request.namespace,
|
|
2549
|
-
void 0,
|
|
2550
|
-
request.authenticatedPrincipal ?? principal
|
|
2551
|
-
);
|
|
2552
|
-
const storage = await this.orchestrator.getStorage(resolvedNamespace);
|
|
2553
|
-
const mode = request.mode === "apply" ? "apply" : "shadow";
|
|
2554
|
-
const boundedBatchSize = typeof request.batchSize === "number" && Number.isFinite(request.batchSize) ? Math.max(1, Math.floor(request.batchSize)) : void 0;
|
|
2555
|
-
const result = await runMemoryGovernance({
|
|
2556
|
-
memoryDir: storage.dir,
|
|
2557
|
-
mode,
|
|
2558
|
-
recentDays: typeof request.recentDays === "number" && Number.isFinite(request.recentDays) ? Math.max(1, Math.floor(request.recentDays)) : void 0,
|
|
2559
|
-
maxMemories: typeof request.maxMemories === "number" && Number.isFinite(request.maxMemories) ? Math.max(1, Math.floor(request.maxMemories)) : void 0,
|
|
2560
|
-
batchSize: boundedBatchSize
|
|
2561
|
-
});
|
|
2562
|
-
if (mode === "apply") {
|
|
2563
|
-
try {
|
|
2564
|
-
await this.orchestrator.processEntitySynthesisQueue(
|
|
2565
|
-
resolvedNamespace,
|
|
2566
|
-
Math.min(boundedBatchSize ?? 5, 5)
|
|
2567
|
-
);
|
|
2568
|
-
} catch (error) {
|
|
2569
|
-
log.debug(`governanceRun: entity synthesis refresh failed after governance apply: ${error}`);
|
|
2570
|
-
}
|
|
2571
|
-
}
|
|
2572
|
-
return {
|
|
2573
|
-
namespace: resolvedNamespace,
|
|
2574
|
-
runId: result.runId,
|
|
2575
|
-
traceId: result.traceId,
|
|
2576
|
-
mode: result.mode,
|
|
2577
|
-
reviewQueueCount: result.reviewQueue.length,
|
|
2578
|
-
proposedActionCount: result.proposedActions.length,
|
|
2579
|
-
appliedActionCount: result.appliedActions.length,
|
|
2580
|
-
summaryPath: result.summaryPath,
|
|
2581
|
-
reportPath: result.reportPath
|
|
2582
|
-
};
|
|
2583
|
-
}
|
|
2584
|
-
async procedureMiningRun(request, principal) {
|
|
2585
|
-
const resolvedNamespace = this.resolveWritableNamespace(
|
|
2586
|
-
request.namespace,
|
|
2587
|
-
void 0,
|
|
2588
|
-
request.authenticatedPrincipal ?? principal
|
|
2589
|
-
);
|
|
2590
|
-
const storage = await this.orchestrator.getStorage(resolvedNamespace);
|
|
2591
|
-
const result = await runProcedureMining({
|
|
2592
|
-
memoryDir: storage.dir,
|
|
2593
|
-
storage,
|
|
2594
|
-
config: this.orchestrator.config
|
|
2595
|
-
});
|
|
2596
|
-
return {
|
|
2597
|
-
namespace: resolvedNamespace,
|
|
2598
|
-
clustersProcessed: result.clustersProcessed,
|
|
2599
|
-
proceduresWritten: result.proceduresWritten,
|
|
2600
|
-
skippedReason: result.skippedReason
|
|
2601
|
-
};
|
|
2602
|
-
}
|
|
2603
|
-
async liveConnectorsRun(request = {}, principal) {
|
|
2604
|
-
this.resolveWritableNamespace(
|
|
2605
|
-
void 0,
|
|
2606
|
-
void 0,
|
|
2607
|
-
request.authenticatedPrincipal ?? principal
|
|
2608
|
-
);
|
|
2609
|
-
return this.orchestrator.runLiveConnectors({
|
|
2610
|
-
force: request.force === true
|
|
2611
|
-
});
|
|
2612
|
-
}
|
|
2613
|
-
/**
|
|
2614
|
-
* Run the pattern-reinforcement maintenance job (issue #687 PR 2/4).
|
|
2615
|
-
*
|
|
2616
|
-
* Cluster duplicate non-procedural memories and reinforce the
|
|
2617
|
-
* canonical (most-recent) member. Gated on
|
|
2618
|
-
* `patternReinforcementEnabled` — when disabled, returns
|
|
2619
|
-
* `{ ran: false, skippedReason: "disabled" }` so the cron payload
|
|
2620
|
-
* surface in CI logs cleanly.
|
|
2621
|
-
*
|
|
2622
|
-
* Resolves the namespace via the same writable path used by
|
|
2623
|
-
* `procedureMiningRun` so cross-tenant writes are impossible
|
|
2624
|
-
* (CLAUDE.md rule 42).
|
|
2625
|
-
*
|
|
2626
|
-
* Delegates the run to `orchestrator.runPatternReinforcement` so
|
|
2627
|
-
* the cadence floor (`patternReinforcementCadenceMs`) is enforced
|
|
2628
|
-
* uniformly across cron + MCP paths (PR #730 review feedback,
|
|
2629
|
-
* Codex P2). Accepts `force: true` for ad-hoc operator runs that
|
|
2630
|
-
* must bypass the cadence floor — mirrors the pattern used by
|
|
2631
|
-
* other maintenance MCP tools.
|
|
2632
|
-
*/
|
|
2633
|
-
async patternReinforcementRun(request = {}, principal) {
|
|
2634
|
-
const resolvedNamespace = this.resolveWritableNamespace(
|
|
2635
|
-
request.namespace,
|
|
2636
|
-
void 0,
|
|
2637
|
-
request.authenticatedPrincipal ?? principal
|
|
2638
|
-
);
|
|
2639
|
-
const outcome = await this.orchestrator.runPatternReinforcement({
|
|
2640
|
-
namespace: resolvedNamespace,
|
|
2641
|
-
force: request.force === true
|
|
2642
|
-
});
|
|
2643
|
-
if (!outcome.ran) {
|
|
2644
|
-
return {
|
|
2645
|
-
namespace: resolvedNamespace,
|
|
2646
|
-
ran: false,
|
|
2647
|
-
skippedReason: outcome.skippedReason,
|
|
2648
|
-
clustersFound: 0,
|
|
2649
|
-
canonicalsUpdated: 0,
|
|
2650
|
-
duplicatesSuperseded: 0
|
|
2651
|
-
};
|
|
2652
|
-
}
|
|
2653
|
-
const result = outcome.result;
|
|
2654
|
-
return {
|
|
2655
|
-
namespace: resolvedNamespace,
|
|
2656
|
-
ran: true,
|
|
2657
|
-
clustersFound: result.clustersFound,
|
|
2658
|
-
canonicalsUpdated: result.canonicalsUpdated,
|
|
2659
|
-
duplicatesSuperseded: result.duplicatesSuperseded,
|
|
2660
|
-
result
|
|
2661
|
-
};
|
|
2662
|
-
}
|
|
2663
|
-
/**
|
|
2664
|
-
* Procedural memory stats (issue #567 PR 5/5). Read-only — resolves the
|
|
2665
|
-
* namespace via the same path used by `recallExplain` / `trustZoneStatus`
|
|
2666
|
-
* so cross-tenant reads are impossible (CLAUDE.md rule 42).
|
|
2667
|
-
*/
|
|
2668
|
-
async procedureStats(request = {}, principal) {
|
|
2669
|
-
const resolvedNamespace = this.resolveReadableNamespace(
|
|
2670
|
-
request.namespace,
|
|
2671
|
-
principal
|
|
2672
|
-
);
|
|
2673
|
-
const storage = await this.orchestrator.getStorage(resolvedNamespace);
|
|
2674
|
-
const report = await computeProcedureStats({
|
|
2675
|
-
storage,
|
|
2676
|
-
config: this.orchestrator.config
|
|
2677
|
-
});
|
|
2678
|
-
return { namespace: resolvedNamespace, ...report };
|
|
2679
|
-
}
|
|
2680
|
-
async memorySummarizeHourly() {
|
|
2681
|
-
await this.orchestrator.summarizer.runHourly();
|
|
2682
|
-
return {
|
|
2683
|
-
ok: true,
|
|
2684
|
-
message: "Hourly summarization completed. Check the summaries directory for results."
|
|
2685
|
-
};
|
|
2686
|
-
}
|
|
2687
|
-
async conversationIndexUpdate(request = {}) {
|
|
2688
|
-
if (!this.orchestrator.config.conversationIndexEnabled) {
|
|
2689
|
-
return {
|
|
2690
|
-
enabled: false,
|
|
2691
|
-
sessions: 0,
|
|
2692
|
-
chunks: 0,
|
|
2693
|
-
skipped: 0,
|
|
2694
|
-
skippedSessionKeys: [],
|
|
2695
|
-
embeddedRuns: 0,
|
|
2696
|
-
reason: "disabled"
|
|
2697
|
-
};
|
|
2698
|
-
}
|
|
2699
|
-
const hours = typeof request.hours === "number" && Number.isFinite(request.hours) ? Math.max(1, Math.floor(request.hours)) : 24;
|
|
2700
|
-
let sessionKey;
|
|
2701
|
-
if (request.sessionKey !== void 0) {
|
|
2702
|
-
if (typeof request.sessionKey !== "string" || request.sessionKey.trim().length === 0) {
|
|
2703
|
-
throw new EngramAccessInputError("sessionKey must be a non-empty string when provided");
|
|
2704
|
-
}
|
|
2705
|
-
sessionKey = request.sessionKey.trim();
|
|
2706
|
-
}
|
|
2707
|
-
if (sessionKey) {
|
|
2708
|
-
const result = await this.orchestrator.updateConversationIndex(
|
|
2709
|
-
sessionKey,
|
|
2710
|
-
hours,
|
|
2711
|
-
{ embed: request.embed }
|
|
2712
|
-
);
|
|
2713
|
-
return {
|
|
2714
|
-
enabled: true,
|
|
2715
|
-
sessionKey,
|
|
2716
|
-
sessions: 1,
|
|
2717
|
-
chunks: result.chunks,
|
|
2718
|
-
skipped: result.skipped ? 1 : 0,
|
|
2719
|
-
skippedSessionKeys: result.skipped ? [sessionKey] : [],
|
|
2720
|
-
embeddedRuns: result.embedded ? 1 : 0,
|
|
2721
|
-
reason: result.reason,
|
|
2722
|
-
retryAfterMs: result.retryAfterMs
|
|
2723
|
-
};
|
|
2724
|
-
}
|
|
2725
|
-
const sessionKeys = await this.orchestrator.transcript.listSessionKeys();
|
|
2726
|
-
let chunks = 0;
|
|
2727
|
-
let skipped = 0;
|
|
2728
|
-
const skippedSessionKeys = [];
|
|
2729
|
-
let embeddedRuns = 0;
|
|
2730
|
-
for (const sessionKey2 of sessionKeys) {
|
|
2731
|
-
const result = await this.orchestrator.updateConversationIndex(
|
|
2732
|
-
sessionKey2,
|
|
2733
|
-
hours,
|
|
2734
|
-
{ embed: request.embed }
|
|
2735
|
-
);
|
|
2736
|
-
chunks += result.chunks;
|
|
2737
|
-
if (result.skipped) {
|
|
2738
|
-
skipped += 1;
|
|
2739
|
-
skippedSessionKeys.push(sessionKey2);
|
|
2740
|
-
}
|
|
2741
|
-
if (result.embedded) {
|
|
2742
|
-
embeddedRuns += 1;
|
|
2743
|
-
}
|
|
2744
|
-
}
|
|
2745
|
-
return {
|
|
2746
|
-
enabled: true,
|
|
2747
|
-
sessions: sessionKeys.length,
|
|
2748
|
-
chunks,
|
|
2749
|
-
skipped,
|
|
2750
|
-
skippedSessionKeys,
|
|
2751
|
-
embeddedRuns
|
|
2752
|
-
};
|
|
2753
|
-
}
|
|
2754
|
-
async profilingReport(request = {}) {
|
|
2755
|
-
const profiler = this.orchestrator.profiler;
|
|
2756
|
-
if (!profiler.isEnabled) {
|
|
2757
|
-
return {
|
|
2758
|
-
enabled: false,
|
|
2759
|
-
reason: "disabled",
|
|
2760
|
-
message: "Profiling is disabled. Set profilingEnabled: true in your plugin config to enable."
|
|
2761
|
-
};
|
|
2762
|
-
}
|
|
2763
|
-
const format = request.format ?? "ascii";
|
|
2764
|
-
if (format !== "ascii" && format !== "json") {
|
|
2765
|
-
throw new EngramAccessInputError("format must be one of: ascii, json");
|
|
2766
|
-
}
|
|
2767
|
-
const limit = request.limit ?? 5;
|
|
2768
|
-
if (!Number.isInteger(limit) || limit < 1 || limit > 20) {
|
|
2769
|
-
throw new EngramAccessInputError("limit must be an integer between 1 and 20");
|
|
2770
|
-
}
|
|
2771
|
-
const traces = profiler.getRecentTraces(limit);
|
|
2772
|
-
const stats = profiler.getStats();
|
|
2773
|
-
const bottleneck = profiler.identifyBottleneck();
|
|
2774
|
-
if (format === "json") {
|
|
2775
|
-
return {
|
|
2776
|
-
enabled: true,
|
|
2777
|
-
format,
|
|
2778
|
-
traces,
|
|
2779
|
-
stats,
|
|
2780
|
-
bottleneck
|
|
2781
|
-
};
|
|
2782
|
-
}
|
|
2783
|
-
const lines = [];
|
|
2784
|
-
lines.push("Engram Profiling Report");
|
|
2785
|
-
lines.push("=".repeat(60));
|
|
2786
|
-
lines.push("");
|
|
2787
|
-
const allBuckets = [
|
|
2788
|
-
["byKind", stats.byKind],
|
|
2789
|
-
["bySpan", stats.bySpan]
|
|
2790
|
-
];
|
|
2791
|
-
const hasStats = allBuckets.some(([, entries]) => Object.keys(entries).length > 0);
|
|
2792
|
-
if (hasStats) {
|
|
2793
|
-
lines.push("Aggregate Stats (all retained traces):");
|
|
2794
|
-
for (const [bucket, entries] of allBuckets) {
|
|
2795
|
-
for (const [key, summary] of Object.entries(entries)) {
|
|
2796
|
-
lines.push(
|
|
2797
|
-
` ${bucket}/${key}: avg=${summary.avgMs}ms p50=${summary.p50Ms}ms p95=${summary.p95Ms}ms max=${summary.maxMs}ms (n=${summary.count})`
|
|
2798
|
-
);
|
|
2799
|
-
}
|
|
2800
|
-
}
|
|
2801
|
-
lines.push("");
|
|
2802
|
-
}
|
|
2803
|
-
if (bottleneck) {
|
|
2804
|
-
lines.push(`Bottleneck: ${bottleneck}`);
|
|
2805
|
-
lines.push("");
|
|
2806
|
-
}
|
|
2807
|
-
if (traces.length === 0) {
|
|
2808
|
-
lines.push("No traces recorded yet. Trigger a recall or extraction to see timing data.");
|
|
2809
|
-
} else {
|
|
2810
|
-
for (const trace of traces) {
|
|
2811
|
-
lines.push(formatProfileTraceAscii(trace));
|
|
2812
|
-
lines.push("");
|
|
2813
|
-
}
|
|
2814
|
-
}
|
|
2815
|
-
return {
|
|
2816
|
-
enabled: true,
|
|
2817
|
-
format,
|
|
2818
|
-
report: lines.join("\n")
|
|
2819
|
-
};
|
|
2820
|
-
}
|
|
2821
|
-
async trustZoneStatus(namespace, principal) {
|
|
2822
|
-
const resolvedNamespace = this.resolveReadableNamespace(namespace, principal);
|
|
2823
|
-
const storage = await this.orchestrator.getStorage(resolvedNamespace);
|
|
2824
|
-
return {
|
|
2825
|
-
namespace: resolvedNamespace,
|
|
2826
|
-
status: await getTrustZoneStoreStatus({
|
|
2827
|
-
memoryDir: storage.dir,
|
|
2828
|
-
trustZoneStoreDir: this.orchestrator.config.trustZoneStoreDir,
|
|
2829
|
-
enabled: this.orchestrator.config.trustZonesEnabled === true,
|
|
2830
|
-
promotionEnabled: this.orchestrator.config.quarantinePromotionEnabled === true,
|
|
2831
|
-
poisoningDefenseEnabled: this.orchestrator.config.memoryPoisoningDefenseEnabled === true
|
|
2832
|
-
})
|
|
2833
|
-
};
|
|
2834
|
-
}
|
|
2835
|
-
async trustZoneBrowse(request, principal) {
|
|
2836
|
-
const resolvedNamespace = this.resolveReadableNamespace(request.namespace, principal);
|
|
2837
|
-
const storage = await this.orchestrator.getStorage(resolvedNamespace);
|
|
2838
|
-
const result = await listTrustZoneRecords({
|
|
2839
|
-
memoryDir: storage.dir,
|
|
2840
|
-
trustZoneStoreDir: this.orchestrator.config.trustZoneStoreDir,
|
|
2841
|
-
query: request.query,
|
|
2842
|
-
zone: request.zone,
|
|
2843
|
-
kind: request.kind,
|
|
2844
|
-
sourceClass: request.sourceClass,
|
|
2845
|
-
limit: request.limit,
|
|
2846
|
-
offset: request.offset
|
|
2847
|
-
});
|
|
2848
|
-
return {
|
|
2849
|
-
namespace: resolvedNamespace,
|
|
2850
|
-
total: result.total,
|
|
2851
|
-
count: result.count,
|
|
2852
|
-
limit: result.limit,
|
|
2853
|
-
offset: result.offset,
|
|
2854
|
-
records: result.records.map((entry) => summarizeTrustZoneRecord(
|
|
2855
|
-
entry.record,
|
|
2856
|
-
entry.filePath,
|
|
2857
|
-
result.allRecords,
|
|
2858
|
-
this.orchestrator.config.memoryPoisoningDefenseEnabled === true,
|
|
2859
|
-
this.orchestrator.config.trustZonesEnabled === true,
|
|
2860
|
-
this.orchestrator.config.quarantinePromotionEnabled === true
|
|
2861
|
-
))
|
|
2862
|
-
};
|
|
2863
|
-
}
|
|
2864
|
-
async trustZonePromote(request) {
|
|
2865
|
-
if (!isTrustZoneName(request.targetZone)) {
|
|
2866
|
-
throw new EngramAccessInputError(`unsupported trust-zone target: ${String(request.targetZone)}`);
|
|
2867
|
-
}
|
|
2868
|
-
const resolvedNamespace = this.resolveWritableNamespace(
|
|
2869
|
-
request.namespace,
|
|
2870
|
-
void 0,
|
|
2871
|
-
request.authenticatedPrincipal
|
|
2872
|
-
);
|
|
2873
|
-
const storage = await this.orchestrator.getStorage(resolvedNamespace);
|
|
2874
|
-
let result;
|
|
2875
|
-
try {
|
|
2876
|
-
result = await promoteTrustZoneRecord({
|
|
2877
|
-
memoryDir: storage.dir,
|
|
2878
|
-
trustZoneStoreDir: this.orchestrator.config.trustZoneStoreDir,
|
|
2879
|
-
enabled: this.orchestrator.config.trustZonesEnabled === true,
|
|
2880
|
-
promotionEnabled: this.orchestrator.config.quarantinePromotionEnabled === true,
|
|
2881
|
-
poisoningDefenseEnabled: this.orchestrator.config.memoryPoisoningDefenseEnabled === true,
|
|
2882
|
-
sourceRecordId: request.recordId,
|
|
2883
|
-
targetZone: request.targetZone,
|
|
2884
|
-
recordedAt: request.recordedAt ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
2885
|
-
promotionReason: request.promotionReason,
|
|
2886
|
-
summary: request.summary,
|
|
2887
|
-
dryRun: request.dryRun === true
|
|
2888
|
-
});
|
|
2889
|
-
} catch (error) {
|
|
2890
|
-
throw normalizeTrustZoneInputError(error) ?? error;
|
|
2891
|
-
}
|
|
2892
|
-
return {
|
|
2893
|
-
namespace: resolvedNamespace,
|
|
2894
|
-
...result,
|
|
2895
|
-
dryRun: request.dryRun === true
|
|
2896
|
-
};
|
|
2897
|
-
}
|
|
2898
|
-
async trustZoneDemoSeed(request) {
|
|
2899
|
-
const resolvedNamespace = this.resolveWritableNamespace(
|
|
2900
|
-
request.namespace,
|
|
2901
|
-
void 0,
|
|
2902
|
-
request.authenticatedPrincipal
|
|
2903
|
-
);
|
|
2904
|
-
const storage = await this.orchestrator.getStorage(resolvedNamespace);
|
|
2905
|
-
let result;
|
|
2906
|
-
try {
|
|
2907
|
-
result = await seedTrustZoneDemoDataset({
|
|
2908
|
-
memoryDir: storage.dir,
|
|
2909
|
-
trustZoneStoreDir: this.orchestrator.config.trustZoneStoreDir,
|
|
2910
|
-
enabled: this.orchestrator.config.trustZonesEnabled === true,
|
|
2911
|
-
scenario: request.scenario,
|
|
2912
|
-
recordedAt: request.recordedAt,
|
|
2913
|
-
dryRun: request.dryRun === true
|
|
2914
|
-
});
|
|
2915
|
-
} catch (error) {
|
|
2916
|
-
throw normalizeTrustZoneInputError(error) ?? error;
|
|
2917
|
-
}
|
|
2918
|
-
return {
|
|
2919
|
-
namespace: resolvedNamespace,
|
|
2920
|
-
...result
|
|
2921
|
-
};
|
|
2922
|
-
}
|
|
2923
|
-
async reviewDisposition(request) {
|
|
2924
|
-
const memoryId = request.memoryId.trim();
|
|
2925
|
-
const reasonCode = request.reasonCode.trim();
|
|
2926
|
-
if (memoryId.length === 0) {
|
|
2927
|
-
throw new EngramAccessInputError("memoryId is required");
|
|
2928
|
-
}
|
|
2929
|
-
if (reasonCode.length === 0) {
|
|
2930
|
-
throw new EngramAccessInputError("reasonCode is required");
|
|
2931
|
-
}
|
|
2932
|
-
const resolvedNamespace = this.resolveWritableNamespace(
|
|
2933
|
-
request.namespace,
|
|
2934
|
-
void 0,
|
|
2935
|
-
request.authenticatedPrincipal
|
|
2936
|
-
);
|
|
2937
|
-
const storage = await this.orchestrator.getStorage(resolvedNamespace);
|
|
2938
|
-
const memory = await storage.getMemoryById(memoryId);
|
|
2939
|
-
if (!memory) {
|
|
2940
|
-
throw new EngramAccessInputError(`memory not found: ${memoryId}`);
|
|
2941
|
-
}
|
|
2942
|
-
const previousStatus = memory.frontmatter.status ?? "active";
|
|
2943
|
-
const updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
2944
|
-
const lifecycle = {
|
|
2945
|
-
actor: "admin-console.review-disposition",
|
|
2946
|
-
reasonCode,
|
|
2947
|
-
ruleVersion: "memory-governance.v1"
|
|
2948
|
-
};
|
|
2949
|
-
if (request.status === "archived") {
|
|
2950
|
-
const archivedPath = await storage.archiveMemory(memory, {
|
|
2951
|
-
at: new Date(updatedAt),
|
|
2952
|
-
...lifecycle
|
|
2953
|
-
});
|
|
2954
|
-
if (!archivedPath) {
|
|
2955
|
-
throw new Error(`failed to archive memory disposition: ${memoryId}`);
|
|
2956
|
-
}
|
|
2957
|
-
return {
|
|
2958
|
-
ok: true,
|
|
2959
|
-
namespace: resolvedNamespace,
|
|
2960
|
-
memoryId,
|
|
2961
|
-
status: "archived",
|
|
2962
|
-
previousStatus,
|
|
2963
|
-
currentPath: archivedPath
|
|
2964
|
-
};
|
|
2965
|
-
}
|
|
2966
|
-
const updated = await storage.writeMemoryFrontmatter(memory, {
|
|
2967
|
-
status: request.status,
|
|
2968
|
-
updated: updatedAt
|
|
2969
|
-
}, lifecycle);
|
|
2970
|
-
if (!updated) {
|
|
2971
|
-
throw new Error(`failed to update memory disposition: ${memoryId}`);
|
|
2972
|
-
}
|
|
2973
|
-
return {
|
|
2974
|
-
ok: true,
|
|
2975
|
-
namespace: resolvedNamespace,
|
|
2976
|
-
memoryId,
|
|
2977
|
-
status: request.status,
|
|
2978
|
-
previousStatus,
|
|
2979
|
-
currentPath: memory.path
|
|
2980
|
-
};
|
|
2981
|
-
}
|
|
2982
|
-
serializeMemory(memory) {
|
|
2983
|
-
return {
|
|
2984
|
-
id: memory.frontmatter.id,
|
|
2985
|
-
path: memory.path,
|
|
2986
|
-
category: memory.frontmatter.category,
|
|
2987
|
-
status: memory.frontmatter.status,
|
|
2988
|
-
created: memory.frontmatter.created,
|
|
2989
|
-
updated: memory.frontmatter.updated,
|
|
2990
|
-
content: memory.content,
|
|
2991
|
-
frontmatter: memory.frontmatter
|
|
2992
|
-
};
|
|
2993
|
-
}
|
|
2994
|
-
serializeMemorySummary(memory, baseDir, disclosure, rawExcerpts) {
|
|
2995
|
-
return shapeMemorySummary(memory, baseDir, disclosure, rawExcerpts);
|
|
2996
|
-
}
|
|
2997
|
-
async observe(request) {
|
|
2998
|
-
if (!request.sessionKey || typeof request.sessionKey !== "string" || request.sessionKey.trim().length === 0) {
|
|
2999
|
-
throw new EngramAccessInputError("sessionKey is required and must be a non-empty string");
|
|
3000
|
-
}
|
|
3001
|
-
if (!Array.isArray(request.messages) || request.messages.length === 0) {
|
|
3002
|
-
throw new EngramAccessInputError("messages is required and must be a non-empty array");
|
|
3003
|
-
}
|
|
3004
|
-
for (const msg of request.messages) {
|
|
3005
|
-
if (!msg || typeof msg !== "object" || typeof msg.role !== "string" || typeof msg.content !== "string") {
|
|
3006
|
-
throw new EngramAccessInputError("each message must have a string 'role' and 'content'");
|
|
3007
|
-
}
|
|
3008
|
-
if (msg.role !== "user" && msg.role !== "assistant") {
|
|
3009
|
-
throw new EngramAccessInputError(`invalid message role: ${msg.role} (expected 'user' or 'assistant')`);
|
|
3010
|
-
}
|
|
3011
|
-
}
|
|
3012
|
-
const hasExplicitNamespace = typeof request.namespace === "string" && request.namespace.trim().length > 0;
|
|
3013
|
-
const principal = this.resolveRequestPrincipal(
|
|
3014
|
-
request.sessionKey,
|
|
3015
|
-
request.authenticatedPrincipal
|
|
3016
|
-
);
|
|
3017
|
-
const namespace = this.resolveWritableNamespace(
|
|
3018
|
-
request.namespace,
|
|
3019
|
-
request.sessionKey,
|
|
3020
|
-
request.authenticatedPrincipal
|
|
3021
|
-
);
|
|
3022
|
-
const shouldWriteObjectiveState = this.orchestrator.config.objectiveStateMemoryEnabled === true && this.orchestrator.config.objectiveStateSnapshotWritesEnabled === true;
|
|
3023
|
-
const objectiveStateBaseNamespace = hasExplicitNamespace ? namespace : defaultNamespaceForPrincipal(principal, this.orchestrator.config);
|
|
3024
|
-
if (shouldWriteObjectiveState && !hasExplicitNamespace && !canWriteNamespace(
|
|
3025
|
-
principal,
|
|
3026
|
-
objectiveStateBaseNamespace,
|
|
3027
|
-
this.orchestrator.config
|
|
3028
|
-
)) {
|
|
3029
|
-
throw new EngramAccessInputError(
|
|
3030
|
-
`namespace is not writable: ${objectiveStateBaseNamespace}`
|
|
3031
|
-
);
|
|
3032
|
-
}
|
|
3033
|
-
await this.maybeAttachCodingContext(request.sessionKey, {
|
|
3034
|
-
cwd: request.cwd,
|
|
3035
|
-
projectTag: request.projectTag
|
|
3036
|
-
});
|
|
3037
|
-
const objectiveStateNamespace = hasExplicitNamespace ? namespace : this.orchestrator.applyCodingNamespaceOverlay(
|
|
3038
|
-
request.sessionKey,
|
|
3039
|
-
objectiveStateBaseNamespace
|
|
3040
|
-
);
|
|
3041
|
-
const lcmSessionKey = namespace !== this.orchestrator.config.defaultNamespace ? `${namespace}:${request.sessionKey}` : request.sessionKey;
|
|
3042
|
-
if (shouldWriteObjectiveState) {
|
|
3043
|
-
try {
|
|
3044
|
-
const objectiveStateLocation = await this.objectiveStateStoreLocationForNamespace(
|
|
3045
|
-
objectiveStateNamespace
|
|
3046
|
-
);
|
|
3047
|
-
await recordObjectiveStateSnapshotsFromObservedMessages({
|
|
3048
|
-
memoryDir: objectiveStateLocation.memoryDir,
|
|
3049
|
-
objectiveStateStoreDir: objectiveStateLocation.objectiveStateStoreDir,
|
|
3050
|
-
objectiveStateMemoryEnabled: this.orchestrator.config.objectiveStateMemoryEnabled,
|
|
3051
|
-
objectiveStateSnapshotWritesEnabled: this.orchestrator.config.objectiveStateSnapshotWritesEnabled,
|
|
3052
|
-
sessionKey: request.sessionKey,
|
|
3053
|
-
recordedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3054
|
-
messages: request.messages
|
|
3055
|
-
});
|
|
3056
|
-
} catch (err) {
|
|
3057
|
-
log.error(`access-observe objective-state snapshot write failed: ${err}`);
|
|
3058
|
-
}
|
|
3059
|
-
}
|
|
3060
|
-
let lcmArchived = false;
|
|
3061
|
-
if (this.orchestrator.lcmEngine && this.orchestrator.lcmEngine.enabled) {
|
|
3062
|
-
try {
|
|
3063
|
-
this.orchestrator.lcmEngine.enqueueObserveMessages(lcmSessionKey, request.messages);
|
|
3064
|
-
lcmArchived = true;
|
|
3065
|
-
} catch (err) {
|
|
3066
|
-
log.error(`access-observe LCM enqueue failed: ${err}`);
|
|
3067
|
-
}
|
|
3068
|
-
}
|
|
3069
|
-
let extractionQueued = false;
|
|
3070
|
-
if (request.skipExtraction !== true) {
|
|
3071
|
-
const turns = request.messages.map((m) => ({
|
|
3072
|
-
source: "openclaw",
|
|
3073
|
-
sessionKey: lcmSessionKey,
|
|
3074
|
-
role: m.role,
|
|
3075
|
-
content: m.content,
|
|
3076
|
-
parts: m.parts,
|
|
3077
|
-
rawContent: m.rawContent,
|
|
3078
|
-
sourceFormat: m.sourceFormat,
|
|
3079
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
3080
|
-
}));
|
|
3081
|
-
try {
|
|
3082
|
-
const extractionPromise = this.orchestrator.ingestReplayBatch(turns, {
|
|
3083
|
-
archiveLcm: false
|
|
3084
|
-
});
|
|
3085
|
-
extractionPromise.catch((err) => {
|
|
3086
|
-
log.error(`access-observe background extraction failed: ${err}`);
|
|
3087
|
-
});
|
|
3088
|
-
extractionQueued = true;
|
|
3089
|
-
} catch (err) {
|
|
3090
|
-
log.error(`access-observe extraction enqueue failed: ${err}`);
|
|
3091
|
-
}
|
|
3092
|
-
}
|
|
3093
|
-
log.info(
|
|
3094
|
-
`access-observe namespace=${namespace} sessionKey=${request.sessionKey} messages=${request.messages.length} lcm=${lcmArchived} extraction=${extractionQueued}`
|
|
3095
|
-
);
|
|
3096
|
-
return {
|
|
3097
|
-
accepted: request.messages.length,
|
|
3098
|
-
sessionKey: request.sessionKey,
|
|
3099
|
-
namespace,
|
|
3100
|
-
lcmArchived,
|
|
3101
|
-
extractionQueued
|
|
3102
|
-
};
|
|
3103
|
-
}
|
|
3104
|
-
async lcmSearch(request) {
|
|
3105
|
-
if (!request.query || typeof request.query !== "string" || request.query.trim().length === 0) {
|
|
3106
|
-
throw new EngramAccessInputError("query is required and must be a non-empty string");
|
|
3107
|
-
}
|
|
3108
|
-
const principal = this.resolveRequestPrincipal(request.sessionKey, request.authenticatedPrincipal);
|
|
3109
|
-
const namespace = this.resolveReadableNamespace(request.namespace, principal);
|
|
3110
|
-
if (!this.orchestrator.lcmEngine || !this.orchestrator.lcmEngine.enabled) {
|
|
3111
|
-
return {
|
|
3112
|
-
query: request.query,
|
|
3113
|
-
namespace,
|
|
3114
|
-
results: [],
|
|
3115
|
-
count: 0,
|
|
3116
|
-
lcmEnabled: false
|
|
3117
|
-
};
|
|
3118
|
-
}
|
|
3119
|
-
const limit = Math.max(1, Math.min(request.limit ?? 10, 100));
|
|
3120
|
-
const lcmSessionKey = request.sessionKey && namespace !== this.orchestrator.config.defaultNamespace ? `${namespace}:${request.sessionKey}` : request.sessionKey;
|
|
3121
|
-
const rawResults = await this.orchestrator.lcmEngine.searchContextFull(
|
|
3122
|
-
request.query,
|
|
3123
|
-
limit,
|
|
3124
|
-
lcmSessionKey
|
|
3125
|
-
);
|
|
3126
|
-
const results = rawResults.map((r) => ({
|
|
3127
|
-
sessionId: r.session_id,
|
|
3128
|
-
content: r.content,
|
|
3129
|
-
turnIndex: r.turn_index
|
|
3130
|
-
}));
|
|
3131
|
-
return {
|
|
3132
|
-
query: request.query,
|
|
3133
|
-
namespace,
|
|
3134
|
-
results,
|
|
3135
|
-
count: results.length,
|
|
3136
|
-
lcmEnabled: true
|
|
3137
|
-
};
|
|
3138
|
-
}
|
|
3139
|
-
async lcmCompactionFlush(request) {
|
|
3140
|
-
if (!request.sessionKey || typeof request.sessionKey !== "string" || request.sessionKey.trim().length === 0) {
|
|
3141
|
-
throw new EngramAccessInputError("sessionKey is required and must be a non-empty string");
|
|
3142
|
-
}
|
|
3143
|
-
const namespace = this.resolveWritableNamespace(
|
|
3144
|
-
request.namespace,
|
|
3145
|
-
request.sessionKey,
|
|
3146
|
-
request.authenticatedPrincipal
|
|
3147
|
-
);
|
|
3148
|
-
if (!this.orchestrator.lcmEngine || !this.orchestrator.lcmEngine.enabled) {
|
|
3149
|
-
return {
|
|
3150
|
-
enabled: false,
|
|
3151
|
-
flushed: false,
|
|
3152
|
-
sessionKey: request.sessionKey,
|
|
3153
|
-
namespace,
|
|
3154
|
-
reason: "LCM is disabled"
|
|
3155
|
-
};
|
|
3156
|
-
}
|
|
3157
|
-
const lcmSessionKey = namespace !== this.orchestrator.config.defaultNamespace ? `${namespace}:${request.sessionKey}` : request.sessionKey;
|
|
3158
|
-
await this.orchestrator.lcmEngine.waitForSessionObserveIdle(lcmSessionKey);
|
|
3159
|
-
await this.orchestrator.lcmEngine.preCompactionFlush(lcmSessionKey);
|
|
3160
|
-
return {
|
|
3161
|
-
enabled: true,
|
|
3162
|
-
flushed: true,
|
|
3163
|
-
sessionKey: request.sessionKey,
|
|
3164
|
-
namespace
|
|
3165
|
-
};
|
|
3166
|
-
}
|
|
3167
|
-
async lcmCompactionRecord(request) {
|
|
3168
|
-
if (!request.sessionKey || typeof request.sessionKey !== "string" || request.sessionKey.trim().length === 0) {
|
|
3169
|
-
throw new EngramAccessInputError("sessionKey is required and must be a non-empty string");
|
|
3170
|
-
}
|
|
3171
|
-
if (!Number.isInteger(request.tokensBefore) || request.tokensBefore < 0) {
|
|
3172
|
-
throw new EngramAccessInputError("tokensBefore must be a non-negative integer");
|
|
3173
|
-
}
|
|
3174
|
-
if (!Number.isInteger(request.tokensAfter) || request.tokensAfter < 0) {
|
|
3175
|
-
throw new EngramAccessInputError("tokensAfter must be a non-negative integer");
|
|
3176
|
-
}
|
|
3177
|
-
const namespace = this.resolveWritableNamespace(
|
|
3178
|
-
request.namespace,
|
|
3179
|
-
request.sessionKey,
|
|
3180
|
-
request.authenticatedPrincipal
|
|
3181
|
-
);
|
|
3182
|
-
if (!this.orchestrator.lcmEngine || !this.orchestrator.lcmEngine.enabled) {
|
|
3183
|
-
return {
|
|
3184
|
-
enabled: false,
|
|
3185
|
-
recorded: false,
|
|
3186
|
-
sessionKey: request.sessionKey,
|
|
3187
|
-
namespace,
|
|
3188
|
-
reason: "LCM is disabled"
|
|
3189
|
-
};
|
|
3190
|
-
}
|
|
3191
|
-
const lcmSessionKey = namespace !== this.orchestrator.config.defaultNamespace ? `${namespace}:${request.sessionKey}` : request.sessionKey;
|
|
3192
|
-
await this.orchestrator.lcmEngine.waitForSessionObserveIdle(lcmSessionKey);
|
|
3193
|
-
await this.orchestrator.lcmEngine.recordCompaction(
|
|
3194
|
-
lcmSessionKey,
|
|
3195
|
-
request.tokensBefore,
|
|
3196
|
-
request.tokensAfter
|
|
3197
|
-
);
|
|
3198
|
-
return {
|
|
3199
|
-
enabled: true,
|
|
3200
|
-
recorded: true,
|
|
3201
|
-
sessionKey: request.sessionKey,
|
|
3202
|
-
namespace
|
|
3203
|
-
};
|
|
3204
|
-
}
|
|
3205
|
-
// ── Parity tools (match OpenClaw plugin feature set) ──────────────────
|
|
3206
|
-
// ── Continuity / Identity ──────────────────────────────────────────────
|
|
3207
|
-
async continuityAuditGenerate(request) {
|
|
3208
|
-
if (!this.orchestrator.config.identityContinuityEnabled) {
|
|
3209
|
-
return { enabled: false, reason: "Identity continuity is disabled. Enable `identityContinuityEnabled: true`." };
|
|
3210
|
-
}
|
|
3211
|
-
if (!this.orchestrator.config.continuityAuditEnabled) {
|
|
3212
|
-
return { enabled: false, reason: "Continuity audits are disabled. Enable `continuityAuditEnabled: true`." };
|
|
3213
|
-
}
|
|
3214
|
-
if (!this.orchestrator.compounding) {
|
|
3215
|
-
return { enabled: false, reason: "Compounding engine is disabled. Enable `compoundingEnabled: true`." };
|
|
3216
|
-
}
|
|
3217
|
-
const period = request.period === "monthly" ? "monthly" : "weekly";
|
|
3218
|
-
const key = request.key?.trim() || void 0;
|
|
3219
|
-
const audit = await this.orchestrator.compounding.synthesizeContinuityAudit({ period, key });
|
|
3220
|
-
return { enabled: true, period: audit.period, key: audit.key, reportPath: audit.reportPath };
|
|
3221
|
-
}
|
|
3222
|
-
async continuityIncidentOpen(request) {
|
|
3223
|
-
if (!this.orchestrator.config.identityContinuityEnabled) {
|
|
3224
|
-
return { enabled: false, reason: "Identity continuity is disabled. Enable `identityContinuityEnabled: true`." };
|
|
3225
|
-
}
|
|
3226
|
-
if (!this.orchestrator.config.continuityIncidentLoggingEnabled) {
|
|
3227
|
-
return { enabled: false, reason: "Continuity incident logging is disabled. Enable `continuityIncidentLoggingEnabled: true`." };
|
|
3228
|
-
}
|
|
3229
|
-
const symptom = request.symptom?.trim();
|
|
3230
|
-
if (!symptom) throw new EngramAccessInputError("symptom is required");
|
|
3231
|
-
const resolvedNs = this.resolveWritableNamespace(request.namespace, void 0, request.principal);
|
|
3232
|
-
const storage = await this.orchestrator.getStorage(resolvedNs);
|
|
3233
|
-
const created = await storage.appendContinuityIncident({
|
|
3234
|
-
symptom,
|
|
3235
|
-
triggerWindow: request.triggerWindow?.trim() || void 0,
|
|
3236
|
-
suspectedCause: request.suspectedCause?.trim() || void 0
|
|
3237
|
-
});
|
|
3238
|
-
return { created: true, incident: created };
|
|
3239
|
-
}
|
|
3240
|
-
async continuityIncidentClose(request) {
|
|
3241
|
-
if (!this.orchestrator.config.identityContinuityEnabled) {
|
|
3242
|
-
return { enabled: false, reason: "Identity continuity is disabled." };
|
|
3243
|
-
}
|
|
3244
|
-
if (!this.orchestrator.config.continuityIncidentLoggingEnabled) {
|
|
3245
|
-
return { enabled: false, reason: "Continuity incident logging is disabled." };
|
|
3246
|
-
}
|
|
3247
|
-
const id = request.id?.trim();
|
|
3248
|
-
if (!id) throw new EngramAccessInputError("id is required");
|
|
3249
|
-
const fixApplied = request.fixApplied?.trim();
|
|
3250
|
-
if (!fixApplied) throw new EngramAccessInputError("fixApplied is required");
|
|
3251
|
-
const verificationResult = request.verificationResult?.trim();
|
|
3252
|
-
if (!verificationResult) throw new EngramAccessInputError("verificationResult is required");
|
|
3253
|
-
const resolvedNs = this.resolveWritableNamespace(request.namespace, void 0, request.principal);
|
|
3254
|
-
const storage = await this.orchestrator.getStorage(resolvedNs);
|
|
3255
|
-
const closed = await storage.closeContinuityIncident(id, {
|
|
3256
|
-
fixApplied,
|
|
3257
|
-
verificationResult,
|
|
3258
|
-
preventiveRule: request.preventiveRule?.trim() || void 0
|
|
3259
|
-
});
|
|
3260
|
-
if (!closed) return { closed: false, reason: `Incident not found: ${id}` };
|
|
3261
|
-
return { closed: true, incident: closed };
|
|
3262
|
-
}
|
|
3263
|
-
async continuityIncidentList(request) {
|
|
3264
|
-
if (!this.orchestrator.config.identityContinuityEnabled) {
|
|
3265
|
-
return { enabled: false, reason: "Identity continuity is disabled." };
|
|
3266
|
-
}
|
|
3267
|
-
const state = request.state === "closed" || request.state === "all" ? request.state : "open";
|
|
3268
|
-
const limit = Math.max(1, Math.min(200, Math.floor(request.limit ?? 25)));
|
|
3269
|
-
const resolvedNs = this.resolveReadableNamespace(request.namespace, request.principal);
|
|
3270
|
-
const storage = await this.orchestrator.getStorage(resolvedNs);
|
|
3271
|
-
const incidents = await storage.readContinuityIncidents(limit, state);
|
|
3272
|
-
return { state, incidents, count: incidents.length };
|
|
3273
|
-
}
|
|
3274
|
-
async continuityLoopAddOrUpdate(request) {
|
|
3275
|
-
if (!this.orchestrator.config.identityContinuityEnabled) {
|
|
3276
|
-
return { enabled: false, reason: "Identity continuity is disabled." };
|
|
3277
|
-
}
|
|
3278
|
-
const resolvedNs = this.resolveWritableNamespace(request.namespace, void 0, request.principal);
|
|
3279
|
-
const storage = await this.orchestrator.getStorage(resolvedNs);
|
|
3280
|
-
const loop = await storage.upsertIdentityImprovementLoop({
|
|
3281
|
-
id: request.id?.trim() || "",
|
|
3282
|
-
cadence: request.cadence,
|
|
3283
|
-
purpose: request.purpose?.trim() || "",
|
|
3284
|
-
status: request.status,
|
|
3285
|
-
killCondition: request.killCondition?.trim() || "",
|
|
3286
|
-
lastReviewed: request.lastReviewed?.trim() || void 0,
|
|
3287
|
-
notes: request.notes?.trim() || void 0
|
|
3288
|
-
});
|
|
3289
|
-
return { saved: true, loop };
|
|
3290
|
-
}
|
|
3291
|
-
async continuityLoopReview(request) {
|
|
3292
|
-
if (!this.orchestrator.config.identityContinuityEnabled) {
|
|
3293
|
-
return { enabled: false, reason: "Identity continuity is disabled." };
|
|
3294
|
-
}
|
|
3295
|
-
const id = request.id?.trim();
|
|
3296
|
-
if (!id) throw new EngramAccessInputError("id is required");
|
|
3297
|
-
const resolvedNs = this.resolveWritableNamespace(request.namespace, void 0, request.principal);
|
|
3298
|
-
const storage = await this.orchestrator.getStorage(resolvedNs);
|
|
3299
|
-
const reviewed = await storage.reviewIdentityImprovementLoop(id, {
|
|
3300
|
-
status: request.status,
|
|
3301
|
-
notes: request.notes?.trim() || void 0,
|
|
3302
|
-
reviewedAt: request.reviewedAt?.trim() || void 0
|
|
3303
|
-
});
|
|
3304
|
-
if (!reviewed) return { reviewed: false, reason: `Continuity loop not found: ${id}` };
|
|
3305
|
-
return { reviewed: true, loop: reviewed };
|
|
3306
|
-
}
|
|
3307
|
-
async identityAnchorGet(request) {
|
|
3308
|
-
if (!this.orchestrator.config.identityContinuityEnabled) {
|
|
3309
|
-
return { enabled: false, reason: "Identity continuity is disabled." };
|
|
3310
|
-
}
|
|
3311
|
-
const resolvedNs = this.resolveReadableNamespace(request.namespace, request.principal);
|
|
3312
|
-
const storage = await this.orchestrator.getStorage(resolvedNs);
|
|
3313
|
-
const anchor = await storage.readIdentityAnchor();
|
|
3314
|
-
if (!anchor) return { found: false, message: "No identity anchor found yet. Use identity_anchor_update to create one." };
|
|
3315
|
-
return { found: true, anchor };
|
|
3316
|
-
}
|
|
3317
|
-
/**
|
|
3318
|
-
* @deprecated since issue #679 PR 5/5 — the identity-anchor model is
|
|
3319
|
-
* superseded by the peer registry. Use `peerSet({ id: "self", ... })` or
|
|
3320
|
-
* `remnic peer set self` to update the self peer's identity kernel, and
|
|
3321
|
-
* `remnic peer migrate` to seed `peers/self/identity.md` from existing
|
|
3322
|
-
* legacy anchor data. This method continues to function for backward
|
|
3323
|
-
* compatibility but will be removed in a future major version.
|
|
3324
|
-
*/
|
|
3325
|
-
async identityAnchorUpdate(request) {
|
|
3326
|
-
if (!this.orchestrator.config.identityContinuityEnabled) {
|
|
3327
|
-
return { enabled: false, reason: "Identity continuity is disabled." };
|
|
3328
|
-
}
|
|
3329
|
-
const updates = {
|
|
3330
|
-
"Identity Traits": request.identityTraits?.trim() || void 0,
|
|
3331
|
-
"Communication Preferences": request.communicationPreferences?.trim() || void 0,
|
|
3332
|
-
"Operating Principles": request.operatingPrinciples?.trim() || void 0,
|
|
3333
|
-
"Continuity Notes": request.continuityNotes?.trim() || void 0
|
|
3334
|
-
};
|
|
3335
|
-
const hasUpdate = Object.values(updates).some((v) => typeof v === "string" && v.length > 0);
|
|
3336
|
-
if (!hasUpdate) throw new EngramAccessInputError("At least one section field is required.");
|
|
3337
|
-
const resolvedNs = this.resolveWritableNamespace(request.namespace, void 0, request.principal);
|
|
3338
|
-
const storage = await this.orchestrator.getStorage(resolvedNs);
|
|
3339
|
-
const existing = await storage.readIdentityAnchor();
|
|
3340
|
-
const merged = this.mergeIdentityAnchorSections(existing, updates);
|
|
3341
|
-
await storage.writeIdentityAnchor(merged);
|
|
3342
|
-
const updatedSections = Object.entries(updates).filter(([, v]) => typeof v === "string" && v.length > 0).map(([name]) => name);
|
|
3343
|
-
return { updated: true, sections: updatedSections, anchor: merged };
|
|
3344
|
-
}
|
|
3345
|
-
async memoryIdentity(request) {
|
|
3346
|
-
const resolvedNs = this.resolveReadableNamespace(request.namespace, request.principal);
|
|
3347
|
-
const storage = await this.orchestrator.getStorage(resolvedNs);
|
|
3348
|
-
const identity = await storage.readIdentityReflections();
|
|
3349
|
-
if (!identity) return { found: false, message: "No identity reflections found." };
|
|
3350
|
-
return { found: true, identity };
|
|
3351
|
-
}
|
|
3352
|
-
// ── Work Layer ──────────────────────────────────────────────────────────
|
|
3353
|
-
async workTask(request) {
|
|
3354
|
-
const STATUSES = /* @__PURE__ */ new Set(["todo", "in_progress", "blocked", "done", "cancelled"]);
|
|
3355
|
-
const PRIORITIES = /* @__PURE__ */ new Set(["low", "medium", "high"]);
|
|
3356
|
-
const asStatus = (v) => v && STATUSES.has(v) ? v : void 0;
|
|
3357
|
-
const asPriority = (v) => v && PRIORITIES.has(v) ? v : void 0;
|
|
3358
|
-
const storage = new WorkStorage(this.orchestrator.config.memoryDir);
|
|
3359
|
-
await storage.ensureDirectories();
|
|
3360
|
-
const action = request.action;
|
|
3361
|
-
if (action === "create") {
|
|
3362
|
-
if (!request.title?.trim()) throw new EngramAccessInputError("title is required for create");
|
|
3363
|
-
const task = await storage.createTask({
|
|
3364
|
-
title: request.title,
|
|
3365
|
-
description: request.description,
|
|
3366
|
-
status: asStatus(request.status),
|
|
3367
|
-
priority: asPriority(request.priority),
|
|
3368
|
-
owner: request.owner?.trim() || void 0,
|
|
3369
|
-
assignee: request.assignee?.trim() || void 0,
|
|
3370
|
-
projectId: request.projectId?.trim() || void 0,
|
|
3371
|
-
tags: request.tags,
|
|
3372
|
-
dueAt: request.dueAt?.trim() || void 0
|
|
3373
|
-
});
|
|
3374
|
-
return { action, task };
|
|
3375
|
-
}
|
|
3376
|
-
if (action === "get") {
|
|
3377
|
-
if (!request.id?.trim()) throw new EngramAccessInputError("id is required for get");
|
|
3378
|
-
return { action, task: await storage.getTask(request.id) };
|
|
3379
|
-
}
|
|
3380
|
-
if (action === "list") {
|
|
3381
|
-
const tasks = await storage.listTasks({
|
|
3382
|
-
status: asStatus(request.status),
|
|
3383
|
-
owner: request.owner?.trim() || void 0,
|
|
3384
|
-
assignee: request.assignee?.trim() || void 0,
|
|
3385
|
-
projectId: request.projectId?.trim() || void 0
|
|
3386
|
-
});
|
|
3387
|
-
return { action, count: tasks.length, tasks };
|
|
3388
|
-
}
|
|
3389
|
-
if (action === "update") {
|
|
3390
|
-
if (!request.id?.trim()) throw new EngramAccessInputError("id is required for update");
|
|
3391
|
-
const patch = {};
|
|
3392
|
-
if (request.title !== void 0) patch.title = request.title;
|
|
3393
|
-
if (request.description !== void 0) patch.description = request.description;
|
|
3394
|
-
const st = asStatus(request.status);
|
|
3395
|
-
if (st) patch.status = st;
|
|
3396
|
-
const pr = asPriority(request.priority);
|
|
3397
|
-
if (pr) patch.priority = pr;
|
|
3398
|
-
if (request.owner !== void 0) patch.owner = request.owner || null;
|
|
3399
|
-
if (request.assignee !== void 0) patch.assignee = request.assignee || null;
|
|
3400
|
-
if (request.projectId !== void 0) patch.projectId = request.projectId || null;
|
|
3401
|
-
if (request.tags) patch.tags = request.tags;
|
|
3402
|
-
if (request.dueAt !== void 0) patch.dueAt = request.dueAt || null;
|
|
3403
|
-
return { action, task: await storage.updateTask(request.id, patch) };
|
|
3404
|
-
}
|
|
3405
|
-
if (action === "transition") {
|
|
3406
|
-
if (!request.id?.trim()) throw new EngramAccessInputError("id is required for transition");
|
|
3407
|
-
const st = asStatus(request.status);
|
|
3408
|
-
if (!st) throw new EngramAccessInputError("valid status is required for transition");
|
|
3409
|
-
return { action, task: await storage.transitionTask(request.id, st) };
|
|
3410
|
-
}
|
|
3411
|
-
if (action === "delete") {
|
|
3412
|
-
if (!request.id?.trim()) throw new EngramAccessInputError("id is required for delete");
|
|
3413
|
-
return { action, deleted: await storage.deleteTask(request.id) };
|
|
3414
|
-
}
|
|
3415
|
-
throw new EngramAccessInputError(`Unsupported work_task action: ${action}`);
|
|
3416
|
-
}
|
|
3417
|
-
async workProject(request) {
|
|
3418
|
-
const STATUSES = /* @__PURE__ */ new Set(["active", "on_hold", "completed", "archived"]);
|
|
3419
|
-
const asStatus = (v) => v && STATUSES.has(v) ? v : void 0;
|
|
3420
|
-
const storage = new WorkStorage(this.orchestrator.config.memoryDir);
|
|
3421
|
-
await storage.ensureDirectories();
|
|
3422
|
-
const action = request.action;
|
|
3423
|
-
if (action === "create") {
|
|
3424
|
-
if (!request.name?.trim()) throw new EngramAccessInputError("name is required for create");
|
|
3425
|
-
const project = await storage.createProject({
|
|
3426
|
-
name: request.name,
|
|
3427
|
-
description: request.description,
|
|
3428
|
-
status: asStatus(request.status),
|
|
3429
|
-
owner: request.owner?.trim() || void 0,
|
|
3430
|
-
tags: request.tags
|
|
3431
|
-
});
|
|
3432
|
-
return { action, project };
|
|
3433
|
-
}
|
|
3434
|
-
if (action === "get") {
|
|
3435
|
-
if (!request.id?.trim()) throw new EngramAccessInputError("id is required for get");
|
|
3436
|
-
return { action, project: await storage.getProject(request.id) };
|
|
3437
|
-
}
|
|
3438
|
-
if (action === "list") {
|
|
3439
|
-
const projects = await storage.listProjects();
|
|
3440
|
-
return { action, count: projects.length, projects };
|
|
3441
|
-
}
|
|
3442
|
-
if (action === "update") {
|
|
3443
|
-
if (!request.id?.trim()) throw new EngramAccessInputError("id is required for update");
|
|
3444
|
-
const patch = {};
|
|
3445
|
-
if (request.name !== void 0) patch.name = request.name;
|
|
3446
|
-
if (request.description !== void 0) patch.description = request.description;
|
|
3447
|
-
const st = asStatus(request.status);
|
|
3448
|
-
if (st) patch.status = st;
|
|
3449
|
-
if (request.owner !== void 0) patch.owner = request.owner || null;
|
|
3450
|
-
if (request.tags) patch.tags = request.tags;
|
|
3451
|
-
return { action, project: await storage.updateProject(request.id, patch) };
|
|
3452
|
-
}
|
|
3453
|
-
if (action === "delete") {
|
|
3454
|
-
if (!request.id?.trim()) throw new EngramAccessInputError("id is required for delete");
|
|
3455
|
-
return { action, deleted: await storage.deleteProject(request.id) };
|
|
3456
|
-
}
|
|
3457
|
-
if (action === "link_task") {
|
|
3458
|
-
if (!request.taskId?.trim() || !request.projectId?.trim()) {
|
|
3459
|
-
throw new EngramAccessInputError("taskId and projectId are required for link_task");
|
|
3460
|
-
}
|
|
3461
|
-
return { action, linked: await storage.linkTaskToProject(request.taskId, request.projectId) };
|
|
3462
|
-
}
|
|
3463
|
-
throw new EngramAccessInputError(`Unsupported work_project action: ${action}`);
|
|
3464
|
-
}
|
|
3465
|
-
async workBoard(request) {
|
|
3466
|
-
const memoryDir = this.orchestrator.config.memoryDir;
|
|
3467
|
-
await new WorkStorage(memoryDir).ensureDirectories();
|
|
3468
|
-
const action = request.action;
|
|
3469
|
-
const projectId = request.projectId?.trim() || void 0;
|
|
3470
|
-
if (action === "export_markdown") {
|
|
3471
|
-
const markdown = await exportWorkBoardMarkdown({ memoryDir, projectId });
|
|
3472
|
-
return { action, markdown: wrapWorkLayerContext(markdown, { linkToMemory: request.linkToMemory === true }) };
|
|
3473
|
-
}
|
|
3474
|
-
if (action === "export_snapshot") {
|
|
3475
|
-
const snapshot = await exportWorkBoardSnapshot({ memoryDir, projectId });
|
|
3476
|
-
return { action, snapshot };
|
|
3477
|
-
}
|
|
3478
|
-
if (action === "import_snapshot") {
|
|
3479
|
-
if (!request.snapshotJson?.trim()) throw new EngramAccessInputError("snapshotJson is required for import_snapshot");
|
|
3480
|
-
const snapshot = JSON.parse(request.snapshotJson);
|
|
3481
|
-
const result = await importWorkBoardSnapshot({ memoryDir, snapshot, projectId });
|
|
3482
|
-
return { action, result };
|
|
3483
|
-
}
|
|
3484
|
-
throw new EngramAccessInputError(`Unsupported work_board action: ${action}`);
|
|
3485
|
-
}
|
|
3486
|
-
// ── Shared Context / Compounding ────────────────────────────────────────
|
|
3487
|
-
async sharedContextWriteOutput(request) {
|
|
3488
|
-
if (!this.orchestrator.sharedContext) {
|
|
3489
|
-
return { enabled: false, reason: "Shared context is disabled. Enable `sharedContextEnabled: true`." };
|
|
3490
|
-
}
|
|
3491
|
-
const fp = await this.orchestrator.sharedContext.writeAgentOutput({
|
|
3492
|
-
agentId: request.agentId,
|
|
3493
|
-
title: request.title,
|
|
3494
|
-
content: request.content
|
|
3495
|
-
});
|
|
3496
|
-
return { written: true, path: fp };
|
|
3497
|
-
}
|
|
3498
|
-
async sharedFeedbackRecord(request) {
|
|
3499
|
-
if (!this.orchestrator.sharedContext) {
|
|
3500
|
-
return { enabled: false, reason: "Shared context is disabled. Enable `sharedContextEnabled: true`." };
|
|
3501
|
-
}
|
|
3502
|
-
await this.orchestrator.sharedContext.appendFeedback({
|
|
3503
|
-
agent: request.agent,
|
|
3504
|
-
decision: request.decision,
|
|
3505
|
-
reason: request.reason,
|
|
3506
|
-
date: request.date?.trim() || (/* @__PURE__ */ new Date()).toISOString(),
|
|
3507
|
-
learning: request.learning,
|
|
3508
|
-
outcome: request.outcome,
|
|
3509
|
-
severity: request.severity,
|
|
3510
|
-
confidence: request.confidence,
|
|
3511
|
-
workflow: request.workflow,
|
|
3512
|
-
tags: request.tags,
|
|
3513
|
-
evidenceWindowStart: request.evidenceWindowStart,
|
|
3514
|
-
evidenceWindowEnd: request.evidenceWindowEnd,
|
|
3515
|
-
refs: request.refs
|
|
3516
|
-
});
|
|
3517
|
-
return { recorded: true };
|
|
3518
|
-
}
|
|
3519
|
-
async sharedPrioritiesAppend(request) {
|
|
3520
|
-
if (!this.orchestrator.sharedContext) {
|
|
3521
|
-
return { enabled: false, reason: "Shared context is disabled. Enable `sharedContextEnabled: true`." };
|
|
3522
|
-
}
|
|
3523
|
-
await this.orchestrator.sharedContext.appendPrioritiesInbox({
|
|
3524
|
-
agentId: request.agentId,
|
|
3525
|
-
text: request.text
|
|
3526
|
-
});
|
|
3527
|
-
return { appended: true };
|
|
3528
|
-
}
|
|
3529
|
-
async sharedContextCrossSignalsRun(request) {
|
|
3530
|
-
if (!this.orchestrator.sharedContext) {
|
|
3531
|
-
return { enabled: false, reason: "Shared context is disabled. Enable `sharedContextEnabled: true`." };
|
|
3532
|
-
}
|
|
3533
|
-
const result = await this.orchestrator.sharedContext.synthesizeCrossSignals({ date: request.date });
|
|
3534
|
-
return {
|
|
3535
|
-
crossSignalsMarkdownPath: result.crossSignalsMarkdownPath,
|
|
3536
|
-
crossSignalsPath: result.crossSignalsPath,
|
|
3537
|
-
sourceCount: result.report.sourceCount,
|
|
3538
|
-
feedbackCount: result.report.feedbackCount,
|
|
3539
|
-
overlapCount: result.overlapCount
|
|
3540
|
-
};
|
|
3541
|
-
}
|
|
3542
|
-
async sharedContextCurateDaily(request) {
|
|
3543
|
-
if (!this.orchestrator.sharedContext) {
|
|
3544
|
-
return { enabled: false, reason: "Shared context is disabled. Enable `sharedContextEnabled: true`." };
|
|
3545
|
-
}
|
|
3546
|
-
const result = await this.orchestrator.sharedContext.curateDaily({ date: request.date });
|
|
3547
|
-
return {
|
|
3548
|
-
roundtablePath: result.roundtablePath,
|
|
3549
|
-
crossSignalsMarkdownPath: result.crossSignalsMarkdownPath,
|
|
3550
|
-
crossSignalsPath: result.crossSignalsPath,
|
|
3551
|
-
overlapCount: result.overlapCount
|
|
3552
|
-
};
|
|
3553
|
-
}
|
|
3554
|
-
async compoundingWeeklySynthesize(request) {
|
|
3555
|
-
if (!this.orchestrator.compounding) {
|
|
3556
|
-
return { enabled: false, reason: "Compounding engine is disabled. Enable `compoundingEnabled: true`." };
|
|
3557
|
-
}
|
|
3558
|
-
const res = await this.orchestrator.compounding.synthesizeWeekly({ weekId: request.weekId });
|
|
3559
|
-
return {
|
|
3560
|
-
weekId: res.weekId,
|
|
3561
|
-
reportPath: res.reportPath,
|
|
3562
|
-
reportJsonPath: res.reportJsonPath,
|
|
3563
|
-
rubricsPath: res.rubricsPath,
|
|
3564
|
-
rubricsIndexPath: res.rubricsIndexPath,
|
|
3565
|
-
mistakesCount: res.mistakesCount,
|
|
3566
|
-
promotionCandidateCount: res.promotionCandidateCount
|
|
3567
|
-
};
|
|
3568
|
-
}
|
|
3569
|
-
async compoundingPromoteCandidate(request) {
|
|
3570
|
-
if (!this.orchestrator.compounding) {
|
|
3571
|
-
return { enabled: false, reason: "Compounding engine is disabled. Enable `compoundingEnabled: true`." };
|
|
3572
|
-
}
|
|
3573
|
-
return await this.orchestrator.compounding.promoteCandidate({
|
|
3574
|
-
weekId: request.weekId,
|
|
3575
|
-
candidateId: request.candidateId,
|
|
3576
|
-
dryRun: request.dryRun
|
|
3577
|
-
});
|
|
3578
|
-
}
|
|
3579
|
-
// ── Compression Guidelines ────────────────────────────────────────────
|
|
3580
|
-
async compressionGuidelinesOptimize(request) {
|
|
3581
|
-
if (!this.orchestrator.config.compressionGuidelineLearningEnabled) {
|
|
3582
|
-
return { enabled: false, reason: "Compression guideline learning is disabled. Enable `compressionGuidelineLearningEnabled: true`." };
|
|
3583
|
-
}
|
|
3584
|
-
return await this.orchestrator.optimizeCompressionGuidelines({
|
|
3585
|
-
dryRun: request.dryRun,
|
|
3586
|
-
eventLimit: request.eventLimit
|
|
3587
|
-
});
|
|
3588
|
-
}
|
|
3589
|
-
async compressionGuidelinesActivate(request) {
|
|
3590
|
-
if (!this.orchestrator.config.compressionGuidelineLearningEnabled) {
|
|
3591
|
-
return { enabled: false, reason: "Compression guideline learning is disabled." };
|
|
3592
|
-
}
|
|
3593
|
-
return await this.orchestrator.activateCompressionGuidelineDraft({
|
|
3594
|
-
expectedContentHash: request.expectedContentHash,
|
|
3595
|
-
expectedGuidelineVersion: request.expectedGuidelineVersion
|
|
3596
|
-
});
|
|
3597
|
-
}
|
|
3598
|
-
/** Conservative identity anchor section merge (matches tools.ts mergeIdentityAnchor logic). */
|
|
3599
|
-
mergeIdentityAnchorSections(existingRaw, updates) {
|
|
3600
|
-
const TITLE = "# Identity Continuity Anchor";
|
|
3601
|
-
const SECTION_ORDER = ["Identity Traits", "Communication Preferences", "Operating Principles", "Continuity Notes"];
|
|
3602
|
-
const lines = (existingRaw ?? "").replace(/\r/g, "").split("\n");
|
|
3603
|
-
const headerLines = [];
|
|
3604
|
-
const sectionContent = /* @__PURE__ */ new Map();
|
|
3605
|
-
const order = [];
|
|
3606
|
-
let current = null;
|
|
3607
|
-
for (const line of lines) {
|
|
3608
|
-
const m = line.match(/^##\s+(.+?)\s*$/);
|
|
3609
|
-
if (m) {
|
|
3610
|
-
current = m[1].trim();
|
|
3611
|
-
if (!sectionContent.has(current)) {
|
|
3612
|
-
sectionContent.set(current, []);
|
|
3613
|
-
order.push(current);
|
|
3614
|
-
}
|
|
3615
|
-
continue;
|
|
3616
|
-
}
|
|
3617
|
-
if (!current) {
|
|
3618
|
-
headerLines.push(line);
|
|
3619
|
-
} else {
|
|
3620
|
-
sectionContent.get(current)?.push(line);
|
|
3621
|
-
}
|
|
3622
|
-
}
|
|
3623
|
-
const sections = /* @__PURE__ */ new Map();
|
|
3624
|
-
for (const [name, cLines] of sectionContent) sections.set(name, cLines.join("\n").trim());
|
|
3625
|
-
const header = headerLines.join("\n").trim() || TITLE;
|
|
3626
|
-
for (const sectionName of SECTION_ORDER) {
|
|
3627
|
-
const prev = sections.get(sectionName)?.trim();
|
|
3628
|
-
const next = updates[sectionName]?.trim();
|
|
3629
|
-
const existing = prev === "- (empty)" ? "" : prev;
|
|
3630
|
-
if (!next) {
|
|
3631
|
-
if (!sections.has(sectionName)) sections.set(sectionName, "");
|
|
3632
|
-
continue;
|
|
3633
|
-
}
|
|
3634
|
-
if (!existing) {
|
|
3635
|
-
sections.set(sectionName, next);
|
|
3636
|
-
continue;
|
|
3637
|
-
}
|
|
3638
|
-
if (existing.includes(next)) continue;
|
|
3639
|
-
if (next.includes(existing)) {
|
|
3640
|
-
sections.set(sectionName, next);
|
|
3641
|
-
continue;
|
|
3642
|
-
}
|
|
3643
|
-
sections.set(sectionName, `${existing}
|
|
3644
|
-
|
|
3645
|
-
${next}`);
|
|
3646
|
-
}
|
|
3647
|
-
const finalOrder = [...SECTION_ORDER.filter((s) => sections.has(s)), ...order.filter((s) => !SECTION_ORDER.includes(s) && sections.has(s))];
|
|
3648
|
-
const out = [header, ""];
|
|
3649
|
-
for (const name of finalOrder) {
|
|
3650
|
-
out.push(`## ${name}`, "");
|
|
3651
|
-
const body = sections.get(name)?.trim();
|
|
3652
|
-
if (body) out.push(body, "");
|
|
3653
|
-
else out.push("");
|
|
3654
|
-
}
|
|
3655
|
-
return out.join("\n").replace(/\n{3,}/g, "\n\n").trimEnd() + "\n";
|
|
3656
|
-
}
|
|
3657
|
-
// ── Memory search & debug ─────────────────────────────────────────────
|
|
3658
|
-
async memorySearch(request) {
|
|
3659
|
-
const { query, namespace, maxResults, collection, principal } = request;
|
|
3660
|
-
const resolvedNs = this.resolveReadableNamespace(namespace, principal);
|
|
3661
|
-
const namespaceFilter = resolvedNs !== this.orchestrator.config.defaultNamespace ? resolvedNs : void 0;
|
|
3662
|
-
const results = collection === "global" ? (await this.orchestrator.qmd.searchGlobal(query, maxResults)).filter(
|
|
3663
|
-
(r) => namespaceFilter ? r.path.includes(`/namespaces/${namespaceFilter}/`) || !r.path.includes("/namespaces/") && namespaceFilter === this.orchestrator.config.defaultNamespace : true
|
|
3664
|
-
) : await this.orchestrator.searchAcrossNamespaces({
|
|
3665
|
-
query,
|
|
3666
|
-
namespaces: namespaceFilter ? [namespaceFilter] : void 0,
|
|
3667
|
-
maxResults,
|
|
3668
|
-
mode: "search"
|
|
3669
|
-
});
|
|
3670
|
-
return {
|
|
3671
|
-
query,
|
|
3672
|
-
results: results.map((r) => ({
|
|
3673
|
-
path: r.path,
|
|
3674
|
-
score: r.score,
|
|
3675
|
-
snippet: (r.snippet ?? "").slice(0, 800)
|
|
3676
|
-
})),
|
|
3677
|
-
count: results.length
|
|
3678
|
-
};
|
|
3679
|
-
}
|
|
3680
|
-
async memoryProfile(namespace, principal) {
|
|
3681
|
-
const resolvedNs = this.resolveReadableNamespace(namespace, principal);
|
|
3682
|
-
const storage = await this.orchestrator.getStorage(resolvedNs);
|
|
3683
|
-
const profile = await storage.readProfile();
|
|
3684
|
-
return {
|
|
3685
|
-
profile: profile || "No profile built yet. The profile builds automatically through conversations."
|
|
3686
|
-
};
|
|
3687
|
-
}
|
|
3688
|
-
async memoryEntitiesList(namespace, principal) {
|
|
3689
|
-
const resolvedNs = this.resolveReadableNamespace(namespace, principal);
|
|
3690
|
-
const storage = await this.orchestrator.getStorage(resolvedNs);
|
|
3691
|
-
const entities = await storage.readEntities();
|
|
3692
|
-
return { entities, count: entities.length };
|
|
3693
|
-
}
|
|
3694
|
-
async memoryQuestions(namespace, principal) {
|
|
3695
|
-
const resolvedNs = this.resolveReadableNamespace(namespace, principal);
|
|
3696
|
-
const storage = await this.orchestrator.getStorage(resolvedNs);
|
|
3697
|
-
const questions = await storage.readQuestions();
|
|
3698
|
-
return {
|
|
3699
|
-
questions: questions.map((q) => ({ id: q.id, question: q.question, resolved: q.resolved })),
|
|
3700
|
-
count: questions.length
|
|
3701
|
-
};
|
|
3702
|
-
}
|
|
3703
|
-
async lastRecallSnapshot(sessionKey) {
|
|
3704
|
-
const snapshot = sessionKey ? this.orchestrator.lastRecall.get(sessionKey) : this.orchestrator.lastRecall.getMostRecent();
|
|
3705
|
-
return snapshot ?? { message: "No recall snapshot available" };
|
|
3706
|
-
}
|
|
3707
|
-
async intentDebug(namespace) {
|
|
3708
|
-
const snapshot = await this.orchestrator.getLastIntentSnapshot(namespace);
|
|
3709
|
-
return snapshot ?? { message: "No intent debug snapshot available" };
|
|
3710
|
-
}
|
|
3711
|
-
async qmdDebug(namespace) {
|
|
3712
|
-
const snapshot = await this.orchestrator.getLastQmdRecallSnapshot(namespace);
|
|
3713
|
-
return snapshot ?? { message: "No QMD debug snapshot available" };
|
|
3714
|
-
}
|
|
3715
|
-
async graphExplainLastRecall(namespace) {
|
|
3716
|
-
const explanation = await this.orchestrator.explainLastGraphRecall({ namespace });
|
|
3717
|
-
return { explanation };
|
|
3718
|
-
}
|
|
3719
|
-
/**
|
|
3720
|
-
* Read-only graph snapshot for the admin pane (issue #691 PR 2/5).
|
|
3721
|
-
*
|
|
3722
|
-
* Reads adjacency from the JSONL edge store written by `GraphIndex` and
|
|
3723
|
-
* resolves node metadata via the namespaced storage manager. Namespace
|
|
3724
|
-
* resolution mirrors the read-side path used by `recall` /
|
|
3725
|
-
* `procedureStats`, so multi-principal deployments can't leak edges from
|
|
3726
|
-
* a peer namespace (CLAUDE.md rule 42).
|
|
3727
|
-
*/
|
|
3728
|
-
async graphSnapshot(request, authenticatedPrincipal) {
|
|
3729
|
-
const namespace = this.resolveReadableNamespace(
|
|
3730
|
-
request.namespace,
|
|
3731
|
-
authenticatedPrincipal
|
|
3732
|
-
);
|
|
3733
|
-
const storage = await this.orchestrator.getStorage(namespace);
|
|
3734
|
-
const cfg = this.orchestrator.config;
|
|
3735
|
-
let namespaceRootReal;
|
|
3736
|
-
try {
|
|
3737
|
-
namespaceRootReal = await nodeFs.realpath(storage.dir);
|
|
3738
|
-
} catch {
|
|
3739
|
-
namespaceRootReal = nodePath.resolve(storage.dir);
|
|
3740
|
-
}
|
|
3741
|
-
const namespaceRootWithSep = namespaceRootReal.endsWith(nodePath.sep) ? namespaceRootReal : namespaceRootReal + nodePath.sep;
|
|
3742
|
-
const loadNode = async (relPath) => {
|
|
3743
|
-
if (nodePath.isAbsolute(relPath)) {
|
|
3744
|
-
log.warn(
|
|
3745
|
-
`graphSnapshot: rejected absolute edge endpoint (len=${relPath.length}) outside namespace root`
|
|
3746
|
-
);
|
|
3747
|
-
return null;
|
|
3748
|
-
}
|
|
3749
|
-
const candidate = nodePath.resolve(namespaceRootReal, relPath);
|
|
3750
|
-
if (candidate !== namespaceRootReal && !candidate.startsWith(namespaceRootWithSep)) {
|
|
3751
|
-
log.warn(
|
|
3752
|
-
`graphSnapshot: rejected traversing edge endpoint (len=${relPath.length}) outside namespace root`
|
|
3753
|
-
);
|
|
3754
|
-
return null;
|
|
3755
|
-
}
|
|
3756
|
-
let canonical;
|
|
3757
|
-
try {
|
|
3758
|
-
canonical = await nodeFs.realpath(candidate);
|
|
3759
|
-
} catch {
|
|
3760
|
-
canonical = candidate;
|
|
3761
|
-
}
|
|
3762
|
-
if (canonical !== namespaceRootReal && !canonical.startsWith(namespaceRootWithSep)) {
|
|
3763
|
-
log.warn(
|
|
3764
|
-
`graphSnapshot: rejected symlinked edge endpoint (len=${relPath.length}) that resolved outside namespace root`
|
|
3765
|
-
);
|
|
3766
|
-
return null;
|
|
3767
|
-
}
|
|
3768
|
-
const memory = await storage.readMemoryByPath(canonical);
|
|
3769
|
-
if (!memory) return null;
|
|
3770
|
-
const fm = memory.frontmatter;
|
|
3771
|
-
return {
|
|
3772
|
-
category: fm.category ?? "unknown",
|
|
3773
|
-
label: fm.id ?? nodePath.basename(canonical, nodePath.extname(canonical)),
|
|
3774
|
-
updated: fm.updated
|
|
3775
|
-
};
|
|
3776
|
-
};
|
|
3777
|
-
return buildGraphSnapshot({
|
|
3778
|
-
memoryDir: namespaceRootReal,
|
|
3779
|
-
graphConfig: {
|
|
3780
|
-
entityGraphEnabled: cfg.entityGraphEnabled === true,
|
|
3781
|
-
timeGraphEnabled: cfg.timeGraphEnabled === true,
|
|
3782
|
-
causalGraphEnabled: cfg.causalGraphEnabled === true
|
|
3783
|
-
},
|
|
3784
|
-
request: {
|
|
3785
|
-
limit: request.limit,
|
|
3786
|
-
since: request.since,
|
|
3787
|
-
focusNodeId: request.focusNodeId,
|
|
3788
|
-
categories: request.categories
|
|
3789
|
-
},
|
|
3790
|
-
loadNode
|
|
3791
|
-
});
|
|
3792
|
-
}
|
|
3793
|
-
async memoryFeedback(request) {
|
|
3794
|
-
if (!this.orchestrator.config.feedbackEnabled) {
|
|
3795
|
-
return {
|
|
3796
|
-
recorded: false,
|
|
3797
|
-
enabled: false,
|
|
3798
|
-
reason: "Feedback is disabled. Enable `feedbackEnabled: true` in the Engram config to store feedback."
|
|
3799
|
-
};
|
|
3800
|
-
}
|
|
3801
|
-
await this.orchestrator.recordMemoryFeedback(
|
|
3802
|
-
request.memoryId,
|
|
3803
|
-
request.vote,
|
|
3804
|
-
request.note
|
|
3805
|
-
);
|
|
3806
|
-
return { recorded: true };
|
|
3807
|
-
}
|
|
3808
|
-
/**
|
|
3809
|
-
* Record a Memory Worth outcome observation (issue #560 PR 3).
|
|
3810
|
-
*
|
|
3811
|
-
* This is distinct from `memoryFeedback` — feedback is a human thumbs
|
|
3812
|
-
* up/down on whether a recalled memory was relevant; outcome is an
|
|
3813
|
-
* automated signal about whether the session that consumed the memory
|
|
3814
|
-
* ultimately succeeded or failed. Outcomes feed the Laplace-smoothed
|
|
3815
|
-
* worth score (`computeMemoryWorth`, PR 2) that PR 4 will use to
|
|
3816
|
-
* downweight memories correlated with bad sessions.
|
|
3817
|
-
*
|
|
3818
|
-
* The underlying writer only touches fact-category memories. Corrections,
|
|
3819
|
-
* procedures, and other kinds return `{ ok: false, reason:
|
|
3820
|
-
* "ineligible_category" }` so a ledger drainer doesn't need to pre-filter.
|
|
3821
|
-
*/
|
|
3822
|
-
async memoryOutcome(request) {
|
|
3823
|
-
if (request.memoryId.includes("/") || request.memoryId.includes("\\")) {
|
|
3824
|
-
throw new EngramAccessInputError(
|
|
3825
|
-
"memoryId must not contain path separators"
|
|
3826
|
-
);
|
|
3827
|
-
}
|
|
3828
|
-
const resolvedNs = this.resolveWritableNamespace(
|
|
3829
|
-
request.namespace,
|
|
3830
|
-
request.sessionKey,
|
|
3831
|
-
request.principal
|
|
3832
|
-
);
|
|
3833
|
-
const storage = await this.orchestrator.getStorage(resolvedNs);
|
|
3834
|
-
return recordMemoryOutcome(storage, {
|
|
3835
|
-
memoryPath: `${request.memoryId}.md`,
|
|
3836
|
-
outcome: request.outcome,
|
|
3837
|
-
timestamp: request.timestamp
|
|
3838
|
-
});
|
|
3839
|
-
}
|
|
3840
|
-
async memoryPromote(request) {
|
|
3841
|
-
const resolvedNs = this.resolveWritableNamespace(request.namespace, request.sessionKey, request.principal);
|
|
3842
|
-
const storage = await this.orchestrator.getStorage(resolvedNs);
|
|
3843
|
-
await storage.updateMemoryFrontmatter(request.memoryId, {
|
|
3844
|
-
lifecycleState: "active",
|
|
3845
|
-
updated: (/* @__PURE__ */ new Date()).toISOString()
|
|
3846
|
-
});
|
|
3847
|
-
return { promoted: true, memoryId: request.memoryId };
|
|
3848
|
-
}
|
|
3849
|
-
async memoryActionApply(request) {
|
|
3850
|
-
const actionTypes = /* @__PURE__ */ new Set([
|
|
3851
|
-
"store_episode",
|
|
3852
|
-
"store_note",
|
|
3853
|
-
"update_note",
|
|
3854
|
-
"create_artifact",
|
|
3855
|
-
"summarize_node",
|
|
3856
|
-
"discard",
|
|
3857
|
-
"link_graph"
|
|
3858
|
-
]);
|
|
3859
|
-
if (!actionTypes.has(request.action)) {
|
|
3860
|
-
throw new EngramAccessInputError(
|
|
3861
|
-
`memory_action_apply: invalid action ${JSON.stringify(request.action)}`
|
|
3862
|
-
);
|
|
3863
|
-
}
|
|
3864
|
-
if (this.orchestrator.config.contextCompressionActionsEnabled !== true) {
|
|
3865
|
-
throw new EngramAccessInputError(
|
|
3866
|
-
"memory_action_apply is disabled; enable contextCompressionActionsEnabled to use this tool"
|
|
3867
|
-
);
|
|
3868
|
-
}
|
|
3869
|
-
const outcome = request.outcome ?? "skipped";
|
|
3870
|
-
if (outcome !== "applied" && outcome !== "skipped" && outcome !== "failed") {
|
|
3871
|
-
throw new EngramAccessInputError(
|
|
3872
|
-
`memory_action_apply: outcome must be "applied", "skipped", or "failed"; got ${JSON.stringify(outcome)}`
|
|
3873
|
-
);
|
|
3874
|
-
}
|
|
3875
|
-
const resolvedNs = this.resolveWritableNamespace(
|
|
3876
|
-
request.namespace,
|
|
3877
|
-
request.sessionKey,
|
|
3878
|
-
request.principal
|
|
3879
|
-
);
|
|
3880
|
-
const inputSummaryParts = [
|
|
3881
|
-
request.content,
|
|
3882
|
-
request.category ? `category=${request.category}` : void 0,
|
|
3883
|
-
request.linkTargetId ? `linkTargetId=${request.linkTargetId}` : void 0,
|
|
3884
|
-
request.linkType ? `linkType=${request.linkType}` : void 0,
|
|
3885
|
-
typeof request.linkStrength === "number" ? `linkStrength=${request.linkStrength}` : void 0,
|
|
3886
|
-
request.artifactType ? `artifactType=${request.artifactType}` : void 0,
|
|
3887
|
-
typeof request.execute === "boolean" ? `execute=${request.execute}` : void 0
|
|
3888
|
-
].filter((part) => typeof part === "string" && part.length > 0);
|
|
3889
|
-
const event = {
|
|
3890
|
-
action: request.action,
|
|
3891
|
-
outcome,
|
|
3892
|
-
namespace: resolvedNs,
|
|
3893
|
-
actor: "access.memory_action_apply",
|
|
3894
|
-
subsystem: "access.memory_action_apply",
|
|
3895
|
-
reason: request.reason,
|
|
3896
|
-
memoryId: request.memoryId,
|
|
3897
|
-
sourceSessionKey: request.sessionKey,
|
|
3898
|
-
inputSummary: inputSummaryParts.length > 0 ? inputSummaryParts.join(" | ").slice(0, 500) : void 0,
|
|
3899
|
-
dryRun: request.dryRun === true,
|
|
3900
|
-
promptHash: typeof request.sourcePrompt === "string" && request.sourcePrompt.length > 0 ? createHash("sha256").update(request.sourcePrompt).digest("hex") : void 0
|
|
3901
|
-
};
|
|
3902
|
-
const preview = this.orchestrator.previewMemoryActionEvent(event);
|
|
3903
|
-
if (request.dryRun === true) {
|
|
3904
|
-
return { recorded: false, dryRun: true, event: preview };
|
|
3905
|
-
}
|
|
3906
|
-
const recorded = await this.orchestrator.appendMemoryActionEvent(event);
|
|
3907
|
-
return { recorded, event: preview };
|
|
3908
|
-
}
|
|
3909
|
-
async contextCheckpoint(request) {
|
|
3910
|
-
const resolvedNs = this.resolveWritableNamespace(request.namespace, request.sessionKey, request.principal);
|
|
3911
|
-
const storage = await this.orchestrator.getStorage(resolvedNs);
|
|
3912
|
-
const storageDir = storage.dir;
|
|
3913
|
-
const { writeFile: writeFile2, mkdir: mkdir2 } = await import("fs/promises");
|
|
3914
|
-
const { join: join2, resolve: resolve2 } = await import("path");
|
|
3915
|
-
const safeKey = request.sessionKey.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
3916
|
-
if (!safeKey) throw new EngramAccessInputError("sessionKey is required");
|
|
3917
|
-
const checkpointDir = join2(storageDir, "checkpoints", safeKey);
|
|
3918
|
-
const resolved = resolve2(checkpointDir);
|
|
3919
|
-
if (!resolved.startsWith(resolve2(storageDir))) {
|
|
3920
|
-
throw new EngramAccessInputError("Invalid sessionKey");
|
|
3921
|
-
}
|
|
3922
|
-
await mkdir2(checkpointDir, { recursive: true });
|
|
3923
|
-
const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
3924
|
-
const filePath = join2(checkpointDir, `checkpoint-${ts}.md`);
|
|
3925
|
-
await writeFile2(filePath, request.context, "utf-8");
|
|
3926
|
-
return { saved: true };
|
|
3927
|
-
}
|
|
3928
|
-
async lcmStatus() {
|
|
3929
|
-
if (!this.orchestrator.lcmEngine || !this.orchestrator.lcmEngine.enabled) {
|
|
3930
|
-
return {
|
|
3931
|
-
enabled: false,
|
|
3932
|
-
archiveAvailable: false
|
|
3933
|
-
};
|
|
3934
|
-
}
|
|
3935
|
-
const stats = await this.orchestrator.lcmEngine.getStats();
|
|
3936
|
-
return {
|
|
3937
|
-
enabled: true,
|
|
3938
|
-
archiveAvailable: true,
|
|
3939
|
-
stats: {
|
|
3940
|
-
totalTurns: stats.totalMessages
|
|
3941
|
-
}
|
|
3942
|
-
};
|
|
3943
|
-
}
|
|
3944
|
-
/**
|
|
3945
|
-
* Record citation usage from an observed oai-mem-citation block.
|
|
3946
|
-
* For each citation entry, extract the memory ID from the path and
|
|
3947
|
-
* increment its access tracking via the orchestrator. Returns the
|
|
3948
|
-
* count of submitted IDs and the count of IDs that matched real memories.
|
|
3949
|
-
*/
|
|
3950
|
-
async recordCitationUsage(request) {
|
|
3951
|
-
if (request.entries.length === 0) return { submitted: 0, matched: 0 };
|
|
3952
|
-
const resolvedNamespace = this.resolveWritableNamespace(
|
|
3953
|
-
request.namespace,
|
|
3954
|
-
request.sessionId,
|
|
3955
|
-
request.authenticatedPrincipal
|
|
3956
|
-
);
|
|
3957
|
-
const memoryIds = [];
|
|
3958
|
-
for (const entry of request.entries) {
|
|
3959
|
-
const basename2 = entry.path.split("/").pop() ?? entry.path;
|
|
3960
|
-
const id = basename2.endsWith(".md") ? basename2.slice(0, -3) : basename2;
|
|
3961
|
-
if (id.length > 0) {
|
|
3962
|
-
memoryIds.push(id);
|
|
3963
|
-
}
|
|
3964
|
-
}
|
|
3965
|
-
if (memoryIds.length === 0) return { submitted: 0, matched: 0 };
|
|
3966
|
-
const storage = await this.orchestrator.getStorage(resolvedNamespace);
|
|
3967
|
-
const existingIds = await storage.filterExistingMemoryIds(memoryIds);
|
|
3968
|
-
const matchedIds = memoryIds.filter((id) => existingIds.has(id));
|
|
3969
|
-
if (matchedIds.length > 0) {
|
|
3970
|
-
try {
|
|
3971
|
-
this.orchestrator.trackMemoryAccess(matchedIds);
|
|
3972
|
-
} catch {
|
|
3973
|
-
log.debug("citation usage tracking: failed to record access for cited memories");
|
|
3974
|
-
}
|
|
3975
|
-
}
|
|
3976
|
-
return { submitted: memoryIds.length, matched: matchedIds.length };
|
|
3977
|
-
}
|
|
3978
|
-
// ── Operator Console state (issue #688 PR 2/3) ────────────────────────────
|
|
3979
|
-
/**
|
|
3980
|
-
* Gather a point-in-time `ConsoleStateSnapshot` from the orchestrator.
|
|
3981
|
-
*
|
|
3982
|
-
* Principal-aware: `resolveReadableNamespace` enforces ACL before the
|
|
3983
|
-
* snapshot is gathered, so callers cannot read a namespace they don't
|
|
3984
|
-
* have read access to (CLAUDE.md rule 42). The resolved namespace's
|
|
3985
|
-
* storage directory is forwarded as `config.memoryDir` so the ledger-
|
|
3986
|
-
* tail reader in `gatherConsoleState` scans the correct namespace root
|
|
3987
|
-
* rather than the global root. Read-only — never mutates orchestrator state.
|
|
3988
|
-
*/
|
|
3989
|
-
async consoleState(namespace, principal) {
|
|
3990
|
-
const resolvedNamespace = this.resolveReadableNamespace(namespace, principal);
|
|
3991
|
-
const storage = await this.orchestrator.getStorage(resolvedNamespace);
|
|
3992
|
-
const { gatherConsoleState } = await import("./state-NCHQ4TRG.js");
|
|
3993
|
-
const orchestratorProxy = Object.create(this.orchestrator, {
|
|
3994
|
-
config: {
|
|
3995
|
-
value: { ...this.orchestrator.config, memoryDir: storage.dir },
|
|
3996
|
-
enumerable: true,
|
|
3997
|
-
configurable: true
|
|
3998
|
-
}
|
|
3999
|
-
});
|
|
4000
|
-
return gatherConsoleState(orchestratorProxy);
|
|
4001
|
-
}
|
|
4002
|
-
// ── Peer Registry surfaces (issue #679 PR 4/5) ────────────────────────────
|
|
4003
|
-
/**
|
|
4004
|
-
* List all registered peers. Returns the array of `Peer` objects in
|
|
4005
|
-
* deterministic alphabetical order (mirroring `listPeers` storage semantics).
|
|
4006
|
-
*/
|
|
4007
|
-
async peerList() {
|
|
4008
|
-
const { listPeers } = await import("./peers-HCVGHMAE.js");
|
|
4009
|
-
const peers = await listPeers(this.orchestrator.config.memoryDir);
|
|
4010
|
-
return { peers };
|
|
4011
|
-
}
|
|
4012
|
-
/**
|
|
4013
|
-
* Get a single peer by id. Returns `{ found: false }` when the peer does
|
|
4014
|
-
* not exist rather than throwing, matching the `memoryGet` / `entityGet`
|
|
4015
|
-
* pattern used throughout the service.
|
|
4016
|
-
*/
|
|
4017
|
-
async peerGet(peerId) {
|
|
4018
|
-
const peers = await import("./peers-HCVGHMAE.js");
|
|
4019
|
-
const validateId = peers.assertValidPeerId;
|
|
4020
|
-
try {
|
|
4021
|
-
validateId(peerId);
|
|
4022
|
-
} catch (err) {
|
|
4023
|
-
throw new EngramAccessInputError(err.message);
|
|
4024
|
-
}
|
|
4025
|
-
const peer = await peers.readPeer(this.orchestrator.config.memoryDir, peerId);
|
|
4026
|
-
if (!peer) return { found: false };
|
|
4027
|
-
return { found: true, peer };
|
|
4028
|
-
}
|
|
4029
|
-
/**
|
|
4030
|
-
* Upsert a peer. Writes `peers/{id}/identity.md`. On first write the
|
|
4031
|
-
* `createdAt` timestamp is set to now; on subsequent writes only
|
|
4032
|
-
* `displayName` and `notes` are mutated (kind and createdAt are immutable
|
|
4033
|
-
* once set, per the storage contract).
|
|
4034
|
-
*
|
|
4035
|
-
* Returns `{ created: true }` on first write, `{ created: false }` on update.
|
|
4036
|
-
*/
|
|
4037
|
-
async peerSet(input) {
|
|
4038
|
-
const peers = await import("./peers-HCVGHMAE.js");
|
|
4039
|
-
const validateId = peers.assertValidPeerId;
|
|
4040
|
-
const { id } = input;
|
|
4041
|
-
try {
|
|
4042
|
-
validateId(id);
|
|
4043
|
-
} catch (err) {
|
|
4044
|
-
throw new EngramAccessInputError(err.message);
|
|
4045
|
-
}
|
|
4046
|
-
const memoryDir = this.orchestrator.config.memoryDir;
|
|
4047
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
4048
|
-
const existing = await peers.readPeer(memoryDir, id);
|
|
4049
|
-
const ALLOWED_KINDS = /* @__PURE__ */ new Set(["self", "human", "agent", "integration"]);
|
|
4050
|
-
if (!existing) {
|
|
4051
|
-
const kind = input.kind ?? "human";
|
|
4052
|
-
if (!ALLOWED_KINDS.has(kind)) {
|
|
4053
|
-
throw new EngramAccessInputError(
|
|
4054
|
-
`peer kind must be one of ${[...ALLOWED_KINDS].join(", ")}`
|
|
4055
|
-
);
|
|
4056
|
-
}
|
|
4057
|
-
const newPeer = {
|
|
4058
|
-
id,
|
|
4059
|
-
kind,
|
|
4060
|
-
displayName: input.displayName ?? id,
|
|
4061
|
-
createdAt: now,
|
|
4062
|
-
updatedAt: now,
|
|
4063
|
-
...typeof input.notes === "string" ? { notes: input.notes } : {}
|
|
4064
|
-
};
|
|
4065
|
-
await peers.writePeer(memoryDir, newPeer);
|
|
4066
|
-
return { ok: true, created: true, peer: newPeer };
|
|
4067
|
-
}
|
|
4068
|
-
const updated = {
|
|
4069
|
-
id: existing.id,
|
|
4070
|
-
kind: existing.kind,
|
|
4071
|
-
createdAt: existing.createdAt,
|
|
4072
|
-
updatedAt: now,
|
|
4073
|
-
displayName: input.displayName !== void 0 ? input.displayName : existing.displayName,
|
|
4074
|
-
...input.notes !== void 0 ? { notes: input.notes } : existing.notes !== void 0 ? { notes: existing.notes } : {}
|
|
4075
|
-
};
|
|
4076
|
-
await peers.writePeer(memoryDir, updated);
|
|
4077
|
-
return { ok: true, created: false, peer: updated };
|
|
4078
|
-
}
|
|
4079
|
-
/**
|
|
4080
|
-
* Delete a peer by removing `peers/{id}/identity.md`. If the file does not
|
|
4081
|
-
* exist the call is a no-op (idempotent). The peer directory itself
|
|
4082
|
-
* (`peers/{id}/`) is intentionally left in place — profile and interaction
|
|
4083
|
-
* log data are not destroyed.
|
|
4084
|
-
*/
|
|
4085
|
-
async peerDelete(peerId) {
|
|
4086
|
-
const peers = await import("./peers-HCVGHMAE.js");
|
|
4087
|
-
const validateId = peers.assertValidPeerId;
|
|
4088
|
-
try {
|
|
4089
|
-
validateId(peerId);
|
|
4090
|
-
} catch (err) {
|
|
4091
|
-
throw new EngramAccessInputError(err.message);
|
|
4092
|
-
}
|
|
4093
|
-
const deleted = await peers.deletePeer(this.orchestrator.config.memoryDir, peerId);
|
|
4094
|
-
return { ok: true, deleted };
|
|
4095
|
-
}
|
|
4096
|
-
/**
|
|
4097
|
-
* Destructively purge the entire peer directory for a given peerId —
|
|
4098
|
-
* `identity.md`, `profile.md`, `interactions.log.md`, and any other
|
|
4099
|
-
* files in `peers/{id}/`. Requires `confirm: "yes"` to prevent
|
|
4100
|
-
* accidental invocation.
|
|
4101
|
-
*
|
|
4102
|
-
* This is the DESTRUCTIVE counterpart to `peerDelete`, which only
|
|
4103
|
-
* removes `identity.md`. All companion files are permanently removed.
|
|
4104
|
-
*
|
|
4105
|
-
* Returns `{ ok: true, purged: true }` when the directory existed and
|
|
4106
|
-
* was removed; `{ ok: true, purged: false }` when the directory did
|
|
4107
|
-
* not exist (idempotent no-op).
|
|
4108
|
-
*/
|
|
4109
|
-
async peerForget(peerId, opts) {
|
|
4110
|
-
const peers = await import("./peers-HCVGHMAE.js");
|
|
4111
|
-
const validateId = peers.assertValidPeerId;
|
|
4112
|
-
try {
|
|
4113
|
-
validateId(peerId);
|
|
4114
|
-
} catch (err) {
|
|
4115
|
-
throw new EngramAccessInputError(err.message);
|
|
4116
|
-
}
|
|
4117
|
-
if (opts.confirm !== "yes") {
|
|
4118
|
-
throw new EngramAccessInputError(
|
|
4119
|
-
"peerForget requires confirm: 'yes' to prevent accidental data loss"
|
|
4120
|
-
);
|
|
4121
|
-
}
|
|
4122
|
-
const result = await peers.forgetPeer(this.orchestrator.config.memoryDir, peerId, {
|
|
4123
|
-
confirm: "yes"
|
|
4124
|
-
});
|
|
4125
|
-
return { ok: true, purged: result.purged };
|
|
4126
|
-
}
|
|
4127
|
-
/**
|
|
4128
|
-
* Get the evolving cognitive profile for a peer. Returns `{ found: false }`
|
|
4129
|
-
* when no profile file exists yet (profile is written by the async reasoner,
|
|
4130
|
-
* PR 2/5). The peer identity itself need not exist for a profile to exist,
|
|
4131
|
-
* but in practice the reasoner only writes profiles for registered peers.
|
|
4132
|
-
*/
|
|
4133
|
-
async peerProfileGet(peerId) {
|
|
4134
|
-
const peers = await import("./peers-HCVGHMAE.js");
|
|
4135
|
-
const validateId = peers.assertValidPeerId;
|
|
4136
|
-
try {
|
|
4137
|
-
validateId(peerId);
|
|
4138
|
-
} catch (err) {
|
|
4139
|
-
throw new EngramAccessInputError(err.message);
|
|
4140
|
-
}
|
|
4141
|
-
const profile = await peers.readPeerProfile(this.orchestrator.config.memoryDir, peerId);
|
|
4142
|
-
if (!profile) return { found: false };
|
|
4143
|
-
return { found: true, profile };
|
|
4144
|
-
}
|
|
4145
|
-
// ── Contradiction Review (issue #520) ──────────────────────────────────────
|
|
4146
|
-
get memoryDir() {
|
|
4147
|
-
return this.orchestrator.config.memoryDir;
|
|
4148
|
-
}
|
|
4149
|
-
/**
|
|
4150
|
-
* Resolve the storage directory for a given namespace. Used by the SSE
|
|
4151
|
-
* graph-event handler to subscribe to the correct per-namespace bus rather
|
|
4152
|
-
* than the global root (CLAUDE.md rule 42 — read/write paths must resolve
|
|
4153
|
-
* through the same namespace layer).
|
|
4154
|
-
*
|
|
4155
|
-
* `principal` must be the transport-bound request principal (from
|
|
4156
|
-
* `resolveRequestPrincipal`). When namespaces are enabled, an absent
|
|
4157
|
-
* principal causes `resolveReadableNamespace` to throw an auth error,
|
|
4158
|
-
* matching the behaviour of every other authenticated read path.
|
|
4159
|
-
*
|
|
4160
|
-
* Falls back to `this.memoryDir` when namespaces are disabled or the
|
|
4161
|
-
* namespace is absent, matching the behaviour of every other read path.
|
|
4162
|
-
*/
|
|
4163
|
-
async getMemoryDirForNamespace(namespace, principal) {
|
|
4164
|
-
const resolved = this.resolveReadableNamespace(namespace, principal);
|
|
4165
|
-
const storage = await this.orchestrator.getStorage(resolved);
|
|
4166
|
-
return storage.dir;
|
|
4167
|
-
}
|
|
4168
|
-
get storageRef() {
|
|
4169
|
-
return this.orchestrator.storage;
|
|
4170
|
-
}
|
|
4171
|
-
get configRef() {
|
|
4172
|
-
return this.orchestrator.config;
|
|
4173
|
-
}
|
|
4174
|
-
get localLlmRef() {
|
|
4175
|
-
return this.orchestrator.localLlm ?? null;
|
|
4176
|
-
}
|
|
4177
|
-
get fallbackLlmRef() {
|
|
4178
|
-
return this.orchestrator.fastGatewayLlm ?? null;
|
|
4179
|
-
}
|
|
4180
|
-
get embeddingLookupFactoryRef() {
|
|
4181
|
-
return (storage) => {
|
|
4182
|
-
if (!this.orchestrator.config.embeddingFallbackEnabled) return void 0;
|
|
4183
|
-
return async (content, limit) => {
|
|
4184
|
-
try {
|
|
4185
|
-
return await this.orchestrator.semanticDedupLookup(content, limit, storage);
|
|
4186
|
-
} catch {
|
|
4187
|
-
return [];
|
|
4188
|
-
}
|
|
4189
|
-
};
|
|
4190
|
-
};
|
|
4191
|
-
}
|
|
4192
|
-
/**
|
|
4193
|
-
* Import a capsule archive into the orchestrator's memory directory.
|
|
4194
|
-
*
|
|
4195
|
-
* Delegates directly to the standalone {@link importCapsuleFn} function.
|
|
4196
|
-
* The `root` parameter defaults to the orchestrator's `memoryDir` when
|
|
4197
|
-
* omitted, so callers that only have access to the service do not need to
|
|
4198
|
-
* thread the config value through.
|
|
4199
|
-
*
|
|
4200
|
-
* `versioning` defaults to the orchestrator's page-versioning config so
|
|
4201
|
-
* `mode: "overwrite"` automatically snapshots prior content without the
|
|
4202
|
-
* caller having to construct the config object.
|
|
4203
|
-
*/
|
|
4204
|
-
async capsuleImport(opts) {
|
|
4205
|
-
const { namespace, principal, root: explicitRoot, memoryDir: explicitMemoryDir, ...importOptions } = opts;
|
|
4206
|
-
const resolvedNamespace = this.resolveWritableNamespace(namespace, void 0, principal);
|
|
4207
|
-
const storage = await this.orchestrator.getStorage(resolvedNamespace);
|
|
4208
|
-
const root = explicitRoot ?? storage.dir;
|
|
4209
|
-
const memoryDir = explicitMemoryDir ?? this.orchestrator.config.memoryDir;
|
|
4210
|
-
const versioning = importOptions.versioning ?? {
|
|
4211
|
-
enabled: this.orchestrator.config.versioningEnabled,
|
|
4212
|
-
maxVersionsPerPage: this.orchestrator.config.versioningMaxPerPage,
|
|
4213
|
-
sidecarDir: this.orchestrator.config.versioningSidecarDir
|
|
4214
|
-
};
|
|
4215
|
-
await this.validateCapsuleImportArchivePath(importOptions.archivePath);
|
|
4216
|
-
try {
|
|
4217
|
-
return await importCapsule({ ...importOptions, root, memoryDir, versioning });
|
|
4218
|
-
} catch (err) {
|
|
4219
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
4220
|
-
if (this.isCapsuleImportArchiveInputError(err, message)) {
|
|
4221
|
-
throw new EngramAccessInputError(`capsule import failed: ${message}`);
|
|
4222
|
-
}
|
|
4223
|
-
throw err;
|
|
4224
|
-
}
|
|
4225
|
-
}
|
|
4226
|
-
async validateCapsuleImportArchivePath(archivePath) {
|
|
4227
|
-
let archiveStat;
|
|
4228
|
-
try {
|
|
4229
|
-
archiveStat = await stat(archivePath);
|
|
4230
|
-
} catch (err) {
|
|
4231
|
-
if (!this.isCapsuleImportPathInputFsError(err)) throw err;
|
|
4232
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
4233
|
-
throw new EngramAccessInputError(`capsule import failed: archive is not readable: ${message}`);
|
|
4234
|
-
}
|
|
4235
|
-
if (!archiveStat.isFile()) {
|
|
4236
|
-
throw new EngramAccessInputError("capsule import failed: archivePath must point to a file");
|
|
4237
|
-
}
|
|
4238
|
-
try {
|
|
4239
|
-
await nodeFs.access(archivePath, fsConstants.R_OK);
|
|
4240
|
-
} catch (err) {
|
|
4241
|
-
if (!this.isCapsuleImportPathInputFsError(err)) throw err;
|
|
4242
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
4243
|
-
throw new EngramAccessInputError(`capsule import failed: archive is not readable: ${message}`);
|
|
4244
|
-
}
|
|
4245
|
-
}
|
|
4246
|
-
isCapsuleImportPathInputFsError(err) {
|
|
4247
|
-
const code = typeof err === "object" && err !== null && "code" in err ? err.code : void 0;
|
|
4248
|
-
return code === "ENOENT" || code === "ENOTDIR" || code === "EACCES" || code === "EPERM" || code === "ELOOP";
|
|
4249
|
-
}
|
|
4250
|
-
isCapsuleImportArchiveInputError(err, message) {
|
|
4251
|
-
if (err instanceof ZodError) return true;
|
|
4252
|
-
const code = typeof err === "object" && err !== null && "code" in err ? err.code : void 0;
|
|
4253
|
-
if (typeof code === "string" && code.startsWith("Z_")) return true;
|
|
4254
|
-
return message.startsWith("importCapsule: archive") || message.startsWith("importCapsule: bundle") || message.startsWith("importCapsule: manifest") || message.startsWith("importCapsule: record") || /incorrect header check|invalid stored block lengths|not in gzip format|unexpected end of file/i.test(message);
|
|
4255
|
-
}
|
|
4256
|
-
/**
|
|
4257
|
-
* Export a capsule archive from the orchestrator's memory directory.
|
|
4258
|
-
*
|
|
4259
|
-
* HTTP and future MCP surfaces use this rather than calling the transfer
|
|
4260
|
-
* helper directly so namespace ACL checks stay consistent with the archive
|
|
4261
|
-
* write side effect. The exporter still owns archive construction and
|
|
4262
|
-
* validation.
|
|
4263
|
-
*/
|
|
4264
|
-
async capsuleExport(opts) {
|
|
4265
|
-
const { namespace, principal, root: explicitRoot, memoryDir: explicitMemoryDir, ...exportOptions } = opts;
|
|
4266
|
-
const resolvedNamespace = this.resolveWritableNamespace(namespace, void 0, principal);
|
|
4267
|
-
const storage = await this.orchestrator.getStorage(resolvedNamespace);
|
|
4268
|
-
const root = explicitRoot ?? storage.dir;
|
|
4269
|
-
const memoryDir = explicitMemoryDir ?? this.orchestrator.config.memoryDir;
|
|
4270
|
-
const pluginVersion = exportOptions.pluginVersion ?? await getPackageVersion();
|
|
4271
|
-
return exportCapsule({
|
|
4272
|
-
...exportOptions,
|
|
4273
|
-
pluginVersion,
|
|
4274
|
-
root,
|
|
4275
|
-
memoryDir: exportOptions.encrypt === true ? memoryDir : void 0
|
|
4276
|
-
});
|
|
4277
|
-
}
|
|
4278
|
-
/**
|
|
4279
|
-
* List capsule archives in the namespace-scoped capsule store.
|
|
4280
|
-
*
|
|
4281
|
-
* MCP uses this access-layer method instead of reading arbitrary paths so
|
|
4282
|
-
* capsule discovery remains bound to the same namespace ACLs as export and
|
|
4283
|
-
* import.
|
|
4284
|
-
*/
|
|
4285
|
-
async capsuleList(options) {
|
|
4286
|
-
const resolvedNamespace = this.resolveReadableNamespace(options?.namespace, options?.principal);
|
|
4287
|
-
const storage = await this.orchestrator.getStorage(resolvedNamespace);
|
|
4288
|
-
const capsulesDir = defaultCapsulesDir(storage.dir);
|
|
4289
|
-
let dirEntries;
|
|
4290
|
-
try {
|
|
4291
|
-
const capsulesDirStat = await nodeFs.lstat(capsulesDir);
|
|
4292
|
-
if (capsulesDirStat.isSymbolicLink()) {
|
|
4293
|
-
throw new EngramAccessInputError("capsule list failed: capsule store directory must not be a symlink");
|
|
4294
|
-
}
|
|
4295
|
-
if (!capsulesDirStat.isDirectory()) {
|
|
4296
|
-
throw new EngramAccessInputError("capsule list failed: capsule store path must be a directory");
|
|
4297
|
-
}
|
|
4298
|
-
dirEntries = await nodeFs.readdir(capsulesDir, { withFileTypes: true });
|
|
4299
|
-
} catch (err) {
|
|
4300
|
-
const code = typeof err === "object" && err !== null && "code" in err ? err.code : void 0;
|
|
4301
|
-
if (code === "ENOENT") {
|
|
4302
|
-
return { namespace: resolvedNamespace, capsulesDir, capsules: [] };
|
|
4303
|
-
}
|
|
4304
|
-
throw err;
|
|
4305
|
-
}
|
|
4306
|
-
const archiveNames = dirEntries.filter(
|
|
4307
|
-
(entry) => entry.isFile() && (entry.name.endsWith(".capsule.json.gz") || entry.name.endsWith(".capsule.json.gz.enc"))
|
|
4308
|
-
).map((entry) => entry.name).sort();
|
|
4309
|
-
const capsules = [];
|
|
4310
|
-
for (const archiveName of archiveNames) {
|
|
4311
|
-
const archivePath = nodePath.join(capsulesDir, archiveName);
|
|
4312
|
-
const id = archiveName.replace(/\.capsule\.json\.gz\.enc$/, "").replace(/\.capsule\.json\.gz$/, "");
|
|
4313
|
-
const manifestPath = nodePath.join(capsulesDir, `${id}.manifest.json`);
|
|
4314
|
-
let createdAt = null;
|
|
4315
|
-
let pluginVersion = null;
|
|
4316
|
-
let fileCount = null;
|
|
4317
|
-
let description = null;
|
|
4318
|
-
let manifestPathOrNull = manifestPath;
|
|
4319
|
-
try {
|
|
4320
|
-
const manifestStat = await nodeFs.lstat(manifestPath);
|
|
4321
|
-
if (manifestStat.isSymbolicLink() || !manifestStat.isFile()) {
|
|
4322
|
-
capsules.push({
|
|
4323
|
-
id,
|
|
4324
|
-
archivePath,
|
|
4325
|
-
manifestPath: manifestPathOrNull,
|
|
4326
|
-
createdAt,
|
|
4327
|
-
pluginVersion,
|
|
4328
|
-
fileCount,
|
|
4329
|
-
description
|
|
4330
|
-
});
|
|
4331
|
-
continue;
|
|
4332
|
-
}
|
|
4333
|
-
const raw = await nodeFs.readFile(manifestPath, "utf-8");
|
|
4334
|
-
const sidecar = JSON.parse(raw);
|
|
4335
|
-
createdAt = typeof sidecar.createdAt === "string" ? sidecar.createdAt : null;
|
|
4336
|
-
pluginVersion = typeof sidecar.pluginVersion === "string" ? sidecar.pluginVersion : null;
|
|
4337
|
-
fileCount = Array.isArray(sidecar.files) ? sidecar.files.length : null;
|
|
4338
|
-
const capsule = sidecar.capsule;
|
|
4339
|
-
description = capsule && typeof capsule.description === "string" ? capsule.description : null;
|
|
4340
|
-
} catch (err) {
|
|
4341
|
-
const code = typeof err === "object" && err !== null && "code" in err ? err.code : void 0;
|
|
4342
|
-
if (code === "ENOENT") {
|
|
4343
|
-
manifestPathOrNull = null;
|
|
4344
|
-
}
|
|
4345
|
-
}
|
|
4346
|
-
capsules.push({
|
|
4347
|
-
id,
|
|
4348
|
-
archivePath,
|
|
4349
|
-
manifestPath: manifestPathOrNull,
|
|
4350
|
-
createdAt,
|
|
4351
|
-
pluginVersion,
|
|
4352
|
-
fileCount,
|
|
4353
|
-
description
|
|
4354
|
-
});
|
|
4355
|
-
}
|
|
4356
|
-
return { namespace: resolvedNamespace, capsulesDir, capsules };
|
|
4357
|
-
}
|
|
4358
|
-
// ── Dreams pipeline telemetry surfaces (issue #678 PR 3+4) ──────────────
|
|
4359
|
-
/**
|
|
4360
|
-
* Return per-phase Dreams telemetry for the last N hours (default 24).
|
|
4361
|
-
*/
|
|
4362
|
-
async dreamsStatus(options) {
|
|
4363
|
-
const { getDreamsStatus, normalizeDreamsStatusWindowHours } = await import("./dreams-ledger-LR2NBAZE.js");
|
|
4364
|
-
let windowHours;
|
|
4365
|
-
try {
|
|
4366
|
-
windowHours = normalizeDreamsStatusWindowHours(options?.windowHours);
|
|
4367
|
-
} catch (error) {
|
|
4368
|
-
throw new EngramAccessInputError(error instanceof Error ? error.message : String(error));
|
|
4369
|
-
}
|
|
4370
|
-
const resolvedNamespace = this.resolveReadableNamespace(options?.namespace, options?.principal);
|
|
4371
|
-
const storage = await this.orchestrator.getStorage(resolvedNamespace);
|
|
4372
|
-
return getDreamsStatus(storage.dir, windowHours);
|
|
4373
|
-
}
|
|
4374
|
-
/**
|
|
4375
|
-
* Manually invoke a single Dreams phase pass (PR 4/4).
|
|
4376
|
-
*
|
|
4377
|
-
* Deep-sleep delegates to memory governance (shadow → dry-run, apply → live).
|
|
4378
|
-
* Light-sleep and REM scan the observation ledger and memory corpus
|
|
4379
|
-
* respectively, returning the same telemetry shape as a scheduled run.
|
|
4380
|
-
*/
|
|
4381
|
-
async dreamsRun(options) {
|
|
4382
|
-
const { runDreamsPhase } = await import("./dreams-ledger-LR2NBAZE.js");
|
|
4383
|
-
const validPhases = ["lightSleep", "rem", "deepSleep"];
|
|
4384
|
-
if (!validPhases.includes(options.phase)) {
|
|
4385
|
-
throw new EngramAccessInputError(
|
|
4386
|
-
`Invalid phase: ${String(options.phase)}. Must be one of: ${validPhases.join(", ")}`
|
|
4387
|
-
);
|
|
4388
|
-
}
|
|
4389
|
-
const deepSleep = this.orchestrator.config.dreamsPhases.deepSleep;
|
|
4390
|
-
if (options.phase === "deepSleep" && deepSleep.enabled === false && deepSleep.enabledExplicitlySet === true) {
|
|
4391
|
-
throw new EngramAccessInputError(
|
|
4392
|
-
"memory governance is disabled by dreams.phases.deepSleep.enabled=false"
|
|
4393
|
-
);
|
|
4394
|
-
}
|
|
4395
|
-
const dryRun = options.dryRun === true;
|
|
4396
|
-
const resolvedNamespace = this.resolveWritableNamespace(
|
|
4397
|
-
options.namespace,
|
|
4398
|
-
void 0,
|
|
4399
|
-
options.authenticatedPrincipal
|
|
4400
|
-
);
|
|
4401
|
-
const storage = await this.orchestrator.getStorage(resolvedNamespace);
|
|
4402
|
-
const memoryDir = storage.dir;
|
|
4403
|
-
const phaseRunner = dryRun || options.phase === "deepSleep" ? void 0 : async (_opts) => {
|
|
4404
|
-
if (_opts.phase === "lightSleep") {
|
|
4405
|
-
const result3 = await this.orchestrator.runLifecyclePolicyNow(storage);
|
|
4406
|
-
return {
|
|
4407
|
-
itemsProcessed: result3.memoriesAssessed,
|
|
4408
|
-
notes: `scored ${result3.memoriesAssessed} memories`
|
|
4409
|
-
};
|
|
4410
|
-
}
|
|
4411
|
-
const result2 = await this.orchestrator.runSemanticConsolidationNow({
|
|
4412
|
-
dryRun: false,
|
|
4413
|
-
storage
|
|
4414
|
-
});
|
|
4415
|
-
const itemsProcessed = result2.clusters.reduce(
|
|
4416
|
-
(sum, cluster) => sum + cluster.memories.length,
|
|
4417
|
-
0
|
|
4418
|
-
);
|
|
4419
|
-
return {
|
|
4420
|
-
itemsProcessed,
|
|
4421
|
-
notes: `REM consolidation found ${result2.clustersFound} clusters`
|
|
4422
|
-
};
|
|
4423
|
-
};
|
|
4424
|
-
const governanceRunner = options.phase === "deepSleep" ? async (_opts) => {
|
|
4425
|
-
return this.orchestrator.runDeepSleepGovernanceNow({
|
|
4426
|
-
storage,
|
|
4427
|
-
dryRun: _opts.dryRun
|
|
4428
|
-
});
|
|
4429
|
-
} : void 0;
|
|
4430
|
-
const result = await runDreamsPhase(
|
|
4431
|
-
{ memoryDir, phase: options.phase, dryRun },
|
|
4432
|
-
governanceRunner,
|
|
4433
|
-
phaseRunner
|
|
4434
|
-
);
|
|
4435
|
-
return {
|
|
4436
|
-
phase: result.phase,
|
|
4437
|
-
dryRun: result.dryRun,
|
|
4438
|
-
durationMs: result.durationMs,
|
|
4439
|
-
itemsProcessed: result.itemsProcessed,
|
|
4440
|
-
notes: result.notes
|
|
4441
|
-
};
|
|
4442
|
-
}
|
|
4443
|
-
};
|
|
4444
|
-
|
|
4445
|
-
export {
|
|
4446
|
-
WorkStorage,
|
|
4447
|
-
computeProcedureStats,
|
|
4448
|
-
formatProcedureStatsText,
|
|
4449
|
-
EngramAccessInputError,
|
|
4450
|
-
ENGRAM_ACCESS_WRITE_SCHEMA_VERSION,
|
|
4451
|
-
shapeMemorySummary,
|
|
4452
|
-
EngramAccessService
|
|
4453
|
-
};
|
|
4454
|
-
//# sourceMappingURL=chunk-MNU6ZBWT.js.map
|