@remnic/core 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/abstraction-nodes.d.ts +52 -0
- package/dist/abstraction-nodes.js +15 -0
- package/dist/abstraction-nodes.js.map +1 -0
- package/dist/access-cli.d.ts +5 -0
- package/dist/access-cli.js +308 -0
- package/dist/access-cli.js.map +1 -0
- package/dist/access-http.d.ts +158 -0
- package/dist/access-http.js +32 -0
- package/dist/access-http.js.map +1 -0
- package/dist/access-idempotency.d.ts +31 -0
- package/dist/access-idempotency.js +11 -0
- package/dist/access-idempotency.js.map +1 -0
- package/dist/access-mcp.d.ts +76 -0
- package/dist/access-mcp.js +8 -0
- package/dist/access-mcp.js.map +1 -0
- package/dist/access-schema.d.ts +266 -0
- package/dist/access-schema.js +29 -0
- package/dist/access-schema.js.map +1 -0
- package/dist/access-service.d.ts +614 -0
- package/dist/access-service.js +32 -0
- package/dist/access-service.js.map +1 -0
- package/dist/behavior-learner.d.ts +16 -0
- package/dist/behavior-learner.js +124 -0
- package/dist/behavior-learner.js.map +1 -0
- package/dist/behavior-signals.d.ts +15 -0
- package/dist/behavior-signals.js +11 -0
- package/dist/behavior-signals.js.map +1 -0
- package/dist/bootstrap.d.ts +46 -0
- package/dist/bootstrap.js +9 -0
- package/dist/bootstrap.js.map +1 -0
- package/dist/boxes.d.ts +93 -0
- package/dist/boxes.js +14 -0
- package/dist/boxes.js.map +1 -0
- package/dist/buffer.d.ts +22 -0
- package/dist/buffer.js +9 -0
- package/dist/buffer.js.map +1 -0
- package/dist/calibration.d.ts +81 -0
- package/dist/calibration.js +239 -0
- package/dist/calibration.js.map +1 -0
- package/dist/causal-behavior.d.ts +79 -0
- package/dist/causal-behavior.js +190 -0
- package/dist/causal-behavior.js.map +1 -0
- package/dist/causal-chain.d.ts +61 -0
- package/dist/causal-chain.js +24 -0
- package/dist/causal-chain.js.map +1 -0
- package/dist/causal-consolidation.d.ts +71 -0
- package/dist/causal-consolidation.js +211 -0
- package/dist/causal-consolidation.js.map +1 -0
- package/dist/causal-retrieval.d.ts +44 -0
- package/dist/causal-retrieval.js +184 -0
- package/dist/causal-retrieval.js.map +1 -0
- package/dist/causal-trajectory-graph.d.ts +13 -0
- package/dist/causal-trajectory-graph.js +59 -0
- package/dist/causal-trajectory-graph.js.map +1 -0
- package/dist/causal-trajectory.d.ts +68 -0
- package/dist/causal-trajectory.js +18 -0
- package/dist/causal-trajectory.js.map +1 -0
- package/dist/chunk-2CJCWDMR.js +87 -0
- package/dist/chunk-2CJCWDMR.js.map +1 -0
- package/dist/chunk-2NMMFZ5T.js +216 -0
- package/dist/chunk-2NMMFZ5T.js.map +1 -0
- package/dist/chunk-2PO5ZRKV.js +103 -0
- package/dist/chunk-2PO5ZRKV.js.map +1 -0
- package/dist/chunk-3QKK7QOS.js +154 -0
- package/dist/chunk-3QKK7QOS.js.map +1 -0
- package/dist/chunk-3SLRNYNG.js +26 -0
- package/dist/chunk-3SLRNYNG.js.map +1 -0
- package/dist/chunk-4A24LIM2.js +68 -0
- package/dist/chunk-4A24LIM2.js.map +1 -0
- package/dist/chunk-6HZ6AO2P.js +164 -0
- package/dist/chunk-6HZ6AO2P.js.map +1 -0
- package/dist/chunk-763GUIOU.js +302 -0
- package/dist/chunk-763GUIOU.js.map +1 -0
- package/dist/chunk-AAI7JARD.js +173 -0
- package/dist/chunk-AAI7JARD.js.map +1 -0
- package/dist/chunk-B7LOFDVE.js +112 -0
- package/dist/chunk-B7LOFDVE.js.map +1 -0
- package/dist/chunk-BDFZXRSO.js +318 -0
- package/dist/chunk-BDFZXRSO.js.map +1 -0
- package/dist/chunk-BOUYNNYD.js +707 -0
- package/dist/chunk-BOUYNNYD.js.map +1 -0
- package/dist/chunk-BRK4ODMI.js +60 -0
- package/dist/chunk-BRK4ODMI.js.map +1 -0
- package/dist/chunk-C6QPK5GG.js +111 -0
- package/dist/chunk-C6QPK5GG.js.map +1 -0
- package/dist/chunk-C7VW7C3F.js +117 -0
- package/dist/chunk-C7VW7C3F.js.map +1 -0
- package/dist/chunk-CDW777AI.js +621 -0
- package/dist/chunk-CDW777AI.js.map +1 -0
- package/dist/chunk-CULXMQJH.js +185 -0
- package/dist/chunk-CULXMQJH.js.map +1 -0
- package/dist/chunk-CXWFUJR2.js +1203 -0
- package/dist/chunk-CXWFUJR2.js.map +1 -0
- package/dist/chunk-DGXUHMOV.js +61 -0
- package/dist/chunk-DGXUHMOV.js.map +1 -0
- package/dist/chunk-DM2T26WE.js +61 -0
- package/dist/chunk-DM2T26WE.js.map +1 -0
- package/dist/chunk-DORBM6OB.js +81 -0
- package/dist/chunk-DORBM6OB.js.map +1 -0
- package/dist/chunk-DT5TVLJE.js +32 -0
- package/dist/chunk-DT5TVLJE.js.map +1 -0
- package/dist/chunk-EEQLFRUM.js +89 -0
- package/dist/chunk-EEQLFRUM.js.map +1 -0
- package/dist/chunk-EQINRHYR.js +672 -0
- package/dist/chunk-EQINRHYR.js.map +1 -0
- package/dist/chunk-ESSMF2FR.js +146 -0
- package/dist/chunk-ESSMF2FR.js.map +1 -0
- package/dist/chunk-ETOW6ACV.js +158 -0
- package/dist/chunk-ETOW6ACV.js.map +1 -0
- package/dist/chunk-FYIYMQ5N.js +221 -0
- package/dist/chunk-FYIYMQ5N.js.map +1 -0
- package/dist/chunk-G3AG3KZN.js +78 -0
- package/dist/chunk-G3AG3KZN.js.map +1 -0
- package/dist/chunk-GJR6D6KC.js +61 -0
- package/dist/chunk-GJR6D6KC.js.map +1 -0
- package/dist/chunk-GPGBSNKM.js +380 -0
- package/dist/chunk-GPGBSNKM.js.map +1 -0
- package/dist/chunk-H63EDPFJ.js +57 -0
- package/dist/chunk-H63EDPFJ.js.map +1 -0
- package/dist/chunk-HG2NKWR2.js +185 -0
- package/dist/chunk-HG2NKWR2.js.map +1 -0
- package/dist/chunk-HL4DB7TO.js +13 -0
- package/dist/chunk-HL4DB7TO.js.map +1 -0
- package/dist/chunk-HLBYLYRD.js +346 -0
- package/dist/chunk-HLBYLYRD.js.map +1 -0
- package/dist/chunk-HLXVTBF3.js +109 -0
- package/dist/chunk-HLXVTBF3.js.map +1 -0
- package/dist/chunk-IFFFR3MR.js +68 -0
- package/dist/chunk-IFFFR3MR.js.map +1 -0
- package/dist/chunk-ISY75RLM.js +1027 -0
- package/dist/chunk-ISY75RLM.js.map +1 -0
- package/dist/chunk-IZME7KW2.js +1886 -0
- package/dist/chunk-IZME7KW2.js.map +1 -0
- package/dist/chunk-J3BT33K7.js +720 -0
- package/dist/chunk-J3BT33K7.js.map +1 -0
- package/dist/chunk-J47FNDR7.js +113 -0
- package/dist/chunk-J47FNDR7.js.map +1 -0
- package/dist/chunk-JWPLJLDU.js +63 -0
- package/dist/chunk-JWPLJLDU.js.map +1 -0
- package/dist/chunk-K6WK37A6.js +865 -0
- package/dist/chunk-K6WK37A6.js.map +1 -0
- package/dist/chunk-KL4CP4SB.js +130 -0
- package/dist/chunk-KL4CP4SB.js.map +1 -0
- package/dist/chunk-KT4NEUNF.js +315 -0
- package/dist/chunk-KT4NEUNF.js.map +1 -0
- package/dist/chunk-KWBU5S5U.js +42 -0
- package/dist/chunk-KWBU5S5U.js.map +1 -0
- package/dist/chunk-L5RPWGFK.js +59 -0
- package/dist/chunk-L5RPWGFK.js.map +1 -0
- package/dist/chunk-L7WO3MZ4.js +128 -0
- package/dist/chunk-L7WO3MZ4.js.map +1 -0
- package/dist/chunk-LIRZNNUP.js +74 -0
- package/dist/chunk-LIRZNNUP.js.map +1 -0
- package/dist/chunk-LK6SGL53.js +22 -0
- package/dist/chunk-LK6SGL53.js.map +1 -0
- package/dist/chunk-LOBRX7VD.js +200 -0
- package/dist/chunk-LOBRX7VD.js.map +1 -0
- package/dist/chunk-LPSF4OQH.js +47 -0
- package/dist/chunk-LPSF4OQH.js.map +1 -0
- package/dist/chunk-LU3GQNDQ.js +152 -0
- package/dist/chunk-LU3GQNDQ.js.map +1 -0
- package/dist/chunk-M5KEYE5E.js +350 -0
- package/dist/chunk-M5KEYE5E.js.map +1 -0
- package/dist/chunk-M62O4P4T.js +41 -0
- package/dist/chunk-M62O4P4T.js.map +1 -0
- package/dist/chunk-MARWOCVP.js +48 -0
- package/dist/chunk-MARWOCVP.js.map +1 -0
- package/dist/chunk-MDDAA2AO.js +925 -0
- package/dist/chunk-MDDAA2AO.js.map +1 -0
- package/dist/chunk-MWGVGUIS.js +198 -0
- package/dist/chunk-MWGVGUIS.js.map +1 -0
- package/dist/chunk-N5AKDXAI.js +74 -0
- package/dist/chunk-N5AKDXAI.js.map +1 -0
- package/dist/chunk-NGAVDO7E.js +115 -0
- package/dist/chunk-NGAVDO7E.js.map +1 -0
- package/dist/chunk-NTTLPF7F.js +283 -0
- package/dist/chunk-NTTLPF7F.js.map +1 -0
- package/dist/chunk-ONRU4L2N.js +240 -0
- package/dist/chunk-ONRU4L2N.js.map +1 -0
- package/dist/chunk-ORZMT74A.js +209 -0
- package/dist/chunk-ORZMT74A.js.map +1 -0
- package/dist/chunk-OTAVQCSF.js +268 -0
- package/dist/chunk-OTAVQCSF.js.map +1 -0
- package/dist/chunk-PGK3VUHN.js +160 -0
- package/dist/chunk-PGK3VUHN.js.map +1 -0
- package/dist/chunk-Q6FETXJA.js +1362 -0
- package/dist/chunk-Q6FETXJA.js.map +1 -0
- package/dist/chunk-QANCTXQF.js +271 -0
- package/dist/chunk-QANCTXQF.js.map +1 -0
- package/dist/chunk-QCCCQT3O.js +189 -0
- package/dist/chunk-QCCCQT3O.js.map +1 -0
- package/dist/chunk-QDOSNLB4.js +1048 -0
- package/dist/chunk-QDOSNLB4.js.map +1 -0
- package/dist/chunk-QFQVZOGA.js +2168 -0
- package/dist/chunk-QFQVZOGA.js.map +1 -0
- package/dist/chunk-QPKFPHOO.js +178 -0
- package/dist/chunk-QPKFPHOO.js.map +1 -0
- package/dist/chunk-QSVPYQPG.js +268 -0
- package/dist/chunk-QSVPYQPG.js.map +1 -0
- package/dist/chunk-QWUUMMIK.js +3045 -0
- package/dist/chunk-QWUUMMIK.js.map +1 -0
- package/dist/chunk-QY2BHY5O.js +2378 -0
- package/dist/chunk-QY2BHY5O.js.map +1 -0
- package/dist/chunk-SCHEKPYH.js +349 -0
- package/dist/chunk-SCHEKPYH.js.map +1 -0
- package/dist/chunk-SCU65EZI.js +15 -0
- package/dist/chunk-SCU65EZI.js.map +1 -0
- package/dist/chunk-T4WRIV2C.js +170 -0
- package/dist/chunk-T4WRIV2C.js.map +1 -0
- package/dist/chunk-TKO4HZCK.js +1852 -0
- package/dist/chunk-TKO4HZCK.js.map +1 -0
- package/dist/chunk-TP4FZJIZ.js +93 -0
- package/dist/chunk-TP4FZJIZ.js.map +1 -0
- package/dist/chunk-TPB3I2AC.js +403 -0
- package/dist/chunk-TPB3I2AC.js.map +1 -0
- package/dist/chunk-TVVVQQAK.js +1431 -0
- package/dist/chunk-TVVVQQAK.js.map +1 -0
- package/dist/chunk-U4PV25RD.js +14 -0
- package/dist/chunk-U4PV25RD.js.map +1 -0
- package/dist/chunk-UCYSTFZR.js +284 -0
- package/dist/chunk-UCYSTFZR.js.map +1 -0
- package/dist/chunk-UHGBNIOS.js +205 -0
- package/dist/chunk-UHGBNIOS.js.map +1 -0
- package/dist/chunk-UIYZ5T3I.js +108 -0
- package/dist/chunk-UIYZ5T3I.js.map +1 -0
- package/dist/chunk-UV2FO7J4.js +747 -0
- package/dist/chunk-UV2FO7J4.js.map +1 -0
- package/dist/chunk-UZB5KHKX.js +63 -0
- package/dist/chunk-UZB5KHKX.js.map +1 -0
- package/dist/chunk-V3RXWQIE.js +626 -0
- package/dist/chunk-V3RXWQIE.js.map +1 -0
- package/dist/chunk-V4YC4LUK.js +444 -0
- package/dist/chunk-V4YC4LUK.js.map +1 -0
- package/dist/chunk-VEWZZM3H.js +133 -0
- package/dist/chunk-VEWZZM3H.js.map +1 -0
- package/dist/chunk-WWIQTB2Y.js +98 -0
- package/dist/chunk-WWIQTB2Y.js.map +1 -0
- package/dist/chunk-X7XN6YU4.js +24 -0
- package/dist/chunk-X7XN6YU4.js.map +1 -0
- package/dist/chunk-XKECPATV.js +202 -0
- package/dist/chunk-XKECPATV.js.map +1 -0
- package/dist/chunk-XYIK4LF6.js +75 -0
- package/dist/chunk-XYIK4LF6.js.map +1 -0
- package/dist/chunk-Y27UJK6V.js +39 -0
- package/dist/chunk-Y27UJK6V.js.map +1 -0
- package/dist/chunk-Y4Z4I6WK.js +9 -0
- package/dist/chunk-Y4Z4I6WK.js.map +1 -0
- package/dist/chunk-YAPUAHAY.js +10761 -0
- package/dist/chunk-YAPUAHAY.js.map +1 -0
- package/dist/chunk-YAZNBMNF.js +92 -0
- package/dist/chunk-YAZNBMNF.js.map +1 -0
- package/dist/chunk-YCN4BVDK.js +66 -0
- package/dist/chunk-YCN4BVDK.js.map +1 -0
- package/dist/chunk-YNCQ7E4M.js +388 -0
- package/dist/chunk-YNCQ7E4M.js.map +1 -0
- package/dist/chunk-YNI4S5WT.js +143 -0
- package/dist/chunk-YNI4S5WT.js.map +1 -0
- package/dist/chunk-YRMVARQP.js +406 -0
- package/dist/chunk-YRMVARQP.js.map +1 -0
- package/dist/chunk-Z5AAYHUC.js +79 -0
- package/dist/chunk-Z5AAYHUC.js.map +1 -0
- package/dist/chunk-Z5LAYHGJ.js +15 -0
- package/dist/chunk-Z5LAYHGJ.js.map +1 -0
- package/dist/chunk-ZJLY4QSU.js +823 -0
- package/dist/chunk-ZJLY4QSU.js.map +1 -0
- package/dist/chunk-ZKYI7UVO.js +276 -0
- package/dist/chunk-ZKYI7UVO.js.map +1 -0
- package/dist/chunk-ZPKBYX2F.js +297 -0
- package/dist/chunk-ZPKBYX2F.js.map +1 -0
- package/dist/chunking.d.ts +48 -0
- package/dist/chunking.js +11 -0
- package/dist/chunking.js.map +1 -0
- package/dist/cli.d.ts +1162 -0
- package/dist/cli.js +7187 -0
- package/dist/cli.js.map +1 -0
- package/dist/commitment-ledger.d.ts +83 -0
- package/dist/commitment-ledger.js +19 -0
- package/dist/commitment-ledger.js.map +1 -0
- package/dist/compression-optimizer.d.ts +37 -0
- package/dist/compression-optimizer.js +13 -0
- package/dist/compression-optimizer.js.map +1 -0
- package/dist/config.d.ts +6 -0
- package/dist/config.js +12 -0
- package/dist/config.js.map +1 -0
- package/dist/cue-anchors.d.ts +50 -0
- package/dist/cue-anchors.js +15 -0
- package/dist/cue-anchors.js.map +1 -0
- package/dist/dashboard-runtime.d.ts +46 -0
- package/dist/dashboard-runtime.js +10 -0
- package/dist/dashboard-runtime.js.map +1 -0
- package/dist/day-summary.d.ts +6 -0
- package/dist/day-summary.js +10 -0
- package/dist/day-summary.js.map +1 -0
- package/dist/delinearize.d.ts +34 -0
- package/dist/delinearize.js +11 -0
- package/dist/delinearize.js.map +1 -0
- package/dist/embedding-fallback.d.ts +22 -0
- package/dist/embedding-fallback.js +8 -0
- package/dist/embedding-fallback.js.map +1 -0
- package/dist/engine-P26JFSVY.js +19 -0
- package/dist/engine-P26JFSVY.js.map +1 -0
- package/dist/entity-retrieval.d.ts +23 -0
- package/dist/entity-retrieval.js +24 -0
- package/dist/entity-retrieval.js.map +1 -0
- package/dist/evals.d.ts +282 -0
- package/dist/evals.js +32 -0
- package/dist/evals.js.map +1 -0
- package/dist/explicit-capture.d.ts +60 -0
- package/dist/explicit-capture.js +23 -0
- package/dist/explicit-capture.js.map +1 -0
- package/dist/extraction.d.ts +141 -0
- package/dist/extraction.js +22 -0
- package/dist/extraction.js.map +1 -0
- package/dist/fallback-llm.d.ts +95 -0
- package/dist/fallback-llm.js +12 -0
- package/dist/fallback-llm.js.map +1 -0
- package/dist/graph-dashboard-diff.d.ts +12 -0
- package/dist/graph-dashboard-diff.js +8 -0
- package/dist/graph-dashboard-diff.js.map +1 -0
- package/dist/graph-dashboard-key.d.ts +5 -0
- package/dist/graph-dashboard-key.js +7 -0
- package/dist/graph-dashboard-key.js.map +1 -0
- package/dist/graph-dashboard-parser.d.ts +20 -0
- package/dist/graph-dashboard-parser.js +8 -0
- package/dist/graph-dashboard-parser.js.map +1 -0
- package/dist/graph.d.ts +157 -0
- package/dist/graph.js +27 -0
- package/dist/graph.js.map +1 -0
- package/dist/harmonic-retrieval.d.ts +27 -0
- package/dist/harmonic-retrieval.js +12 -0
- package/dist/harmonic-retrieval.js.map +1 -0
- package/dist/himem.d.ts +23 -0
- package/dist/himem.js +7 -0
- package/dist/himem.js.map +1 -0
- package/dist/hygiene.d.ts +24 -0
- package/dist/hygiene.js +9 -0
- package/dist/hygiene.js.map +1 -0
- package/dist/identity-continuity.d.ts +17 -0
- package/dist/identity-continuity.js +19 -0
- package/dist/identity-continuity.js.map +1 -0
- package/dist/importance.d.ts +25 -0
- package/dist/importance.js +11 -0
- package/dist/importance.js.map +1 -0
- package/dist/index.d.ts +923 -0
- package/dist/index.js +2512 -0
- package/dist/index.js.map +1 -0
- package/dist/intent.d.ts +8 -0
- package/dist/intent.js +13 -0
- package/dist/intent.js.map +1 -0
- package/dist/json-extract.d.ts +14 -0
- package/dist/json-extract.js +9 -0
- package/dist/json-extract.js.map +1 -0
- package/dist/json-store.d.ts +5 -0
- package/dist/json-store.js +11 -0
- package/dist/json-store.js.map +1 -0
- package/dist/legacy-hook-compat.d.ts +3 -0
- package/dist/legacy-hook-compat.js +35 -0
- package/dist/legacy-hook-compat.js.map +1 -0
- package/dist/lifecycle.d.ts +52 -0
- package/dist/lifecycle.js +21 -0
- package/dist/lifecycle.js.map +1 -0
- package/dist/local-llm.d.ts +154 -0
- package/dist/local-llm.js +10 -0
- package/dist/local-llm.js.map +1 -0
- package/dist/logger.d.ts +15 -0
- package/dist/logger.js +9 -0
- package/dist/logger.js.map +1 -0
- package/dist/memory-action-policy.d.ts +13 -0
- package/dist/memory-action-policy.js +7 -0
- package/dist/memory-action-policy.js.map +1 -0
- package/dist/memory-cache.d.ts +35 -0
- package/dist/memory-cache.js +37 -0
- package/dist/memory-cache.js.map +1 -0
- package/dist/memory-lifecycle-ledger-utils.d.ts +13 -0
- package/dist/memory-lifecycle-ledger-utils.js +23 -0
- package/dist/memory-lifecycle-ledger-utils.js.map +1 -0
- package/dist/memory-projection-format.d.ts +4 -0
- package/dist/memory-projection-format.js +9 -0
- package/dist/memory-projection-format.js.map +1 -0
- package/dist/memory-projection-store-NxMkbocT.d.ts +221 -0
- package/dist/memory-projection-store.d.ts +3 -0
- package/dist/memory-projection-store.js +31 -0
- package/dist/memory-projection-store.js.map +1 -0
- package/dist/model-registry.d.ts +60 -0
- package/dist/model-registry.js +8 -0
- package/dist/model-registry.js.map +1 -0
- package/dist/native-knowledge.d.ts +94 -0
- package/dist/native-knowledge.js +26 -0
- package/dist/native-knowledge.js.map +1 -0
- package/dist/negative.d.ts +26 -0
- package/dist/negative.js +8 -0
- package/dist/negative.js.map +1 -0
- package/dist/objective-state-writers.d.ts +22 -0
- package/dist/objective-state-writers.js +313 -0
- package/dist/objective-state-writers.js.map +1 -0
- package/dist/objective-state.d.ts +75 -0
- package/dist/objective-state.js +17 -0
- package/dist/objective-state.js.map +1 -0
- package/dist/openai-chat-compat.d.ts +13 -0
- package/dist/openai-chat-compat.js +11 -0
- package/dist/openai-chat-compat.js.map +1 -0
- package/dist/operator-toolkit.d.ts +304 -0
- package/dist/operator-toolkit.js +41 -0
- package/dist/operator-toolkit.js.map +1 -0
- package/dist/opik-exporter.d.ts +72 -0
- package/dist/opik-exporter.js +361 -0
- package/dist/opik-exporter.js.map +1 -0
- package/dist/orchestrator-zTa-Qo-1.d.ts +1104 -0
- package/dist/orchestrator.d.ts +21 -0
- package/dist/orchestrator.js +145 -0
- package/dist/orchestrator.js.map +1 -0
- package/dist/policy-runtime.d.ts +37 -0
- package/dist/policy-runtime.js +13 -0
- package/dist/policy-runtime.js.map +1 -0
- package/dist/port-C1GZFv8h.d.ts +41 -0
- package/dist/profiling.d.ts +80 -0
- package/dist/profiling.js +10 -0
- package/dist/profiling.js.map +1 -0
- package/dist/qmd-recall-cache.d.ts +29 -0
- package/dist/qmd-recall-cache.js +13 -0
- package/dist/qmd-recall-cache.js.map +1 -0
- package/dist/qmd.d.ts +105 -0
- package/dist/qmd.js +13 -0
- package/dist/qmd.js.map +1 -0
- package/dist/recall-qos.d.ts +33 -0
- package/dist/recall-qos.js +10 -0
- package/dist/recall-qos.js.map +1 -0
- package/dist/recall-query-policy.d.ts +20 -0
- package/dist/recall-query-policy.js +11 -0
- package/dist/recall-query-policy.js.map +1 -0
- package/dist/recall-state.d.ts +113 -0
- package/dist/recall-state.js +12 -0
- package/dist/recall-state.js.map +1 -0
- package/dist/recall-tokenization.d.ts +4 -0
- package/dist/recall-tokenization.js +9 -0
- package/dist/recall-tokenization.js.map +1 -0
- package/dist/reconstruct.d.ts +16 -0
- package/dist/reconstruct.js +7 -0
- package/dist/reconstruct.js.map +1 -0
- package/dist/release-changelog.d.ts +7 -0
- package/dist/release-changelog.js +30 -0
- package/dist/release-changelog.js.map +1 -0
- package/dist/relevance.d.ts +18 -0
- package/dist/relevance.js +8 -0
- package/dist/relevance.js.map +1 -0
- package/dist/rerank.d.ts +57 -0
- package/dist/rerank.js +11 -0
- package/dist/rerank.js.map +1 -0
- package/dist/resolve-provider-secret.d.ts +16 -0
- package/dist/resolve-provider-secret.js +11 -0
- package/dist/resolve-provider-secret.js.map +1 -0
- package/dist/resume-bundles.d.ts +66 -0
- package/dist/resume-bundles.js +27 -0
- package/dist/resume-bundles.js.map +1 -0
- package/dist/retrieval-agents.d.ts +129 -0
- package/dist/retrieval-agents.js +23 -0
- package/dist/retrieval-agents.js.map +1 -0
- package/dist/retrieval.d.ts +19 -0
- package/dist/retrieval.js +10 -0
- package/dist/retrieval.js.map +1 -0
- package/dist/sanitize.d.ts +9 -0
- package/dist/sanitize.js +9 -0
- package/dist/sanitize.js.map +1 -0
- package/dist/schemas.d.ts +688 -0
- package/dist/schemas.js +51 -0
- package/dist/schemas.js.map +1 -0
- package/dist/sdk-compat.d.ts +21 -0
- package/dist/sdk-compat.js +28 -0
- package/dist/sdk-compat.js.map +1 -0
- package/dist/semantic-consolidation.d.ts +42 -0
- package/dist/semantic-consolidation.js +12 -0
- package/dist/semantic-consolidation.js.map +1 -0
- package/dist/semantic-rule-promotion.d.ts +28 -0
- package/dist/semantic-rule-promotion.js +17 -0
- package/dist/semantic-rule-promotion.js.map +1 -0
- package/dist/semantic-rule-verifier.d.ts +19 -0
- package/dist/semantic-rule-verifier.js +18 -0
- package/dist/semantic-rule-verifier.js.map +1 -0
- package/dist/session-integrity.d.ts +67 -0
- package/dist/session-integrity.js +11 -0
- package/dist/session-integrity.js.map +1 -0
- package/dist/session-observer-bands.d.ts +6 -0
- package/dist/session-observer-bands.js +9 -0
- package/dist/session-observer-bands.js.map +1 -0
- package/dist/session-observer-state.d.ts +40 -0
- package/dist/session-observer-state.js +11 -0
- package/dist/session-observer-state.js.map +1 -0
- package/dist/signal.d.ts +6 -0
- package/dist/signal.js +9 -0
- package/dist/signal.js.map +1 -0
- package/dist/storage.d.ts +453 -0
- package/dist/storage.js +24 -0
- package/dist/storage.js.map +1 -0
- package/dist/store-contract.d.ts +10 -0
- package/dist/store-contract.js +21 -0
- package/dist/store-contract.js.map +1 -0
- package/dist/summarizer.d.ts +35 -0
- package/dist/summarizer.js +17 -0
- package/dist/summarizer.js.map +1 -0
- package/dist/summary-snapshot.d.ts +8 -0
- package/dist/summary-snapshot.js +13 -0
- package/dist/summary-snapshot.js.map +1 -0
- package/dist/temporal-index.d.ts +139 -0
- package/dist/temporal-index.js +29 -0
- package/dist/temporal-index.js.map +1 -0
- package/dist/threading.d.ts +62 -0
- package/dist/threading.js +8 -0
- package/dist/threading.js.map +1 -0
- package/dist/tier-migration.d.ts +44 -0
- package/dist/tier-migration.js +7 -0
- package/dist/tier-migration.js.map +1 -0
- package/dist/tier-routing.d.ts +21 -0
- package/dist/tier-routing.js +10 -0
- package/dist/tier-routing.js.map +1 -0
- package/dist/tmt.d.ts +79 -0
- package/dist/tmt.js +29 -0
- package/dist/tmt.js.map +1 -0
- package/dist/tokens.d.ts +24 -0
- package/dist/tokens.js +21 -0
- package/dist/tokens.js.map +1 -0
- package/dist/topics.d.ts +29 -0
- package/dist/topics.js +9 -0
- package/dist/topics.js.map +1 -0
- package/dist/transcript.d.ts +171 -0
- package/dist/transcript.js +9 -0
- package/dist/transcript.js.map +1 -0
- package/dist/trust-zones.d.ts +170 -0
- package/dist/trust-zones.js +32 -0
- package/dist/trust-zones.js.map +1 -0
- package/dist/types.d.ts +1243 -0
- package/dist/types.js +9 -0
- package/dist/types.js.map +1 -0
- package/dist/utility-learner.d.ts +59 -0
- package/dist/utility-learner.js +17 -0
- package/dist/utility-learner.js.map +1 -0
- package/dist/utility-runtime.d.ts +21 -0
- package/dist/utility-runtime.js +16 -0
- package/dist/utility-runtime.js.map +1 -0
- package/dist/utility-telemetry.d.ts +68 -0
- package/dist/utility-telemetry.js +17 -0
- package/dist/utility-telemetry.js.map +1 -0
- package/dist/verified-recall.d.ts +17 -0
- package/dist/verified-recall.js +19 -0
- package/dist/verified-recall.js.map +1 -0
- package/dist/version-utils.d.ts +4 -0
- package/dist/version-utils.js +7 -0
- package/dist/version-utils.js.map +1 -0
- package/dist/work-product-ledger.d.ts +65 -0
- package/dist/work-product-ledger.js +18 -0
- package/dist/work-product-ledger.js.map +1 -0
- package/package.json +58 -0
|
@@ -0,0 +1,2378 @@
|
|
|
1
|
+
import {
|
|
2
|
+
canReadNamespace,
|
|
3
|
+
canWriteNamespace,
|
|
4
|
+
resolvePrincipal
|
|
5
|
+
} from "./chunk-N5AKDXAI.js";
|
|
6
|
+
import {
|
|
7
|
+
getTrustZoneStoreStatus,
|
|
8
|
+
isTrustZoneName,
|
|
9
|
+
listTrustZoneRecords,
|
|
10
|
+
promoteTrustZoneRecord,
|
|
11
|
+
scoreTrustZoneProvenance,
|
|
12
|
+
seedTrustZoneDemoDataset,
|
|
13
|
+
summarizeTrustZonePromotionReadiness
|
|
14
|
+
} from "./chunk-EQINRHYR.js";
|
|
15
|
+
import {
|
|
16
|
+
buildProposedActions,
|
|
17
|
+
buildQualityScore,
|
|
18
|
+
groupActionsByStatus,
|
|
19
|
+
listMemoryGovernanceRuns,
|
|
20
|
+
readMemoryGovernanceRunArtifact,
|
|
21
|
+
runMemoryGovernance
|
|
22
|
+
} from "./chunk-J3BT33K7.js";
|
|
23
|
+
import {
|
|
24
|
+
wrapWorkLayerContext
|
|
25
|
+
} from "./chunk-EEQLFRUM.js";
|
|
26
|
+
import {
|
|
27
|
+
parseEntityFile
|
|
28
|
+
} from "./chunk-QWUUMMIK.js";
|
|
29
|
+
import {
|
|
30
|
+
inferMemoryStatus,
|
|
31
|
+
toMemoryPathRel
|
|
32
|
+
} from "./chunk-TP4FZJIZ.js";
|
|
33
|
+
import {
|
|
34
|
+
normalizeProjectionPreview,
|
|
35
|
+
normalizeProjectionTags
|
|
36
|
+
} from "./chunk-SCU65EZI.js";
|
|
37
|
+
import {
|
|
38
|
+
getMemoryProjectionPath
|
|
39
|
+
} from "./chunk-BOUYNNYD.js";
|
|
40
|
+
import {
|
|
41
|
+
persistExplicitCapture,
|
|
42
|
+
queueExplicitCaptureForReview,
|
|
43
|
+
validateExplicitCaptureInput
|
|
44
|
+
} from "./chunk-YNCQ7E4M.js";
|
|
45
|
+
import {
|
|
46
|
+
log
|
|
47
|
+
} from "./chunk-KWBU5S5U.js";
|
|
48
|
+
import {
|
|
49
|
+
AccessIdempotencyStore,
|
|
50
|
+
hashAccessIdempotencyPayload
|
|
51
|
+
} from "./chunk-XKECPATV.js";
|
|
52
|
+
|
|
53
|
+
// src/access-service.ts
|
|
54
|
+
import { stat } from "fs/promises";
|
|
55
|
+
|
|
56
|
+
// src/work/storage.ts
|
|
57
|
+
import path from "path";
|
|
58
|
+
import { randomUUID } from "crypto";
|
|
59
|
+
import { mkdir, readdir, readFile, rm, writeFile } from "fs/promises";
|
|
60
|
+
var TASK_TRANSITIONS = {
|
|
61
|
+
todo: /* @__PURE__ */ new Set(["in_progress", "blocked", "cancelled"]),
|
|
62
|
+
in_progress: /* @__PURE__ */ new Set(["todo", "blocked", "done", "cancelled"]),
|
|
63
|
+
blocked: /* @__PURE__ */ new Set(["todo", "in_progress", "cancelled"]),
|
|
64
|
+
done: /* @__PURE__ */ new Set(),
|
|
65
|
+
cancelled: /* @__PURE__ */ new Set()
|
|
66
|
+
};
|
|
67
|
+
function serializeFrontmatter(values) {
|
|
68
|
+
const lines = Object.entries(values).map(([k, v]) => `${k}: ${JSON.stringify(v)}`);
|
|
69
|
+
return `---
|
|
70
|
+
${lines.join("\n")}
|
|
71
|
+
---`;
|
|
72
|
+
}
|
|
73
|
+
function parseFrontmatter(raw) {
|
|
74
|
+
const match = raw.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);
|
|
75
|
+
if (!match) return null;
|
|
76
|
+
const fm = match[1] ?? "";
|
|
77
|
+
const body = match[2] ?? "";
|
|
78
|
+
const data = {};
|
|
79
|
+
for (const line of fm.split("\n")) {
|
|
80
|
+
if (!line.trim()) continue;
|
|
81
|
+
const idx = line.indexOf(":");
|
|
82
|
+
if (idx <= 0) continue;
|
|
83
|
+
const key = line.slice(0, idx).trim();
|
|
84
|
+
const rawValue = line.slice(idx + 1).trim();
|
|
85
|
+
try {
|
|
86
|
+
data[key] = JSON.parse(rawValue);
|
|
87
|
+
} catch {
|
|
88
|
+
data[key] = rawValue;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return { data, body };
|
|
92
|
+
}
|
|
93
|
+
function toSafeSlug(value) {
|
|
94
|
+
let slug = value.toLowerCase().trim().replace(/[^a-z0-9]+/g, "-");
|
|
95
|
+
let start = 0;
|
|
96
|
+
while (start < slug.length && slug[start] === "-") start++;
|
|
97
|
+
let end = slug.length;
|
|
98
|
+
while (end > start && slug[end - 1] === "-") end--;
|
|
99
|
+
return slug.slice(start, end).slice(0, 80);
|
|
100
|
+
}
|
|
101
|
+
var WORK_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9-]{0,127}$/;
|
|
102
|
+
function makeId(prefix, titleOrName, now) {
|
|
103
|
+
const slug = toSafeSlug(titleOrName) || "item";
|
|
104
|
+
const nonce = randomUUID().slice(0, 8);
|
|
105
|
+
return `${prefix}-${now.getTime()}-${slug}-${nonce}`;
|
|
106
|
+
}
|
|
107
|
+
function assertValidWorkId(id, kind) {
|
|
108
|
+
if (!WORK_ID_PATTERN.test(id)) {
|
|
109
|
+
throw new Error(`invalid ${kind} id: ${id}`);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
function ensureString(value, fallback = "") {
|
|
113
|
+
return typeof value === "string" ? value : fallback;
|
|
114
|
+
}
|
|
115
|
+
function ensureStringArray(value) {
|
|
116
|
+
if (!Array.isArray(value)) return [];
|
|
117
|
+
return value.filter((entry) => typeof entry === "string");
|
|
118
|
+
}
|
|
119
|
+
function ensureNullableString(value) {
|
|
120
|
+
return typeof value === "string" ? value : null;
|
|
121
|
+
}
|
|
122
|
+
function ensureTaskStatus(value) {
|
|
123
|
+
if (value === "todo" || value === "in_progress" || value === "blocked" || value === "done" || value === "cancelled") {
|
|
124
|
+
return value;
|
|
125
|
+
}
|
|
126
|
+
return "todo";
|
|
127
|
+
}
|
|
128
|
+
function ensureTaskPriority(value) {
|
|
129
|
+
if (value === "low" || value === "medium" || value === "high") return value;
|
|
130
|
+
return "medium";
|
|
131
|
+
}
|
|
132
|
+
function ensureProjectStatus(value) {
|
|
133
|
+
if (value === "active" || value === "on_hold" || value === "completed" || value === "archived") return value;
|
|
134
|
+
return "active";
|
|
135
|
+
}
|
|
136
|
+
var WorkStorage = class {
|
|
137
|
+
constructor(memoryDir) {
|
|
138
|
+
this.memoryDir = memoryDir;
|
|
139
|
+
this.tasksDir = path.join(memoryDir, "work", "tasks");
|
|
140
|
+
this.projectsDir = path.join(memoryDir, "work", "projects");
|
|
141
|
+
}
|
|
142
|
+
memoryDir;
|
|
143
|
+
tasksDir;
|
|
144
|
+
projectsDir;
|
|
145
|
+
async ensureDirectories() {
|
|
146
|
+
await mkdir(this.tasksDir, { recursive: true });
|
|
147
|
+
await mkdir(this.projectsDir, { recursive: true });
|
|
148
|
+
}
|
|
149
|
+
taskPath(id) {
|
|
150
|
+
assertValidWorkId(id, "task");
|
|
151
|
+
return path.join(this.tasksDir, `${id}.md`);
|
|
152
|
+
}
|
|
153
|
+
projectPath(id) {
|
|
154
|
+
assertValidWorkId(id, "project");
|
|
155
|
+
return path.join(this.projectsDir, `${id}.md`);
|
|
156
|
+
}
|
|
157
|
+
serializeTask(task) {
|
|
158
|
+
return `${serializeFrontmatter(task)}
|
|
159
|
+
|
|
160
|
+
${task.description}
|
|
161
|
+
`;
|
|
162
|
+
}
|
|
163
|
+
serializeProject(project) {
|
|
164
|
+
return `${serializeFrontmatter(project)}
|
|
165
|
+
|
|
166
|
+
${project.description}
|
|
167
|
+
`;
|
|
168
|
+
}
|
|
169
|
+
parseTask(raw) {
|
|
170
|
+
const parsed = parseFrontmatter(raw);
|
|
171
|
+
if (!parsed) return null;
|
|
172
|
+
const d = parsed.data;
|
|
173
|
+
return {
|
|
174
|
+
id: ensureString(d.id),
|
|
175
|
+
title: ensureString(d.title),
|
|
176
|
+
description: ensureString(d.description, parsed.body.trim()),
|
|
177
|
+
status: ensureTaskStatus(d.status),
|
|
178
|
+
priority: ensureTaskPriority(d.priority),
|
|
179
|
+
owner: ensureNullableString(d.owner),
|
|
180
|
+
assignee: ensureNullableString(d.assignee),
|
|
181
|
+
projectId: ensureNullableString(d.projectId),
|
|
182
|
+
tags: ensureStringArray(d.tags),
|
|
183
|
+
dueAt: ensureNullableString(d.dueAt),
|
|
184
|
+
createdAt: ensureString(d.createdAt),
|
|
185
|
+
updatedAt: ensureString(d.updatedAt)
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
parseProject(raw) {
|
|
189
|
+
const parsed = parseFrontmatter(raw);
|
|
190
|
+
if (!parsed) return null;
|
|
191
|
+
const d = parsed.data;
|
|
192
|
+
return {
|
|
193
|
+
id: ensureString(d.id),
|
|
194
|
+
name: ensureString(d.name),
|
|
195
|
+
description: ensureString(d.description, parsed.body.trim()),
|
|
196
|
+
status: ensureProjectStatus(d.status),
|
|
197
|
+
owner: ensureNullableString(d.owner),
|
|
198
|
+
tags: ensureStringArray(d.tags),
|
|
199
|
+
taskIds: ensureStringArray(d.taskIds),
|
|
200
|
+
createdAt: ensureString(d.createdAt),
|
|
201
|
+
updatedAt: ensureString(d.updatedAt)
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
async createTask(input, now = /* @__PURE__ */ new Date()) {
|
|
205
|
+
await this.ensureDirectories();
|
|
206
|
+
const timestamp = now.toISOString();
|
|
207
|
+
const task = {
|
|
208
|
+
id: input.id ?? makeId("task", input.title, now),
|
|
209
|
+
title: input.title,
|
|
210
|
+
description: input.description ?? "",
|
|
211
|
+
status: input.status ?? "todo",
|
|
212
|
+
priority: input.priority ?? "medium",
|
|
213
|
+
owner: input.owner ?? null,
|
|
214
|
+
assignee: input.assignee ?? null,
|
|
215
|
+
projectId: input.projectId ?? null,
|
|
216
|
+
tags: input.tags ?? [],
|
|
217
|
+
dueAt: input.dueAt ?? null,
|
|
218
|
+
createdAt: timestamp,
|
|
219
|
+
updatedAt: timestamp
|
|
220
|
+
};
|
|
221
|
+
if (task.projectId) {
|
|
222
|
+
const project = await this.getProject(task.projectId);
|
|
223
|
+
if (!project) {
|
|
224
|
+
throw new Error(`project not found: ${task.projectId}`);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
await writeFile(this.taskPath(task.id), this.serializeTask(task), "utf-8");
|
|
228
|
+
if (task.projectId) {
|
|
229
|
+
await this.addTaskIdToProject(task.projectId, task.id, now);
|
|
230
|
+
}
|
|
231
|
+
return task;
|
|
232
|
+
}
|
|
233
|
+
async getTask(id) {
|
|
234
|
+
try {
|
|
235
|
+
const raw = await readFile(this.taskPath(id), "utf-8");
|
|
236
|
+
return this.parseTask(raw);
|
|
237
|
+
} catch {
|
|
238
|
+
return null;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
async listTasks(filter) {
|
|
242
|
+
await this.ensureDirectories();
|
|
243
|
+
const entries = await readdir(this.tasksDir, { withFileTypes: true });
|
|
244
|
+
const out = [];
|
|
245
|
+
for (const entry of entries) {
|
|
246
|
+
if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
|
|
247
|
+
const raw = await readFile(path.join(this.tasksDir, entry.name), "utf-8");
|
|
248
|
+
const task = this.parseTask(raw);
|
|
249
|
+
if (!task) continue;
|
|
250
|
+
if (filter?.status && task.status !== filter.status) continue;
|
|
251
|
+
if (filter?.owner && task.owner !== filter.owner) continue;
|
|
252
|
+
if (filter?.assignee && task.assignee !== filter.assignee) continue;
|
|
253
|
+
if (filter?.projectId && task.projectId !== filter.projectId) continue;
|
|
254
|
+
out.push(task);
|
|
255
|
+
}
|
|
256
|
+
out.sort((a, b) => a.createdAt.localeCompare(b.createdAt));
|
|
257
|
+
return out;
|
|
258
|
+
}
|
|
259
|
+
async updateTask(id, patch, now = /* @__PURE__ */ new Date(), options) {
|
|
260
|
+
const existing = await this.getTask(id);
|
|
261
|
+
if (!existing) return null;
|
|
262
|
+
const projectIdPatched = Object.prototype.hasOwnProperty.call(patch, "projectId");
|
|
263
|
+
const statusPatched = Object.prototype.hasOwnProperty.call(patch, "status");
|
|
264
|
+
const nextProjectId = projectIdPatched ? patch.projectId ?? null : existing.projectId;
|
|
265
|
+
if (statusPatched && patch.status && existing.status !== patch.status && options?.skipStatusTransitionValidation !== true && !TASK_TRANSITIONS[existing.status].has(patch.status)) {
|
|
266
|
+
throw new Error(`invalid task status transition: ${existing.status} -> ${patch.status}`);
|
|
267
|
+
}
|
|
268
|
+
if (projectIdPatched && nextProjectId) {
|
|
269
|
+
const nextProject = await this.getProject(nextProjectId);
|
|
270
|
+
if (!nextProject) {
|
|
271
|
+
throw new Error(`project not found: ${nextProjectId}`);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
if (projectIdPatched && existing.projectId !== nextProjectId) {
|
|
275
|
+
if (existing.projectId) {
|
|
276
|
+
await this.removeTaskIdFromProject(existing.projectId, id, now);
|
|
277
|
+
}
|
|
278
|
+
if (nextProjectId) {
|
|
279
|
+
await this.addTaskIdToProject(nextProjectId, id, now);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
const next = {
|
|
283
|
+
...existing,
|
|
284
|
+
...patch,
|
|
285
|
+
projectId: nextProjectId,
|
|
286
|
+
tags: patch.tags ?? existing.tags,
|
|
287
|
+
updatedAt: now.toISOString()
|
|
288
|
+
};
|
|
289
|
+
await writeFile(this.taskPath(id), this.serializeTask(next), "utf-8");
|
|
290
|
+
return next;
|
|
291
|
+
}
|
|
292
|
+
async transitionTask(id, nextStatus, now = /* @__PURE__ */ new Date()) {
|
|
293
|
+
const existing = await this.getTask(id);
|
|
294
|
+
if (!existing) throw new Error(`task not found: ${id}`);
|
|
295
|
+
if (existing.status === nextStatus) return existing;
|
|
296
|
+
if (!TASK_TRANSITIONS[existing.status].has(nextStatus)) {
|
|
297
|
+
throw new Error(`invalid task status transition: ${existing.status} -> ${nextStatus}`);
|
|
298
|
+
}
|
|
299
|
+
const updated = await this.updateTask(id, { status: nextStatus }, now);
|
|
300
|
+
if (!updated) throw new Error(`task not found after update: ${id}`);
|
|
301
|
+
return updated;
|
|
302
|
+
}
|
|
303
|
+
async deleteTask(id) {
|
|
304
|
+
try {
|
|
305
|
+
const existing = await this.getTask(id);
|
|
306
|
+
await rm(this.taskPath(id));
|
|
307
|
+
if (existing?.projectId) {
|
|
308
|
+
await this.removeTaskIdFromProject(existing.projectId, id);
|
|
309
|
+
}
|
|
310
|
+
return true;
|
|
311
|
+
} catch {
|
|
312
|
+
return false;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
async createProject(input, now = /* @__PURE__ */ new Date()) {
|
|
316
|
+
await this.ensureDirectories();
|
|
317
|
+
const timestamp = now.toISOString();
|
|
318
|
+
const project = {
|
|
319
|
+
id: input.id ?? makeId("project", input.name, now),
|
|
320
|
+
name: input.name,
|
|
321
|
+
description: input.description ?? "",
|
|
322
|
+
status: input.status ?? "active",
|
|
323
|
+
owner: input.owner ?? null,
|
|
324
|
+
tags: input.tags ?? [],
|
|
325
|
+
taskIds: [],
|
|
326
|
+
createdAt: timestamp,
|
|
327
|
+
updatedAt: timestamp
|
|
328
|
+
};
|
|
329
|
+
await writeFile(this.projectPath(project.id), this.serializeProject(project), "utf-8");
|
|
330
|
+
return project;
|
|
331
|
+
}
|
|
332
|
+
async getProject(id) {
|
|
333
|
+
try {
|
|
334
|
+
const raw = await readFile(this.projectPath(id), "utf-8");
|
|
335
|
+
return this.parseProject(raw);
|
|
336
|
+
} catch {
|
|
337
|
+
return null;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
async listProjects() {
|
|
341
|
+
await this.ensureDirectories();
|
|
342
|
+
const entries = await readdir(this.projectsDir, { withFileTypes: true });
|
|
343
|
+
const out = [];
|
|
344
|
+
for (const entry of entries) {
|
|
345
|
+
if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
|
|
346
|
+
const raw = await readFile(path.join(this.projectsDir, entry.name), "utf-8");
|
|
347
|
+
const project = this.parseProject(raw);
|
|
348
|
+
if (project) out.push(project);
|
|
349
|
+
}
|
|
350
|
+
out.sort((a, b) => a.createdAt.localeCompare(b.createdAt));
|
|
351
|
+
return out;
|
|
352
|
+
}
|
|
353
|
+
async updateProject(id, patch, now = /* @__PURE__ */ new Date()) {
|
|
354
|
+
const existing = await this.getProject(id);
|
|
355
|
+
if (!existing) return null;
|
|
356
|
+
const next = {
|
|
357
|
+
...existing,
|
|
358
|
+
...patch,
|
|
359
|
+
tags: patch.tags ?? existing.tags,
|
|
360
|
+
taskIds: patch.taskIds ? [...patch.taskIds].sort() : existing.taskIds,
|
|
361
|
+
updatedAt: now.toISOString()
|
|
362
|
+
};
|
|
363
|
+
await writeFile(this.projectPath(id), this.serializeProject(next), "utf-8");
|
|
364
|
+
return next;
|
|
365
|
+
}
|
|
366
|
+
async deleteProject(id) {
|
|
367
|
+
try {
|
|
368
|
+
const existing = await this.getProject(id);
|
|
369
|
+
if (existing) {
|
|
370
|
+
for (const taskId of existing.taskIds) {
|
|
371
|
+
await this.updateTask(taskId, { projectId: null });
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
await rm(this.projectPath(id));
|
|
375
|
+
return true;
|
|
376
|
+
} catch {
|
|
377
|
+
return false;
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
async linkTaskToProject(taskId, projectId, now = /* @__PURE__ */ new Date()) {
|
|
381
|
+
const task = await this.getTask(taskId);
|
|
382
|
+
if (!task) throw new Error(`task not found: ${taskId}`);
|
|
383
|
+
const project = await this.getProject(projectId);
|
|
384
|
+
if (!project) throw new Error(`project not found: ${projectId}`);
|
|
385
|
+
const updatedTask = await this.updateTask(taskId, { projectId }, now);
|
|
386
|
+
if (!updatedTask) throw new Error(`task not found after update: ${taskId}`);
|
|
387
|
+
const updatedProject = await this.getProject(projectId);
|
|
388
|
+
if (!updatedProject) throw new Error(`project not found after update: ${projectId}`);
|
|
389
|
+
return { task: updatedTask, project: updatedProject };
|
|
390
|
+
}
|
|
391
|
+
async removeTaskIdFromProject(projectId, taskId, now = /* @__PURE__ */ new Date()) {
|
|
392
|
+
const project = await this.getProject(projectId);
|
|
393
|
+
if (!project) return;
|
|
394
|
+
const filtered = project.taskIds.filter((id) => id !== taskId);
|
|
395
|
+
if (filtered.length === project.taskIds.length) return;
|
|
396
|
+
await this.updateProject(projectId, { taskIds: filtered }, now);
|
|
397
|
+
}
|
|
398
|
+
async addTaskIdToProject(projectId, taskId, now = /* @__PURE__ */ new Date()) {
|
|
399
|
+
const project = await this.getProject(projectId);
|
|
400
|
+
if (!project) return;
|
|
401
|
+
const taskIds = new Set(project.taskIds);
|
|
402
|
+
taskIds.add(taskId);
|
|
403
|
+
await this.updateProject(projectId, { taskIds: Array.from(taskIds) }, now);
|
|
404
|
+
}
|
|
405
|
+
};
|
|
406
|
+
|
|
407
|
+
// src/work/board.ts
|
|
408
|
+
var BOARD_STATUS_ORDER = [
|
|
409
|
+
"todo",
|
|
410
|
+
"in_progress",
|
|
411
|
+
"blocked",
|
|
412
|
+
"done",
|
|
413
|
+
"cancelled"
|
|
414
|
+
];
|
|
415
|
+
var BOARD_STATUS_LABEL = {
|
|
416
|
+
todo: "Todo",
|
|
417
|
+
in_progress: "In Progress",
|
|
418
|
+
blocked: "Blocked",
|
|
419
|
+
done: "Done",
|
|
420
|
+
cancelled: "Cancelled"
|
|
421
|
+
};
|
|
422
|
+
var PRIORITY_WEIGHT = {
|
|
423
|
+
high: 0,
|
|
424
|
+
medium: 1,
|
|
425
|
+
low: 2
|
|
426
|
+
};
|
|
427
|
+
function stableSortTasks(tasks) {
|
|
428
|
+
return [...tasks].sort((a, b) => {
|
|
429
|
+
const priorityCmp = PRIORITY_WEIGHT[a.priority] - PRIORITY_WEIGHT[b.priority];
|
|
430
|
+
if (priorityCmp !== 0) return priorityCmp;
|
|
431
|
+
const createdCmp = a.createdAt.localeCompare(b.createdAt);
|
|
432
|
+
if (createdCmp !== 0) return createdCmp;
|
|
433
|
+
return a.id.localeCompare(b.id);
|
|
434
|
+
});
|
|
435
|
+
}
|
|
436
|
+
function projectMatches(task, projectId) {
|
|
437
|
+
if (!projectId) return true;
|
|
438
|
+
return task.projectId === projectId;
|
|
439
|
+
}
|
|
440
|
+
function assertValidImportEnums(item) {
|
|
441
|
+
if (!["todo", "in_progress", "blocked", "done", "cancelled"].includes(item.status)) {
|
|
442
|
+
throw new Error(`invalid task status in snapshot for ${item.id}: ${item.status}`);
|
|
443
|
+
}
|
|
444
|
+
if (!["low", "medium", "high"].includes(item.priority)) {
|
|
445
|
+
throw new Error(`invalid task priority in snapshot for ${item.id}: ${item.priority}`);
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
function normalizeImportedProjectId(rawValue, taskId, fallbackForUndefined) {
|
|
449
|
+
if (rawValue === void 0) return fallbackForUndefined;
|
|
450
|
+
if (rawValue === null) return null;
|
|
451
|
+
if (typeof rawValue === "string") {
|
|
452
|
+
const trimmed = rawValue.trim();
|
|
453
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
454
|
+
}
|
|
455
|
+
throw new Error(`invalid task projectId in snapshot for ${taskId}`);
|
|
456
|
+
}
|
|
457
|
+
function normalizeImportedTags(rawValue, taskId) {
|
|
458
|
+
if (rawValue === void 0 || rawValue === null) return [];
|
|
459
|
+
if (!Array.isArray(rawValue)) {
|
|
460
|
+
throw new Error(`invalid task tags in snapshot for ${taskId}`);
|
|
461
|
+
}
|
|
462
|
+
if (!rawValue.every((entry) => typeof entry === "string")) {
|
|
463
|
+
throw new Error(`invalid task tags in snapshot for ${taskId}`);
|
|
464
|
+
}
|
|
465
|
+
return [...rawValue];
|
|
466
|
+
}
|
|
467
|
+
function assertValidImportedTaskId(rawValue) {
|
|
468
|
+
if (typeof rawValue !== "string") {
|
|
469
|
+
throw new Error("invalid task id in snapshot");
|
|
470
|
+
}
|
|
471
|
+
const trimmed = rawValue.trim();
|
|
472
|
+
if (!WORK_ID_PATTERN.test(trimmed)) {
|
|
473
|
+
throw new Error(`invalid task id in snapshot: ${trimmed}`);
|
|
474
|
+
}
|
|
475
|
+
return trimmed;
|
|
476
|
+
}
|
|
477
|
+
function normalizeImportedNullableField(rawValue, taskId, fieldName, fallbackForUndefined) {
|
|
478
|
+
if (rawValue === void 0) return fallbackForUndefined;
|
|
479
|
+
if (rawValue === null) return null;
|
|
480
|
+
if (typeof rawValue === "string") return rawValue;
|
|
481
|
+
throw new Error(`invalid task ${fieldName} in snapshot for ${taskId}`);
|
|
482
|
+
}
|
|
483
|
+
function normalizeImportedTitle(rawValue, taskId) {
|
|
484
|
+
if (typeof rawValue !== "string") {
|
|
485
|
+
throw new Error(`invalid task title in snapshot for ${taskId}`);
|
|
486
|
+
}
|
|
487
|
+
const trimmed = rawValue.trim();
|
|
488
|
+
if (trimmed.length === 0) {
|
|
489
|
+
throw new Error(`invalid task title in snapshot for ${taskId}`);
|
|
490
|
+
}
|
|
491
|
+
return trimmed;
|
|
492
|
+
}
|
|
493
|
+
function normalizeImportedDescription(rawValue, taskId) {
|
|
494
|
+
if (typeof rawValue !== "string") {
|
|
495
|
+
throw new Error(`invalid task description in snapshot for ${taskId}`);
|
|
496
|
+
}
|
|
497
|
+
return rawValue;
|
|
498
|
+
}
|
|
499
|
+
function asBoardItem(task) {
|
|
500
|
+
return {
|
|
501
|
+
id: task.id,
|
|
502
|
+
title: task.title,
|
|
503
|
+
description: task.description,
|
|
504
|
+
status: task.status,
|
|
505
|
+
priority: task.priority,
|
|
506
|
+
owner: task.owner,
|
|
507
|
+
assignee: task.assignee,
|
|
508
|
+
projectId: task.projectId,
|
|
509
|
+
tags: [...task.tags],
|
|
510
|
+
dueAt: task.dueAt
|
|
511
|
+
};
|
|
512
|
+
}
|
|
513
|
+
function formatTaskLine(task) {
|
|
514
|
+
const bits = [`id:${task.id}`, `priority:${task.priority}`];
|
|
515
|
+
if (task.assignee) bits.push(`assignee:${task.assignee}`);
|
|
516
|
+
if (task.owner) bits.push(`owner:${task.owner}`);
|
|
517
|
+
if (task.dueAt) bits.push(`due:${task.dueAt}`);
|
|
518
|
+
if (task.tags.length > 0) bits.push(`tags:${task.tags.join(",")}`);
|
|
519
|
+
const checked = task.status === "done";
|
|
520
|
+
return `- [${checked ? "x" : " "}] ${task.title} \`[${bits.join(" ")}]\``;
|
|
521
|
+
}
|
|
522
|
+
async function exportWorkBoardSnapshot(options) {
|
|
523
|
+
const storage = new WorkStorage(options.memoryDir);
|
|
524
|
+
await storage.ensureDirectories();
|
|
525
|
+
const projectId = options.projectId?.trim() || void 0;
|
|
526
|
+
let project = null;
|
|
527
|
+
if (projectId) {
|
|
528
|
+
project = await storage.getProject(projectId);
|
|
529
|
+
if (!project) throw new Error(`project not found: ${projectId}`);
|
|
530
|
+
}
|
|
531
|
+
const allTasks = await storage.listTasks();
|
|
532
|
+
const filtered = stableSortTasks(allTasks.filter((task) => projectMatches(task, projectId)));
|
|
533
|
+
return {
|
|
534
|
+
version: 1,
|
|
535
|
+
generatedAt: (options.now ?? /* @__PURE__ */ new Date()).toISOString(),
|
|
536
|
+
projectId: projectId ?? null,
|
|
537
|
+
projectName: project?.name ?? null,
|
|
538
|
+
items: filtered.map(asBoardItem)
|
|
539
|
+
};
|
|
540
|
+
}
|
|
541
|
+
function renderWorkBoardMarkdown(snapshot) {
|
|
542
|
+
const lines = [];
|
|
543
|
+
lines.push("# Work Board");
|
|
544
|
+
lines.push("");
|
|
545
|
+
lines.push(`Generated: ${snapshot.generatedAt}`);
|
|
546
|
+
lines.push(`Project: ${snapshot.projectName ?? "all"} (${snapshot.projectId ?? "all"})`);
|
|
547
|
+
lines.push("");
|
|
548
|
+
for (const status of BOARD_STATUS_ORDER) {
|
|
549
|
+
const bucket = snapshot.items.filter((item) => item.status === status);
|
|
550
|
+
lines.push(`## ${BOARD_STATUS_LABEL[status]} (${bucket.length})`);
|
|
551
|
+
if (bucket.length === 0) {
|
|
552
|
+
lines.push("_none_");
|
|
553
|
+
} else {
|
|
554
|
+
for (const item of bucket) {
|
|
555
|
+
lines.push(formatTaskLine(item));
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
lines.push("");
|
|
559
|
+
}
|
|
560
|
+
return `${lines.join("\n").trim()}
|
|
561
|
+
`;
|
|
562
|
+
}
|
|
563
|
+
async function exportWorkBoardMarkdown(options) {
|
|
564
|
+
const snapshot = await exportWorkBoardSnapshot(options);
|
|
565
|
+
return renderWorkBoardMarkdown(snapshot);
|
|
566
|
+
}
|
|
567
|
+
async function importWorkBoardSnapshot(options) {
|
|
568
|
+
if (options.snapshot.version !== 1) {
|
|
569
|
+
throw new Error(`unsupported work board snapshot version: ${options.snapshot.version}`);
|
|
570
|
+
}
|
|
571
|
+
const storage = new WorkStorage(options.memoryDir);
|
|
572
|
+
await storage.ensureDirectories();
|
|
573
|
+
const forcedProjectId = options.projectId === void 0 ? void 0 : options.projectId?.trim() || null;
|
|
574
|
+
const snapshotProjectId = normalizeImportedProjectId(
|
|
575
|
+
options.snapshot.projectId,
|
|
576
|
+
"snapshot",
|
|
577
|
+
null
|
|
578
|
+
);
|
|
579
|
+
const preparedRows = [];
|
|
580
|
+
const seenItemIds = /* @__PURE__ */ new Set();
|
|
581
|
+
for (const item of options.snapshot.items) {
|
|
582
|
+
const id = assertValidImportedTaskId(item.id);
|
|
583
|
+
if (seenItemIds.has(id)) {
|
|
584
|
+
throw new Error(`duplicate task id in snapshot: ${id}`);
|
|
585
|
+
}
|
|
586
|
+
seenItemIds.add(id);
|
|
587
|
+
assertValidImportEnums(item);
|
|
588
|
+
const existing = await storage.getTask(id);
|
|
589
|
+
const title = normalizeImportedTitle(item.title, id);
|
|
590
|
+
const description = normalizeImportedDescription(item.description, id);
|
|
591
|
+
const fallbackProjectId = existing ? existing.projectId : snapshotProjectId;
|
|
592
|
+
const projectId = forcedProjectId === void 0 ? normalizeImportedProjectId(
|
|
593
|
+
item.projectId,
|
|
594
|
+
item.id,
|
|
595
|
+
fallbackProjectId
|
|
596
|
+
) : forcedProjectId;
|
|
597
|
+
const hasTagsField = Object.prototype.hasOwnProperty.call(
|
|
598
|
+
item,
|
|
599
|
+
"tags"
|
|
600
|
+
);
|
|
601
|
+
const tags = hasTagsField ? normalizeImportedTags(item.tags, item.id) : existing ? [...existing.tags] : [];
|
|
602
|
+
const owner = normalizeImportedNullableField(
|
|
603
|
+
item.owner,
|
|
604
|
+
id,
|
|
605
|
+
"owner",
|
|
606
|
+
existing?.owner ?? null
|
|
607
|
+
);
|
|
608
|
+
const assignee = normalizeImportedNullableField(
|
|
609
|
+
item.assignee,
|
|
610
|
+
id,
|
|
611
|
+
"assignee",
|
|
612
|
+
existing?.assignee ?? null
|
|
613
|
+
);
|
|
614
|
+
const dueAt = normalizeImportedNullableField(
|
|
615
|
+
item.dueAt,
|
|
616
|
+
id,
|
|
617
|
+
"dueAt",
|
|
618
|
+
existing?.dueAt ?? null
|
|
619
|
+
);
|
|
620
|
+
preparedRows.push({ item, existing, id, title, description, projectId, tags, owner, assignee, dueAt });
|
|
621
|
+
}
|
|
622
|
+
const projectIdsToValidate = new Set(
|
|
623
|
+
preparedRows.map((row) => row.projectId).filter((projectId) => typeof projectId === "string")
|
|
624
|
+
);
|
|
625
|
+
for (const projectId of projectIdsToValidate) {
|
|
626
|
+
const project = await storage.getProject(projectId);
|
|
627
|
+
if (!project) throw new Error(`project not found: ${projectId}`);
|
|
628
|
+
}
|
|
629
|
+
let created = 0;
|
|
630
|
+
let updated = 0;
|
|
631
|
+
for (const row of preparedRows) {
|
|
632
|
+
const { item, existing, id, title, description, projectId, tags, owner, assignee, dueAt } = row;
|
|
633
|
+
if (existing) {
|
|
634
|
+
await storage.updateTask(id, {
|
|
635
|
+
title,
|
|
636
|
+
description,
|
|
637
|
+
status: item.status,
|
|
638
|
+
priority: item.priority,
|
|
639
|
+
owner,
|
|
640
|
+
assignee,
|
|
641
|
+
projectId,
|
|
642
|
+
tags,
|
|
643
|
+
dueAt
|
|
644
|
+
}, options.now, { skipStatusTransitionValidation: true });
|
|
645
|
+
updated += 1;
|
|
646
|
+
continue;
|
|
647
|
+
}
|
|
648
|
+
await storage.createTask({
|
|
649
|
+
id,
|
|
650
|
+
title,
|
|
651
|
+
description,
|
|
652
|
+
status: item.status,
|
|
653
|
+
priority: item.priority,
|
|
654
|
+
owner,
|
|
655
|
+
assignee,
|
|
656
|
+
projectId,
|
|
657
|
+
tags,
|
|
658
|
+
dueAt
|
|
659
|
+
}, options.now);
|
|
660
|
+
created += 1;
|
|
661
|
+
}
|
|
662
|
+
return { created, updated };
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
// src/access-service.ts
|
|
666
|
+
var EngramAccessInputError = class extends Error {
|
|
667
|
+
};
|
|
668
|
+
function normalizeTrustZoneInputError(error) {
|
|
669
|
+
const message = error instanceof Error ? error.message : null;
|
|
670
|
+
if (!message) {
|
|
671
|
+
return null;
|
|
672
|
+
}
|
|
673
|
+
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)) {
|
|
674
|
+
return new EngramAccessInputError(message);
|
|
675
|
+
}
|
|
676
|
+
return null;
|
|
677
|
+
}
|
|
678
|
+
var ENGRAM_ACCESS_WRITE_SCHEMA_VERSION = 1;
|
|
679
|
+
async function buildProjectedGovernanceProposedActions(storage, projected) {
|
|
680
|
+
const reviewQueue = projected.reviewQueueRows.map((row) => ({
|
|
681
|
+
entryId: row.entryId,
|
|
682
|
+
memoryId: row.memoryId,
|
|
683
|
+
path: row.path,
|
|
684
|
+
reasonCode: row.reasonCode,
|
|
685
|
+
severity: row.severity,
|
|
686
|
+
suggestedAction: row.suggestedAction,
|
|
687
|
+
suggestedStatus: row.suggestedStatus,
|
|
688
|
+
relatedMemoryIds: row.relatedMemoryIds
|
|
689
|
+
}));
|
|
690
|
+
const memories = (await Promise.all(projected.reviewQueueRows.map((row) => storage.getMemoryById(row.memoryId)))).filter((memory) => Boolean(memory));
|
|
691
|
+
return buildProposedActions(reviewQueue, memories);
|
|
692
|
+
}
|
|
693
|
+
function hasGroupedGovernanceActions(grouped) {
|
|
694
|
+
if (!grouped) return false;
|
|
695
|
+
return Object.values(grouped).some((actions) => Array.isArray(actions) && actions.length > 0);
|
|
696
|
+
}
|
|
697
|
+
function normalizePagination(limit, offset) {
|
|
698
|
+
const normalizedLimit = Number.isFinite(limit) ? Math.max(1, Math.min(200, Math.floor(limit ?? 50))) : 50;
|
|
699
|
+
const normalizedOffset = Number.isFinite(offset) ? Math.max(0, Math.floor(offset ?? 0)) : 0;
|
|
700
|
+
return { limit: normalizedLimit, offset: normalizedOffset };
|
|
701
|
+
}
|
|
702
|
+
function normalizeBrowseSort(sort) {
|
|
703
|
+
switch (sort) {
|
|
704
|
+
case "updated_asc":
|
|
705
|
+
case "created_desc":
|
|
706
|
+
case "created_asc":
|
|
707
|
+
return sort;
|
|
708
|
+
case "updated_desc":
|
|
709
|
+
default:
|
|
710
|
+
return "updated_desc";
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
function bucketMemoryAge(referenceIso, nowMs) {
|
|
714
|
+
const referenceMs = referenceIso ? Date.parse(referenceIso) : Number.NaN;
|
|
715
|
+
if (!Number.isFinite(referenceMs)) return "unknown";
|
|
716
|
+
const ageDays = Math.floor((nowMs - referenceMs) / 864e5);
|
|
717
|
+
if (ageDays <= 7) return "0_7_days";
|
|
718
|
+
if (ageDays <= 30) return "8_30_days";
|
|
719
|
+
if (ageDays <= 90) return "31_90_days";
|
|
720
|
+
return "91_plus_days";
|
|
721
|
+
}
|
|
722
|
+
function incrementCount(counts, key) {
|
|
723
|
+
counts[key] = (counts[key] ?? 0) + 1;
|
|
724
|
+
}
|
|
725
|
+
function summarizeTrustZoneRecord(record, filePath, allRecords, poisoningDefenseEnabled, trustZonesEnabled, promotionEnabled) {
|
|
726
|
+
const trustScore = poisoningDefenseEnabled ? scoreTrustZoneProvenance(record) : void 0;
|
|
727
|
+
const readiness = summarizeTrustZonePromotionReadiness({
|
|
728
|
+
record,
|
|
729
|
+
allRecords,
|
|
730
|
+
poisoningDefenseEnabled
|
|
731
|
+
});
|
|
732
|
+
const promotionReasons = [...readiness.reasons];
|
|
733
|
+
const promotionAllowed = readiness.allowed && trustZonesEnabled === true && promotionEnabled === true;
|
|
734
|
+
if (trustZonesEnabled !== true) {
|
|
735
|
+
promotionReasons.push("trust zone promotion requires trustZonesEnabled=true");
|
|
736
|
+
}
|
|
737
|
+
if (promotionEnabled !== true) {
|
|
738
|
+
promotionReasons.push("trust zone promotion requires quarantinePromotionEnabled=true");
|
|
739
|
+
}
|
|
740
|
+
return {
|
|
741
|
+
recordId: record.recordId,
|
|
742
|
+
filePath,
|
|
743
|
+
zone: record.zone,
|
|
744
|
+
recordedAt: record.recordedAt,
|
|
745
|
+
kind: record.kind,
|
|
746
|
+
summary: record.summary,
|
|
747
|
+
sourceClass: record.provenance.sourceClass,
|
|
748
|
+
sessionKey: record.provenance.sessionKey,
|
|
749
|
+
sourceId: record.provenance.sourceId,
|
|
750
|
+
evidenceHashPresent: typeof record.provenance.evidenceHash === "string",
|
|
751
|
+
anchored: Boolean(record.provenance.sourceId && record.provenance.evidenceHash),
|
|
752
|
+
entityRefs: [...record.entityRefs ?? []],
|
|
753
|
+
tags: [...record.tags ?? []],
|
|
754
|
+
metadata: record.metadata,
|
|
755
|
+
trustScore,
|
|
756
|
+
nextPromotionTarget: readiness.nextTargetZone,
|
|
757
|
+
nextPromotionAllowed: promotionAllowed,
|
|
758
|
+
nextPromotionReasons: promotionReasons,
|
|
759
|
+
corroborationCount: readiness.requiresCorroboration ? readiness.corroborationCount : void 0,
|
|
760
|
+
corroborationSourceClasses: readiness.requiresCorroboration ? readiness.corroborationSourceClasses : void 0
|
|
761
|
+
};
|
|
762
|
+
}
|
|
763
|
+
function compareBrowseMemory(sort, left, right) {
|
|
764
|
+
const leftUpdated = left.frontmatter.updated ?? left.frontmatter.created ?? "";
|
|
765
|
+
const rightUpdated = right.frontmatter.updated ?? right.frontmatter.created ?? "";
|
|
766
|
+
const leftCreated = left.frontmatter.created ?? "";
|
|
767
|
+
const rightCreated = right.frontmatter.created ?? "";
|
|
768
|
+
switch (sort) {
|
|
769
|
+
case "updated_asc":
|
|
770
|
+
return leftUpdated.localeCompare(rightUpdated) || leftCreated.localeCompare(rightCreated) || left.frontmatter.id.localeCompare(right.frontmatter.id);
|
|
771
|
+
case "created_desc":
|
|
772
|
+
return rightCreated.localeCompare(leftCreated) || rightUpdated.localeCompare(leftUpdated) || left.frontmatter.id.localeCompare(right.frontmatter.id);
|
|
773
|
+
case "created_asc":
|
|
774
|
+
return leftCreated.localeCompare(rightCreated) || leftUpdated.localeCompare(rightUpdated) || left.frontmatter.id.localeCompare(right.frontmatter.id);
|
|
775
|
+
case "updated_desc":
|
|
776
|
+
default:
|
|
777
|
+
return rightUpdated.localeCompare(leftUpdated) || rightCreated.localeCompare(leftCreated) || left.frontmatter.id.localeCompare(right.frontmatter.id);
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
var EngramAccessService = class {
|
|
781
|
+
constructor(orchestrator) {
|
|
782
|
+
this.orchestrator = orchestrator;
|
|
783
|
+
this.idempotency = new AccessIdempotencyStore(orchestrator.config.memoryDir);
|
|
784
|
+
}
|
|
785
|
+
orchestrator;
|
|
786
|
+
idempotency;
|
|
787
|
+
idempotencyLocks = /* @__PURE__ */ new Map();
|
|
788
|
+
resolveNamespace(namespace) {
|
|
789
|
+
const requested = namespace?.trim();
|
|
790
|
+
if (!requested) return this.orchestrator.config.defaultNamespace;
|
|
791
|
+
if (!this.orchestrator.config.namespacesEnabled && requested !== this.orchestrator.config.defaultNamespace) {
|
|
792
|
+
throw new EngramAccessInputError(`unsupported namespace: ${requested}`);
|
|
793
|
+
}
|
|
794
|
+
return requested;
|
|
795
|
+
}
|
|
796
|
+
normalizeRecallMode(mode) {
|
|
797
|
+
if (!mode || mode === "auto") return void 0;
|
|
798
|
+
if (mode === "no_recall" || mode === "minimal" || mode === "full" || mode === "graph_mode") {
|
|
799
|
+
return mode;
|
|
800
|
+
}
|
|
801
|
+
throw new EngramAccessInputError(`unsupported recall mode: ${mode}`);
|
|
802
|
+
}
|
|
803
|
+
resolveRecallNamespace(namespace, sessionKey) {
|
|
804
|
+
const requested = namespace?.trim();
|
|
805
|
+
if (!requested) return void 0;
|
|
806
|
+
const resolved = this.resolveNamespace(requested);
|
|
807
|
+
const principal = resolvePrincipal(sessionKey, this.orchestrator.config);
|
|
808
|
+
if (!canReadNamespace(principal, resolved, this.orchestrator.config)) {
|
|
809
|
+
throw new EngramAccessInputError(`namespace override is not readable: ${resolved}`);
|
|
810
|
+
}
|
|
811
|
+
return resolved;
|
|
812
|
+
}
|
|
813
|
+
resolveWritePrincipal(sessionKey, authenticatedPrincipal) {
|
|
814
|
+
const trusted = authenticatedPrincipal?.trim();
|
|
815
|
+
if (trusted) return trusted;
|
|
816
|
+
return resolvePrincipal(sessionKey, this.orchestrator.config);
|
|
817
|
+
}
|
|
818
|
+
resolveWritableNamespace(namespace, sessionKey, authenticatedPrincipal) {
|
|
819
|
+
const resolved = this.resolveNamespace(namespace);
|
|
820
|
+
const principal = this.resolveWritePrincipal(sessionKey, authenticatedPrincipal);
|
|
821
|
+
if (!canWriteNamespace(principal, resolved, this.orchestrator.config)) {
|
|
822
|
+
throw new EngramAccessInputError(`namespace is not writable: ${resolved}`);
|
|
823
|
+
}
|
|
824
|
+
return resolved;
|
|
825
|
+
}
|
|
826
|
+
resolveReadableNamespace(namespace, principal) {
|
|
827
|
+
const resolved = this.resolveNamespace(namespace);
|
|
828
|
+
if (principal && !canReadNamespace(principal, resolved, this.orchestrator.config)) {
|
|
829
|
+
throw new EngramAccessInputError(`namespace is not readable: ${resolved}`);
|
|
830
|
+
}
|
|
831
|
+
return resolved;
|
|
832
|
+
}
|
|
833
|
+
async buildRecallDebug(snapshot, namespace, includeDebug, sessionKey) {
|
|
834
|
+
if (!includeDebug) return void 0;
|
|
835
|
+
if (!sessionKey?.trim()) return void 0;
|
|
836
|
+
const [intent, graph] = await Promise.all([
|
|
837
|
+
this.orchestrator.getLastIntentSnapshot(namespace),
|
|
838
|
+
this.orchestrator.getLastGraphRecallSnapshot(namespace)
|
|
839
|
+
]);
|
|
840
|
+
return snapshot || intent || graph ? {
|
|
841
|
+
snapshot: snapshot ?? void 0,
|
|
842
|
+
intent,
|
|
843
|
+
graph
|
|
844
|
+
} : void 0;
|
|
845
|
+
}
|
|
846
|
+
async serializeRecallResults(snapshot) {
|
|
847
|
+
if (!snapshot) return [];
|
|
848
|
+
const namespace = snapshot.namespace ? this.resolveNamespace(snapshot.namespace) : this.orchestrator.config.defaultNamespace;
|
|
849
|
+
const storage = await this.orchestrator.getStorage(namespace);
|
|
850
|
+
const storageDir = storage.dir;
|
|
851
|
+
const results = [];
|
|
852
|
+
const seen = /* @__PURE__ */ new Set();
|
|
853
|
+
for (const memoryPath of snapshot.resultPaths ?? []) {
|
|
854
|
+
if (!memoryPath || seen.has(memoryPath)) continue;
|
|
855
|
+
const memory = await storage.readMemoryByPath(memoryPath);
|
|
856
|
+
if (!memory) continue;
|
|
857
|
+
seen.add(memoryPath);
|
|
858
|
+
results.push(this.serializeMemorySummary(memory, storageDir));
|
|
859
|
+
}
|
|
860
|
+
if (results.length > 0) return results;
|
|
861
|
+
for (const memoryId of snapshot.memoryIds) {
|
|
862
|
+
const memory = await storage.getMemoryById(memoryId);
|
|
863
|
+
if (!memory || seen.has(memory.path)) continue;
|
|
864
|
+
seen.add(memory.path);
|
|
865
|
+
results.push(this.serializeMemorySummary(memory, storageDir));
|
|
866
|
+
}
|
|
867
|
+
return results;
|
|
868
|
+
}
|
|
869
|
+
async handleIdempotentWrite(options) {
|
|
870
|
+
if (options.skip === true) {
|
|
871
|
+
return options.execute();
|
|
872
|
+
}
|
|
873
|
+
const key = options.idempotencyKey?.trim();
|
|
874
|
+
if (!key) {
|
|
875
|
+
return options.execute();
|
|
876
|
+
}
|
|
877
|
+
return this.withIdempotencyLock(key, async () => {
|
|
878
|
+
return this.idempotency.withKeyLock(key, async () => {
|
|
879
|
+
const requestHash = hashAccessIdempotencyPayload({
|
|
880
|
+
operation: options.operation,
|
|
881
|
+
request: options.requestFingerprint
|
|
882
|
+
});
|
|
883
|
+
const existing = await this.idempotency.get(key, requestHash);
|
|
884
|
+
if (existing.conflict) {
|
|
885
|
+
throw new EngramAccessInputError(`idempotencyKey reuse conflict: ${key}`);
|
|
886
|
+
}
|
|
887
|
+
if (existing.response) {
|
|
888
|
+
return {
|
|
889
|
+
...existing.response,
|
|
890
|
+
idempotencyReplay: true
|
|
891
|
+
};
|
|
892
|
+
}
|
|
893
|
+
const response = await options.execute();
|
|
894
|
+
await this.idempotency.put(key, requestHash, response);
|
|
895
|
+
return response;
|
|
896
|
+
});
|
|
897
|
+
});
|
|
898
|
+
}
|
|
899
|
+
async peekIdempotentWrite(options) {
|
|
900
|
+
if (options.skip === true) {
|
|
901
|
+
return "miss";
|
|
902
|
+
}
|
|
903
|
+
const key = options.idempotencyKey?.trim();
|
|
904
|
+
if (!key) {
|
|
905
|
+
return "miss";
|
|
906
|
+
}
|
|
907
|
+
return this.withIdempotencyLock(key, async () => {
|
|
908
|
+
return this.idempotency.withKeyLock(key, async () => {
|
|
909
|
+
const requestHash = hashAccessIdempotencyPayload({
|
|
910
|
+
operation: options.operation,
|
|
911
|
+
request: options.requestFingerprint
|
|
912
|
+
});
|
|
913
|
+
const existing = await this.idempotency.get(key, requestHash);
|
|
914
|
+
if (existing.conflict) {
|
|
915
|
+
return "conflict";
|
|
916
|
+
}
|
|
917
|
+
return existing.response ? "replay" : "miss";
|
|
918
|
+
});
|
|
919
|
+
});
|
|
920
|
+
}
|
|
921
|
+
async withIdempotencyLock(key, fn) {
|
|
922
|
+
const previous = this.idempotencyLocks.get(key) ?? Promise.resolve();
|
|
923
|
+
let release;
|
|
924
|
+
const current = new Promise((resolve) => {
|
|
925
|
+
release = resolve;
|
|
926
|
+
});
|
|
927
|
+
const queued = previous.then(() => current, () => current);
|
|
928
|
+
this.idempotencyLocks.set(key, queued);
|
|
929
|
+
await previous.catch(() => {
|
|
930
|
+
});
|
|
931
|
+
try {
|
|
932
|
+
return await fn();
|
|
933
|
+
} finally {
|
|
934
|
+
release();
|
|
935
|
+
if (this.idempotencyLocks.get(key) === queued) {
|
|
936
|
+
this.idempotencyLocks.delete(key);
|
|
937
|
+
}
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
async health(namespace) {
|
|
941
|
+
const resolvedNamespace = this.resolveNamespace(namespace);
|
|
942
|
+
const storage = await this.orchestrator.getStorage(resolvedNamespace);
|
|
943
|
+
let projectionAvailable = false;
|
|
944
|
+
try {
|
|
945
|
+
await stat(getMemoryProjectionPath(storage.dir));
|
|
946
|
+
projectionAvailable = true;
|
|
947
|
+
} catch {
|
|
948
|
+
projectionAvailable = false;
|
|
949
|
+
}
|
|
950
|
+
return {
|
|
951
|
+
ok: true,
|
|
952
|
+
memoryDir: storage.dir,
|
|
953
|
+
namespacesEnabled: this.orchestrator.config.namespacesEnabled === true,
|
|
954
|
+
defaultNamespace: this.orchestrator.config.defaultNamespace,
|
|
955
|
+
searchBackend: this.orchestrator.config.searchBackend ?? "qmd",
|
|
956
|
+
qmdEnabled: this.orchestrator.config.qmdEnabled === true,
|
|
957
|
+
nativeKnowledgeEnabled: this.orchestrator.config.nativeKnowledge?.enabled === true,
|
|
958
|
+
projectionAvailable
|
|
959
|
+
};
|
|
960
|
+
}
|
|
961
|
+
async daySummary(request) {
|
|
962
|
+
if (!this.orchestrator.config.daySummaryEnabled) {
|
|
963
|
+
throw new EngramAccessInputError("day summary is disabled");
|
|
964
|
+
}
|
|
965
|
+
const memories = (request.memories ?? "").trim();
|
|
966
|
+
const namespace = this.resolveRecallNamespace(request.namespace, request.sessionKey);
|
|
967
|
+
if (memories.length === 0) {
|
|
968
|
+
return this.orchestrator.generateDaySummaryAuto(namespace);
|
|
969
|
+
}
|
|
970
|
+
return this.orchestrator.generateDaySummary(memories);
|
|
971
|
+
}
|
|
972
|
+
async recall(request) {
|
|
973
|
+
const query = request.query.trim();
|
|
974
|
+
if (query.length === 0) {
|
|
975
|
+
throw new EngramAccessInputError("query is required");
|
|
976
|
+
}
|
|
977
|
+
const namespaceOverride = this.resolveRecallNamespace(request.namespace, request.sessionKey);
|
|
978
|
+
const namespace = namespaceOverride ?? this.orchestrator.config.defaultNamespace;
|
|
979
|
+
const mode = this.normalizeRecallMode(request.mode);
|
|
980
|
+
const topK = Number.isFinite(request.topK) ? Math.max(0, Math.floor(request.topK ?? 0)) : void 0;
|
|
981
|
+
const recallOptions = {
|
|
982
|
+
namespace: namespaceOverride,
|
|
983
|
+
topK,
|
|
984
|
+
mode
|
|
985
|
+
};
|
|
986
|
+
const startedAt = Date.now();
|
|
987
|
+
const context = await this.orchestrator.recall(query, request.sessionKey, recallOptions);
|
|
988
|
+
const snapshot = request.sessionKey ? this.orchestrator.lastRecall.get(request.sessionKey) : null;
|
|
989
|
+
const effectiveNamespace = snapshot?.namespace ? this.resolveNamespace(snapshot.namespace) : namespace;
|
|
990
|
+
const results = await this.serializeRecallResults(snapshot);
|
|
991
|
+
const debug = await this.buildRecallDebug(
|
|
992
|
+
snapshot,
|
|
993
|
+
effectiveNamespace,
|
|
994
|
+
request.includeDebug === true,
|
|
995
|
+
request.sessionKey
|
|
996
|
+
);
|
|
997
|
+
return {
|
|
998
|
+
query,
|
|
999
|
+
sessionKey: request.sessionKey,
|
|
1000
|
+
namespace: effectiveNamespace,
|
|
1001
|
+
context,
|
|
1002
|
+
count: snapshot?.memoryIds.length ?? results.length,
|
|
1003
|
+
memoryIds: snapshot?.memoryIds ?? [],
|
|
1004
|
+
results,
|
|
1005
|
+
recordedAt: snapshot?.recordedAt,
|
|
1006
|
+
traceId: snapshot?.traceId,
|
|
1007
|
+
plannerMode: snapshot?.plannerMode ?? mode,
|
|
1008
|
+
fallbackUsed: snapshot?.fallbackUsed ?? false,
|
|
1009
|
+
sourcesUsed: snapshot?.sourcesUsed ?? [],
|
|
1010
|
+
budgetsApplied: snapshot?.budgetsApplied,
|
|
1011
|
+
latencyMs: snapshot?.latencyMs ?? Date.now() - startedAt,
|
|
1012
|
+
debug
|
|
1013
|
+
};
|
|
1014
|
+
}
|
|
1015
|
+
async recallExplain(request = {}) {
|
|
1016
|
+
const requestedNamespace = request.namespace?.trim() ? this.resolveNamespace(request.namespace) : void 0;
|
|
1017
|
+
if (requestedNamespace) {
|
|
1018
|
+
const principal = resolvePrincipal(request.sessionKey, this.orchestrator.config);
|
|
1019
|
+
if (!canReadNamespace(principal, requestedNamespace, this.orchestrator.config)) {
|
|
1020
|
+
return { found: false };
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
const snapshot = request.sessionKey ? (() => {
|
|
1024
|
+
const candidate = this.orchestrator.lastRecall.get(request.sessionKey);
|
|
1025
|
+
if (!candidate) return null;
|
|
1026
|
+
if (!requestedNamespace) return candidate;
|
|
1027
|
+
return candidate.namespace === requestedNamespace ? candidate : null;
|
|
1028
|
+
})() : (() => {
|
|
1029
|
+
const candidate = this.orchestrator.lastRecall.getMostRecent();
|
|
1030
|
+
if (!candidate) return null;
|
|
1031
|
+
if (!requestedNamespace) return candidate;
|
|
1032
|
+
return candidate.namespace === requestedNamespace ? candidate : null;
|
|
1033
|
+
})();
|
|
1034
|
+
const namespace = requestedNamespace ?? snapshot?.namespace ?? this.orchestrator.config.defaultNamespace;
|
|
1035
|
+
const [intent, graph] = await Promise.all([
|
|
1036
|
+
this.orchestrator.getLastIntentSnapshot(namespace),
|
|
1037
|
+
this.orchestrator.getLastGraphRecallSnapshot(namespace)
|
|
1038
|
+
]);
|
|
1039
|
+
if (!snapshot && !intent && !graph) return { found: false };
|
|
1040
|
+
return { found: true, snapshot: snapshot ?? void 0, intent, graph };
|
|
1041
|
+
}
|
|
1042
|
+
async memoryStore(request) {
|
|
1043
|
+
const namespace = this.resolveWritableNamespace(
|
|
1044
|
+
request.namespace,
|
|
1045
|
+
request.sessionKey,
|
|
1046
|
+
request.authenticatedPrincipal
|
|
1047
|
+
);
|
|
1048
|
+
const schemaVersion = request.schemaVersion ?? ENGRAM_ACCESS_WRITE_SCHEMA_VERSION;
|
|
1049
|
+
if (schemaVersion !== ENGRAM_ACCESS_WRITE_SCHEMA_VERSION) {
|
|
1050
|
+
throw new EngramAccessInputError(`unsupported schemaVersion: ${schemaVersion}`);
|
|
1051
|
+
}
|
|
1052
|
+
const execute = async () => {
|
|
1053
|
+
const candidate = this.validateWriteCandidate(request, namespace);
|
|
1054
|
+
if (request.dryRun === true) {
|
|
1055
|
+
return {
|
|
1056
|
+
schemaVersion: ENGRAM_ACCESS_WRITE_SCHEMA_VERSION,
|
|
1057
|
+
operation: "memory_store",
|
|
1058
|
+
namespace,
|
|
1059
|
+
dryRun: true,
|
|
1060
|
+
accepted: true,
|
|
1061
|
+
queued: false,
|
|
1062
|
+
status: "validated",
|
|
1063
|
+
idempotencyKey: request.idempotencyKey?.trim() || void 0
|
|
1064
|
+
};
|
|
1065
|
+
}
|
|
1066
|
+
const result = await persistExplicitCapture(this.orchestrator, candidate, "memory_store");
|
|
1067
|
+
const response = {
|
|
1068
|
+
schemaVersion: ENGRAM_ACCESS_WRITE_SCHEMA_VERSION,
|
|
1069
|
+
operation: "memory_store",
|
|
1070
|
+
namespace,
|
|
1071
|
+
dryRun: false,
|
|
1072
|
+
accepted: true,
|
|
1073
|
+
queued: false,
|
|
1074
|
+
status: result.duplicateOf ? "duplicate" : "stored",
|
|
1075
|
+
memoryId: result.id,
|
|
1076
|
+
duplicateOf: result.duplicateOf,
|
|
1077
|
+
idempotencyKey: request.idempotencyKey?.trim() || void 0
|
|
1078
|
+
};
|
|
1079
|
+
log.info(
|
|
1080
|
+
`access-write op=memory_store namespace=${namespace} dryRun=false status=${response.status} memoryId=${response.memoryId ?? "-"} idempotency=${response.idempotencyKey ? "yes" : "no"}`
|
|
1081
|
+
);
|
|
1082
|
+
return response;
|
|
1083
|
+
};
|
|
1084
|
+
return this.handleIdempotentWrite({
|
|
1085
|
+
operation: "memory_store",
|
|
1086
|
+
idempotencyKey: request.idempotencyKey,
|
|
1087
|
+
requestFingerprint: {
|
|
1088
|
+
schemaVersion,
|
|
1089
|
+
content: request.content,
|
|
1090
|
+
category: request.category,
|
|
1091
|
+
confidence: request.confidence,
|
|
1092
|
+
namespace,
|
|
1093
|
+
tags: request.tags,
|
|
1094
|
+
entityRef: request.entityRef,
|
|
1095
|
+
ttl: request.ttl,
|
|
1096
|
+
sourceReason: request.sourceReason
|
|
1097
|
+
},
|
|
1098
|
+
skip: request.dryRun === true,
|
|
1099
|
+
execute
|
|
1100
|
+
});
|
|
1101
|
+
}
|
|
1102
|
+
async peekMemoryStoreIdempotency(request) {
|
|
1103
|
+
const namespace = this.resolveWritableNamespace(
|
|
1104
|
+
request.namespace,
|
|
1105
|
+
request.sessionKey,
|
|
1106
|
+
request.authenticatedPrincipal
|
|
1107
|
+
);
|
|
1108
|
+
const schemaVersion = request.schemaVersion ?? ENGRAM_ACCESS_WRITE_SCHEMA_VERSION;
|
|
1109
|
+
if (schemaVersion !== ENGRAM_ACCESS_WRITE_SCHEMA_VERSION) {
|
|
1110
|
+
throw new EngramAccessInputError(`unsupported schemaVersion: ${schemaVersion}`);
|
|
1111
|
+
}
|
|
1112
|
+
return this.peekIdempotentWrite({
|
|
1113
|
+
operation: "memory_store",
|
|
1114
|
+
idempotencyKey: request.idempotencyKey,
|
|
1115
|
+
requestFingerprint: {
|
|
1116
|
+
schemaVersion,
|
|
1117
|
+
content: request.content,
|
|
1118
|
+
category: request.category,
|
|
1119
|
+
confidence: request.confidence,
|
|
1120
|
+
namespace,
|
|
1121
|
+
tags: request.tags,
|
|
1122
|
+
entityRef: request.entityRef,
|
|
1123
|
+
ttl: request.ttl,
|
|
1124
|
+
sourceReason: request.sourceReason
|
|
1125
|
+
},
|
|
1126
|
+
skip: request.dryRun === true
|
|
1127
|
+
});
|
|
1128
|
+
}
|
|
1129
|
+
async suggestionSubmit(request) {
|
|
1130
|
+
const namespace = this.resolveWritableNamespace(
|
|
1131
|
+
request.namespace,
|
|
1132
|
+
request.sessionKey,
|
|
1133
|
+
request.authenticatedPrincipal
|
|
1134
|
+
);
|
|
1135
|
+
const schemaVersion = request.schemaVersion ?? ENGRAM_ACCESS_WRITE_SCHEMA_VERSION;
|
|
1136
|
+
if (schemaVersion !== ENGRAM_ACCESS_WRITE_SCHEMA_VERSION) {
|
|
1137
|
+
throw new EngramAccessInputError(`unsupported schemaVersion: ${schemaVersion}`);
|
|
1138
|
+
}
|
|
1139
|
+
const execute = async () => {
|
|
1140
|
+
const candidate = this.validateWriteCandidate(request, namespace);
|
|
1141
|
+
if (request.dryRun === true) {
|
|
1142
|
+
return {
|
|
1143
|
+
schemaVersion: ENGRAM_ACCESS_WRITE_SCHEMA_VERSION,
|
|
1144
|
+
operation: "suggestion_submit",
|
|
1145
|
+
namespace,
|
|
1146
|
+
dryRun: true,
|
|
1147
|
+
accepted: true,
|
|
1148
|
+
queued: true,
|
|
1149
|
+
status: "validated",
|
|
1150
|
+
idempotencyKey: request.idempotencyKey?.trim() || void 0
|
|
1151
|
+
};
|
|
1152
|
+
}
|
|
1153
|
+
const result = await queueExplicitCaptureForReview(
|
|
1154
|
+
this.orchestrator,
|
|
1155
|
+
candidate,
|
|
1156
|
+
"suggestion_submit",
|
|
1157
|
+
new Error(request.sourceReason?.trim() || "submitted via engram suggestion_submit")
|
|
1158
|
+
);
|
|
1159
|
+
const response = {
|
|
1160
|
+
schemaVersion: ENGRAM_ACCESS_WRITE_SCHEMA_VERSION,
|
|
1161
|
+
operation: "suggestion_submit",
|
|
1162
|
+
namespace,
|
|
1163
|
+
dryRun: false,
|
|
1164
|
+
accepted: true,
|
|
1165
|
+
queued: true,
|
|
1166
|
+
status: "queued_for_review",
|
|
1167
|
+
memoryId: result.id,
|
|
1168
|
+
duplicateOf: result.duplicateOf,
|
|
1169
|
+
idempotencyKey: request.idempotencyKey?.trim() || void 0
|
|
1170
|
+
};
|
|
1171
|
+
log.info(
|
|
1172
|
+
`access-write op=suggestion_submit namespace=${namespace} dryRun=false status=${response.status} memoryId=${response.memoryId ?? "-"} idempotency=${response.idempotencyKey ? "yes" : "no"}`
|
|
1173
|
+
);
|
|
1174
|
+
return response;
|
|
1175
|
+
};
|
|
1176
|
+
return this.handleIdempotentWrite({
|
|
1177
|
+
operation: "suggestion_submit",
|
|
1178
|
+
idempotencyKey: request.idempotencyKey,
|
|
1179
|
+
requestFingerprint: {
|
|
1180
|
+
schemaVersion,
|
|
1181
|
+
content: request.content,
|
|
1182
|
+
category: request.category,
|
|
1183
|
+
confidence: request.confidence,
|
|
1184
|
+
namespace,
|
|
1185
|
+
tags: request.tags,
|
|
1186
|
+
entityRef: request.entityRef,
|
|
1187
|
+
ttl: request.ttl,
|
|
1188
|
+
sourceReason: request.sourceReason
|
|
1189
|
+
},
|
|
1190
|
+
skip: request.dryRun === true,
|
|
1191
|
+
execute
|
|
1192
|
+
});
|
|
1193
|
+
}
|
|
1194
|
+
async peekSuggestionSubmitIdempotency(request) {
|
|
1195
|
+
const namespace = this.resolveWritableNamespace(
|
|
1196
|
+
request.namespace,
|
|
1197
|
+
request.sessionKey,
|
|
1198
|
+
request.authenticatedPrincipal
|
|
1199
|
+
);
|
|
1200
|
+
const schemaVersion = request.schemaVersion ?? ENGRAM_ACCESS_WRITE_SCHEMA_VERSION;
|
|
1201
|
+
if (schemaVersion !== ENGRAM_ACCESS_WRITE_SCHEMA_VERSION) {
|
|
1202
|
+
throw new EngramAccessInputError(`unsupported schemaVersion: ${schemaVersion}`);
|
|
1203
|
+
}
|
|
1204
|
+
return this.peekIdempotentWrite({
|
|
1205
|
+
operation: "suggestion_submit",
|
|
1206
|
+
idempotencyKey: request.idempotencyKey,
|
|
1207
|
+
requestFingerprint: {
|
|
1208
|
+
schemaVersion,
|
|
1209
|
+
content: request.content,
|
|
1210
|
+
category: request.category,
|
|
1211
|
+
confidence: request.confidence,
|
|
1212
|
+
namespace,
|
|
1213
|
+
tags: request.tags,
|
|
1214
|
+
entityRef: request.entityRef,
|
|
1215
|
+
ttl: request.ttl,
|
|
1216
|
+
sourceReason: request.sourceReason
|
|
1217
|
+
},
|
|
1218
|
+
skip: request.dryRun === true
|
|
1219
|
+
});
|
|
1220
|
+
}
|
|
1221
|
+
validateWriteCandidate(request, namespace) {
|
|
1222
|
+
try {
|
|
1223
|
+
return validateExplicitCaptureInput(
|
|
1224
|
+
{
|
|
1225
|
+
...request,
|
|
1226
|
+
namespace
|
|
1227
|
+
},
|
|
1228
|
+
"legacy_tool"
|
|
1229
|
+
);
|
|
1230
|
+
} catch (error) {
|
|
1231
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1232
|
+
throw new EngramAccessInputError(message);
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1235
|
+
async memoryGet(memoryId, namespace, principal) {
|
|
1236
|
+
const resolvedNamespace = this.resolveReadableNamespace(namespace, principal);
|
|
1237
|
+
const storage = await this.orchestrator.getStorage(resolvedNamespace);
|
|
1238
|
+
const memory = await storage.getMemoryById(memoryId);
|
|
1239
|
+
if (!memory) {
|
|
1240
|
+
return { found: false, namespace: resolvedNamespace };
|
|
1241
|
+
}
|
|
1242
|
+
return {
|
|
1243
|
+
found: true,
|
|
1244
|
+
namespace: resolvedNamespace,
|
|
1245
|
+
memory: this.serializeMemory(memory)
|
|
1246
|
+
};
|
|
1247
|
+
}
|
|
1248
|
+
async memoryBrowse(request = {}) {
|
|
1249
|
+
const storage = await this.orchestrator.getStorage(request.namespace);
|
|
1250
|
+
const resolvedNamespace = request.namespace?.trim() || this.orchestrator.config.defaultNamespace;
|
|
1251
|
+
const { limit, offset } = normalizePagination(request.limit, request.offset);
|
|
1252
|
+
const sort = normalizeBrowseSort(request.sort);
|
|
1253
|
+
const query = request.query?.trim().toLowerCase() ?? "";
|
|
1254
|
+
const statusFilter = request.status?.trim().toLowerCase();
|
|
1255
|
+
const categoryFilter = request.category?.trim().toLowerCase();
|
|
1256
|
+
const projected = await storage.browseProjectedMemories({
|
|
1257
|
+
query,
|
|
1258
|
+
status: statusFilter,
|
|
1259
|
+
category: categoryFilter,
|
|
1260
|
+
sort,
|
|
1261
|
+
limit,
|
|
1262
|
+
offset
|
|
1263
|
+
});
|
|
1264
|
+
if (projected) {
|
|
1265
|
+
return {
|
|
1266
|
+
namespace: resolvedNamespace,
|
|
1267
|
+
sort,
|
|
1268
|
+
total: projected.total,
|
|
1269
|
+
count: projected.memories.length,
|
|
1270
|
+
limit,
|
|
1271
|
+
offset,
|
|
1272
|
+
memories: projected.memories.map((row) => ({ ...row }))
|
|
1273
|
+
};
|
|
1274
|
+
}
|
|
1275
|
+
let memories = [...await storage.readAllMemories(), ...await storage.readArchivedMemories()];
|
|
1276
|
+
memories = memories.filter((memory) => {
|
|
1277
|
+
const status = inferMemoryStatus(memory.frontmatter, toMemoryPathRel(storage.dir, memory.path)).toLowerCase();
|
|
1278
|
+
if (statusFilter && status !== statusFilter) return false;
|
|
1279
|
+
if (categoryFilter && memory.frontmatter.category.toLowerCase() !== categoryFilter) return false;
|
|
1280
|
+
if (!query) return true;
|
|
1281
|
+
const haystack = [
|
|
1282
|
+
memory.frontmatter.id,
|
|
1283
|
+
memory.path,
|
|
1284
|
+
memory.content,
|
|
1285
|
+
memory.frontmatter.entityRef ?? "",
|
|
1286
|
+
...memory.frontmatter.tags
|
|
1287
|
+
].join("\n").toLowerCase();
|
|
1288
|
+
return haystack.includes(query);
|
|
1289
|
+
});
|
|
1290
|
+
memories.sort((left, right) => compareBrowseMemory(sort, left, right));
|
|
1291
|
+
const page = memories.slice(offset, offset + limit).map((memory) => this.serializeMemorySummary(memory, storage.dir));
|
|
1292
|
+
return {
|
|
1293
|
+
namespace: resolvedNamespace,
|
|
1294
|
+
sort,
|
|
1295
|
+
total: memories.length,
|
|
1296
|
+
count: page.length,
|
|
1297
|
+
limit,
|
|
1298
|
+
offset,
|
|
1299
|
+
memories: page
|
|
1300
|
+
};
|
|
1301
|
+
}
|
|
1302
|
+
async memoryTimeline(memoryId, namespace, limit = 200, principal) {
|
|
1303
|
+
const resolvedNamespace = this.resolveReadableNamespace(namespace, principal);
|
|
1304
|
+
const storage = await this.orchestrator.getStorage(resolvedNamespace);
|
|
1305
|
+
const timeline = await storage.getMemoryTimeline(memoryId, limit);
|
|
1306
|
+
return {
|
|
1307
|
+
found: timeline.length > 0,
|
|
1308
|
+
namespace: resolvedNamespace,
|
|
1309
|
+
count: timeline.length,
|
|
1310
|
+
timeline
|
|
1311
|
+
};
|
|
1312
|
+
}
|
|
1313
|
+
async entityList(options = {}) {
|
|
1314
|
+
const storage = await this.orchestrator.getStorage(options.namespace);
|
|
1315
|
+
const resolvedNamespace = options.namespace?.trim() || this.orchestrator.config.defaultNamespace;
|
|
1316
|
+
const { limit, offset } = normalizePagination(options.limit, options.offset);
|
|
1317
|
+
const query = options.query?.trim().toLowerCase() ?? "";
|
|
1318
|
+
const names = await storage.listEntityNames();
|
|
1319
|
+
const entities = [];
|
|
1320
|
+
for (const name of names) {
|
|
1321
|
+
const raw = await storage.readEntity(name);
|
|
1322
|
+
if (!raw) continue;
|
|
1323
|
+
const entity = parseEntityFile(raw);
|
|
1324
|
+
if (query) {
|
|
1325
|
+
const haystack = [
|
|
1326
|
+
entity.name,
|
|
1327
|
+
entity.type,
|
|
1328
|
+
entity.summary ?? "",
|
|
1329
|
+
...entity.aliases,
|
|
1330
|
+
...entity.facts
|
|
1331
|
+
].join("\n").toLowerCase();
|
|
1332
|
+
if (!haystack.includes(query)) continue;
|
|
1333
|
+
}
|
|
1334
|
+
entities.push({
|
|
1335
|
+
name: entity.name,
|
|
1336
|
+
type: entity.type,
|
|
1337
|
+
updated: entity.updated,
|
|
1338
|
+
summary: entity.summary,
|
|
1339
|
+
aliases: entity.aliases
|
|
1340
|
+
});
|
|
1341
|
+
}
|
|
1342
|
+
entities.sort((left, right) => left.name.localeCompare(right.name));
|
|
1343
|
+
const page = entities.slice(offset, offset + limit);
|
|
1344
|
+
return {
|
|
1345
|
+
namespace: resolvedNamespace,
|
|
1346
|
+
total: entities.length,
|
|
1347
|
+
count: page.length,
|
|
1348
|
+
limit,
|
|
1349
|
+
offset,
|
|
1350
|
+
entities: page
|
|
1351
|
+
};
|
|
1352
|
+
}
|
|
1353
|
+
async entityGet(name, namespace) {
|
|
1354
|
+
const storage = await this.orchestrator.getStorage(namespace);
|
|
1355
|
+
const resolvedNamespace = namespace?.trim() || this.orchestrator.config.defaultNamespace;
|
|
1356
|
+
const raw = await storage.readEntity(name);
|
|
1357
|
+
if (!raw) return { found: false, namespace: resolvedNamespace };
|
|
1358
|
+
return {
|
|
1359
|
+
found: true,
|
|
1360
|
+
namespace: resolvedNamespace,
|
|
1361
|
+
entity: parseEntityFile(raw)
|
|
1362
|
+
};
|
|
1363
|
+
}
|
|
1364
|
+
async reviewQueue(runId, namespace, principal) {
|
|
1365
|
+
const resolvedNamespace = this.resolveReadableNamespace(namespace, principal);
|
|
1366
|
+
const storage = await this.orchestrator.getStorage(resolvedNamespace);
|
|
1367
|
+
const projected = await storage.getProjectedGovernanceRecord();
|
|
1368
|
+
if (projected && (!runId || projected.runId === runId.trim())) {
|
|
1369
|
+
const projectedAppliedActions = projected.appliedActionRows.map((row) => ({
|
|
1370
|
+
action: row.action,
|
|
1371
|
+
memoryId: row.memoryId,
|
|
1372
|
+
reasonCode: row.reasonCode,
|
|
1373
|
+
beforeStatus: row.beforeStatus,
|
|
1374
|
+
afterStatus: row.afterStatus,
|
|
1375
|
+
originalPath: row.originalPath,
|
|
1376
|
+
currentPath: row.currentPath
|
|
1377
|
+
}));
|
|
1378
|
+
const projectedProposedActions = await buildProjectedGovernanceProposedActions(storage, projected);
|
|
1379
|
+
const projectedArtifact = await (async () => {
|
|
1380
|
+
try {
|
|
1381
|
+
return await readMemoryGovernanceRunArtifact(storage.dir, projected.runId);
|
|
1382
|
+
} catch {
|
|
1383
|
+
return null;
|
|
1384
|
+
}
|
|
1385
|
+
})();
|
|
1386
|
+
const metrics = projected.metrics;
|
|
1387
|
+
const fallbackTransitionReport = {
|
|
1388
|
+
proposed: groupActionsByStatus(projectedProposedActions),
|
|
1389
|
+
applied: groupActionsByStatus(projectedAppliedActions)
|
|
1390
|
+
};
|
|
1391
|
+
const transitionReport = projectedArtifact?.transitionReport ? {
|
|
1392
|
+
proposed: hasGroupedGovernanceActions(projectedArtifact.transitionReport.proposed) || projectedProposedActions.length === 0 ? projectedArtifact.transitionReport.proposed : fallbackTransitionReport.proposed,
|
|
1393
|
+
applied: hasGroupedGovernanceActions(projectedArtifact.transitionReport.applied) || projectedAppliedActions.length === 0 ? projectedArtifact.transitionReport.applied : fallbackTransitionReport.applied
|
|
1394
|
+
} : fallbackTransitionReport;
|
|
1395
|
+
const qualityScore = projectedArtifact?.qualityScore ?? metrics?.qualityScore ?? buildQualityScore(metrics?.reviewReasons ?? {
|
|
1396
|
+
exact_duplicate: 0,
|
|
1397
|
+
semantic_duplicate_candidate: 0,
|
|
1398
|
+
disputed_memory: 0,
|
|
1399
|
+
speculative_low_confidence: 0,
|
|
1400
|
+
archive_candidate: 0,
|
|
1401
|
+
explicit_capture_review: 0,
|
|
1402
|
+
malformed_import: 0
|
|
1403
|
+
});
|
|
1404
|
+
const effectiveMetrics = metrics ? { ...metrics, qualityScore: metrics.qualityScore ?? qualityScore } : metrics;
|
|
1405
|
+
return {
|
|
1406
|
+
found: true,
|
|
1407
|
+
namespace: resolvedNamespace,
|
|
1408
|
+
runId: projected.runId,
|
|
1409
|
+
summary: projected.summary,
|
|
1410
|
+
metrics: effectiveMetrics,
|
|
1411
|
+
qualityScore,
|
|
1412
|
+
reviewQueue: projected.reviewQueueRows.map((row) => ({
|
|
1413
|
+
entryId: row.entryId,
|
|
1414
|
+
memoryId: row.memoryId,
|
|
1415
|
+
path: row.path,
|
|
1416
|
+
reasonCode: row.reasonCode,
|
|
1417
|
+
severity: row.severity,
|
|
1418
|
+
suggestedAction: row.suggestedAction,
|
|
1419
|
+
suggestedStatus: row.suggestedStatus,
|
|
1420
|
+
relatedMemoryIds: row.relatedMemoryIds
|
|
1421
|
+
})),
|
|
1422
|
+
appliedActions: projectedAppliedActions,
|
|
1423
|
+
transitionReport,
|
|
1424
|
+
report: projected.report
|
|
1425
|
+
};
|
|
1426
|
+
}
|
|
1427
|
+
const resolvedRunId = runId?.trim() || (await listMemoryGovernanceRuns(storage.dir))[0];
|
|
1428
|
+
if (!resolvedRunId) return { found: false, namespace: resolvedNamespace };
|
|
1429
|
+
const artifact = await readMemoryGovernanceRunArtifact(storage.dir, resolvedRunId);
|
|
1430
|
+
return {
|
|
1431
|
+
found: true,
|
|
1432
|
+
namespace: resolvedNamespace,
|
|
1433
|
+
runId: resolvedRunId,
|
|
1434
|
+
summary: artifact.summary,
|
|
1435
|
+
metrics: artifact.metrics,
|
|
1436
|
+
qualityScore: artifact.qualityScore,
|
|
1437
|
+
reviewQueue: artifact.reviewQueue,
|
|
1438
|
+
appliedActions: artifact.appliedActions,
|
|
1439
|
+
transitionReport: artifact.transitionReport,
|
|
1440
|
+
report: artifact.report
|
|
1441
|
+
};
|
|
1442
|
+
}
|
|
1443
|
+
async maintenance(namespace, principal) {
|
|
1444
|
+
const resolvedNamespace = this.resolveReadableNamespace(namespace, principal);
|
|
1445
|
+
return {
|
|
1446
|
+
namespace: resolvedNamespace,
|
|
1447
|
+
health: await this.health(resolvedNamespace),
|
|
1448
|
+
latestGovernanceRun: await this.reviewQueue(void 0, resolvedNamespace, principal)
|
|
1449
|
+
};
|
|
1450
|
+
}
|
|
1451
|
+
async quality(namespace, principal) {
|
|
1452
|
+
const resolvedNamespace = this.resolveReadableNamespace(namespace, principal);
|
|
1453
|
+
const storage = await this.orchestrator.getStorage(resolvedNamespace);
|
|
1454
|
+
const governance = await this.reviewQueue(void 0, resolvedNamespace, principal);
|
|
1455
|
+
const nowMs = Date.now();
|
|
1456
|
+
const statusCounts = {};
|
|
1457
|
+
const categoryCounts = {};
|
|
1458
|
+
const confidenceTierCounts = {};
|
|
1459
|
+
const ageBucketCounts = {};
|
|
1460
|
+
let staleActive = 0;
|
|
1461
|
+
let lowConfidenceActive = 0;
|
|
1462
|
+
const memories = [...await storage.readAllMemories(), ...await storage.readArchivedMemories()];
|
|
1463
|
+
for (const memory of memories) {
|
|
1464
|
+
const status = inferMemoryStatus(memory.frontmatter, toMemoryPathRel(storage.dir, memory.path)).toLowerCase();
|
|
1465
|
+
const confidenceTier = memory.frontmatter.confidenceTier ?? "unknown";
|
|
1466
|
+
const ageBucket = bucketMemoryAge(memory.frontmatter.updated ?? memory.frontmatter.created, nowMs);
|
|
1467
|
+
incrementCount(statusCounts, status);
|
|
1468
|
+
incrementCount(categoryCounts, memory.frontmatter.category);
|
|
1469
|
+
incrementCount(confidenceTierCounts, confidenceTier);
|
|
1470
|
+
incrementCount(ageBucketCounts, ageBucket);
|
|
1471
|
+
if (status === "active") {
|
|
1472
|
+
if (ageBucket === "91_plus_days") staleActive += 1;
|
|
1473
|
+
if ((memory.frontmatter.confidence ?? 0) < 0.6) lowConfidenceActive += 1;
|
|
1474
|
+
}
|
|
1475
|
+
}
|
|
1476
|
+
return {
|
|
1477
|
+
namespace: resolvedNamespace,
|
|
1478
|
+
totalMemories: memories.length,
|
|
1479
|
+
statusCounts,
|
|
1480
|
+
categoryCounts,
|
|
1481
|
+
confidenceTierCounts,
|
|
1482
|
+
ageBucketCounts,
|
|
1483
|
+
archivePressure: {
|
|
1484
|
+
pendingReview: statusCounts.pending_review ?? 0,
|
|
1485
|
+
quarantined: statusCounts.quarantined ?? 0,
|
|
1486
|
+
archived: statusCounts.archived ?? 0,
|
|
1487
|
+
staleActive,
|
|
1488
|
+
lowConfidenceActive
|
|
1489
|
+
},
|
|
1490
|
+
latestGovernanceRun: {
|
|
1491
|
+
found: governance.found,
|
|
1492
|
+
runId: governance.runId,
|
|
1493
|
+
qualityScore: governance.qualityScore ?? governance.metrics?.qualityScore,
|
|
1494
|
+
reviewQueueCount: governance.reviewQueue?.length ?? 0
|
|
1495
|
+
}
|
|
1496
|
+
};
|
|
1497
|
+
}
|
|
1498
|
+
async governanceRun(request, principal) {
|
|
1499
|
+
const resolvedNamespace = this.resolveWritableNamespace(
|
|
1500
|
+
request.namespace,
|
|
1501
|
+
void 0,
|
|
1502
|
+
request.authenticatedPrincipal ?? principal
|
|
1503
|
+
);
|
|
1504
|
+
const storage = await this.orchestrator.getStorage(resolvedNamespace);
|
|
1505
|
+
const result = await runMemoryGovernance({
|
|
1506
|
+
memoryDir: storage.dir,
|
|
1507
|
+
mode: request.mode === "apply" ? "apply" : "shadow",
|
|
1508
|
+
recentDays: typeof request.recentDays === "number" && Number.isFinite(request.recentDays) ? Math.max(1, Math.floor(request.recentDays)) : void 0,
|
|
1509
|
+
maxMemories: typeof request.maxMemories === "number" && Number.isFinite(request.maxMemories) ? Math.max(1, Math.floor(request.maxMemories)) : void 0,
|
|
1510
|
+
batchSize: typeof request.batchSize === "number" && Number.isFinite(request.batchSize) ? Math.max(1, Math.floor(request.batchSize)) : void 0
|
|
1511
|
+
});
|
|
1512
|
+
return {
|
|
1513
|
+
namespace: resolvedNamespace,
|
|
1514
|
+
runId: result.runId,
|
|
1515
|
+
traceId: result.traceId,
|
|
1516
|
+
mode: result.mode,
|
|
1517
|
+
reviewQueueCount: result.reviewQueue.length,
|
|
1518
|
+
proposedActionCount: result.proposedActions.length,
|
|
1519
|
+
appliedActionCount: result.appliedActions.length,
|
|
1520
|
+
summaryPath: result.summaryPath,
|
|
1521
|
+
reportPath: result.reportPath
|
|
1522
|
+
};
|
|
1523
|
+
}
|
|
1524
|
+
async trustZoneStatus(namespace, principal) {
|
|
1525
|
+
const resolvedNamespace = this.resolveReadableNamespace(namespace, principal);
|
|
1526
|
+
const storage = await this.orchestrator.getStorage(resolvedNamespace);
|
|
1527
|
+
return {
|
|
1528
|
+
namespace: resolvedNamespace,
|
|
1529
|
+
status: await getTrustZoneStoreStatus({
|
|
1530
|
+
memoryDir: storage.dir,
|
|
1531
|
+
trustZoneStoreDir: this.orchestrator.config.trustZoneStoreDir,
|
|
1532
|
+
enabled: this.orchestrator.config.trustZonesEnabled === true,
|
|
1533
|
+
promotionEnabled: this.orchestrator.config.quarantinePromotionEnabled === true,
|
|
1534
|
+
poisoningDefenseEnabled: this.orchestrator.config.memoryPoisoningDefenseEnabled === true
|
|
1535
|
+
})
|
|
1536
|
+
};
|
|
1537
|
+
}
|
|
1538
|
+
async trustZoneBrowse(request, principal) {
|
|
1539
|
+
const resolvedNamespace = this.resolveReadableNamespace(request.namespace, principal);
|
|
1540
|
+
const storage = await this.orchestrator.getStorage(resolvedNamespace);
|
|
1541
|
+
const result = await listTrustZoneRecords({
|
|
1542
|
+
memoryDir: storage.dir,
|
|
1543
|
+
trustZoneStoreDir: this.orchestrator.config.trustZoneStoreDir,
|
|
1544
|
+
query: request.query,
|
|
1545
|
+
zone: request.zone,
|
|
1546
|
+
kind: request.kind,
|
|
1547
|
+
sourceClass: request.sourceClass,
|
|
1548
|
+
limit: request.limit,
|
|
1549
|
+
offset: request.offset
|
|
1550
|
+
});
|
|
1551
|
+
return {
|
|
1552
|
+
namespace: resolvedNamespace,
|
|
1553
|
+
total: result.total,
|
|
1554
|
+
count: result.count,
|
|
1555
|
+
limit: result.limit,
|
|
1556
|
+
offset: result.offset,
|
|
1557
|
+
records: result.records.map((entry) => summarizeTrustZoneRecord(
|
|
1558
|
+
entry.record,
|
|
1559
|
+
entry.filePath,
|
|
1560
|
+
result.allRecords,
|
|
1561
|
+
this.orchestrator.config.memoryPoisoningDefenseEnabled === true,
|
|
1562
|
+
this.orchestrator.config.trustZonesEnabled === true,
|
|
1563
|
+
this.orchestrator.config.quarantinePromotionEnabled === true
|
|
1564
|
+
))
|
|
1565
|
+
};
|
|
1566
|
+
}
|
|
1567
|
+
async trustZonePromote(request) {
|
|
1568
|
+
if (!isTrustZoneName(request.targetZone)) {
|
|
1569
|
+
throw new EngramAccessInputError(`unsupported trust-zone target: ${String(request.targetZone)}`);
|
|
1570
|
+
}
|
|
1571
|
+
const resolvedNamespace = this.resolveWritableNamespace(
|
|
1572
|
+
request.namespace,
|
|
1573
|
+
void 0,
|
|
1574
|
+
request.authenticatedPrincipal
|
|
1575
|
+
);
|
|
1576
|
+
const storage = await this.orchestrator.getStorage(resolvedNamespace);
|
|
1577
|
+
let result;
|
|
1578
|
+
try {
|
|
1579
|
+
result = await promoteTrustZoneRecord({
|
|
1580
|
+
memoryDir: storage.dir,
|
|
1581
|
+
trustZoneStoreDir: this.orchestrator.config.trustZoneStoreDir,
|
|
1582
|
+
enabled: this.orchestrator.config.trustZonesEnabled === true,
|
|
1583
|
+
promotionEnabled: this.orchestrator.config.quarantinePromotionEnabled === true,
|
|
1584
|
+
poisoningDefenseEnabled: this.orchestrator.config.memoryPoisoningDefenseEnabled === true,
|
|
1585
|
+
sourceRecordId: request.recordId,
|
|
1586
|
+
targetZone: request.targetZone,
|
|
1587
|
+
recordedAt: request.recordedAt ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
1588
|
+
promotionReason: request.promotionReason,
|
|
1589
|
+
summary: request.summary,
|
|
1590
|
+
dryRun: request.dryRun === true
|
|
1591
|
+
});
|
|
1592
|
+
} catch (error) {
|
|
1593
|
+
throw normalizeTrustZoneInputError(error) ?? error;
|
|
1594
|
+
}
|
|
1595
|
+
return {
|
|
1596
|
+
namespace: resolvedNamespace,
|
|
1597
|
+
...result,
|
|
1598
|
+
dryRun: request.dryRun === true
|
|
1599
|
+
};
|
|
1600
|
+
}
|
|
1601
|
+
async trustZoneDemoSeed(request) {
|
|
1602
|
+
const resolvedNamespace = this.resolveWritableNamespace(
|
|
1603
|
+
request.namespace,
|
|
1604
|
+
void 0,
|
|
1605
|
+
request.authenticatedPrincipal
|
|
1606
|
+
);
|
|
1607
|
+
const storage = await this.orchestrator.getStorage(resolvedNamespace);
|
|
1608
|
+
let result;
|
|
1609
|
+
try {
|
|
1610
|
+
result = await seedTrustZoneDemoDataset({
|
|
1611
|
+
memoryDir: storage.dir,
|
|
1612
|
+
trustZoneStoreDir: this.orchestrator.config.trustZoneStoreDir,
|
|
1613
|
+
enabled: this.orchestrator.config.trustZonesEnabled === true,
|
|
1614
|
+
scenario: request.scenario,
|
|
1615
|
+
recordedAt: request.recordedAt,
|
|
1616
|
+
dryRun: request.dryRun === true
|
|
1617
|
+
});
|
|
1618
|
+
} catch (error) {
|
|
1619
|
+
throw normalizeTrustZoneInputError(error) ?? error;
|
|
1620
|
+
}
|
|
1621
|
+
return {
|
|
1622
|
+
namespace: resolvedNamespace,
|
|
1623
|
+
...result
|
|
1624
|
+
};
|
|
1625
|
+
}
|
|
1626
|
+
async reviewDisposition(request) {
|
|
1627
|
+
const memoryId = request.memoryId.trim();
|
|
1628
|
+
const reasonCode = request.reasonCode.trim();
|
|
1629
|
+
if (memoryId.length === 0) {
|
|
1630
|
+
throw new EngramAccessInputError("memoryId is required");
|
|
1631
|
+
}
|
|
1632
|
+
if (reasonCode.length === 0) {
|
|
1633
|
+
throw new EngramAccessInputError("reasonCode is required");
|
|
1634
|
+
}
|
|
1635
|
+
const resolvedNamespace = this.resolveWritableNamespace(
|
|
1636
|
+
request.namespace,
|
|
1637
|
+
void 0,
|
|
1638
|
+
request.authenticatedPrincipal
|
|
1639
|
+
);
|
|
1640
|
+
const storage = await this.orchestrator.getStorage(resolvedNamespace);
|
|
1641
|
+
const memory = await storage.getMemoryById(memoryId);
|
|
1642
|
+
if (!memory) {
|
|
1643
|
+
throw new EngramAccessInputError(`memory not found: ${memoryId}`);
|
|
1644
|
+
}
|
|
1645
|
+
const previousStatus = memory.frontmatter.status ?? "active";
|
|
1646
|
+
const updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1647
|
+
const lifecycle = {
|
|
1648
|
+
actor: "admin-console.review-disposition",
|
|
1649
|
+
reasonCode,
|
|
1650
|
+
ruleVersion: "memory-governance.v1"
|
|
1651
|
+
};
|
|
1652
|
+
if (request.status === "archived") {
|
|
1653
|
+
const archivedPath = await storage.archiveMemory(memory, {
|
|
1654
|
+
at: new Date(updatedAt),
|
|
1655
|
+
...lifecycle
|
|
1656
|
+
});
|
|
1657
|
+
if (!archivedPath) {
|
|
1658
|
+
throw new Error(`failed to archive memory disposition: ${memoryId}`);
|
|
1659
|
+
}
|
|
1660
|
+
return {
|
|
1661
|
+
ok: true,
|
|
1662
|
+
namespace: resolvedNamespace,
|
|
1663
|
+
memoryId,
|
|
1664
|
+
status: "archived",
|
|
1665
|
+
previousStatus,
|
|
1666
|
+
currentPath: archivedPath
|
|
1667
|
+
};
|
|
1668
|
+
}
|
|
1669
|
+
const updated = await storage.writeMemoryFrontmatter(memory, {
|
|
1670
|
+
status: request.status,
|
|
1671
|
+
updated: updatedAt
|
|
1672
|
+
}, lifecycle);
|
|
1673
|
+
if (!updated) {
|
|
1674
|
+
throw new Error(`failed to update memory disposition: ${memoryId}`);
|
|
1675
|
+
}
|
|
1676
|
+
return {
|
|
1677
|
+
ok: true,
|
|
1678
|
+
namespace: resolvedNamespace,
|
|
1679
|
+
memoryId,
|
|
1680
|
+
status: request.status,
|
|
1681
|
+
previousStatus,
|
|
1682
|
+
currentPath: memory.path
|
|
1683
|
+
};
|
|
1684
|
+
}
|
|
1685
|
+
serializeMemory(memory) {
|
|
1686
|
+
return {
|
|
1687
|
+
id: memory.frontmatter.id,
|
|
1688
|
+
path: memory.path,
|
|
1689
|
+
category: memory.frontmatter.category,
|
|
1690
|
+
status: memory.frontmatter.status,
|
|
1691
|
+
created: memory.frontmatter.created,
|
|
1692
|
+
updated: memory.frontmatter.updated,
|
|
1693
|
+
content: memory.content,
|
|
1694
|
+
frontmatter: memory.frontmatter
|
|
1695
|
+
};
|
|
1696
|
+
}
|
|
1697
|
+
serializeMemorySummary(memory, baseDir) {
|
|
1698
|
+
return {
|
|
1699
|
+
id: memory.frontmatter.id,
|
|
1700
|
+
path: memory.path,
|
|
1701
|
+
category: memory.frontmatter.category,
|
|
1702
|
+
status: inferMemoryStatus(memory.frontmatter, toMemoryPathRel(baseDir, memory.path)),
|
|
1703
|
+
created: memory.frontmatter.created,
|
|
1704
|
+
updated: memory.frontmatter.updated,
|
|
1705
|
+
tags: normalizeProjectionTags(memory.frontmatter.tags),
|
|
1706
|
+
entityRef: memory.frontmatter.entityRef,
|
|
1707
|
+
preview: normalizeProjectionPreview(memory.content)
|
|
1708
|
+
};
|
|
1709
|
+
}
|
|
1710
|
+
async observe(request) {
|
|
1711
|
+
if (!request.sessionKey || typeof request.sessionKey !== "string" || request.sessionKey.trim().length === 0) {
|
|
1712
|
+
throw new EngramAccessInputError("sessionKey is required and must be a non-empty string");
|
|
1713
|
+
}
|
|
1714
|
+
if (!Array.isArray(request.messages) || request.messages.length === 0) {
|
|
1715
|
+
throw new EngramAccessInputError("messages is required and must be a non-empty array");
|
|
1716
|
+
}
|
|
1717
|
+
for (const msg of request.messages) {
|
|
1718
|
+
if (!msg || typeof msg !== "object" || typeof msg.role !== "string" || typeof msg.content !== "string") {
|
|
1719
|
+
throw new EngramAccessInputError("each message must have a string 'role' and 'content'");
|
|
1720
|
+
}
|
|
1721
|
+
if (msg.role !== "user" && msg.role !== "assistant") {
|
|
1722
|
+
throw new EngramAccessInputError(`invalid message role: ${msg.role} (expected 'user' or 'assistant')`);
|
|
1723
|
+
}
|
|
1724
|
+
}
|
|
1725
|
+
const namespace = this.resolveWritableNamespace(
|
|
1726
|
+
request.namespace,
|
|
1727
|
+
request.sessionKey,
|
|
1728
|
+
request.authenticatedPrincipal
|
|
1729
|
+
);
|
|
1730
|
+
const lcmSessionKey = namespace !== this.orchestrator.config.defaultNamespace ? `${namespace}:${request.sessionKey}` : request.sessionKey;
|
|
1731
|
+
let lcmArchived = false;
|
|
1732
|
+
if (this.orchestrator.lcmEngine && this.orchestrator.lcmEngine.enabled) {
|
|
1733
|
+
try {
|
|
1734
|
+
this.orchestrator.lcmEngine.enqueueObserveMessages(lcmSessionKey, request.messages);
|
|
1735
|
+
lcmArchived = true;
|
|
1736
|
+
} catch (err) {
|
|
1737
|
+
log.error(`access-observe LCM enqueue failed: ${err}`);
|
|
1738
|
+
}
|
|
1739
|
+
}
|
|
1740
|
+
let extractionQueued = false;
|
|
1741
|
+
if (request.skipExtraction !== true) {
|
|
1742
|
+
const turns = request.messages.map((m) => ({
|
|
1743
|
+
source: "openclaw",
|
|
1744
|
+
sessionKey: lcmSessionKey,
|
|
1745
|
+
role: m.role,
|
|
1746
|
+
content: m.content,
|
|
1747
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1748
|
+
}));
|
|
1749
|
+
try {
|
|
1750
|
+
const extractionPromise = this.orchestrator.ingestReplayBatch(turns);
|
|
1751
|
+
extractionPromise.catch((err) => {
|
|
1752
|
+
log.error(`access-observe background extraction failed: ${err}`);
|
|
1753
|
+
});
|
|
1754
|
+
extractionQueued = true;
|
|
1755
|
+
} catch (err) {
|
|
1756
|
+
log.error(`access-observe extraction enqueue failed: ${err}`);
|
|
1757
|
+
}
|
|
1758
|
+
}
|
|
1759
|
+
log.info(
|
|
1760
|
+
`access-observe namespace=${namespace} sessionKey=${request.sessionKey} messages=${request.messages.length} lcm=${lcmArchived} extraction=${extractionQueued}`
|
|
1761
|
+
);
|
|
1762
|
+
return {
|
|
1763
|
+
accepted: request.messages.length,
|
|
1764
|
+
sessionKey: request.sessionKey,
|
|
1765
|
+
namespace,
|
|
1766
|
+
lcmArchived,
|
|
1767
|
+
extractionQueued
|
|
1768
|
+
};
|
|
1769
|
+
}
|
|
1770
|
+
async lcmSearch(request) {
|
|
1771
|
+
if (!request.query || typeof request.query !== "string" || request.query.trim().length === 0) {
|
|
1772
|
+
throw new EngramAccessInputError("query is required and must be a non-empty string");
|
|
1773
|
+
}
|
|
1774
|
+
const principal = this.resolveWritePrincipal(request.sessionKey, request.authenticatedPrincipal);
|
|
1775
|
+
const namespace = this.resolveReadableNamespace(request.namespace, principal);
|
|
1776
|
+
if (!this.orchestrator.lcmEngine || !this.orchestrator.lcmEngine.enabled) {
|
|
1777
|
+
return {
|
|
1778
|
+
query: request.query,
|
|
1779
|
+
namespace,
|
|
1780
|
+
results: [],
|
|
1781
|
+
count: 0,
|
|
1782
|
+
lcmEnabled: false
|
|
1783
|
+
};
|
|
1784
|
+
}
|
|
1785
|
+
const limit = Math.max(1, Math.min(request.limit ?? 10, 100));
|
|
1786
|
+
const lcmSessionKey = request.sessionKey && namespace !== this.orchestrator.config.defaultNamespace ? `${namespace}:${request.sessionKey}` : request.sessionKey;
|
|
1787
|
+
const rawResults = await this.orchestrator.lcmEngine.searchContextFull(
|
|
1788
|
+
request.query,
|
|
1789
|
+
limit,
|
|
1790
|
+
lcmSessionKey
|
|
1791
|
+
);
|
|
1792
|
+
const results = rawResults.map((r) => ({
|
|
1793
|
+
sessionId: r.session_id,
|
|
1794
|
+
content: r.content,
|
|
1795
|
+
turnIndex: r.turn_index
|
|
1796
|
+
}));
|
|
1797
|
+
return {
|
|
1798
|
+
query: request.query,
|
|
1799
|
+
namespace,
|
|
1800
|
+
results,
|
|
1801
|
+
count: results.length,
|
|
1802
|
+
lcmEnabled: true
|
|
1803
|
+
};
|
|
1804
|
+
}
|
|
1805
|
+
// ── Parity tools (match OpenClaw plugin feature set) ──────────────────
|
|
1806
|
+
// ── Continuity / Identity ──────────────────────────────────────────────
|
|
1807
|
+
async continuityAuditGenerate(request) {
|
|
1808
|
+
if (!this.orchestrator.config.identityContinuityEnabled) {
|
|
1809
|
+
return { enabled: false, reason: "Identity continuity is disabled. Enable `identityContinuityEnabled: true`." };
|
|
1810
|
+
}
|
|
1811
|
+
if (!this.orchestrator.config.continuityAuditEnabled) {
|
|
1812
|
+
return { enabled: false, reason: "Continuity audits are disabled. Enable `continuityAuditEnabled: true`." };
|
|
1813
|
+
}
|
|
1814
|
+
if (!this.orchestrator.compounding) {
|
|
1815
|
+
return { enabled: false, reason: "Compounding engine is disabled. Enable `compoundingEnabled: true`." };
|
|
1816
|
+
}
|
|
1817
|
+
const period = request.period === "monthly" ? "monthly" : "weekly";
|
|
1818
|
+
const key = request.key?.trim() || void 0;
|
|
1819
|
+
const audit = await this.orchestrator.compounding.synthesizeContinuityAudit({ period, key });
|
|
1820
|
+
return { enabled: true, period: audit.period, key: audit.key, reportPath: audit.reportPath };
|
|
1821
|
+
}
|
|
1822
|
+
async continuityIncidentOpen(request) {
|
|
1823
|
+
if (!this.orchestrator.config.identityContinuityEnabled) {
|
|
1824
|
+
return { enabled: false, reason: "Identity continuity is disabled. Enable `identityContinuityEnabled: true`." };
|
|
1825
|
+
}
|
|
1826
|
+
if (!this.orchestrator.config.continuityIncidentLoggingEnabled) {
|
|
1827
|
+
return { enabled: false, reason: "Continuity incident logging is disabled. Enable `continuityIncidentLoggingEnabled: true`." };
|
|
1828
|
+
}
|
|
1829
|
+
const symptom = request.symptom?.trim();
|
|
1830
|
+
if (!symptom) throw new EngramAccessInputError("symptom is required");
|
|
1831
|
+
const resolvedNs = this.resolveWritableNamespace(request.namespace, void 0, request.principal);
|
|
1832
|
+
const storage = await this.orchestrator.getStorage(resolvedNs);
|
|
1833
|
+
const created = await storage.appendContinuityIncident({
|
|
1834
|
+
symptom,
|
|
1835
|
+
triggerWindow: request.triggerWindow?.trim() || void 0,
|
|
1836
|
+
suspectedCause: request.suspectedCause?.trim() || void 0
|
|
1837
|
+
});
|
|
1838
|
+
return { created: true, incident: created };
|
|
1839
|
+
}
|
|
1840
|
+
async continuityIncidentClose(request) {
|
|
1841
|
+
if (!this.orchestrator.config.identityContinuityEnabled) {
|
|
1842
|
+
return { enabled: false, reason: "Identity continuity is disabled." };
|
|
1843
|
+
}
|
|
1844
|
+
if (!this.orchestrator.config.continuityIncidentLoggingEnabled) {
|
|
1845
|
+
return { enabled: false, reason: "Continuity incident logging is disabled." };
|
|
1846
|
+
}
|
|
1847
|
+
const id = request.id?.trim();
|
|
1848
|
+
if (!id) throw new EngramAccessInputError("id is required");
|
|
1849
|
+
const fixApplied = request.fixApplied?.trim();
|
|
1850
|
+
if (!fixApplied) throw new EngramAccessInputError("fixApplied is required");
|
|
1851
|
+
const verificationResult = request.verificationResult?.trim();
|
|
1852
|
+
if (!verificationResult) throw new EngramAccessInputError("verificationResult is required");
|
|
1853
|
+
const resolvedNs = this.resolveWritableNamespace(request.namespace, void 0, request.principal);
|
|
1854
|
+
const storage = await this.orchestrator.getStorage(resolvedNs);
|
|
1855
|
+
const closed = await storage.closeContinuityIncident(id, {
|
|
1856
|
+
fixApplied,
|
|
1857
|
+
verificationResult,
|
|
1858
|
+
preventiveRule: request.preventiveRule?.trim() || void 0
|
|
1859
|
+
});
|
|
1860
|
+
if (!closed) return { closed: false, reason: `Incident not found: ${id}` };
|
|
1861
|
+
return { closed: true, incident: closed };
|
|
1862
|
+
}
|
|
1863
|
+
async continuityIncidentList(request) {
|
|
1864
|
+
if (!this.orchestrator.config.identityContinuityEnabled) {
|
|
1865
|
+
return { enabled: false, reason: "Identity continuity is disabled." };
|
|
1866
|
+
}
|
|
1867
|
+
const state = request.state === "closed" || request.state === "all" ? request.state : "open";
|
|
1868
|
+
const limit = Math.max(1, Math.min(200, Math.floor(request.limit ?? 25)));
|
|
1869
|
+
const resolvedNs = this.resolveReadableNamespace(request.namespace, request.principal);
|
|
1870
|
+
const storage = await this.orchestrator.getStorage(resolvedNs);
|
|
1871
|
+
const incidents = await storage.readContinuityIncidents(limit, state);
|
|
1872
|
+
return { state, incidents, count: incidents.length };
|
|
1873
|
+
}
|
|
1874
|
+
async continuityLoopAddOrUpdate(request) {
|
|
1875
|
+
if (!this.orchestrator.config.identityContinuityEnabled) {
|
|
1876
|
+
return { enabled: false, reason: "Identity continuity is disabled." };
|
|
1877
|
+
}
|
|
1878
|
+
const resolvedNs = this.resolveWritableNamespace(request.namespace, void 0, request.principal);
|
|
1879
|
+
const storage = await this.orchestrator.getStorage(resolvedNs);
|
|
1880
|
+
const loop = await storage.upsertIdentityImprovementLoop({
|
|
1881
|
+
id: request.id?.trim() || "",
|
|
1882
|
+
cadence: request.cadence,
|
|
1883
|
+
purpose: request.purpose?.trim() || "",
|
|
1884
|
+
status: request.status,
|
|
1885
|
+
killCondition: request.killCondition?.trim() || "",
|
|
1886
|
+
lastReviewed: request.lastReviewed?.trim() || void 0,
|
|
1887
|
+
notes: request.notes?.trim() || void 0
|
|
1888
|
+
});
|
|
1889
|
+
return { saved: true, loop };
|
|
1890
|
+
}
|
|
1891
|
+
async continuityLoopReview(request) {
|
|
1892
|
+
if (!this.orchestrator.config.identityContinuityEnabled) {
|
|
1893
|
+
return { enabled: false, reason: "Identity continuity is disabled." };
|
|
1894
|
+
}
|
|
1895
|
+
const id = request.id?.trim();
|
|
1896
|
+
if (!id) throw new EngramAccessInputError("id is required");
|
|
1897
|
+
const resolvedNs = this.resolveWritableNamespace(request.namespace, void 0, request.principal);
|
|
1898
|
+
const storage = await this.orchestrator.getStorage(resolvedNs);
|
|
1899
|
+
const reviewed = await storage.reviewIdentityImprovementLoop(id, {
|
|
1900
|
+
status: request.status,
|
|
1901
|
+
notes: request.notes?.trim() || void 0,
|
|
1902
|
+
reviewedAt: request.reviewedAt?.trim() || void 0
|
|
1903
|
+
});
|
|
1904
|
+
if (!reviewed) return { reviewed: false, reason: `Continuity loop not found: ${id}` };
|
|
1905
|
+
return { reviewed: true, loop: reviewed };
|
|
1906
|
+
}
|
|
1907
|
+
async identityAnchorGet(request) {
|
|
1908
|
+
if (!this.orchestrator.config.identityContinuityEnabled) {
|
|
1909
|
+
return { enabled: false, reason: "Identity continuity is disabled." };
|
|
1910
|
+
}
|
|
1911
|
+
const resolvedNs = this.resolveReadableNamespace(request.namespace, request.principal);
|
|
1912
|
+
const storage = await this.orchestrator.getStorage(resolvedNs);
|
|
1913
|
+
const anchor = await storage.readIdentityAnchor();
|
|
1914
|
+
if (!anchor) return { found: false, message: "No identity anchor found yet. Use identity_anchor_update to create one." };
|
|
1915
|
+
return { found: true, anchor };
|
|
1916
|
+
}
|
|
1917
|
+
async identityAnchorUpdate(request) {
|
|
1918
|
+
if (!this.orchestrator.config.identityContinuityEnabled) {
|
|
1919
|
+
return { enabled: false, reason: "Identity continuity is disabled." };
|
|
1920
|
+
}
|
|
1921
|
+
const updates = {
|
|
1922
|
+
"Identity Traits": request.identityTraits?.trim() || void 0,
|
|
1923
|
+
"Communication Preferences": request.communicationPreferences?.trim() || void 0,
|
|
1924
|
+
"Operating Principles": request.operatingPrinciples?.trim() || void 0,
|
|
1925
|
+
"Continuity Notes": request.continuityNotes?.trim() || void 0
|
|
1926
|
+
};
|
|
1927
|
+
const hasUpdate = Object.values(updates).some((v) => typeof v === "string" && v.length > 0);
|
|
1928
|
+
if (!hasUpdate) throw new EngramAccessInputError("At least one section field is required.");
|
|
1929
|
+
const resolvedNs = this.resolveWritableNamespace(request.namespace, void 0, request.principal);
|
|
1930
|
+
const storage = await this.orchestrator.getStorage(resolvedNs);
|
|
1931
|
+
const existing = await storage.readIdentityAnchor();
|
|
1932
|
+
const merged = this.mergeIdentityAnchorSections(existing, updates);
|
|
1933
|
+
await storage.writeIdentityAnchor(merged);
|
|
1934
|
+
const updatedSections = Object.entries(updates).filter(([, v]) => typeof v === "string" && v.length > 0).map(([name]) => name);
|
|
1935
|
+
return { updated: true, sections: updatedSections, anchor: merged };
|
|
1936
|
+
}
|
|
1937
|
+
async memoryIdentity(request) {
|
|
1938
|
+
const resolvedNs = this.resolveReadableNamespace(request.namespace, request.principal);
|
|
1939
|
+
const storage = await this.orchestrator.getStorage(resolvedNs);
|
|
1940
|
+
const identity = await storage.readIdentityReflections();
|
|
1941
|
+
if (!identity) return { found: false, message: "No identity reflections found." };
|
|
1942
|
+
return { found: true, identity };
|
|
1943
|
+
}
|
|
1944
|
+
// ── Work Layer ──────────────────────────────────────────────────────────
|
|
1945
|
+
async workTask(request) {
|
|
1946
|
+
const STATUSES = /* @__PURE__ */ new Set(["todo", "in_progress", "blocked", "done", "cancelled"]);
|
|
1947
|
+
const PRIORITIES = /* @__PURE__ */ new Set(["low", "medium", "high"]);
|
|
1948
|
+
const asStatus = (v) => v && STATUSES.has(v) ? v : void 0;
|
|
1949
|
+
const asPriority = (v) => v && PRIORITIES.has(v) ? v : void 0;
|
|
1950
|
+
const storage = new WorkStorage(this.orchestrator.config.memoryDir);
|
|
1951
|
+
await storage.ensureDirectories();
|
|
1952
|
+
const action = request.action;
|
|
1953
|
+
if (action === "create") {
|
|
1954
|
+
if (!request.title?.trim()) throw new EngramAccessInputError("title is required for create");
|
|
1955
|
+
const task = await storage.createTask({
|
|
1956
|
+
title: request.title,
|
|
1957
|
+
description: request.description,
|
|
1958
|
+
status: asStatus(request.status),
|
|
1959
|
+
priority: asPriority(request.priority),
|
|
1960
|
+
owner: request.owner?.trim() || void 0,
|
|
1961
|
+
assignee: request.assignee?.trim() || void 0,
|
|
1962
|
+
projectId: request.projectId?.trim() || void 0,
|
|
1963
|
+
tags: request.tags,
|
|
1964
|
+
dueAt: request.dueAt?.trim() || void 0
|
|
1965
|
+
});
|
|
1966
|
+
return { action, task };
|
|
1967
|
+
}
|
|
1968
|
+
if (action === "get") {
|
|
1969
|
+
if (!request.id?.trim()) throw new EngramAccessInputError("id is required for get");
|
|
1970
|
+
return { action, task: await storage.getTask(request.id) };
|
|
1971
|
+
}
|
|
1972
|
+
if (action === "list") {
|
|
1973
|
+
const tasks = await storage.listTasks({
|
|
1974
|
+
status: asStatus(request.status),
|
|
1975
|
+
owner: request.owner?.trim() || void 0,
|
|
1976
|
+
assignee: request.assignee?.trim() || void 0,
|
|
1977
|
+
projectId: request.projectId?.trim() || void 0
|
|
1978
|
+
});
|
|
1979
|
+
return { action, count: tasks.length, tasks };
|
|
1980
|
+
}
|
|
1981
|
+
if (action === "update") {
|
|
1982
|
+
if (!request.id?.trim()) throw new EngramAccessInputError("id is required for update");
|
|
1983
|
+
const patch = {};
|
|
1984
|
+
if (request.title !== void 0) patch.title = request.title;
|
|
1985
|
+
if (request.description !== void 0) patch.description = request.description;
|
|
1986
|
+
const st = asStatus(request.status);
|
|
1987
|
+
if (st) patch.status = st;
|
|
1988
|
+
const pr = asPriority(request.priority);
|
|
1989
|
+
if (pr) patch.priority = pr;
|
|
1990
|
+
if (request.owner !== void 0) patch.owner = request.owner || null;
|
|
1991
|
+
if (request.assignee !== void 0) patch.assignee = request.assignee || null;
|
|
1992
|
+
if (request.projectId !== void 0) patch.projectId = request.projectId || null;
|
|
1993
|
+
if (request.tags) patch.tags = request.tags;
|
|
1994
|
+
if (request.dueAt !== void 0) patch.dueAt = request.dueAt || null;
|
|
1995
|
+
return { action, task: await storage.updateTask(request.id, patch) };
|
|
1996
|
+
}
|
|
1997
|
+
if (action === "transition") {
|
|
1998
|
+
if (!request.id?.trim()) throw new EngramAccessInputError("id is required for transition");
|
|
1999
|
+
const st = asStatus(request.status);
|
|
2000
|
+
if (!st) throw new EngramAccessInputError("valid status is required for transition");
|
|
2001
|
+
return { action, task: await storage.transitionTask(request.id, st) };
|
|
2002
|
+
}
|
|
2003
|
+
if (action === "delete") {
|
|
2004
|
+
if (!request.id?.trim()) throw new EngramAccessInputError("id is required for delete");
|
|
2005
|
+
return { action, deleted: await storage.deleteTask(request.id) };
|
|
2006
|
+
}
|
|
2007
|
+
throw new EngramAccessInputError(`Unsupported work_task action: ${action}`);
|
|
2008
|
+
}
|
|
2009
|
+
async workProject(request) {
|
|
2010
|
+
const STATUSES = /* @__PURE__ */ new Set(["active", "on_hold", "completed", "archived"]);
|
|
2011
|
+
const asStatus = (v) => v && STATUSES.has(v) ? v : void 0;
|
|
2012
|
+
const storage = new WorkStorage(this.orchestrator.config.memoryDir);
|
|
2013
|
+
await storage.ensureDirectories();
|
|
2014
|
+
const action = request.action;
|
|
2015
|
+
if (action === "create") {
|
|
2016
|
+
if (!request.name?.trim()) throw new EngramAccessInputError("name is required for create");
|
|
2017
|
+
const project = await storage.createProject({
|
|
2018
|
+
name: request.name,
|
|
2019
|
+
description: request.description,
|
|
2020
|
+
status: asStatus(request.status),
|
|
2021
|
+
owner: request.owner?.trim() || void 0,
|
|
2022
|
+
tags: request.tags
|
|
2023
|
+
});
|
|
2024
|
+
return { action, project };
|
|
2025
|
+
}
|
|
2026
|
+
if (action === "get") {
|
|
2027
|
+
if (!request.id?.trim()) throw new EngramAccessInputError("id is required for get");
|
|
2028
|
+
return { action, project: await storage.getProject(request.id) };
|
|
2029
|
+
}
|
|
2030
|
+
if (action === "list") {
|
|
2031
|
+
const projects = await storage.listProjects();
|
|
2032
|
+
return { action, count: projects.length, projects };
|
|
2033
|
+
}
|
|
2034
|
+
if (action === "update") {
|
|
2035
|
+
if (!request.id?.trim()) throw new EngramAccessInputError("id is required for update");
|
|
2036
|
+
const patch = {};
|
|
2037
|
+
if (request.name !== void 0) patch.name = request.name;
|
|
2038
|
+
if (request.description !== void 0) patch.description = request.description;
|
|
2039
|
+
const st = asStatus(request.status);
|
|
2040
|
+
if (st) patch.status = st;
|
|
2041
|
+
if (request.owner !== void 0) patch.owner = request.owner || null;
|
|
2042
|
+
if (request.tags) patch.tags = request.tags;
|
|
2043
|
+
return { action, project: await storage.updateProject(request.id, patch) };
|
|
2044
|
+
}
|
|
2045
|
+
if (action === "delete") {
|
|
2046
|
+
if (!request.id?.trim()) throw new EngramAccessInputError("id is required for delete");
|
|
2047
|
+
return { action, deleted: await storage.deleteProject(request.id) };
|
|
2048
|
+
}
|
|
2049
|
+
if (action === "link_task") {
|
|
2050
|
+
if (!request.taskId?.trim() || !request.projectId?.trim()) {
|
|
2051
|
+
throw new EngramAccessInputError("taskId and projectId are required for link_task");
|
|
2052
|
+
}
|
|
2053
|
+
return { action, linked: await storage.linkTaskToProject(request.taskId, request.projectId) };
|
|
2054
|
+
}
|
|
2055
|
+
throw new EngramAccessInputError(`Unsupported work_project action: ${action}`);
|
|
2056
|
+
}
|
|
2057
|
+
async workBoard(request) {
|
|
2058
|
+
const memoryDir = this.orchestrator.config.memoryDir;
|
|
2059
|
+
await new WorkStorage(memoryDir).ensureDirectories();
|
|
2060
|
+
const action = request.action;
|
|
2061
|
+
const projectId = request.projectId?.trim() || void 0;
|
|
2062
|
+
if (action === "export_markdown") {
|
|
2063
|
+
const markdown = await exportWorkBoardMarkdown({ memoryDir, projectId });
|
|
2064
|
+
return { action, markdown: wrapWorkLayerContext(markdown, { linkToMemory: request.linkToMemory === true }) };
|
|
2065
|
+
}
|
|
2066
|
+
if (action === "export_snapshot") {
|
|
2067
|
+
const snapshot = await exportWorkBoardSnapshot({ memoryDir, projectId });
|
|
2068
|
+
return { action, snapshot };
|
|
2069
|
+
}
|
|
2070
|
+
if (action === "import_snapshot") {
|
|
2071
|
+
if (!request.snapshotJson?.trim()) throw new EngramAccessInputError("snapshotJson is required for import_snapshot");
|
|
2072
|
+
const snapshot = JSON.parse(request.snapshotJson);
|
|
2073
|
+
const result = await importWorkBoardSnapshot({ memoryDir, snapshot, projectId });
|
|
2074
|
+
return { action, result };
|
|
2075
|
+
}
|
|
2076
|
+
throw new EngramAccessInputError(`Unsupported work_board action: ${action}`);
|
|
2077
|
+
}
|
|
2078
|
+
// ── Shared Context / Compounding ────────────────────────────────────────
|
|
2079
|
+
async sharedContextWriteOutput(request) {
|
|
2080
|
+
if (!this.orchestrator.sharedContext) {
|
|
2081
|
+
return { enabled: false, reason: "Shared context is disabled. Enable `sharedContextEnabled: true`." };
|
|
2082
|
+
}
|
|
2083
|
+
const fp = await this.orchestrator.sharedContext.writeAgentOutput({
|
|
2084
|
+
agentId: request.agentId,
|
|
2085
|
+
title: request.title,
|
|
2086
|
+
content: request.content
|
|
2087
|
+
});
|
|
2088
|
+
return { written: true, path: fp };
|
|
2089
|
+
}
|
|
2090
|
+
async sharedFeedbackRecord(request) {
|
|
2091
|
+
if (!this.orchestrator.sharedContext) {
|
|
2092
|
+
return { enabled: false, reason: "Shared context is disabled. Enable `sharedContextEnabled: true`." };
|
|
2093
|
+
}
|
|
2094
|
+
await this.orchestrator.sharedContext.appendFeedback({
|
|
2095
|
+
agent: request.agent,
|
|
2096
|
+
decision: request.decision,
|
|
2097
|
+
reason: request.reason,
|
|
2098
|
+
date: request.date?.trim() || (/* @__PURE__ */ new Date()).toISOString(),
|
|
2099
|
+
learning: request.learning,
|
|
2100
|
+
outcome: request.outcome,
|
|
2101
|
+
severity: request.severity,
|
|
2102
|
+
confidence: request.confidence,
|
|
2103
|
+
workflow: request.workflow,
|
|
2104
|
+
tags: request.tags,
|
|
2105
|
+
evidenceWindowStart: request.evidenceWindowStart,
|
|
2106
|
+
evidenceWindowEnd: request.evidenceWindowEnd,
|
|
2107
|
+
refs: request.refs
|
|
2108
|
+
});
|
|
2109
|
+
return { recorded: true };
|
|
2110
|
+
}
|
|
2111
|
+
async sharedPrioritiesAppend(request) {
|
|
2112
|
+
if (!this.orchestrator.sharedContext) {
|
|
2113
|
+
return { enabled: false, reason: "Shared context is disabled. Enable `sharedContextEnabled: true`." };
|
|
2114
|
+
}
|
|
2115
|
+
await this.orchestrator.sharedContext.appendPrioritiesInbox({
|
|
2116
|
+
agentId: request.agentId,
|
|
2117
|
+
text: request.text
|
|
2118
|
+
});
|
|
2119
|
+
return { appended: true };
|
|
2120
|
+
}
|
|
2121
|
+
async sharedContextCrossSignalsRun(request) {
|
|
2122
|
+
if (!this.orchestrator.sharedContext) {
|
|
2123
|
+
return { enabled: false, reason: "Shared context is disabled. Enable `sharedContextEnabled: true`." };
|
|
2124
|
+
}
|
|
2125
|
+
const result = await this.orchestrator.sharedContext.synthesizeCrossSignals({ date: request.date });
|
|
2126
|
+
return {
|
|
2127
|
+
crossSignalsMarkdownPath: result.crossSignalsMarkdownPath,
|
|
2128
|
+
crossSignalsPath: result.crossSignalsPath,
|
|
2129
|
+
sourceCount: result.report.sourceCount,
|
|
2130
|
+
feedbackCount: result.report.feedbackCount,
|
|
2131
|
+
overlapCount: result.overlapCount
|
|
2132
|
+
};
|
|
2133
|
+
}
|
|
2134
|
+
async sharedContextCurateDaily(request) {
|
|
2135
|
+
if (!this.orchestrator.sharedContext) {
|
|
2136
|
+
return { enabled: false, reason: "Shared context is disabled. Enable `sharedContextEnabled: true`." };
|
|
2137
|
+
}
|
|
2138
|
+
const result = await this.orchestrator.sharedContext.curateDaily({ date: request.date });
|
|
2139
|
+
return {
|
|
2140
|
+
roundtablePath: result.roundtablePath,
|
|
2141
|
+
crossSignalsMarkdownPath: result.crossSignalsMarkdownPath,
|
|
2142
|
+
crossSignalsPath: result.crossSignalsPath,
|
|
2143
|
+
overlapCount: result.overlapCount
|
|
2144
|
+
};
|
|
2145
|
+
}
|
|
2146
|
+
async compoundingWeeklySynthesize(request) {
|
|
2147
|
+
if (!this.orchestrator.compounding) {
|
|
2148
|
+
return { enabled: false, reason: "Compounding engine is disabled. Enable `compoundingEnabled: true`." };
|
|
2149
|
+
}
|
|
2150
|
+
const res = await this.orchestrator.compounding.synthesizeWeekly({ weekId: request.weekId });
|
|
2151
|
+
return {
|
|
2152
|
+
weekId: res.weekId,
|
|
2153
|
+
reportPath: res.reportPath,
|
|
2154
|
+
reportJsonPath: res.reportJsonPath,
|
|
2155
|
+
rubricsPath: res.rubricsPath,
|
|
2156
|
+
rubricsIndexPath: res.rubricsIndexPath,
|
|
2157
|
+
mistakesCount: res.mistakesCount,
|
|
2158
|
+
promotionCandidateCount: res.promotionCandidateCount
|
|
2159
|
+
};
|
|
2160
|
+
}
|
|
2161
|
+
async compoundingPromoteCandidate(request) {
|
|
2162
|
+
if (!this.orchestrator.compounding) {
|
|
2163
|
+
return { enabled: false, reason: "Compounding engine is disabled. Enable `compoundingEnabled: true`." };
|
|
2164
|
+
}
|
|
2165
|
+
return await this.orchestrator.compounding.promoteCandidate({
|
|
2166
|
+
weekId: request.weekId,
|
|
2167
|
+
candidateId: request.candidateId,
|
|
2168
|
+
dryRun: request.dryRun
|
|
2169
|
+
});
|
|
2170
|
+
}
|
|
2171
|
+
// ── Compression Guidelines ────────────────────────────────────────────
|
|
2172
|
+
async compressionGuidelinesOptimize(request) {
|
|
2173
|
+
if (!this.orchestrator.config.compressionGuidelineLearningEnabled) {
|
|
2174
|
+
return { enabled: false, reason: "Compression guideline learning is disabled. Enable `compressionGuidelineLearningEnabled: true`." };
|
|
2175
|
+
}
|
|
2176
|
+
return await this.orchestrator.optimizeCompressionGuidelines({
|
|
2177
|
+
dryRun: request.dryRun,
|
|
2178
|
+
eventLimit: request.eventLimit
|
|
2179
|
+
});
|
|
2180
|
+
}
|
|
2181
|
+
async compressionGuidelinesActivate(request) {
|
|
2182
|
+
if (!this.orchestrator.config.compressionGuidelineLearningEnabled) {
|
|
2183
|
+
return { enabled: false, reason: "Compression guideline learning is disabled." };
|
|
2184
|
+
}
|
|
2185
|
+
return await this.orchestrator.activateCompressionGuidelineDraft({
|
|
2186
|
+
expectedContentHash: request.expectedContentHash,
|
|
2187
|
+
expectedGuidelineVersion: request.expectedGuidelineVersion
|
|
2188
|
+
});
|
|
2189
|
+
}
|
|
2190
|
+
/** Conservative identity anchor section merge (matches tools.ts mergeIdentityAnchor logic). */
|
|
2191
|
+
mergeIdentityAnchorSections(existingRaw, updates) {
|
|
2192
|
+
const TITLE = "# Identity Continuity Anchor";
|
|
2193
|
+
const SECTION_ORDER = ["Identity Traits", "Communication Preferences", "Operating Principles", "Continuity Notes"];
|
|
2194
|
+
const lines = (existingRaw ?? "").replace(/\r/g, "").split("\n");
|
|
2195
|
+
const headerLines = [];
|
|
2196
|
+
const sectionContent = /* @__PURE__ */ new Map();
|
|
2197
|
+
const order = [];
|
|
2198
|
+
let current = null;
|
|
2199
|
+
for (const line of lines) {
|
|
2200
|
+
const m = line.match(/^##\s+(.+?)\s*$/);
|
|
2201
|
+
if (m) {
|
|
2202
|
+
current = m[1].trim();
|
|
2203
|
+
if (!sectionContent.has(current)) {
|
|
2204
|
+
sectionContent.set(current, []);
|
|
2205
|
+
order.push(current);
|
|
2206
|
+
}
|
|
2207
|
+
continue;
|
|
2208
|
+
}
|
|
2209
|
+
if (!current) {
|
|
2210
|
+
headerLines.push(line);
|
|
2211
|
+
} else {
|
|
2212
|
+
sectionContent.get(current)?.push(line);
|
|
2213
|
+
}
|
|
2214
|
+
}
|
|
2215
|
+
const sections = /* @__PURE__ */ new Map();
|
|
2216
|
+
for (const [name, cLines] of sectionContent) sections.set(name, cLines.join("\n").trim());
|
|
2217
|
+
const header = headerLines.join("\n").trim() || TITLE;
|
|
2218
|
+
for (const sectionName of SECTION_ORDER) {
|
|
2219
|
+
const prev = sections.get(sectionName)?.trim();
|
|
2220
|
+
const next = updates[sectionName]?.trim();
|
|
2221
|
+
const existing = prev === "- (empty)" ? "" : prev;
|
|
2222
|
+
if (!next) {
|
|
2223
|
+
if (!sections.has(sectionName)) sections.set(sectionName, "");
|
|
2224
|
+
continue;
|
|
2225
|
+
}
|
|
2226
|
+
if (!existing) {
|
|
2227
|
+
sections.set(sectionName, next);
|
|
2228
|
+
continue;
|
|
2229
|
+
}
|
|
2230
|
+
if (existing.includes(next)) continue;
|
|
2231
|
+
if (next.includes(existing)) {
|
|
2232
|
+
sections.set(sectionName, next);
|
|
2233
|
+
continue;
|
|
2234
|
+
}
|
|
2235
|
+
sections.set(sectionName, `${existing}
|
|
2236
|
+
|
|
2237
|
+
${next}`);
|
|
2238
|
+
}
|
|
2239
|
+
const finalOrder = [...SECTION_ORDER.filter((s) => sections.has(s)), ...order.filter((s) => !SECTION_ORDER.includes(s) && sections.has(s))];
|
|
2240
|
+
const out = [header, ""];
|
|
2241
|
+
for (const name of finalOrder) {
|
|
2242
|
+
out.push(`## ${name}`, "");
|
|
2243
|
+
const body = sections.get(name)?.trim();
|
|
2244
|
+
if (body) out.push(body, "");
|
|
2245
|
+
else out.push("");
|
|
2246
|
+
}
|
|
2247
|
+
return out.join("\n").replace(/\n{3,}/g, "\n\n").trimEnd() + "\n";
|
|
2248
|
+
}
|
|
2249
|
+
// ── Memory search & debug ─────────────────────────────────────────────
|
|
2250
|
+
async memorySearch(request) {
|
|
2251
|
+
const { query, namespace, maxResults, collection, principal } = request;
|
|
2252
|
+
const resolvedNs = this.resolveReadableNamespace(namespace, principal);
|
|
2253
|
+
const namespaceFilter = resolvedNs !== this.orchestrator.config.defaultNamespace ? resolvedNs : void 0;
|
|
2254
|
+
const results = collection === "global" ? (await this.orchestrator.qmd.searchGlobal(query, maxResults)).filter(
|
|
2255
|
+
(r) => namespaceFilter ? r.path.includes(`/namespaces/${namespaceFilter}/`) || !r.path.includes("/namespaces/") && namespaceFilter === this.orchestrator.config.defaultNamespace : true
|
|
2256
|
+
) : await this.orchestrator.searchAcrossNamespaces({
|
|
2257
|
+
query,
|
|
2258
|
+
namespaces: namespaceFilter ? [namespaceFilter] : void 0,
|
|
2259
|
+
maxResults,
|
|
2260
|
+
mode: "search"
|
|
2261
|
+
});
|
|
2262
|
+
return {
|
|
2263
|
+
query,
|
|
2264
|
+
results: results.map((r) => ({
|
|
2265
|
+
path: r.path,
|
|
2266
|
+
score: r.score,
|
|
2267
|
+
snippet: (r.snippet ?? "").slice(0, 800)
|
|
2268
|
+
})),
|
|
2269
|
+
count: results.length
|
|
2270
|
+
};
|
|
2271
|
+
}
|
|
2272
|
+
async memoryProfile(namespace, principal) {
|
|
2273
|
+
const resolvedNs = this.resolveReadableNamespace(namespace, principal);
|
|
2274
|
+
const storage = await this.orchestrator.getStorage(resolvedNs);
|
|
2275
|
+
const profile = await storage.readProfile();
|
|
2276
|
+
return {
|
|
2277
|
+
profile: profile || "No profile built yet. The profile builds automatically through conversations."
|
|
2278
|
+
};
|
|
2279
|
+
}
|
|
2280
|
+
async memoryEntitiesList(namespace, principal) {
|
|
2281
|
+
const resolvedNs = this.resolveReadableNamespace(namespace, principal);
|
|
2282
|
+
const storage = await this.orchestrator.getStorage(resolvedNs);
|
|
2283
|
+
const entities = await storage.readEntities();
|
|
2284
|
+
return { entities, count: entities.length };
|
|
2285
|
+
}
|
|
2286
|
+
async memoryQuestions(namespace, principal) {
|
|
2287
|
+
const resolvedNs = this.resolveReadableNamespace(namespace, principal);
|
|
2288
|
+
const storage = await this.orchestrator.getStorage(resolvedNs);
|
|
2289
|
+
const questions = await storage.readQuestions();
|
|
2290
|
+
return {
|
|
2291
|
+
questions: questions.map((q) => ({ id: q.id, question: q.question, resolved: q.resolved })),
|
|
2292
|
+
count: questions.length
|
|
2293
|
+
};
|
|
2294
|
+
}
|
|
2295
|
+
async lastRecallSnapshot(sessionKey) {
|
|
2296
|
+
const snapshot = sessionKey ? this.orchestrator.lastRecall.get(sessionKey) : this.orchestrator.lastRecall.getMostRecent();
|
|
2297
|
+
return snapshot ?? { message: "No recall snapshot available" };
|
|
2298
|
+
}
|
|
2299
|
+
async intentDebug(namespace) {
|
|
2300
|
+
const snapshot = await this.orchestrator.getLastIntentSnapshot(namespace);
|
|
2301
|
+
return snapshot ?? { message: "No intent debug snapshot available" };
|
|
2302
|
+
}
|
|
2303
|
+
async qmdDebug(namespace) {
|
|
2304
|
+
const snapshot = await this.orchestrator.getLastQmdRecallSnapshot(namespace);
|
|
2305
|
+
return snapshot ?? { message: "No QMD debug snapshot available" };
|
|
2306
|
+
}
|
|
2307
|
+
async graphExplainLastRecall(namespace) {
|
|
2308
|
+
const explanation = await this.orchestrator.explainLastGraphRecall({ namespace });
|
|
2309
|
+
return { explanation };
|
|
2310
|
+
}
|
|
2311
|
+
async memoryFeedback(request) {
|
|
2312
|
+
if (!this.orchestrator.config.feedbackEnabled) {
|
|
2313
|
+
return {
|
|
2314
|
+
recorded: false,
|
|
2315
|
+
enabled: false,
|
|
2316
|
+
reason: "Feedback is disabled. Enable `feedbackEnabled: true` in the Engram config to store feedback."
|
|
2317
|
+
};
|
|
2318
|
+
}
|
|
2319
|
+
await this.orchestrator.recordMemoryFeedback(
|
|
2320
|
+
request.memoryId,
|
|
2321
|
+
request.vote,
|
|
2322
|
+
request.note
|
|
2323
|
+
);
|
|
2324
|
+
return { recorded: true };
|
|
2325
|
+
}
|
|
2326
|
+
async memoryPromote(request) {
|
|
2327
|
+
const resolvedNs = this.resolveWritableNamespace(request.namespace, request.sessionKey, request.principal);
|
|
2328
|
+
const storage = await this.orchestrator.getStorage(resolvedNs);
|
|
2329
|
+
await storage.updateMemoryFrontmatter(request.memoryId, {
|
|
2330
|
+
lifecycleState: "active",
|
|
2331
|
+
updated: (/* @__PURE__ */ new Date()).toISOString()
|
|
2332
|
+
});
|
|
2333
|
+
return { promoted: true, memoryId: request.memoryId };
|
|
2334
|
+
}
|
|
2335
|
+
async contextCheckpoint(request) {
|
|
2336
|
+
const resolvedNs = this.resolveWritableNamespace(request.namespace, request.sessionKey, request.principal);
|
|
2337
|
+
const storage = await this.orchestrator.getStorage(resolvedNs);
|
|
2338
|
+
const storageDir = storage.dir;
|
|
2339
|
+
const { writeFile: writeFile2, mkdir: mkdir2 } = await import("fs/promises");
|
|
2340
|
+
const { join, resolve } = await import("path");
|
|
2341
|
+
const safeKey = request.sessionKey.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
2342
|
+
if (!safeKey) throw new EngramAccessInputError("sessionKey is required");
|
|
2343
|
+
const checkpointDir = join(storageDir, "checkpoints", safeKey);
|
|
2344
|
+
const resolved = resolve(checkpointDir);
|
|
2345
|
+
if (!resolved.startsWith(resolve(storageDir))) {
|
|
2346
|
+
throw new EngramAccessInputError("Invalid sessionKey");
|
|
2347
|
+
}
|
|
2348
|
+
await mkdir2(checkpointDir, { recursive: true });
|
|
2349
|
+
const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
2350
|
+
const filePath = join(checkpointDir, `checkpoint-${ts}.md`);
|
|
2351
|
+
await writeFile2(filePath, request.context, "utf-8");
|
|
2352
|
+
return { saved: true };
|
|
2353
|
+
}
|
|
2354
|
+
async lcmStatus() {
|
|
2355
|
+
if (!this.orchestrator.lcmEngine || !this.orchestrator.lcmEngine.enabled) {
|
|
2356
|
+
return {
|
|
2357
|
+
enabled: false,
|
|
2358
|
+
archiveAvailable: false
|
|
2359
|
+
};
|
|
2360
|
+
}
|
|
2361
|
+
const stats = await this.orchestrator.lcmEngine.getStats();
|
|
2362
|
+
return {
|
|
2363
|
+
enabled: true,
|
|
2364
|
+
archiveAvailable: true,
|
|
2365
|
+
stats: {
|
|
2366
|
+
totalTurns: stats.totalMessages
|
|
2367
|
+
}
|
|
2368
|
+
};
|
|
2369
|
+
}
|
|
2370
|
+
};
|
|
2371
|
+
|
|
2372
|
+
export {
|
|
2373
|
+
WorkStorage,
|
|
2374
|
+
EngramAccessInputError,
|
|
2375
|
+
ENGRAM_ACCESS_WRITE_SCHEMA_VERSION,
|
|
2376
|
+
EngramAccessService
|
|
2377
|
+
};
|
|
2378
|
+
//# sourceMappingURL=chunk-QY2BHY5O.js.map
|