@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
package/dist/index.js
ADDED
|
@@ -0,0 +1,2512 @@
|
|
|
1
|
+
import {
|
|
2
|
+
generateToken,
|
|
3
|
+
getAllValidTokens,
|
|
4
|
+
getAllValidTokensCached,
|
|
5
|
+
listTokens,
|
|
6
|
+
loadTokenStore,
|
|
7
|
+
resolveConnectorFromToken,
|
|
8
|
+
revokeToken,
|
|
9
|
+
saveTokenStore
|
|
10
|
+
} from "./chunk-KL4CP4SB.js";
|
|
11
|
+
import {
|
|
12
|
+
Orchestrator,
|
|
13
|
+
defaultWorkspaceDir,
|
|
14
|
+
migrateFromEngram,
|
|
15
|
+
rollbackFromEngramMigration,
|
|
16
|
+
sanitizeSessionKeyForFilename
|
|
17
|
+
} from "./chunk-YAPUAHAY.js";
|
|
18
|
+
import "./chunk-IFFFR3MR.js";
|
|
19
|
+
import "./chunk-TKO4HZCK.js";
|
|
20
|
+
import "./chunk-Z5AAYHUC.js";
|
|
21
|
+
import "./chunk-4A24LIM2.js";
|
|
22
|
+
import "./chunk-TPB3I2AC.js";
|
|
23
|
+
import "./chunk-UHGBNIOS.js";
|
|
24
|
+
import "./chunk-ZKYI7UVO.js";
|
|
25
|
+
import "./chunk-CDW777AI.js";
|
|
26
|
+
import "./chunk-ETOW6ACV.js";
|
|
27
|
+
import "./chunk-G3AG3KZN.js";
|
|
28
|
+
import "./chunk-2CJCWDMR.js";
|
|
29
|
+
import "./chunk-X7XN6YU4.js";
|
|
30
|
+
import "./chunk-BRK4ODMI.js";
|
|
31
|
+
import "./chunk-C7VW7C3F.js";
|
|
32
|
+
import "./chunk-GPGBSNKM.js";
|
|
33
|
+
import "./chunk-V3RXWQIE.js";
|
|
34
|
+
import "./chunk-YCN4BVDK.js";
|
|
35
|
+
import "./chunk-L5RPWGFK.js";
|
|
36
|
+
import "./chunk-HG2NKWR2.js";
|
|
37
|
+
import "./chunk-GJR6D6KC.js";
|
|
38
|
+
import "./chunk-H63EDPFJ.js";
|
|
39
|
+
import "./chunk-WWIQTB2Y.js";
|
|
40
|
+
import {
|
|
41
|
+
ExtractionEngine
|
|
42
|
+
} from "./chunk-QFQVZOGA.js";
|
|
43
|
+
import "./chunk-MWGVGUIS.js";
|
|
44
|
+
import "./chunk-763GUIOU.js";
|
|
45
|
+
import "./chunk-ONRU4L2N.js";
|
|
46
|
+
import "./chunk-MDDAA2AO.js";
|
|
47
|
+
import "./chunk-YAZNBMNF.js";
|
|
48
|
+
import {
|
|
49
|
+
loadDaySummaryPrompt
|
|
50
|
+
} from "./chunk-2PO5ZRKV.js";
|
|
51
|
+
import "./chunk-VEWZZM3H.js";
|
|
52
|
+
import "./chunk-QPKFPHOO.js";
|
|
53
|
+
import {
|
|
54
|
+
buildEntityRecallSection
|
|
55
|
+
} from "./chunk-V4YC4LUK.js";
|
|
56
|
+
import "./chunk-HLBYLYRD.js";
|
|
57
|
+
import "./chunk-OTAVQCSF.js";
|
|
58
|
+
import "./chunk-3QKK7QOS.js";
|
|
59
|
+
import "./chunk-UIYZ5T3I.js";
|
|
60
|
+
import "./chunk-UCYSTFZR.js";
|
|
61
|
+
import "./chunk-J47FNDR7.js";
|
|
62
|
+
import "./chunk-CULXMQJH.js";
|
|
63
|
+
import "./chunk-UV2FO7J4.js";
|
|
64
|
+
import "./chunk-T4WRIV2C.js";
|
|
65
|
+
import "./chunk-LOBRX7VD.js";
|
|
66
|
+
import {
|
|
67
|
+
LanceDbBackend,
|
|
68
|
+
MeilisearchBackend,
|
|
69
|
+
OramaBackend
|
|
70
|
+
} from "./chunk-IZME7KW2.js";
|
|
71
|
+
import "./chunk-YRMVARQP.js";
|
|
72
|
+
import {
|
|
73
|
+
QmdClient
|
|
74
|
+
} from "./chunk-TVVVQQAK.js";
|
|
75
|
+
import "./chunk-BDFZXRSO.js";
|
|
76
|
+
import "./chunk-LK6SGL53.js";
|
|
77
|
+
import "./chunk-AAI7JARD.js";
|
|
78
|
+
import "./chunk-C6QPK5GG.js";
|
|
79
|
+
import "./chunk-Q6FETXJA.js";
|
|
80
|
+
import "./chunk-K6WK37A6.js";
|
|
81
|
+
import "./chunk-SCHEKPYH.js";
|
|
82
|
+
import "./chunk-ORZMT74A.js";
|
|
83
|
+
import "./chunk-B7LOFDVE.js";
|
|
84
|
+
import "./chunk-FYIYMQ5N.js";
|
|
85
|
+
import "./chunk-2NMMFZ5T.js";
|
|
86
|
+
import {
|
|
87
|
+
parseConfig
|
|
88
|
+
} from "./chunk-ISY75RLM.js";
|
|
89
|
+
import "./chunk-Z5LAYHGJ.js";
|
|
90
|
+
import "./chunk-JWPLJLDU.js";
|
|
91
|
+
import {
|
|
92
|
+
BootstrapEngine
|
|
93
|
+
} from "./chunk-YNI4S5WT.js";
|
|
94
|
+
import "./chunk-DORBM6OB.js";
|
|
95
|
+
import "./chunk-XYIK4LF6.js";
|
|
96
|
+
import "./chunk-KT4NEUNF.js";
|
|
97
|
+
import "./chunk-LU3GQNDQ.js";
|
|
98
|
+
import "./chunk-Y27UJK6V.js";
|
|
99
|
+
import "./chunk-UZB5KHKX.js";
|
|
100
|
+
import "./chunk-M5KEYE5E.js";
|
|
101
|
+
import "./chunk-NGAVDO7E.js";
|
|
102
|
+
import {
|
|
103
|
+
EngramAccessHttpServer
|
|
104
|
+
} from "./chunk-ZJLY4QSU.js";
|
|
105
|
+
import {
|
|
106
|
+
EngramMcpServer
|
|
107
|
+
} from "./chunk-CXWFUJR2.js";
|
|
108
|
+
import "./chunk-MARWOCVP.js";
|
|
109
|
+
import {
|
|
110
|
+
formatZodError,
|
|
111
|
+
memoryStoreRequestSchema,
|
|
112
|
+
observeRequestSchema,
|
|
113
|
+
recallRequestSchema,
|
|
114
|
+
suggestionSubmitRequestSchema,
|
|
115
|
+
validateRequest
|
|
116
|
+
} from "./chunk-PGK3VUHN.js";
|
|
117
|
+
import {
|
|
118
|
+
EngramAccessInputError,
|
|
119
|
+
EngramAccessService
|
|
120
|
+
} from "./chunk-QY2BHY5O.js";
|
|
121
|
+
import "./chunk-N5AKDXAI.js";
|
|
122
|
+
import {
|
|
123
|
+
isTrustZoneName
|
|
124
|
+
} from "./chunk-EQINRHYR.js";
|
|
125
|
+
import "./chunk-J3BT33K7.js";
|
|
126
|
+
import "./chunk-EEQLFRUM.js";
|
|
127
|
+
import {
|
|
128
|
+
StorageManager
|
|
129
|
+
} from "./chunk-QWUUMMIK.js";
|
|
130
|
+
import "./chunk-U4PV25RD.js";
|
|
131
|
+
import "./chunk-ESSMF2FR.js";
|
|
132
|
+
import "./chunk-TP4FZJIZ.js";
|
|
133
|
+
import "./chunk-SCU65EZI.js";
|
|
134
|
+
import "./chunk-BOUYNNYD.js";
|
|
135
|
+
import "./chunk-DM2T26WE.js";
|
|
136
|
+
import "./chunk-QSVPYQPG.js";
|
|
137
|
+
import "./chunk-YNCQ7E4M.js";
|
|
138
|
+
import "./chunk-HLXVTBF3.js";
|
|
139
|
+
import "./chunk-M62O4P4T.js";
|
|
140
|
+
import "./chunk-DT5TVLJE.js";
|
|
141
|
+
import {
|
|
142
|
+
initLogger,
|
|
143
|
+
log
|
|
144
|
+
} from "./chunk-KWBU5S5U.js";
|
|
145
|
+
import "./chunk-DGXUHMOV.js";
|
|
146
|
+
import "./chunk-LPSF4OQH.js";
|
|
147
|
+
import "./chunk-XKECPATV.js";
|
|
148
|
+
import "./chunk-6HZ6AO2P.js";
|
|
149
|
+
import "./chunk-QCCCQT3O.js";
|
|
150
|
+
|
|
151
|
+
// src/projection/index.ts
|
|
152
|
+
import fs from "fs";
|
|
153
|
+
import path2 from "path";
|
|
154
|
+
|
|
155
|
+
// src/utils/category-dir.ts
|
|
156
|
+
import path from "path";
|
|
157
|
+
var CATEGORY_DIR_MAP = {
|
|
158
|
+
correction: "corrections",
|
|
159
|
+
question: "questions",
|
|
160
|
+
preference: "preferences",
|
|
161
|
+
decision: "decisions",
|
|
162
|
+
moment: "moments",
|
|
163
|
+
commitment: "commitments",
|
|
164
|
+
principle: "principles",
|
|
165
|
+
rule: "rules",
|
|
166
|
+
skill: "skills",
|
|
167
|
+
relationship: "relationships"
|
|
168
|
+
};
|
|
169
|
+
var ALL_CATEGORY_DIRS = [
|
|
170
|
+
"facts",
|
|
171
|
+
...Object.values(CATEGORY_DIR_MAP)
|
|
172
|
+
];
|
|
173
|
+
var ALL_CATEGORY_KEYS = [
|
|
174
|
+
"fact",
|
|
175
|
+
...Object.keys(CATEGORY_DIR_MAP)
|
|
176
|
+
];
|
|
177
|
+
function getCategoryDir(memoryDir, category) {
|
|
178
|
+
const dir = CATEGORY_DIR_MAP[category];
|
|
179
|
+
return dir ? path.join(memoryDir, dir) : path.join(memoryDir, "facts");
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// src/projection/index.ts
|
|
183
|
+
async function generateContextTree(options) {
|
|
184
|
+
const startTime = Date.now();
|
|
185
|
+
const {
|
|
186
|
+
memoryDir,
|
|
187
|
+
outputDir,
|
|
188
|
+
categories: filterCategories,
|
|
189
|
+
includeEntities = true,
|
|
190
|
+
includeQuestions = true,
|
|
191
|
+
maxPerCategory = Infinity
|
|
192
|
+
} = options;
|
|
193
|
+
let nodesGenerated = 0;
|
|
194
|
+
let nodesSkipped = 0;
|
|
195
|
+
const categoryCounts = {};
|
|
196
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
197
|
+
const allCategories = filterCategories ?? ALL_CATEGORY_KEYS.filter((c) => c !== "question");
|
|
198
|
+
for (const category of allCategories) {
|
|
199
|
+
const categoryDir = getCategoryDir(memoryDir, category);
|
|
200
|
+
if (!fs.existsSync(categoryDir)) continue;
|
|
201
|
+
categoryCounts[category] = 0;
|
|
202
|
+
const files = walkR(categoryDir);
|
|
203
|
+
let count = 0;
|
|
204
|
+
for (const filePath of files) {
|
|
205
|
+
if (count >= maxPerCategory) {
|
|
206
|
+
nodesSkipped++;
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
209
|
+
const content = fs.readFileSync(filePath, "utf8");
|
|
210
|
+
const fm = parseFrontmatter(content);
|
|
211
|
+
if (!fm) {
|
|
212
|
+
nodesSkipped++;
|
|
213
|
+
continue;
|
|
214
|
+
}
|
|
215
|
+
const node = projectNode(filePath, category, fm, content);
|
|
216
|
+
if (!node) {
|
|
217
|
+
nodesSkipped++;
|
|
218
|
+
continue;
|
|
219
|
+
}
|
|
220
|
+
const outputPath = path2.join(outputDir, node.path);
|
|
221
|
+
fs.mkdirSync(path2.dirname(outputPath), { recursive: true });
|
|
222
|
+
fs.writeFileSync(outputPath, node.content);
|
|
223
|
+
nodesGenerated++;
|
|
224
|
+
categoryCounts[category] = (categoryCounts[category] ?? 0) + 1;
|
|
225
|
+
count++;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
if (includeEntities) {
|
|
229
|
+
const entitiesDir = path2.join(memoryDir, "entities");
|
|
230
|
+
if (fs.existsSync(entitiesDir)) {
|
|
231
|
+
categoryCounts["entity"] = 0;
|
|
232
|
+
const entityFiles = walkR(entitiesDir);
|
|
233
|
+
let count = 0;
|
|
234
|
+
for (const filePath of entityFiles) {
|
|
235
|
+
if (count >= maxPerCategory) {
|
|
236
|
+
nodesSkipped++;
|
|
237
|
+
continue;
|
|
238
|
+
}
|
|
239
|
+
const content = fs.readFileSync(filePath, "utf8");
|
|
240
|
+
const fileName = path2.basename(filePath, ".md");
|
|
241
|
+
const node = projectEntityNode(fileName, content);
|
|
242
|
+
const outputPath = path2.join(outputDir, "entities", `${fileName}.md`);
|
|
243
|
+
fs.mkdirSync(path2.dirname(outputPath), { recursive: true });
|
|
244
|
+
fs.writeFileSync(outputPath, node.content);
|
|
245
|
+
nodesGenerated++;
|
|
246
|
+
categoryCounts["entity"] = (categoryCounts["entity"] ?? 0) + 1;
|
|
247
|
+
count++;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
if (includeQuestions) {
|
|
252
|
+
const questionsDir = path2.join(memoryDir, "questions");
|
|
253
|
+
if (fs.existsSync(questionsDir)) {
|
|
254
|
+
categoryCounts["question"] = 0;
|
|
255
|
+
const qFiles = walkR(questionsDir);
|
|
256
|
+
let count = 0;
|
|
257
|
+
for (const filePath of qFiles) {
|
|
258
|
+
if (count >= maxPerCategory) {
|
|
259
|
+
nodesSkipped++;
|
|
260
|
+
continue;
|
|
261
|
+
}
|
|
262
|
+
const content = fs.readFileSync(filePath, "utf8");
|
|
263
|
+
const fm = parseFrontmatter(content);
|
|
264
|
+
if (!fm) {
|
|
265
|
+
nodesSkipped++;
|
|
266
|
+
continue;
|
|
267
|
+
}
|
|
268
|
+
const node = projectNode(filePath, "question", fm, content);
|
|
269
|
+
if (!node) {
|
|
270
|
+
nodesSkipped++;
|
|
271
|
+
continue;
|
|
272
|
+
}
|
|
273
|
+
const outputPath = path2.join(outputDir, node.path);
|
|
274
|
+
fs.mkdirSync(path2.dirname(outputPath), { recursive: true });
|
|
275
|
+
fs.writeFileSync(outputPath, node.content);
|
|
276
|
+
nodesGenerated++;
|
|
277
|
+
categoryCounts["question"] = (categoryCounts["question"] ?? 0) + 1;
|
|
278
|
+
count++;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
const index = generateIndex(categoryCounts, outputDir);
|
|
283
|
+
fs.writeFileSync(path2.join(outputDir, "INDEX.md"), index);
|
|
284
|
+
return {
|
|
285
|
+
nodesGenerated,
|
|
286
|
+
nodesSkipped,
|
|
287
|
+
categories: categoryCounts,
|
|
288
|
+
durationMs: Date.now() - startTime,
|
|
289
|
+
outputDir
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
function walkR(dir) {
|
|
293
|
+
const results = [];
|
|
294
|
+
function walk(directory) {
|
|
295
|
+
for (const entry of fs.readdirSync(directory, { withFileTypes: true })) {
|
|
296
|
+
const fullPath = path2.join(directory, entry.name);
|
|
297
|
+
if (entry.isDirectory()) {
|
|
298
|
+
walk(fullPath);
|
|
299
|
+
} else if (entry.name.endsWith(".md")) {
|
|
300
|
+
results.push(fullPath);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
walk(dir);
|
|
305
|
+
return results;
|
|
306
|
+
}
|
|
307
|
+
function parseFrontmatter(content) {
|
|
308
|
+
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
309
|
+
if (!match) return null;
|
|
310
|
+
const fmText = match[1];
|
|
311
|
+
const fm = {};
|
|
312
|
+
for (const line of fmText.split("\n")) {
|
|
313
|
+
const colonIdx = line.indexOf(":");
|
|
314
|
+
if (colonIdx === -1) continue;
|
|
315
|
+
const key = line.slice(0, colonIdx).trim();
|
|
316
|
+
const value = line.slice(colonIdx + 1).trim();
|
|
317
|
+
if (key === "tags") {
|
|
318
|
+
try {
|
|
319
|
+
fm[key] = JSON.parse(value);
|
|
320
|
+
} catch {
|
|
321
|
+
fm[key] = [];
|
|
322
|
+
}
|
|
323
|
+
} else if (key === "confidence") {
|
|
324
|
+
const parsed = parseFloat(value);
|
|
325
|
+
fm[key] = Number.isFinite(parsed) ? parsed : 0;
|
|
326
|
+
} else {
|
|
327
|
+
fm[key] = value;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
return fm;
|
|
331
|
+
}
|
|
332
|
+
function extractBody(content) {
|
|
333
|
+
const match = content.match(/^---\n[\s\S]*?\n---\n([\s\S]*)/);
|
|
334
|
+
return match ? match[1].trim() : content.trim();
|
|
335
|
+
}
|
|
336
|
+
function projectNode(filePath, category, fm, rawContent) {
|
|
337
|
+
const body = extractBody(rawContent);
|
|
338
|
+
const fileName = path2.basename(filePath, ".md");
|
|
339
|
+
const dateDir = path2.basename(path2.dirname(filePath));
|
|
340
|
+
let relPath;
|
|
341
|
+
if (/^\d{4}-\d{2}-\d{2}$/.test(dateDir)) {
|
|
342
|
+
relPath = path2.join(category, dateDir, `${fileName}.md`);
|
|
343
|
+
} else {
|
|
344
|
+
relPath = path2.join(category, `${fileName}.md`);
|
|
345
|
+
}
|
|
346
|
+
const generatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
347
|
+
const md = `# ${fm.id}
|
|
348
|
+
|
|
349
|
+
> **Category:** ${fm.category}
|
|
350
|
+
> **Created:** ${fm.created}
|
|
351
|
+
> **Updated:** ${fm.updated ?? fm.created}
|
|
352
|
+
> **Confidence:** ${fm.confidence} (${fm.confidenceTier}${fm.lifecycleState ? `, ${fm.lifecycleState}` : ""})
|
|
353
|
+
${fm.tags?.length ? `
|
|
354
|
+
> **Tags:** ${fm.tags.join(", ")}` : ""}
|
|
355
|
+
${fm.entityRef ? `
|
|
356
|
+
> **Entity:** ${fm.entityRef}` : ""}
|
|
357
|
+
> **Source:** ${fm.source ?? "unknown"}
|
|
358
|
+
> **Projected:** ${generatedAt}
|
|
359
|
+
|
|
360
|
+
---
|
|
361
|
+
|
|
362
|
+
${body}
|
|
363
|
+
`;
|
|
364
|
+
return {
|
|
365
|
+
path: relPath,
|
|
366
|
+
category,
|
|
367
|
+
title: fm.id,
|
|
368
|
+
content: md,
|
|
369
|
+
sourceAnchors: [fm.id],
|
|
370
|
+
confidence: fm.confidence ?? 0,
|
|
371
|
+
confidenceTier: fm.confidenceTier ?? "unknown",
|
|
372
|
+
generatedAt,
|
|
373
|
+
provenance: [{
|
|
374
|
+
memoryId: fm.id,
|
|
375
|
+
source: fm.source ?? "unknown",
|
|
376
|
+
extracted: fm.created
|
|
377
|
+
}]
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
function projectEntityNode(fileName, content) {
|
|
381
|
+
const generatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
382
|
+
const md = `> **Projected:** ${generatedAt}
|
|
383
|
+
> **Source:** canonical
|
|
384
|
+
|
|
385
|
+
---
|
|
386
|
+
|
|
387
|
+
${content}
|
|
388
|
+
`;
|
|
389
|
+
return {
|
|
390
|
+
path: path2.join("entities", `${fileName}.md`),
|
|
391
|
+
category: "entity",
|
|
392
|
+
title: fileName,
|
|
393
|
+
content: md,
|
|
394
|
+
sourceAnchors: [fileName],
|
|
395
|
+
confidence: 1,
|
|
396
|
+
confidenceTier: "explicit",
|
|
397
|
+
generatedAt,
|
|
398
|
+
provenance: [{
|
|
399
|
+
memoryId: fileName,
|
|
400
|
+
source: "canonical",
|
|
401
|
+
extracted: generatedAt
|
|
402
|
+
}]
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
function generateIndex(categoryCounts, outputDir) {
|
|
406
|
+
const lines = [
|
|
407
|
+
"# Context Tree Index",
|
|
408
|
+
"",
|
|
409
|
+
`Generated: ${(/* @__PURE__ */ new Date()).toISOString()}`,
|
|
410
|
+
"",
|
|
411
|
+
"## Summary",
|
|
412
|
+
"",
|
|
413
|
+
`| Category | Count |`,
|
|
414
|
+
`|----------|-------|`
|
|
415
|
+
];
|
|
416
|
+
let total = 0;
|
|
417
|
+
for (const [cat, count] of Object.entries(categoryCounts).sort()) {
|
|
418
|
+
lines.push(`| ${cat} | ${count} |`);
|
|
419
|
+
total += count;
|
|
420
|
+
}
|
|
421
|
+
lines.push("");
|
|
422
|
+
lines.push(`**Total:** ${total} nodes`);
|
|
423
|
+
lines.push("");
|
|
424
|
+
lines.push("## Structure");
|
|
425
|
+
lines.push("");
|
|
426
|
+
lines.push("```");
|
|
427
|
+
lines.push("context-tree/");
|
|
428
|
+
lines.push("\u251C\u2500\u2500 entities/ # Entity knowledge graph");
|
|
429
|
+
lines.push("\u251C\u2500\u2500 fact/ # Factual memories (date-partitioned)");
|
|
430
|
+
lines.push("\u251C\u2500\u2500 correction/ # Correction memories");
|
|
431
|
+
lines.push("\u251C\u2500\u2500 decision/ # Decisions");
|
|
432
|
+
lines.push("\u251C\u2500\u2500 moment/ # Notable moments");
|
|
433
|
+
lines.push("\u251C\u2500\u2500 preference/ # Preferences");
|
|
434
|
+
lines.push("\u251C\u2500\u2500 principle/ # Principles");
|
|
435
|
+
lines.push("\u251C\u2500\u2500 question/ # Open questions");
|
|
436
|
+
lines.push("\u2514\u2500\u2500 INDEX.md # This file");
|
|
437
|
+
lines.push("```");
|
|
438
|
+
return lines.join("\n") + "\n";
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
// src/onboarding/index.ts
|
|
442
|
+
import fs2 from "fs";
|
|
443
|
+
import path3 from "path";
|
|
444
|
+
var LANGUAGE_RULES = [
|
|
445
|
+
{
|
|
446
|
+
language: "TypeScript",
|
|
447
|
+
extensions: [".ts", ".tsx"],
|
|
448
|
+
manifests: ["package.json"],
|
|
449
|
+
configFiles: ["tsconfig.json", "tsup.config.ts"]
|
|
450
|
+
},
|
|
451
|
+
{
|
|
452
|
+
language: "JavaScript",
|
|
453
|
+
extensions: [".js", ".jsx", ".mjs", ".cjs"],
|
|
454
|
+
manifests: ["package.json"],
|
|
455
|
+
configFiles: [".eslintrc", ".prettierrc"]
|
|
456
|
+
},
|
|
457
|
+
{
|
|
458
|
+
language: "Python",
|
|
459
|
+
extensions: [".py", ".pyi"],
|
|
460
|
+
manifests: ["pyproject.toml", "setup.py", "setup.cfg", "requirements.txt"],
|
|
461
|
+
configFiles: ["mypy.ini", ".flake8", "tox.ini"]
|
|
462
|
+
},
|
|
463
|
+
{
|
|
464
|
+
language: "Go",
|
|
465
|
+
extensions: [".go"],
|
|
466
|
+
manifests: ["go.mod", "go.sum"],
|
|
467
|
+
configFiles: []
|
|
468
|
+
},
|
|
469
|
+
{
|
|
470
|
+
language: "Rust",
|
|
471
|
+
extensions: [".rs"],
|
|
472
|
+
manifests: ["Cargo.toml"],
|
|
473
|
+
configFiles: []
|
|
474
|
+
},
|
|
475
|
+
{
|
|
476
|
+
language: "Ruby",
|
|
477
|
+
extensions: [".rb"],
|
|
478
|
+
manifests: ["Gemfile", "*.gemspec"],
|
|
479
|
+
configFiles: [".rubocop.yml"]
|
|
480
|
+
},
|
|
481
|
+
{
|
|
482
|
+
language: "PHP",
|
|
483
|
+
extensions: [".php"],
|
|
484
|
+
manifests: ["composer.json"],
|
|
485
|
+
configFiles: ["phpcs.xml"]
|
|
486
|
+
},
|
|
487
|
+
{
|
|
488
|
+
language: "Java",
|
|
489
|
+
extensions: [".java", ".kt"],
|
|
490
|
+
manifests: ["pom.xml", "build.gradle", "build.gradle.kts"],
|
|
491
|
+
configFiles: []
|
|
492
|
+
},
|
|
493
|
+
{
|
|
494
|
+
language: "Swift",
|
|
495
|
+
extensions: [".swift"],
|
|
496
|
+
manifests: ["Package.swift", "Podfile"],
|
|
497
|
+
configFiles: []
|
|
498
|
+
},
|
|
499
|
+
{
|
|
500
|
+
language: "C#",
|
|
501
|
+
extensions: [".cs"],
|
|
502
|
+
manifests: ["*.csproj", "*.sln"],
|
|
503
|
+
configFiles: []
|
|
504
|
+
},
|
|
505
|
+
{
|
|
506
|
+
language: "Shell",
|
|
507
|
+
extensions: [".sh", ".bash", ".zsh"],
|
|
508
|
+
manifests: [],
|
|
509
|
+
configFiles: []
|
|
510
|
+
},
|
|
511
|
+
{
|
|
512
|
+
language: "Dart",
|
|
513
|
+
extensions: [".dart"],
|
|
514
|
+
manifests: ["pubspec.yaml"],
|
|
515
|
+
configFiles: []
|
|
516
|
+
},
|
|
517
|
+
{
|
|
518
|
+
language: "Elixir",
|
|
519
|
+
extensions: [".ex", ".exs"],
|
|
520
|
+
manifests: ["mix.exs"],
|
|
521
|
+
configFiles: []
|
|
522
|
+
}
|
|
523
|
+
];
|
|
524
|
+
var DEFAULT_EXCLUDE = /* @__PURE__ */ new Set([
|
|
525
|
+
"node_modules",
|
|
526
|
+
".git",
|
|
527
|
+
"vendor",
|
|
528
|
+
"__pycache__",
|
|
529
|
+
".venv",
|
|
530
|
+
"venv",
|
|
531
|
+
"dist",
|
|
532
|
+
"build",
|
|
533
|
+
".next",
|
|
534
|
+
".nuxt",
|
|
535
|
+
"target",
|
|
536
|
+
"coverage",
|
|
537
|
+
".engram"
|
|
538
|
+
]);
|
|
539
|
+
function onboard(options) {
|
|
540
|
+
const startTime = Date.now();
|
|
541
|
+
const {
|
|
542
|
+
directory,
|
|
543
|
+
maxDepth = 6,
|
|
544
|
+
excludeDirs = []
|
|
545
|
+
} = options;
|
|
546
|
+
const exclude = /* @__PURE__ */ new Set([...DEFAULT_EXCLUDE, ...excludeDirs]);
|
|
547
|
+
const files = walkDir(directory, exclude, maxDepth);
|
|
548
|
+
const languages = detectLanguages(files, directory);
|
|
549
|
+
const { shape, evidence: shapeEvidence } = detectShape(files, directory);
|
|
550
|
+
const docs = discoverDocs(files, directory);
|
|
551
|
+
const plan = buildPlan(languages, shape, docs, directory);
|
|
552
|
+
return {
|
|
553
|
+
directory,
|
|
554
|
+
languages,
|
|
555
|
+
shape,
|
|
556
|
+
shapeEvidence,
|
|
557
|
+
docs,
|
|
558
|
+
totalFiles: files.length,
|
|
559
|
+
durationMs: Date.now() - startTime,
|
|
560
|
+
plan
|
|
561
|
+
};
|
|
562
|
+
}
|
|
563
|
+
function walkDir(root, exclude, maxDepth) {
|
|
564
|
+
const results = [];
|
|
565
|
+
function walk(dir, depth) {
|
|
566
|
+
if (depth > maxDepth) return;
|
|
567
|
+
let entries;
|
|
568
|
+
try {
|
|
569
|
+
entries = fs2.readdirSync(dir, { withFileTypes: true });
|
|
570
|
+
} catch {
|
|
571
|
+
return;
|
|
572
|
+
}
|
|
573
|
+
for (const entry of entries) {
|
|
574
|
+
if (exclude.has(entry.name)) continue;
|
|
575
|
+
const fullPath = path3.join(dir, entry.name);
|
|
576
|
+
if (entry.isDirectory()) {
|
|
577
|
+
walk(fullPath, depth + 1);
|
|
578
|
+
} else if (entry.isFile()) {
|
|
579
|
+
results.push(fullPath);
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
walk(root, 0);
|
|
584
|
+
return results;
|
|
585
|
+
}
|
|
586
|
+
function detectLanguages(files, root) {
|
|
587
|
+
const results = [];
|
|
588
|
+
const extCounts = /* @__PURE__ */ new Map();
|
|
589
|
+
for (const f of files) {
|
|
590
|
+
const ext = path3.extname(f).toLowerCase();
|
|
591
|
+
if (ext) extCounts.set(ext, (extCounts.get(ext) ?? 0) + 1);
|
|
592
|
+
}
|
|
593
|
+
const rootFiles = new Set(
|
|
594
|
+
files.filter((f) => path3.dirname(f) === root).map((f) => path3.basename(f))
|
|
595
|
+
);
|
|
596
|
+
for (const rule of LANGUAGE_RULES) {
|
|
597
|
+
const evidence = [];
|
|
598
|
+
let score = 0;
|
|
599
|
+
let extMatch = 0;
|
|
600
|
+
for (const ext of rule.extensions) {
|
|
601
|
+
const count = extCounts.get(ext) ?? 0;
|
|
602
|
+
if (count > 0) {
|
|
603
|
+
extMatch += count;
|
|
604
|
+
evidence.push(`${ext} files (${count})`);
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
score += Math.min(extMatch * 0.05, 0.5);
|
|
608
|
+
for (const manifest of rule.manifests) {
|
|
609
|
+
if (manifest.includes("*")) {
|
|
610
|
+
const suffix = manifest.replaceAll(/\*/g, "");
|
|
611
|
+
if ([...rootFiles].some((f) => f.endsWith(suffix))) {
|
|
612
|
+
score += 0.2;
|
|
613
|
+
evidence.push(manifest);
|
|
614
|
+
}
|
|
615
|
+
} else if (rootFiles.has(manifest)) {
|
|
616
|
+
score += 0.2;
|
|
617
|
+
evidence.push(manifest);
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
for (const cfg of rule.configFiles) {
|
|
621
|
+
if (rootFiles.has(cfg)) {
|
|
622
|
+
score += 0.1;
|
|
623
|
+
evidence.push(cfg);
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
if (score > 0) {
|
|
627
|
+
results.push({
|
|
628
|
+
language: rule.language,
|
|
629
|
+
confidence: Math.min(score, 1),
|
|
630
|
+
evidence
|
|
631
|
+
});
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
return results.sort((a, b) => b.confidence - a.confidence);
|
|
635
|
+
}
|
|
636
|
+
function detectShape(files, root) {
|
|
637
|
+
const rootFiles = new Set(
|
|
638
|
+
files.filter((f) => path3.dirname(f) === root).map((f) => path3.basename(f))
|
|
639
|
+
);
|
|
640
|
+
const rootDirs = /* @__PURE__ */ new Set();
|
|
641
|
+
try {
|
|
642
|
+
for (const entry of fs2.readdirSync(root, { withFileTypes: true })) {
|
|
643
|
+
if (entry.isDirectory()) rootDirs.add(entry.name);
|
|
644
|
+
}
|
|
645
|
+
} catch {
|
|
646
|
+
}
|
|
647
|
+
const evidence = [];
|
|
648
|
+
if (rootFiles.has("package.json")) {
|
|
649
|
+
const pkg = readJsonSafe(path3.join(root, "package.json"));
|
|
650
|
+
if (pkg?.workspaces) {
|
|
651
|
+
evidence.push("package.json has workspaces");
|
|
652
|
+
return { shape: "monorepo", evidence };
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
if (rootDirs.has("packages") || rootDirs.has("libs")) {
|
|
656
|
+
evidence.push("has packages/ or libs/ directory");
|
|
657
|
+
return { shape: "monorepo", evidence };
|
|
658
|
+
}
|
|
659
|
+
if (rootFiles.has("pnpm-workspace.yaml") || rootFiles.has("go.work")) {
|
|
660
|
+
evidence.push("workspace manifest found");
|
|
661
|
+
return { shape: "workspace", evidence };
|
|
662
|
+
}
|
|
663
|
+
const cargoToml = readTomlWorkspace(path3.join(root, "Cargo.toml"));
|
|
664
|
+
if (cargoToml) {
|
|
665
|
+
evidence.push("Cargo.toml has workspace");
|
|
666
|
+
return { shape: "workspace", evidence };
|
|
667
|
+
}
|
|
668
|
+
if (rootFiles.has("package.json")) {
|
|
669
|
+
const pkg = readJsonSafe(path3.join(root, "package.json"));
|
|
670
|
+
if (pkg?.exports || pkg?.main) {
|
|
671
|
+
if (pkg?.bin) {
|
|
672
|
+
evidence.push("package.json has bin");
|
|
673
|
+
return { shape: "app", evidence };
|
|
674
|
+
}
|
|
675
|
+
evidence.push("package.json has exports/main");
|
|
676
|
+
return { shape: "library", evidence };
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
if (rootFiles.has("Dockerfile") || rootFiles.has("docker-compose.yml") || rootFiles.has("docker-compose.yaml") || rootDirs.has("app") || rootDirs.has("src") && rootDirs.has("public")) {
|
|
680
|
+
evidence.push("app-like structure detected");
|
|
681
|
+
return { shape: "app", evidence };
|
|
682
|
+
}
|
|
683
|
+
if (files.length <= 5 && !rootFiles.has("package.json") && !rootFiles.has("pyproject.toml")) {
|
|
684
|
+
evidence.push("few files, no manifest");
|
|
685
|
+
return { shape: "script", evidence };
|
|
686
|
+
}
|
|
687
|
+
return { shape: "unknown", evidence: ["no strong shape signal"] };
|
|
688
|
+
}
|
|
689
|
+
function discoverDocs(files, root) {
|
|
690
|
+
const docs = [];
|
|
691
|
+
const docPatterns = [
|
|
692
|
+
{ pattern: /^readme(\.\w+)?$/i, kind: "readme" },
|
|
693
|
+
{ pattern: /^changelog(\.\w+)?$/i, kind: "changelog" },
|
|
694
|
+
{ pattern: /^changes(\.\w+)?$/i, kind: "changelog" },
|
|
695
|
+
{ pattern: /^contributing(\.\w+)?$/i, kind: "contributing" },
|
|
696
|
+
{ pattern: /^code[_-]of[_-]conduct(\.\w+)?$/i, kind: "contributing" },
|
|
697
|
+
{ pattern: /^license(\.\w+)?$/i, kind: "license" },
|
|
698
|
+
{ pattern: /^copying(\.\w+)?$/i, kind: "license" },
|
|
699
|
+
{ pattern: /^\.env\.example$/i, kind: "config" },
|
|
700
|
+
{ pattern: /^\.editorconfig$/i, kind: "config" }
|
|
701
|
+
];
|
|
702
|
+
for (const filePath of files) {
|
|
703
|
+
const basename = path3.basename(filePath).toLowerCase();
|
|
704
|
+
const relPath = path3.relative(root, filePath);
|
|
705
|
+
let kind;
|
|
706
|
+
for (const { pattern, kind: k } of docPatterns) {
|
|
707
|
+
if (pattern.test(basename)) {
|
|
708
|
+
kind = k;
|
|
709
|
+
break;
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
if (!kind && isUnderDocsDir(relPath)) {
|
|
713
|
+
kind = "docs";
|
|
714
|
+
}
|
|
715
|
+
if (!kind && (basename.endsWith(".md") || basename.endsWith(".mdx"))) {
|
|
716
|
+
if (path3.dirname(relPath) === "." || isUnderDocsDir(relPath)) {
|
|
717
|
+
kind = "docs";
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
if (kind) {
|
|
721
|
+
let size = 0;
|
|
722
|
+
try {
|
|
723
|
+
size = fs2.statSync(filePath).size;
|
|
724
|
+
} catch {
|
|
725
|
+
}
|
|
726
|
+
docs.push({
|
|
727
|
+
path: filePath,
|
|
728
|
+
relativePath: relPath,
|
|
729
|
+
kind,
|
|
730
|
+
size
|
|
731
|
+
});
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
return docs;
|
|
735
|
+
}
|
|
736
|
+
function isUnderDocsDir(relPath) {
|
|
737
|
+
const parts = relPath.split(path3.sep);
|
|
738
|
+
return parts[0] === "docs" || parts[0] === "doc" || parts[0] === "documentation";
|
|
739
|
+
}
|
|
740
|
+
function buildPlan(languages, shape, docs, _root) {
|
|
741
|
+
const priorityOrder = {
|
|
742
|
+
readme: 0,
|
|
743
|
+
contributing: 1,
|
|
744
|
+
changelog: 2,
|
|
745
|
+
license: 3,
|
|
746
|
+
docs: 4,
|
|
747
|
+
config: 5,
|
|
748
|
+
other: 6
|
|
749
|
+
};
|
|
750
|
+
const priorityFiles = [...docs].filter((d) => d.size > 0).sort((a, b) => priorityOrder[a.kind] - priorityOrder[b.kind]);
|
|
751
|
+
const categories = ["fact", "preference", "decision", "principle"];
|
|
752
|
+
if (shape === "monorepo" || shape === "workspace") {
|
|
753
|
+
categories.push("entity");
|
|
754
|
+
}
|
|
755
|
+
const suggestedNamespace = languages.length > 0 ? languages[0].language.toLowerCase() : "project";
|
|
756
|
+
return {
|
|
757
|
+
priorityFiles,
|
|
758
|
+
estimatedFiles: docs.filter((d) => d.size > 0).length,
|
|
759
|
+
categories,
|
|
760
|
+
suggestedNamespace
|
|
761
|
+
};
|
|
762
|
+
}
|
|
763
|
+
function readJsonSafe(filePath) {
|
|
764
|
+
try {
|
|
765
|
+
return JSON.parse(fs2.readFileSync(filePath, "utf8"));
|
|
766
|
+
} catch {
|
|
767
|
+
return null;
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
function readTomlWorkspace(filePath) {
|
|
771
|
+
try {
|
|
772
|
+
const content = fs2.readFileSync(filePath, "utf8");
|
|
773
|
+
return content.includes("[workspace]");
|
|
774
|
+
} catch {
|
|
775
|
+
return false;
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
// src/curation/index.ts
|
|
780
|
+
import fs3 from "fs";
|
|
781
|
+
import path4 from "path";
|
|
782
|
+
import crypto from "crypto";
|
|
783
|
+
async function curate(options) {
|
|
784
|
+
const startTime = Date.now();
|
|
785
|
+
const {
|
|
786
|
+
targetPath,
|
|
787
|
+
memoryDir,
|
|
788
|
+
source = "curation",
|
|
789
|
+
category: categoryOverride,
|
|
790
|
+
confidence = 0.9,
|
|
791
|
+
entityRef,
|
|
792
|
+
tags = [],
|
|
793
|
+
checkDuplicates = true,
|
|
794
|
+
checkContradictions = false,
|
|
795
|
+
write = true
|
|
796
|
+
} = options;
|
|
797
|
+
const statements = [];
|
|
798
|
+
const written = [];
|
|
799
|
+
const duplicates = [];
|
|
800
|
+
const contradictions = [];
|
|
801
|
+
let filesProcessed = 0;
|
|
802
|
+
let filesSkipped = 0;
|
|
803
|
+
const targets = resolveTargets(targetPath);
|
|
804
|
+
const existingMemories = checkDuplicates || checkContradictions ? loadExistingMemories(memoryDir) : /* @__PURE__ */ new Map();
|
|
805
|
+
for (const filePath of targets) {
|
|
806
|
+
const content = readFileSafe(filePath);
|
|
807
|
+
if (!content) {
|
|
808
|
+
filesSkipped++;
|
|
809
|
+
continue;
|
|
810
|
+
}
|
|
811
|
+
if (isBinary(content)) {
|
|
812
|
+
filesSkipped++;
|
|
813
|
+
continue;
|
|
814
|
+
}
|
|
815
|
+
filesProcessed++;
|
|
816
|
+
const sourceFileHash = hashContent(content);
|
|
817
|
+
const fileStatements = extractStatements(
|
|
818
|
+
content,
|
|
819
|
+
filePath,
|
|
820
|
+
targetPath,
|
|
821
|
+
source,
|
|
822
|
+
sourceFileHash,
|
|
823
|
+
categoryOverride,
|
|
824
|
+
confidence,
|
|
825
|
+
entityRef,
|
|
826
|
+
tags
|
|
827
|
+
);
|
|
828
|
+
for (const stmt of fileStatements) {
|
|
829
|
+
if (checkDuplicates) {
|
|
830
|
+
const dup = findDuplicate(stmt, existingMemories);
|
|
831
|
+
if (dup) {
|
|
832
|
+
duplicates.push(dup);
|
|
833
|
+
if (dup.action === "skip") continue;
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
if (checkContradictions) {
|
|
837
|
+
const contra = findContradiction(stmt, existingMemories);
|
|
838
|
+
if (contra) {
|
|
839
|
+
contradictions.push(contra);
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
statements.push(stmt);
|
|
843
|
+
if (write) {
|
|
844
|
+
const writtenPath = writeStatement(stmt, memoryDir);
|
|
845
|
+
if (writtenPath) {
|
|
846
|
+
written.push(writtenPath);
|
|
847
|
+
existingMemories.set(stmt.contentHash, {
|
|
848
|
+
id: stmt.id,
|
|
849
|
+
content: stmt.content,
|
|
850
|
+
category: stmt.category
|
|
851
|
+
});
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
return {
|
|
857
|
+
statements,
|
|
858
|
+
filesProcessed,
|
|
859
|
+
filesSkipped,
|
|
860
|
+
duplicates,
|
|
861
|
+
contradictions,
|
|
862
|
+
written,
|
|
863
|
+
durationMs: Date.now() - startTime
|
|
864
|
+
};
|
|
865
|
+
}
|
|
866
|
+
function resolveTargets(targetPath) {
|
|
867
|
+
const stat = fs3.statSync(targetPath);
|
|
868
|
+
if (stat.isFile()) return [targetPath];
|
|
869
|
+
const results = [];
|
|
870
|
+
const extensions = /* @__PURE__ */ new Set([".md", ".txt", ".mdx", ".rst"]);
|
|
871
|
+
function walk(dir) {
|
|
872
|
+
for (const entry of fs3.readdirSync(dir, { withFileTypes: true })) {
|
|
873
|
+
const fullPath = path4.join(dir, entry.name);
|
|
874
|
+
if (entry.isDirectory()) {
|
|
875
|
+
if (entry.name !== "node_modules" && entry.name !== ".git") {
|
|
876
|
+
walk(fullPath);
|
|
877
|
+
}
|
|
878
|
+
} else if (extensions.has(path4.extname(entry.name).toLowerCase())) {
|
|
879
|
+
results.push(fullPath);
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
walk(targetPath);
|
|
884
|
+
return results;
|
|
885
|
+
}
|
|
886
|
+
function extractStatements(content, filePath, projectRoot, source, sourceFileHash, categoryOverride, confidence, entityRef, tags) {
|
|
887
|
+
const relativePath = path4.relative(projectRoot, filePath);
|
|
888
|
+
const statements = [];
|
|
889
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
890
|
+
const paragraphs = content.split(/\n{2,}/).map((p) => p.trim()).filter((p) => p.length > 20 && p.length < 2e3);
|
|
891
|
+
const listItems = content.split("\n").filter((l) => /^\s*[-*]\s+/.test(l)).map((l) => l.replace(/^\s*[-*]\s+/, "").trim()).filter((l) => l.length > 10 && l.length < 500);
|
|
892
|
+
const allItems = [...paragraphs, ...listItems];
|
|
893
|
+
const seen = /* @__PURE__ */ new Set();
|
|
894
|
+
for (const item of allItems) {
|
|
895
|
+
const hash = hashContent(item.toLowerCase());
|
|
896
|
+
if (seen.has(hash)) continue;
|
|
897
|
+
seen.add(hash);
|
|
898
|
+
const id = generateId();
|
|
899
|
+
const category = categoryOverride ?? detectCategory(item);
|
|
900
|
+
statements.push({
|
|
901
|
+
id,
|
|
902
|
+
content: item,
|
|
903
|
+
category,
|
|
904
|
+
confidence,
|
|
905
|
+
provenance: {
|
|
906
|
+
sourcePath: filePath,
|
|
907
|
+
relativePath,
|
|
908
|
+
source,
|
|
909
|
+
lineNumber: 0,
|
|
910
|
+
ingestedAt: now,
|
|
911
|
+
sourceFileHash
|
|
912
|
+
},
|
|
913
|
+
contentHash: hash,
|
|
914
|
+
tags: [...tags],
|
|
915
|
+
entityRef
|
|
916
|
+
});
|
|
917
|
+
}
|
|
918
|
+
return statements;
|
|
919
|
+
}
|
|
920
|
+
function detectCategory(text) {
|
|
921
|
+
const lower = text.toLowerCase();
|
|
922
|
+
if (/^(always|never|must|should|don't|avoid|ensure)/.test(lower)) return "principle";
|
|
923
|
+
if (/^(we|team|project)\s+(decided|chose|will|use)/.test(lower)) return "decision";
|
|
924
|
+
if (/^(i|we)\s+(prefer|like|want|hate|dislike)/.test(lower)) return "preference";
|
|
925
|
+
if (/fix|bug|issue|broken|error/i.test(lower)) return "correction";
|
|
926
|
+
if (/\?.+$/.test(lower.trim())) return "question";
|
|
927
|
+
return "fact";
|
|
928
|
+
}
|
|
929
|
+
function findDuplicate(stmt, existing) {
|
|
930
|
+
const stmtLower = stmt.content.toLowerCase();
|
|
931
|
+
const exactMatch = existing.get(stmt.contentHash);
|
|
932
|
+
if (exactMatch) {
|
|
933
|
+
return {
|
|
934
|
+
newStatement: stmt,
|
|
935
|
+
existingId: exactMatch.id,
|
|
936
|
+
similarity: 1,
|
|
937
|
+
action: "skip"
|
|
938
|
+
};
|
|
939
|
+
}
|
|
940
|
+
for (const [_, mem] of existing) {
|
|
941
|
+
const memLower = mem.content.toLowerCase();
|
|
942
|
+
if (memLower.length > 50 && stmtLower.length > 50) {
|
|
943
|
+
if (memLower.includes(stmtLower.slice(0, 40)) || stmtLower.includes(memLower.slice(0, 40))) {
|
|
944
|
+
return {
|
|
945
|
+
newStatement: stmt,
|
|
946
|
+
existingId: mem.id,
|
|
947
|
+
similarity: 0.85,
|
|
948
|
+
action: "skip"
|
|
949
|
+
};
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
return null;
|
|
954
|
+
}
|
|
955
|
+
function findContradiction(stmt, existing) {
|
|
956
|
+
const negationPatterns = [
|
|
957
|
+
/\b(not|don't|doesn't|isn't|aren't|won't|can't|never|no)\b/i
|
|
958
|
+
];
|
|
959
|
+
const hasNegation = negationPatterns.some((p) => p.test(stmt.content));
|
|
960
|
+
if (!hasNegation) return null;
|
|
961
|
+
const stripped = stmt.content.toLowerCase().replace(/\b(not|don't|doesn't|isn't|aren't|won't|can't|never|no)\b/gi, "").trim();
|
|
962
|
+
if (stripped.length < 20) return null;
|
|
963
|
+
for (const [_, mem] of existing) {
|
|
964
|
+
const memLower = mem.content.toLowerCase();
|
|
965
|
+
if (memLower.includes(stripped.slice(0, Math.min(30, stripped.length)))) {
|
|
966
|
+
return {
|
|
967
|
+
newStatement: stmt,
|
|
968
|
+
conflictingId: mem.id,
|
|
969
|
+
conflictingContent: mem.content,
|
|
970
|
+
severity: "high"
|
|
971
|
+
};
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
return null;
|
|
975
|
+
}
|
|
976
|
+
function loadExistingMemories(memoryDir) {
|
|
977
|
+
const result = /* @__PURE__ */ new Map();
|
|
978
|
+
if (!fs3.existsSync(memoryDir)) return result;
|
|
979
|
+
const dirs = ALL_CATEGORY_DIRS;
|
|
980
|
+
for (const dir of dirs) {
|
|
981
|
+
const fullDir = path4.join(memoryDir, dir);
|
|
982
|
+
if (!fs3.existsSync(fullDir)) continue;
|
|
983
|
+
walkFiles(fullDir, (filePath) => {
|
|
984
|
+
const content = readFileSafe(filePath);
|
|
985
|
+
if (!content) return;
|
|
986
|
+
const fm = parseFrontmatter2(content);
|
|
987
|
+
const body = extractBody2(content);
|
|
988
|
+
if (!fm?.id || !body) return;
|
|
989
|
+
const hash = hashContent(body.toLowerCase());
|
|
990
|
+
result.set(hash, {
|
|
991
|
+
id: fm.id,
|
|
992
|
+
content: body,
|
|
993
|
+
category: fm.category ?? dir.slice(0, -1)
|
|
994
|
+
});
|
|
995
|
+
});
|
|
996
|
+
}
|
|
997
|
+
return result;
|
|
998
|
+
}
|
|
999
|
+
function writeStatement(stmt, memoryDir) {
|
|
1000
|
+
const now = /* @__PURE__ */ new Date();
|
|
1001
|
+
const dateDir = now.toISOString().split("T")[0];
|
|
1002
|
+
const categoryDir = getCategoryDir(memoryDir, stmt.category);
|
|
1003
|
+
const dir = path4.join(categoryDir, dateDir);
|
|
1004
|
+
fs3.mkdirSync(dir, { recursive: true });
|
|
1005
|
+
const fileName = `${stmt.category}-${Date.now()}-${stmt.id.slice(0, 8)}.md`;
|
|
1006
|
+
const filePath = path4.join(dir, fileName);
|
|
1007
|
+
const frontmatter = [
|
|
1008
|
+
"---",
|
|
1009
|
+
`id: ${stmt.id}`,
|
|
1010
|
+
`category: ${stmt.category}`,
|
|
1011
|
+
`created: ${stmt.provenance.ingestedAt}`,
|
|
1012
|
+
`updated: ${stmt.provenance.ingestedAt}`,
|
|
1013
|
+
`confidence: ${stmt.confidence}`,
|
|
1014
|
+
`confidenceTier: ${tierFromConfidence(stmt.confidence)}`,
|
|
1015
|
+
`source: ${stmt.provenance.source}`,
|
|
1016
|
+
`tags: ${JSON.stringify(stmt.tags)}`,
|
|
1017
|
+
stmt.entityRef ? `entityRef: ${stmt.entityRef}` : null,
|
|
1018
|
+
`provenanceFile: ${stmt.provenance.relativePath}`,
|
|
1019
|
+
`provenanceHash: ${stmt.provenance.sourceFileHash}`,
|
|
1020
|
+
"---"
|
|
1021
|
+
].filter(Boolean).join("\n");
|
|
1022
|
+
const body = `${frontmatter}
|
|
1023
|
+
|
|
1024
|
+
${stmt.content}
|
|
1025
|
+
`;
|
|
1026
|
+
try {
|
|
1027
|
+
fs3.writeFileSync(filePath, body);
|
|
1028
|
+
return filePath;
|
|
1029
|
+
} catch {
|
|
1030
|
+
return null;
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
function generateId() {
|
|
1034
|
+
return crypto.randomUUID();
|
|
1035
|
+
}
|
|
1036
|
+
function hashContent(content) {
|
|
1037
|
+
return crypto.createHash("sha256").update(content).digest("hex").slice(0, 16);
|
|
1038
|
+
}
|
|
1039
|
+
function tierFromConfidence(confidence) {
|
|
1040
|
+
if (confidence >= 0.95) return "explicit";
|
|
1041
|
+
if (confidence >= 0.8) return "high";
|
|
1042
|
+
if (confidence >= 0.5) return "medium";
|
|
1043
|
+
return "low";
|
|
1044
|
+
}
|
|
1045
|
+
function readFileSafe(filePath) {
|
|
1046
|
+
try {
|
|
1047
|
+
return fs3.readFileSync(filePath, "utf8");
|
|
1048
|
+
} catch {
|
|
1049
|
+
return null;
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
function isBinary(content) {
|
|
1053
|
+
for (let i = 0; i < Math.min(content.length, 8e3); i++) {
|
|
1054
|
+
if (content.charCodeAt(i) === 0) return true;
|
|
1055
|
+
}
|
|
1056
|
+
return false;
|
|
1057
|
+
}
|
|
1058
|
+
function parseFrontmatter2(content) {
|
|
1059
|
+
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
1060
|
+
if (!match) return null;
|
|
1061
|
+
const fm = {};
|
|
1062
|
+
for (const line of match[1].split("\n")) {
|
|
1063
|
+
const colonIdx = line.indexOf(":");
|
|
1064
|
+
if (colonIdx === -1) continue;
|
|
1065
|
+
const key = line.slice(0, colonIdx).trim();
|
|
1066
|
+
const value = line.slice(colonIdx + 1).trim();
|
|
1067
|
+
fm[key] = value;
|
|
1068
|
+
}
|
|
1069
|
+
return fm;
|
|
1070
|
+
}
|
|
1071
|
+
function extractBody2(content) {
|
|
1072
|
+
const match = content.match(/^---\n[\s\S]*?\n---\n([\s\S]*)/);
|
|
1073
|
+
return match ? match[1].trim() : content.trim();
|
|
1074
|
+
}
|
|
1075
|
+
function walkFiles(dir, callback) {
|
|
1076
|
+
for (const entry of fs3.readdirSync(dir, { withFileTypes: true })) {
|
|
1077
|
+
const fullPath = path4.join(dir, entry.name);
|
|
1078
|
+
if (entry.isDirectory()) {
|
|
1079
|
+
walkFiles(fullPath, callback);
|
|
1080
|
+
} else if (entry.name.endsWith(".md")) {
|
|
1081
|
+
callback(fullPath);
|
|
1082
|
+
}
|
|
1083
|
+
}
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
// src/dedup/index.ts
|
|
1087
|
+
import fs4 from "fs";
|
|
1088
|
+
import path5 from "path";
|
|
1089
|
+
import crypto2 from "crypto";
|
|
1090
|
+
function findDuplicates(options) {
|
|
1091
|
+
const startTime = Date.now();
|
|
1092
|
+
const { memoryDir, threshold = 0.85, maxLoad = 1e4 } = options;
|
|
1093
|
+
const memories = loadMemories(memoryDir, options.categories, maxLoad);
|
|
1094
|
+
const duplicates = [];
|
|
1095
|
+
for (let i = 0; i < memories.length; i++) {
|
|
1096
|
+
for (let j = i + 1; j < memories.length; j++) {
|
|
1097
|
+
const sim = computeSimilarity(memories[i].content, memories[j].content);
|
|
1098
|
+
if (sim >= threshold) {
|
|
1099
|
+
duplicates.push({
|
|
1100
|
+
left: memories[i],
|
|
1101
|
+
right: memories[j],
|
|
1102
|
+
similarity: sim,
|
|
1103
|
+
action: sim >= 0.98 ? "merge" : sim >= 0.9 ? "keep_right" : "keep_left"
|
|
1104
|
+
});
|
|
1105
|
+
}
|
|
1106
|
+
}
|
|
1107
|
+
}
|
|
1108
|
+
return {
|
|
1109
|
+
scanned: memories.length,
|
|
1110
|
+
duplicates,
|
|
1111
|
+
durationMs: Date.now() - startTime
|
|
1112
|
+
};
|
|
1113
|
+
}
|
|
1114
|
+
function findContradictions(options) {
|
|
1115
|
+
const startTime = Date.now();
|
|
1116
|
+
const { memoryDir, maxLoad = 1e4 } = options;
|
|
1117
|
+
const memories = loadMemories(memoryDir, options.categories, maxLoad);
|
|
1118
|
+
const contradictions = [];
|
|
1119
|
+
for (let i = 0; i < memories.length; i++) {
|
|
1120
|
+
for (let j = i + 1; j < memories.length; j++) {
|
|
1121
|
+
const contra = detectContradiction(memories[i], memories[j]);
|
|
1122
|
+
if (contra) {
|
|
1123
|
+
contradictions.push(contra);
|
|
1124
|
+
}
|
|
1125
|
+
}
|
|
1126
|
+
}
|
|
1127
|
+
return {
|
|
1128
|
+
scanned: memories.length,
|
|
1129
|
+
contradictions,
|
|
1130
|
+
durationMs: Date.now() - startTime
|
|
1131
|
+
};
|
|
1132
|
+
}
|
|
1133
|
+
function computeSimilarity(a, b) {
|
|
1134
|
+
const normA = normalize(a);
|
|
1135
|
+
const normB = normalize(b);
|
|
1136
|
+
if (normA === normB) return 1;
|
|
1137
|
+
if (hashContent2(normA) === hashContent2(normB)) return 0.99;
|
|
1138
|
+
if (normA.length > 50 && normB.length > 50) {
|
|
1139
|
+
if (normA.includes(normB.slice(0, 40)) || normB.includes(normA.slice(0, 40))) {
|
|
1140
|
+
return 0.9;
|
|
1141
|
+
}
|
|
1142
|
+
}
|
|
1143
|
+
const wordsA = new Set(normA.split(/\s+/));
|
|
1144
|
+
const wordsB = new Set(normB.split(/\s+/));
|
|
1145
|
+
const intersection = new Set([...wordsA].filter((w) => wordsB.has(w)));
|
|
1146
|
+
const union = /* @__PURE__ */ new Set([...wordsA, ...wordsB]);
|
|
1147
|
+
if (union.size === 0) return 0;
|
|
1148
|
+
return intersection.size / union.size;
|
|
1149
|
+
}
|
|
1150
|
+
function normalize(text) {
|
|
1151
|
+
return text.toLowerCase().replace(/[^\w\s']/g, "").replace(/\s+/g, " ").trim();
|
|
1152
|
+
}
|
|
1153
|
+
var NEGATION_WORDS = /* @__PURE__ */ new Set([
|
|
1154
|
+
"not",
|
|
1155
|
+
"don't",
|
|
1156
|
+
"doesn't",
|
|
1157
|
+
"isn't",
|
|
1158
|
+
"aren't",
|
|
1159
|
+
"won't",
|
|
1160
|
+
"can't",
|
|
1161
|
+
"never",
|
|
1162
|
+
"no",
|
|
1163
|
+
"none",
|
|
1164
|
+
"neither",
|
|
1165
|
+
"nor",
|
|
1166
|
+
"nothing",
|
|
1167
|
+
"nowhere"
|
|
1168
|
+
]);
|
|
1169
|
+
function detectContradiction(a, b) {
|
|
1170
|
+
const normA = normalize(a.content);
|
|
1171
|
+
const normB = normalize(b.content);
|
|
1172
|
+
const aHasNegation = containsNegation(normA);
|
|
1173
|
+
const bHasNegation = containsNegation(normB);
|
|
1174
|
+
if (aHasNegation === bHasNegation) return null;
|
|
1175
|
+
const strippedA = stripNegation(normA);
|
|
1176
|
+
const strippedB = stripNegation(normB);
|
|
1177
|
+
const sim = computeSimilarity(strippedA, strippedB);
|
|
1178
|
+
if (sim < 0.7) return null;
|
|
1179
|
+
const oppQuantifiers = [
|
|
1180
|
+
["always", "never"],
|
|
1181
|
+
["all", "none"],
|
|
1182
|
+
["every", "no"],
|
|
1183
|
+
["must", "must not"],
|
|
1184
|
+
["should", "should not"],
|
|
1185
|
+
["can", "cannot"]
|
|
1186
|
+
];
|
|
1187
|
+
for (const [pos, neg] of oppQuantifiers) {
|
|
1188
|
+
if (a.content.toLowerCase().includes(pos) && b.content.toLowerCase().includes(neg) || a.content.toLowerCase().includes(neg) && b.content.toLowerCase().includes(pos)) {
|
|
1189
|
+
return {
|
|
1190
|
+
left: a,
|
|
1191
|
+
right: b,
|
|
1192
|
+
severity: "high",
|
|
1193
|
+
reason: `Opposite quantifiers: "${pos}" vs "${neg}"`
|
|
1194
|
+
};
|
|
1195
|
+
}
|
|
1196
|
+
}
|
|
1197
|
+
return {
|
|
1198
|
+
left: a,
|
|
1199
|
+
right: b,
|
|
1200
|
+
severity: sim >= 0.85 ? "high" : "medium",
|
|
1201
|
+
reason: "Negated version of similar content"
|
|
1202
|
+
};
|
|
1203
|
+
}
|
|
1204
|
+
function containsNegation(text) {
|
|
1205
|
+
const words = text.split(/\s+/);
|
|
1206
|
+
return words.some((w) => NEGATION_WORDS.has(w));
|
|
1207
|
+
}
|
|
1208
|
+
function stripNegation(text) {
|
|
1209
|
+
return text.replace(/\b(not|don't|doesn't|isn't|aren't|won't|can't|never|no|none|neither|nor|nothing|nowhere)\b/gi, "").replace(/\s+/g, " ").trim();
|
|
1210
|
+
}
|
|
1211
|
+
function loadMemories(memoryDir, categories, maxLoad = 1e4) {
|
|
1212
|
+
const result = [];
|
|
1213
|
+
const allCategories = categories ?? ALL_CATEGORY_DIRS;
|
|
1214
|
+
for (const category of allCategories) {
|
|
1215
|
+
if (result.length >= maxLoad) break;
|
|
1216
|
+
const dir = path5.join(memoryDir, category);
|
|
1217
|
+
if (!fs4.existsSync(dir)) continue;
|
|
1218
|
+
walkMdFiles(dir, (filePath) => {
|
|
1219
|
+
if (result.length >= maxLoad) return;
|
|
1220
|
+
const content = readFileSafe2(filePath);
|
|
1221
|
+
if (!content) return;
|
|
1222
|
+
const fm = parseFrontmatter3(content);
|
|
1223
|
+
const body = extractBody3(content);
|
|
1224
|
+
if (!fm?.id || !body) return;
|
|
1225
|
+
result.push({
|
|
1226
|
+
id: fm.id,
|
|
1227
|
+
content: body,
|
|
1228
|
+
category: fm.category ?? category.slice(0, -1),
|
|
1229
|
+
filePath
|
|
1230
|
+
});
|
|
1231
|
+
});
|
|
1232
|
+
}
|
|
1233
|
+
return result;
|
|
1234
|
+
}
|
|
1235
|
+
function hashContent2(content) {
|
|
1236
|
+
return crypto2.createHash("sha256").update(content).digest("hex").slice(0, 16);
|
|
1237
|
+
}
|
|
1238
|
+
function readFileSafe2(filePath) {
|
|
1239
|
+
try {
|
|
1240
|
+
return fs4.readFileSync(filePath, "utf8");
|
|
1241
|
+
} catch {
|
|
1242
|
+
return null;
|
|
1243
|
+
}
|
|
1244
|
+
}
|
|
1245
|
+
function parseFrontmatter3(content) {
|
|
1246
|
+
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
1247
|
+
if (!match) return null;
|
|
1248
|
+
const fm = {};
|
|
1249
|
+
for (const line of match[1].split("\n")) {
|
|
1250
|
+
const colonIdx = line.indexOf(":");
|
|
1251
|
+
if (colonIdx === -1) continue;
|
|
1252
|
+
const key = line.slice(0, colonIdx).trim();
|
|
1253
|
+
const value = line.slice(colonIdx + 1).trim();
|
|
1254
|
+
fm[key] = value;
|
|
1255
|
+
}
|
|
1256
|
+
return fm;
|
|
1257
|
+
}
|
|
1258
|
+
function extractBody3(content) {
|
|
1259
|
+
const match = content.match(/^---\n[\s\S]*?\n---\n([\s\S]*)/);
|
|
1260
|
+
return match ? match[1].trim() : content.trim();
|
|
1261
|
+
}
|
|
1262
|
+
function walkMdFiles(dir, callback) {
|
|
1263
|
+
for (const entry of fs4.readdirSync(dir, { withFileTypes: true })) {
|
|
1264
|
+
const fullPath = path5.join(dir, entry.name);
|
|
1265
|
+
if (entry.isDirectory()) {
|
|
1266
|
+
walkMdFiles(fullPath, callback);
|
|
1267
|
+
} else if (entry.name.endsWith(".md")) {
|
|
1268
|
+
callback(fullPath);
|
|
1269
|
+
}
|
|
1270
|
+
}
|
|
1271
|
+
}
|
|
1272
|
+
|
|
1273
|
+
// src/review/index.ts
|
|
1274
|
+
import fs5 from "fs";
|
|
1275
|
+
import path6 from "path";
|
|
1276
|
+
function listReviewItems(options) {
|
|
1277
|
+
const startTime = Date.now();
|
|
1278
|
+
const {
|
|
1279
|
+
memoryDir,
|
|
1280
|
+
reason: filterReason,
|
|
1281
|
+
limit = 50,
|
|
1282
|
+
confidenceThreshold = 0.7
|
|
1283
|
+
} = options;
|
|
1284
|
+
const items = [];
|
|
1285
|
+
const suggestionsDir = path6.join(memoryDir, "suggestions");
|
|
1286
|
+
if (fs5.existsSync(suggestionsDir)) {
|
|
1287
|
+
walkMd(suggestionsDir, (filePath, content) => {
|
|
1288
|
+
if (items.length >= limit) return;
|
|
1289
|
+
const fm = parseFrontmatter4(content);
|
|
1290
|
+
const body = extractBody4(content);
|
|
1291
|
+
if (!fm?.id) return;
|
|
1292
|
+
items.push({
|
|
1293
|
+
id: fm.id,
|
|
1294
|
+
content: body,
|
|
1295
|
+
category: fm.category ?? "suggestion",
|
|
1296
|
+
confidence: parseConfidence(fm.confidence, 0.5),
|
|
1297
|
+
confidenceTier: fm.confidenceTier ?? "low",
|
|
1298
|
+
source: fm.source ?? "unknown",
|
|
1299
|
+
filePath,
|
|
1300
|
+
created: fm.created ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
1301
|
+
reviewReason: "suggestion"
|
|
1302
|
+
});
|
|
1303
|
+
});
|
|
1304
|
+
}
|
|
1305
|
+
const reviewDir = path6.join(memoryDir, "review");
|
|
1306
|
+
if (fs5.existsSync(reviewDir)) {
|
|
1307
|
+
walkMd(reviewDir, (filePath, content) => {
|
|
1308
|
+
if (items.length >= limit) return;
|
|
1309
|
+
const fm = parseFrontmatter4(content);
|
|
1310
|
+
const body = extractBody4(content);
|
|
1311
|
+
if (!fm?.id) return;
|
|
1312
|
+
items.push({
|
|
1313
|
+
id: fm.id,
|
|
1314
|
+
content: body,
|
|
1315
|
+
category: fm.category ?? "review",
|
|
1316
|
+
confidence: parseConfidence(fm.confidence, 0.5),
|
|
1317
|
+
confidenceTier: fm.confidenceTier ?? "low",
|
|
1318
|
+
source: fm.source ?? "unknown",
|
|
1319
|
+
filePath,
|
|
1320
|
+
created: fm.created ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
1321
|
+
reviewReason: fm.reviewReason ?? "low_confidence",
|
|
1322
|
+
context: fm.context
|
|
1323
|
+
});
|
|
1324
|
+
});
|
|
1325
|
+
}
|
|
1326
|
+
const categories = ALL_CATEGORY_DIRS;
|
|
1327
|
+
for (const category of categories) {
|
|
1328
|
+
if (items.length >= limit) break;
|
|
1329
|
+
const dir = path6.join(memoryDir, category);
|
|
1330
|
+
if (!fs5.existsSync(dir)) continue;
|
|
1331
|
+
walkMd(dir, (filePath, content) => {
|
|
1332
|
+
if (items.length >= limit) return;
|
|
1333
|
+
const fm = parseFrontmatter4(content);
|
|
1334
|
+
const body = extractBody4(content);
|
|
1335
|
+
if (!fm?.id) return;
|
|
1336
|
+
const confidence = parseConfidence(fm.confidence, 1);
|
|
1337
|
+
if (confidence >= confidenceThreshold) return;
|
|
1338
|
+
if (items.some((i) => i.id === fm.id)) return;
|
|
1339
|
+
items.push({
|
|
1340
|
+
id: fm.id,
|
|
1341
|
+
content: body,
|
|
1342
|
+
category: fm.category ?? category.slice(0, -1),
|
|
1343
|
+
confidence,
|
|
1344
|
+
confidenceTier: fm.confidenceTier ?? "low",
|
|
1345
|
+
source: fm.source ?? "unknown",
|
|
1346
|
+
filePath,
|
|
1347
|
+
created: fm.created ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
1348
|
+
reviewReason: "low_confidence"
|
|
1349
|
+
});
|
|
1350
|
+
});
|
|
1351
|
+
}
|
|
1352
|
+
const filtered = filterReason ? items.filter((i) => i.reviewReason === filterReason) : items;
|
|
1353
|
+
return {
|
|
1354
|
+
items: filtered.slice(0, limit),
|
|
1355
|
+
total: filtered.length,
|
|
1356
|
+
durationMs: Date.now() - startTime
|
|
1357
|
+
};
|
|
1358
|
+
}
|
|
1359
|
+
function performReview(memoryDir, itemId, action) {
|
|
1360
|
+
switch (action) {
|
|
1361
|
+
case "approve":
|
|
1362
|
+
return approveItem(memoryDir, itemId);
|
|
1363
|
+
case "dismiss":
|
|
1364
|
+
return dismissItem(memoryDir, itemId);
|
|
1365
|
+
case "flag":
|
|
1366
|
+
return flagItem(memoryDir, itemId);
|
|
1367
|
+
}
|
|
1368
|
+
}
|
|
1369
|
+
function approveItem(memoryDir, itemId) {
|
|
1370
|
+
const locations = ["suggestions", "review"];
|
|
1371
|
+
for (const loc of locations) {
|
|
1372
|
+
const dir = path6.join(memoryDir, loc);
|
|
1373
|
+
if (!fs5.existsSync(dir)) continue;
|
|
1374
|
+
const found = findFileById(dir, itemId);
|
|
1375
|
+
if (!found) continue;
|
|
1376
|
+
const content = fs5.readFileSync(found, "utf8");
|
|
1377
|
+
const fm = parseFrontmatter4(content);
|
|
1378
|
+
const body = extractBody4(content);
|
|
1379
|
+
if (!fm) return { itemId, action: "approve", message: "Could not parse frontmatter" };
|
|
1380
|
+
const category = fm.category ?? "fact";
|
|
1381
|
+
const targetDir = getCategoryDir(memoryDir, category);
|
|
1382
|
+
const dateDir = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
1383
|
+
const outputPath = path6.join(targetDir, dateDir, path6.basename(found));
|
|
1384
|
+
const updatedContent = content.replace(/confidence: [\d.]+/, "confidence: 0.9").replace(/confidenceTier: \w+/, "confidenceTier: high");
|
|
1385
|
+
fs5.mkdirSync(path6.dirname(outputPath), { recursive: true });
|
|
1386
|
+
fs5.writeFileSync(outputPath, updatedContent);
|
|
1387
|
+
fs5.unlinkSync(found);
|
|
1388
|
+
return {
|
|
1389
|
+
itemId,
|
|
1390
|
+
action: "approve",
|
|
1391
|
+
updatedPath: outputPath,
|
|
1392
|
+
message: `Promoted to ${category} with confidence 0.9`
|
|
1393
|
+
};
|
|
1394
|
+
}
|
|
1395
|
+
return { itemId, action: "approve", message: "Item not found" };
|
|
1396
|
+
}
|
|
1397
|
+
function dismissItem(memoryDir, itemId) {
|
|
1398
|
+
const locations = ["suggestions", "review"];
|
|
1399
|
+
for (const loc of locations) {
|
|
1400
|
+
const dir = path6.join(memoryDir, loc);
|
|
1401
|
+
if (!fs5.existsSync(dir)) continue;
|
|
1402
|
+
const found = findFileById(dir, itemId);
|
|
1403
|
+
if (found) {
|
|
1404
|
+
fs5.unlinkSync(found);
|
|
1405
|
+
return { itemId, action: "dismiss", message: "Dismissed and removed" };
|
|
1406
|
+
}
|
|
1407
|
+
}
|
|
1408
|
+
return { itemId, action: "dismiss", message: "Item not found" };
|
|
1409
|
+
}
|
|
1410
|
+
function flagItem(memoryDir, itemId) {
|
|
1411
|
+
const locations = ["suggestions", "review"];
|
|
1412
|
+
for (const loc of locations) {
|
|
1413
|
+
const dir = path6.join(memoryDir, loc);
|
|
1414
|
+
if (!fs5.existsSync(dir)) continue;
|
|
1415
|
+
const found = findFileById(dir, itemId);
|
|
1416
|
+
if (found) {
|
|
1417
|
+
const content = fs5.readFileSync(found, "utf8");
|
|
1418
|
+
const fixed = content.replace(
|
|
1419
|
+
/^(---\n)/,
|
|
1420
|
+
`---
|
|
1421
|
+
flagged: true
|
|
1422
|
+
flaggedAt: ${(/* @__PURE__ */ new Date()).toISOString()}
|
|
1423
|
+
`
|
|
1424
|
+
);
|
|
1425
|
+
fs5.writeFileSync(found, fixed);
|
|
1426
|
+
return { itemId, action: "flag", message: "Flagged for further review" };
|
|
1427
|
+
}
|
|
1428
|
+
}
|
|
1429
|
+
return { itemId, action: "flag", message: "Item not found" };
|
|
1430
|
+
}
|
|
1431
|
+
function findFileById(dir, id) {
|
|
1432
|
+
const files = walkMdPaths(dir);
|
|
1433
|
+
for (const filePath of files) {
|
|
1434
|
+
const content = readFileSafe3(filePath);
|
|
1435
|
+
if (!content) continue;
|
|
1436
|
+
const fm = parseFrontmatter4(content);
|
|
1437
|
+
if (fm?.id === id) return filePath;
|
|
1438
|
+
}
|
|
1439
|
+
return null;
|
|
1440
|
+
}
|
|
1441
|
+
function parseConfidence(value, fallback) {
|
|
1442
|
+
if (typeof value === "number") return Number.isFinite(value) ? value : fallback;
|
|
1443
|
+
if (typeof value === "string") {
|
|
1444
|
+
const n = parseFloat(value);
|
|
1445
|
+
return Number.isFinite(n) ? n : fallback;
|
|
1446
|
+
}
|
|
1447
|
+
return fallback;
|
|
1448
|
+
}
|
|
1449
|
+
function readFileSafe3(filePath) {
|
|
1450
|
+
try {
|
|
1451
|
+
return fs5.readFileSync(filePath, "utf8");
|
|
1452
|
+
} catch {
|
|
1453
|
+
return null;
|
|
1454
|
+
}
|
|
1455
|
+
}
|
|
1456
|
+
function parseFrontmatter4(content) {
|
|
1457
|
+
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
1458
|
+
if (!match) return null;
|
|
1459
|
+
const fm = {};
|
|
1460
|
+
for (const line of match[1].split("\n")) {
|
|
1461
|
+
const colonIdx = line.indexOf(":");
|
|
1462
|
+
if (colonIdx === -1) continue;
|
|
1463
|
+
const key = line.slice(0, colonIdx).trim();
|
|
1464
|
+
const value = line.slice(colonIdx + 1).trim();
|
|
1465
|
+
fm[key] = value;
|
|
1466
|
+
}
|
|
1467
|
+
return fm;
|
|
1468
|
+
}
|
|
1469
|
+
function extractBody4(content) {
|
|
1470
|
+
const match = content.match(/^---\n[\s\S]*?\n---\n([\s\S]*)/);
|
|
1471
|
+
return match ? match[1].trim() : content.trim();
|
|
1472
|
+
}
|
|
1473
|
+
function walkMd(dir, callback) {
|
|
1474
|
+
for (const entry of fs5.readdirSync(dir, { withFileTypes: true })) {
|
|
1475
|
+
const fullPath = path6.join(dir, entry.name);
|
|
1476
|
+
if (entry.isDirectory()) {
|
|
1477
|
+
walkMd(fullPath, callback);
|
|
1478
|
+
} else if (entry.name.endsWith(".md")) {
|
|
1479
|
+
const content = readFileSafe3(fullPath);
|
|
1480
|
+
if (content) callback(fullPath, content);
|
|
1481
|
+
}
|
|
1482
|
+
}
|
|
1483
|
+
}
|
|
1484
|
+
function walkMdPaths(dir) {
|
|
1485
|
+
const results = [];
|
|
1486
|
+
for (const entry of fs5.readdirSync(dir, { withFileTypes: true })) {
|
|
1487
|
+
const fullPath = path6.join(dir, entry.name);
|
|
1488
|
+
if (entry.isDirectory()) {
|
|
1489
|
+
results.push(...walkMdPaths(fullPath));
|
|
1490
|
+
} else if (entry.name.endsWith(".md")) {
|
|
1491
|
+
results.push(fullPath);
|
|
1492
|
+
}
|
|
1493
|
+
}
|
|
1494
|
+
return results;
|
|
1495
|
+
}
|
|
1496
|
+
|
|
1497
|
+
// src/sync/index.ts
|
|
1498
|
+
import fs6 from "fs";
|
|
1499
|
+
import path7 from "path";
|
|
1500
|
+
import crypto3 from "crypto";
|
|
1501
|
+
var DEFAULT_EXTENSIONS = /* @__PURE__ */ new Set([".md", ".txt", ".mdx", ".rst"]);
|
|
1502
|
+
var DEFAULT_EXCLUDE2 = /* @__PURE__ */ new Set([
|
|
1503
|
+
"node_modules",
|
|
1504
|
+
".git",
|
|
1505
|
+
"dist",
|
|
1506
|
+
"build",
|
|
1507
|
+
".engram",
|
|
1508
|
+
"coverage"
|
|
1509
|
+
]);
|
|
1510
|
+
function syncChanges(options) {
|
|
1511
|
+
const startTime = Date.now();
|
|
1512
|
+
const {
|
|
1513
|
+
sourceDir,
|
|
1514
|
+
memoryDir,
|
|
1515
|
+
extensions = [...DEFAULT_EXTENSIONS],
|
|
1516
|
+
excludeDirs = [],
|
|
1517
|
+
dryRun = false
|
|
1518
|
+
} = options;
|
|
1519
|
+
const extSet = new Set(extensions);
|
|
1520
|
+
const excludeSet = /* @__PURE__ */ new Set([...DEFAULT_EXCLUDE2, ...excludeDirs]);
|
|
1521
|
+
const stateFilePath = options.stateFile ?? path7.join(memoryDir, ".sync-state.json");
|
|
1522
|
+
const prevState = loadState(stateFilePath);
|
|
1523
|
+
const currentFiles = scanFiles(sourceDir, extSet, excludeSet);
|
|
1524
|
+
const changes = computeDiff(currentFiles, prevState.fileHashes, sourceDir);
|
|
1525
|
+
const added = changes.filter((c) => c.type === "added").map((c) => c.relativePath);
|
|
1526
|
+
const modified = changes.filter((c) => c.type === "modified");
|
|
1527
|
+
const deleted = changes.filter((c) => c.type === "deleted").map((c) => c.relativePath);
|
|
1528
|
+
if (!dryRun) {
|
|
1529
|
+
const newState = {
|
|
1530
|
+
fileHashes: {},
|
|
1531
|
+
lastSyncAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1532
|
+
version: 1
|
|
1533
|
+
};
|
|
1534
|
+
for (const [relPath, hash] of Object.entries(currentFiles)) {
|
|
1535
|
+
newState.fileHashes[relPath] = hash;
|
|
1536
|
+
}
|
|
1537
|
+
fs6.mkdirSync(path7.dirname(stateFilePath), { recursive: true });
|
|
1538
|
+
fs6.writeFileSync(stateFilePath, JSON.stringify(newState, null, 2));
|
|
1539
|
+
}
|
|
1540
|
+
return {
|
|
1541
|
+
scanned: Object.keys(currentFiles).length,
|
|
1542
|
+
changed: changes,
|
|
1543
|
+
unchanged: Object.keys(currentFiles).length - changes.filter((c) => c.type !== "deleted").length,
|
|
1544
|
+
deleted,
|
|
1545
|
+
added,
|
|
1546
|
+
durationMs: Date.now() - startTime,
|
|
1547
|
+
stateFile: stateFilePath
|
|
1548
|
+
};
|
|
1549
|
+
}
|
|
1550
|
+
function watchForChanges(options, onChange) {
|
|
1551
|
+
const { sourceDir, extensions, excludeDirs } = options;
|
|
1552
|
+
const extSet = new Set(extensions ?? DEFAULT_EXTENSIONS);
|
|
1553
|
+
const excludeSet = /* @__PURE__ */ new Set([...DEFAULT_EXCLUDE2, ...excludeDirs ?? []]);
|
|
1554
|
+
let lastHashes = {};
|
|
1555
|
+
const currentFiles = scanFiles(sourceDir, extSet, excludeSet);
|
|
1556
|
+
lastHashes = { ...currentFiles };
|
|
1557
|
+
const interval = setInterval(() => {
|
|
1558
|
+
const nowFiles = scanFiles(sourceDir, extSet, excludeSet);
|
|
1559
|
+
const changes = computeDiff(nowFiles, lastHashes, sourceDir);
|
|
1560
|
+
if (changes.length > 0) {
|
|
1561
|
+
for (const change of changes) {
|
|
1562
|
+
if (change.type === "deleted") {
|
|
1563
|
+
delete lastHashes[change.relativePath];
|
|
1564
|
+
} else {
|
|
1565
|
+
lastHashes[change.relativePath] = change.currentHash;
|
|
1566
|
+
}
|
|
1567
|
+
}
|
|
1568
|
+
onChange(changes);
|
|
1569
|
+
}
|
|
1570
|
+
}, 5e3);
|
|
1571
|
+
return {
|
|
1572
|
+
stop: () => clearInterval(interval)
|
|
1573
|
+
};
|
|
1574
|
+
}
|
|
1575
|
+
function scanFiles(root, extensions, exclude) {
|
|
1576
|
+
const result = {};
|
|
1577
|
+
function walk(dir) {
|
|
1578
|
+
let entries;
|
|
1579
|
+
try {
|
|
1580
|
+
entries = fs6.readdirSync(dir, { withFileTypes: true });
|
|
1581
|
+
} catch {
|
|
1582
|
+
return;
|
|
1583
|
+
}
|
|
1584
|
+
for (const entry of entries) {
|
|
1585
|
+
if (exclude.has(entry.name)) continue;
|
|
1586
|
+
const fullPath = path7.join(dir, entry.name);
|
|
1587
|
+
if (entry.isDirectory()) {
|
|
1588
|
+
walk(fullPath);
|
|
1589
|
+
} else if (entry.isFile()) {
|
|
1590
|
+
const ext = path7.extname(entry.name).toLowerCase();
|
|
1591
|
+
if (!extensions.has(ext)) continue;
|
|
1592
|
+
const relPath = path7.relative(root, fullPath);
|
|
1593
|
+
try {
|
|
1594
|
+
const content = fs6.readFileSync(fullPath, "utf8");
|
|
1595
|
+
result[relPath] = hashContent3(content);
|
|
1596
|
+
} catch {
|
|
1597
|
+
}
|
|
1598
|
+
}
|
|
1599
|
+
}
|
|
1600
|
+
}
|
|
1601
|
+
walk(root);
|
|
1602
|
+
return result;
|
|
1603
|
+
}
|
|
1604
|
+
function computeDiff(current, previous, sourceDir) {
|
|
1605
|
+
const changes = [];
|
|
1606
|
+
for (const [relPath, hash] of Object.entries(current)) {
|
|
1607
|
+
const fullPath = path7.join(sourceDir, relPath);
|
|
1608
|
+
if (!(relPath in previous)) {
|
|
1609
|
+
let size = 0;
|
|
1610
|
+
try {
|
|
1611
|
+
size = fs6.statSync(fullPath).size;
|
|
1612
|
+
} catch {
|
|
1613
|
+
}
|
|
1614
|
+
changes.push({
|
|
1615
|
+
filePath: fullPath,
|
|
1616
|
+
relativePath: relPath,
|
|
1617
|
+
type: "added",
|
|
1618
|
+
currentHash: hash,
|
|
1619
|
+
size
|
|
1620
|
+
});
|
|
1621
|
+
} else if (previous[relPath] !== hash) {
|
|
1622
|
+
let size = 0;
|
|
1623
|
+
try {
|
|
1624
|
+
size = fs6.statSync(fullPath).size;
|
|
1625
|
+
} catch {
|
|
1626
|
+
}
|
|
1627
|
+
changes.push({
|
|
1628
|
+
filePath: fullPath,
|
|
1629
|
+
relativePath: relPath,
|
|
1630
|
+
type: "modified",
|
|
1631
|
+
currentHash: hash,
|
|
1632
|
+
previousHash: previous[relPath],
|
|
1633
|
+
size
|
|
1634
|
+
});
|
|
1635
|
+
}
|
|
1636
|
+
}
|
|
1637
|
+
for (const relPath of Object.keys(previous)) {
|
|
1638
|
+
if (!(relPath in current)) {
|
|
1639
|
+
changes.push({
|
|
1640
|
+
filePath: path7.join(sourceDir, relPath),
|
|
1641
|
+
relativePath: relPath,
|
|
1642
|
+
type: "deleted",
|
|
1643
|
+
currentHash: "",
|
|
1644
|
+
size: 0
|
|
1645
|
+
});
|
|
1646
|
+
}
|
|
1647
|
+
}
|
|
1648
|
+
return changes;
|
|
1649
|
+
}
|
|
1650
|
+
function loadState(stateFilePath) {
|
|
1651
|
+
try {
|
|
1652
|
+
const raw = fs6.readFileSync(stateFilePath, "utf8");
|
|
1653
|
+
return JSON.parse(raw);
|
|
1654
|
+
} catch {
|
|
1655
|
+
return {
|
|
1656
|
+
fileHashes: {},
|
|
1657
|
+
lastSyncAt: (/* @__PURE__ */ new Date(0)).toISOString(),
|
|
1658
|
+
version: 1
|
|
1659
|
+
};
|
|
1660
|
+
}
|
|
1661
|
+
}
|
|
1662
|
+
function hashContent3(content) {
|
|
1663
|
+
return crypto3.createHash("sha256").update(content).digest("hex").slice(0, 16);
|
|
1664
|
+
}
|
|
1665
|
+
|
|
1666
|
+
// src/connectors/index.ts
|
|
1667
|
+
import fs7 from "fs";
|
|
1668
|
+
import path8 from "path";
|
|
1669
|
+
var BUILTIN_CONNECTORS = [
|
|
1670
|
+
{
|
|
1671
|
+
id: "claude-code",
|
|
1672
|
+
name: "Claude Code",
|
|
1673
|
+
version: "1.0.0",
|
|
1674
|
+
description: "Anthropic's Claude Code CLI \u2014 direct memory access via MCP",
|
|
1675
|
+
capabilities: {
|
|
1676
|
+
observe: true,
|
|
1677
|
+
recall: true,
|
|
1678
|
+
store: true,
|
|
1679
|
+
search: true,
|
|
1680
|
+
entities: true,
|
|
1681
|
+
realtimeSync: true,
|
|
1682
|
+
batch: false,
|
|
1683
|
+
maxBudgetChars: 32e3,
|
|
1684
|
+
connectionType: "mcp"
|
|
1685
|
+
},
|
|
1686
|
+
configSchema: {
|
|
1687
|
+
mcpServerUrl: "URL of the MCP Remnic server",
|
|
1688
|
+
namespace: "Optional namespace (default: 'default')"
|
|
1689
|
+
},
|
|
1690
|
+
homepage: "https://claude.ai/code",
|
|
1691
|
+
author: "Anthropic",
|
|
1692
|
+
tags: ["official", "ai", "claude"]
|
|
1693
|
+
},
|
|
1694
|
+
{
|
|
1695
|
+
id: "codex-cli",
|
|
1696
|
+
name: "Codex CLI",
|
|
1697
|
+
version: "1.0.0",
|
|
1698
|
+
description: "OpenAI Codex CLI \u2014 memory via MCP tool",
|
|
1699
|
+
capabilities: {
|
|
1700
|
+
observe: true,
|
|
1701
|
+
recall: true,
|
|
1702
|
+
store: true,
|
|
1703
|
+
search: false,
|
|
1704
|
+
entities: false,
|
|
1705
|
+
realtimeSync: false,
|
|
1706
|
+
batch: true,
|
|
1707
|
+
maxBudgetChars: 8e3,
|
|
1708
|
+
connectionType: "mcp"
|
|
1709
|
+
},
|
|
1710
|
+
configSchema: {
|
|
1711
|
+
mcpServerUrl: "URL of the MCP Remnic server",
|
|
1712
|
+
namespace: "Optional namespace"
|
|
1713
|
+
},
|
|
1714
|
+
homepage: "https://openai.com/codex",
|
|
1715
|
+
author: "OpenAI",
|
|
1716
|
+
tags: ["official", "ai", "codex"]
|
|
1717
|
+
},
|
|
1718
|
+
{
|
|
1719
|
+
id: "cursor",
|
|
1720
|
+
name: "Cursor IDE",
|
|
1721
|
+
version: "1.0.0",
|
|
1722
|
+
description: "Cursor IDE \u2014 memory via config file + tool calls",
|
|
1723
|
+
capabilities: {
|
|
1724
|
+
observe: false,
|
|
1725
|
+
recall: true,
|
|
1726
|
+
store: false,
|
|
1727
|
+
search: true,
|
|
1728
|
+
entities: false,
|
|
1729
|
+
realtimeSync: false,
|
|
1730
|
+
batch: false,
|
|
1731
|
+
maxBudgetChars: 32e3,
|
|
1732
|
+
connectionType: "embedded"
|
|
1733
|
+
},
|
|
1734
|
+
configSchema: {
|
|
1735
|
+
memoryDir: "Path to Remnic memory directory"
|
|
1736
|
+
},
|
|
1737
|
+
homepage: "https://cursor.com",
|
|
1738
|
+
author: "Cursor Inc.",
|
|
1739
|
+
tags: ["official", "ide"]
|
|
1740
|
+
},
|
|
1741
|
+
{
|
|
1742
|
+
id: "cline",
|
|
1743
|
+
name: "Cline",
|
|
1744
|
+
version: "1.0.0",
|
|
1745
|
+
description: "VS Code Cline extension \u2014 memory via MCP",
|
|
1746
|
+
capabilities: {
|
|
1747
|
+
observe: true,
|
|
1748
|
+
recall: true,
|
|
1749
|
+
store: true,
|
|
1750
|
+
search: false,
|
|
1751
|
+
entities: false,
|
|
1752
|
+
realtimeSync: false,
|
|
1753
|
+
batch: true,
|
|
1754
|
+
maxBudgetChars: 8e3,
|
|
1755
|
+
connectionType: "mcp"
|
|
1756
|
+
},
|
|
1757
|
+
configSchema: {
|
|
1758
|
+
mcpServerUrl: "URL of the MCP Remnic server",
|
|
1759
|
+
namespace: "Optional namespace"
|
|
1760
|
+
},
|
|
1761
|
+
homepage: "https://github.com/cline/cline",
|
|
1762
|
+
author: "Cline",
|
|
1763
|
+
tags: ["community", "vscode"]
|
|
1764
|
+
},
|
|
1765
|
+
{
|
|
1766
|
+
id: "github-copilot",
|
|
1767
|
+
name: "GitHub Copilot",
|
|
1768
|
+
version: "1.0.0",
|
|
1769
|
+
description: "GitHub Copilot \u2014 memory via MCP server",
|
|
1770
|
+
capabilities: {
|
|
1771
|
+
observe: false,
|
|
1772
|
+
recall: true,
|
|
1773
|
+
store: false,
|
|
1774
|
+
search: true,
|
|
1775
|
+
entities: false,
|
|
1776
|
+
realtimeSync: false,
|
|
1777
|
+
batch: false,
|
|
1778
|
+
maxBudgetChars: 16e3,
|
|
1779
|
+
connectionType: "mcp"
|
|
1780
|
+
},
|
|
1781
|
+
configSchema: {
|
|
1782
|
+
mcpServerUrl: "URL of the MCP Remnic server"
|
|
1783
|
+
},
|
|
1784
|
+
homepage: "https://github.com/features/copilot",
|
|
1785
|
+
author: "GitHub",
|
|
1786
|
+
tags: ["official", "ai", "github"]
|
|
1787
|
+
},
|
|
1788
|
+
{
|
|
1789
|
+
id: "roo-code",
|
|
1790
|
+
name: "Roo Code",
|
|
1791
|
+
version: "1.0.0",
|
|
1792
|
+
description: "Roo Code \u2014 memory via MCP",
|
|
1793
|
+
capabilities: {
|
|
1794
|
+
observe: true,
|
|
1795
|
+
recall: true,
|
|
1796
|
+
store: true,
|
|
1797
|
+
search: false,
|
|
1798
|
+
entities: false,
|
|
1799
|
+
realtimeSync: false,
|
|
1800
|
+
batch: true,
|
|
1801
|
+
maxBudgetChars: 16e3,
|
|
1802
|
+
connectionType: "mcp"
|
|
1803
|
+
},
|
|
1804
|
+
configSchema: {
|
|
1805
|
+
mcpServerUrl: "URL of the MCP Remnic server",
|
|
1806
|
+
namespace: "Optional namespace"
|
|
1807
|
+
},
|
|
1808
|
+
homepage: "https://roocode.com",
|
|
1809
|
+
author: "Roo Code",
|
|
1810
|
+
tags: ["community", "vscode"]
|
|
1811
|
+
},
|
|
1812
|
+
{
|
|
1813
|
+
id: "windsurf",
|
|
1814
|
+
name: "Windsurf",
|
|
1815
|
+
version: "1.0.0",
|
|
1816
|
+
description: "Windsurf IDE \u2014 memory via MCP",
|
|
1817
|
+
capabilities: {
|
|
1818
|
+
observe: true,
|
|
1819
|
+
recall: true,
|
|
1820
|
+
store: true,
|
|
1821
|
+
search: true,
|
|
1822
|
+
entities: false,
|
|
1823
|
+
realtimeSync: false,
|
|
1824
|
+
batch: false,
|
|
1825
|
+
maxBudgetChars: 32e3,
|
|
1826
|
+
connectionType: "mcp"
|
|
1827
|
+
},
|
|
1828
|
+
configSchema: {
|
|
1829
|
+
mcpServerUrl: "URL of the MCP Remnic server"
|
|
1830
|
+
},
|
|
1831
|
+
homepage: "https://windsurf.com",
|
|
1832
|
+
author: "Codeium",
|
|
1833
|
+
tags: ["official", "ide"]
|
|
1834
|
+
},
|
|
1835
|
+
{
|
|
1836
|
+
id: "amp",
|
|
1837
|
+
name: "Amp",
|
|
1838
|
+
version: "1.0.0",
|
|
1839
|
+
description: "Amp coding agent \u2014 memory via MCP",
|
|
1840
|
+
capabilities: {
|
|
1841
|
+
observe: true,
|
|
1842
|
+
recall: true,
|
|
1843
|
+
store: true,
|
|
1844
|
+
search: true,
|
|
1845
|
+
entities: false,
|
|
1846
|
+
realtimeSync: false,
|
|
1847
|
+
batch: false,
|
|
1848
|
+
maxBudgetChars: 32e3,
|
|
1849
|
+
connectionType: "mcp"
|
|
1850
|
+
},
|
|
1851
|
+
configSchema: {
|
|
1852
|
+
mcpServerUrl: "URL of the MCP Remnic server"
|
|
1853
|
+
},
|
|
1854
|
+
homepage: "https://ampcode.com",
|
|
1855
|
+
author: "Sourcegraph",
|
|
1856
|
+
tags: ["official", "ai"]
|
|
1857
|
+
},
|
|
1858
|
+
{
|
|
1859
|
+
id: "replit",
|
|
1860
|
+
name: "Replit Agent",
|
|
1861
|
+
version: "1.0.0",
|
|
1862
|
+
description: "Replit Agent \u2014 memory via HTTP API (reduced capabilities)",
|
|
1863
|
+
capabilities: {
|
|
1864
|
+
observe: true,
|
|
1865
|
+
recall: true,
|
|
1866
|
+
store: true,
|
|
1867
|
+
search: false,
|
|
1868
|
+
entities: false,
|
|
1869
|
+
realtimeSync: false,
|
|
1870
|
+
batch: false,
|
|
1871
|
+
maxBudgetChars: 8e3,
|
|
1872
|
+
connectionType: "http"
|
|
1873
|
+
},
|
|
1874
|
+
configSchema: {
|
|
1875
|
+
apiUrl: "URL of the Remnic HTTP API",
|
|
1876
|
+
authToken: "Bearer token for authentication"
|
|
1877
|
+
},
|
|
1878
|
+
homepage: "https://replit.com",
|
|
1879
|
+
author: "Replit",
|
|
1880
|
+
tags: ["official", "cloud"]
|
|
1881
|
+
},
|
|
1882
|
+
{
|
|
1883
|
+
id: "generic-mcp",
|
|
1884
|
+
name: "Generic MCP Client",
|
|
1885
|
+
version: "1.0.0",
|
|
1886
|
+
description: "Any MCP-compatible client \u2014 connect via standard MCP protocol",
|
|
1887
|
+
capabilities: {
|
|
1888
|
+
observe: true,
|
|
1889
|
+
recall: true,
|
|
1890
|
+
store: true,
|
|
1891
|
+
search: true,
|
|
1892
|
+
entities: true,
|
|
1893
|
+
realtimeSync: true,
|
|
1894
|
+
batch: true,
|
|
1895
|
+
maxBudgetChars: 64e3,
|
|
1896
|
+
connectionType: "mcp"
|
|
1897
|
+
},
|
|
1898
|
+
configSchema: {
|
|
1899
|
+
mcpServerUrl: "URL of the MCP Remnic server",
|
|
1900
|
+
namespace: "Optional namespace",
|
|
1901
|
+
authToken: "Bearer token for authentication"
|
|
1902
|
+
},
|
|
1903
|
+
homepage: "https://github.com/joshuaswarren/remnic",
|
|
1904
|
+
author: "Remnic",
|
|
1905
|
+
tags: ["generic", "mcp"]
|
|
1906
|
+
}
|
|
1907
|
+
];
|
|
1908
|
+
var REGISTRY_DIR_NAME = ".engram-connectors";
|
|
1909
|
+
function getRegistryPath() {
|
|
1910
|
+
const configDir = process.env.XDG_CONFIG_HOME ? path8.join(process.env.XDG_CONFIG_HOME, "engram") : path8.join(process.env.HOME ?? "~", ".config", "engram");
|
|
1911
|
+
return path8.join(configDir, REGISTRY_DIR_NAME, "registry.json");
|
|
1912
|
+
}
|
|
1913
|
+
function loadRegistry() {
|
|
1914
|
+
const regPath = getRegistryPath();
|
|
1915
|
+
if (!fs7.existsSync(regPath)) {
|
|
1916
|
+
const registry = {
|
|
1917
|
+
connectors: BUILTIN_CONNECTORS,
|
|
1918
|
+
registryPath: regPath
|
|
1919
|
+
};
|
|
1920
|
+
saveRegistry(registry);
|
|
1921
|
+
return registry;
|
|
1922
|
+
}
|
|
1923
|
+
const raw = fs7.readFileSync(regPath, "utf8");
|
|
1924
|
+
try {
|
|
1925
|
+
const parsed = JSON.parse(raw);
|
|
1926
|
+
const customIds = new Set((parsed.connectors ?? []).map((c) => c.id));
|
|
1927
|
+
const merged = [
|
|
1928
|
+
...BUILTIN_CONNECTORS.filter((b) => !customIds.has(b.id)),
|
|
1929
|
+
...parsed.connectors ?? []
|
|
1930
|
+
];
|
|
1931
|
+
return {
|
|
1932
|
+
connectors: merged,
|
|
1933
|
+
registryPath: regPath
|
|
1934
|
+
};
|
|
1935
|
+
} catch {
|
|
1936
|
+
const registry = {
|
|
1937
|
+
connectors: BUILTIN_CONNECTORS,
|
|
1938
|
+
registryPath: regPath
|
|
1939
|
+
};
|
|
1940
|
+
saveRegistry(registry);
|
|
1941
|
+
return registry;
|
|
1942
|
+
}
|
|
1943
|
+
}
|
|
1944
|
+
function saveRegistry(registry) {
|
|
1945
|
+
const regPath = registry.registryPath;
|
|
1946
|
+
fs7.mkdirSync(path8.dirname(regPath), { recursive: true });
|
|
1947
|
+
fs7.writeFileSync(regPath, JSON.stringify({ connectors: registry.connectors }, null, 2));
|
|
1948
|
+
}
|
|
1949
|
+
function listConnectors() {
|
|
1950
|
+
const registry = loadRegistry();
|
|
1951
|
+
const connectorsDir = getConnectorsDir();
|
|
1952
|
+
const installedIds = /* @__PURE__ */ new Set();
|
|
1953
|
+
if (fs7.existsSync(connectorsDir)) {
|
|
1954
|
+
for (const entry of fs7.readdirSync(connectorsDir)) {
|
|
1955
|
+
if (entry.endsWith(".json")) {
|
|
1956
|
+
try {
|
|
1957
|
+
const config = JSON.parse(
|
|
1958
|
+
fs7.readFileSync(path8.join(connectorsDir, entry), "utf8")
|
|
1959
|
+
);
|
|
1960
|
+
installedIds.add(config.connectorId);
|
|
1961
|
+
} catch {
|
|
1962
|
+
}
|
|
1963
|
+
}
|
|
1964
|
+
}
|
|
1965
|
+
}
|
|
1966
|
+
const available = registry.connectors.map((manifest) => ({
|
|
1967
|
+
...manifest,
|
|
1968
|
+
installed: installedIds.has(manifest.id)
|
|
1969
|
+
}));
|
|
1970
|
+
const installed = [];
|
|
1971
|
+
for (const id of installedIds) {
|
|
1972
|
+
const configPath = path8.join(connectorsDir, `${id}.json`);
|
|
1973
|
+
try {
|
|
1974
|
+
const config = JSON.parse(fs7.readFileSync(configPath, "utf8"));
|
|
1975
|
+
installed.push({
|
|
1976
|
+
connectorId: id,
|
|
1977
|
+
config,
|
|
1978
|
+
status: "installed",
|
|
1979
|
+
installedAt: config.installedAt
|
|
1980
|
+
});
|
|
1981
|
+
} catch {
|
|
1982
|
+
}
|
|
1983
|
+
}
|
|
1984
|
+
return { installed, available };
|
|
1985
|
+
}
|
|
1986
|
+
function installConnector(options) {
|
|
1987
|
+
const registry = loadRegistry();
|
|
1988
|
+
const manifest = registry.connectors.find((c) => c.id === options.connectorId);
|
|
1989
|
+
if (!manifest) {
|
|
1990
|
+
return {
|
|
1991
|
+
connectorId: options.connectorId,
|
|
1992
|
+
status: "error",
|
|
1993
|
+
message: `Unknown connector: ${options.connectorId}`
|
|
1994
|
+
};
|
|
1995
|
+
}
|
|
1996
|
+
const existing = listConnectors().installed.find(
|
|
1997
|
+
(c) => c.connectorId === options.connectorId
|
|
1998
|
+
);
|
|
1999
|
+
if (existing && !options.force) {
|
|
2000
|
+
return {
|
|
2001
|
+
connectorId: options.connectorId,
|
|
2002
|
+
status: "already_installed",
|
|
2003
|
+
message: "Already installed. Use --force to reinstall."
|
|
2004
|
+
};
|
|
2005
|
+
}
|
|
2006
|
+
const configDir = getConnectorsDir();
|
|
2007
|
+
fs7.mkdirSync(configDir, { recursive: true });
|
|
2008
|
+
const configPath = path8.join(configDir, `${options.connectorId}.json`);
|
|
2009
|
+
const resolvedConfig = {
|
|
2010
|
+
connectorId: options.connectorId,
|
|
2011
|
+
installedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2012
|
+
...options.config
|
|
2013
|
+
};
|
|
2014
|
+
fs7.writeFileSync(configPath, JSON.stringify(resolvedConfig, null, 2));
|
|
2015
|
+
return {
|
|
2016
|
+
connectorId: options.connectorId,
|
|
2017
|
+
status: "installed",
|
|
2018
|
+
configPath,
|
|
2019
|
+
message: `Installed ${manifest.name} v${manifest.version}`
|
|
2020
|
+
};
|
|
2021
|
+
}
|
|
2022
|
+
function removeConnector(connectorId) {
|
|
2023
|
+
const configDir = getConnectorsDir();
|
|
2024
|
+
const configPath = path8.join(configDir, `${connectorId}.json`);
|
|
2025
|
+
if (!fs7.existsSync(configPath)) {
|
|
2026
|
+
return {
|
|
2027
|
+
connectorId,
|
|
2028
|
+
configPath,
|
|
2029
|
+
message: "Not installed"
|
|
2030
|
+
};
|
|
2031
|
+
}
|
|
2032
|
+
fs7.unlinkSync(configPath);
|
|
2033
|
+
return {
|
|
2034
|
+
connectorId,
|
|
2035
|
+
configPath,
|
|
2036
|
+
message: "Removed"
|
|
2037
|
+
};
|
|
2038
|
+
}
|
|
2039
|
+
async function doctorConnector(connectorId) {
|
|
2040
|
+
const installed = listConnectors().installed;
|
|
2041
|
+
const instance = installed.find((c) => c.connectorId === connectorId);
|
|
2042
|
+
if (!instance) {
|
|
2043
|
+
return {
|
|
2044
|
+
connectorId,
|
|
2045
|
+
checks: [{ name: "Installed", ok: false, detail: "Not installed" }],
|
|
2046
|
+
healthy: false
|
|
2047
|
+
};
|
|
2048
|
+
}
|
|
2049
|
+
const configPath = path8.join(getConnectorsDir(), `${connectorId}.json`);
|
|
2050
|
+
const checks = [];
|
|
2051
|
+
checks.push({
|
|
2052
|
+
name: "Config file",
|
|
2053
|
+
ok: fs7.existsSync(configPath),
|
|
2054
|
+
detail: configPath
|
|
2055
|
+
});
|
|
2056
|
+
try {
|
|
2057
|
+
const raw = fs7.readFileSync(configPath, "utf8");
|
|
2058
|
+
JSON.parse(raw);
|
|
2059
|
+
checks.push({ name: "Config valid", ok: true, detail: "OK" });
|
|
2060
|
+
} catch (e) {
|
|
2061
|
+
checks.push({ name: "Config valid", ok: false, detail: String(e) });
|
|
2062
|
+
}
|
|
2063
|
+
const mcpUrl = instance.config.mcpServerUrl;
|
|
2064
|
+
if (mcpUrl) {
|
|
2065
|
+
try {
|
|
2066
|
+
const controller = new AbortController();
|
|
2067
|
+
const timeoutId = setTimeout(() => controller.abort(), 3e3);
|
|
2068
|
+
const response = await fetch(mcpUrl, { signal: controller.signal });
|
|
2069
|
+
clearTimeout(timeoutId);
|
|
2070
|
+
checks.push({ name: "MCP server", ok: response.ok, detail: mcpUrl });
|
|
2071
|
+
} catch (e) {
|
|
2072
|
+
checks.push({
|
|
2073
|
+
name: "MCP server",
|
|
2074
|
+
ok: false,
|
|
2075
|
+
detail: `Cannot reach ${mcpUrl}: ${e instanceof Error ? e.message : "unknown"}`
|
|
2076
|
+
});
|
|
2077
|
+
}
|
|
2078
|
+
}
|
|
2079
|
+
const memoryDir = instance.config.memoryDir;
|
|
2080
|
+
if (memoryDir) {
|
|
2081
|
+
if (fs7.existsSync(memoryDir)) {
|
|
2082
|
+
checks.push({ name: "Memory directory", ok: true, detail: memoryDir });
|
|
2083
|
+
} else {
|
|
2084
|
+
checks.push({ name: "Memory directory", ok: false, detail: `Not found: ${memoryDir}` });
|
|
2085
|
+
}
|
|
2086
|
+
}
|
|
2087
|
+
const healthy = checks.every((c) => c.ok);
|
|
2088
|
+
return { connectorId, checks, healthy };
|
|
2089
|
+
}
|
|
2090
|
+
function getConnectorsDir() {
|
|
2091
|
+
const configDir = process.env.XDG_CONFIG_HOME ? path8.join(process.env.XDG_CONFIG_HOME, "engram") : path8.join(process.env.HOME ?? "~", ".config", "engram");
|
|
2092
|
+
return path8.join(configDir, REGISTRY_DIR_NAME, "connectors");
|
|
2093
|
+
}
|
|
2094
|
+
|
|
2095
|
+
// src/spaces/index.ts
|
|
2096
|
+
import fs8 from "fs";
|
|
2097
|
+
import path9 from "path";
|
|
2098
|
+
import crypto4 from "crypto";
|
|
2099
|
+
var MANIFEST_VERSION = 1;
|
|
2100
|
+
function getSpacesDir(baseDir) {
|
|
2101
|
+
const homeDir = baseDir ?? process.env.HOME ?? "~";
|
|
2102
|
+
return path9.join(homeDir, ".config", "engram", "spaces");
|
|
2103
|
+
}
|
|
2104
|
+
function getManifestPath(baseDir) {
|
|
2105
|
+
return path9.join(getSpacesDir(baseDir), "manifest.json");
|
|
2106
|
+
}
|
|
2107
|
+
function loadManifest(baseDir, memoryDirOverride) {
|
|
2108
|
+
const manifestPath = getManifestPath(baseDir);
|
|
2109
|
+
if (!fs8.existsSync(manifestPath)) {
|
|
2110
|
+
const personalSpace = createPersonalSpace(baseDir, memoryDirOverride);
|
|
2111
|
+
const manifest = {
|
|
2112
|
+
activeSpaceId: personalSpace.id,
|
|
2113
|
+
spaces: [personalSpace],
|
|
2114
|
+
version: MANIFEST_VERSION
|
|
2115
|
+
};
|
|
2116
|
+
saveManifest(manifest, baseDir);
|
|
2117
|
+
return manifest;
|
|
2118
|
+
}
|
|
2119
|
+
const raw = JSON.parse(fs8.readFileSync(manifestPath, "utf8"));
|
|
2120
|
+
return raw;
|
|
2121
|
+
}
|
|
2122
|
+
function saveManifest(manifest, baseDir) {
|
|
2123
|
+
const manifestPath = getManifestPath(baseDir);
|
|
2124
|
+
fs8.mkdirSync(path9.dirname(manifestPath), { recursive: true });
|
|
2125
|
+
fs8.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2) + "\n");
|
|
2126
|
+
}
|
|
2127
|
+
function createPersonalSpace(baseDir, memoryDirOverride) {
|
|
2128
|
+
const homeDir = baseDir ?? process.env.HOME ?? "~";
|
|
2129
|
+
const standalonePath = path9.join(homeDir, ".engram", "memory");
|
|
2130
|
+
const openclawPath = path9.join(homeDir, ".openclaw", "workspace", "memory", "local");
|
|
2131
|
+
const memoryDir = memoryDirOverride ?? process.env.ENGRAM_MEMORY_DIR ?? (fs8.existsSync(standalonePath) ? standalonePath : fs8.existsSync(openclawPath) ? openclawPath : standalonePath);
|
|
2132
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
2133
|
+
return {
|
|
2134
|
+
id: "personal",
|
|
2135
|
+
name: "Personal",
|
|
2136
|
+
kind: "personal",
|
|
2137
|
+
description: "Default personal memory space",
|
|
2138
|
+
memoryDir,
|
|
2139
|
+
createdAt: now,
|
|
2140
|
+
updatedAt: now,
|
|
2141
|
+
owner: process.env.USER
|
|
2142
|
+
};
|
|
2143
|
+
}
|
|
2144
|
+
function listSpaces(baseDir) {
|
|
2145
|
+
const manifest = loadManifest(baseDir);
|
|
2146
|
+
return manifest.spaces;
|
|
2147
|
+
}
|
|
2148
|
+
function getActiveSpace(baseDir) {
|
|
2149
|
+
const manifest = loadManifest(baseDir);
|
|
2150
|
+
const space = manifest.spaces.find((s) => s.id === manifest.activeSpaceId);
|
|
2151
|
+
if (!space) throw new Error(`Active space ${manifest.activeSpaceId} not found`);
|
|
2152
|
+
return space;
|
|
2153
|
+
}
|
|
2154
|
+
function createSpace(options) {
|
|
2155
|
+
const manifest = loadManifest(options.baseDir);
|
|
2156
|
+
const id = options.name.toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/-+/g, "-");
|
|
2157
|
+
if (manifest.spaces.some((s) => s.id === id)) {
|
|
2158
|
+
throw new Error(`Space "${id}" already exists`);
|
|
2159
|
+
}
|
|
2160
|
+
if (options.parentSpaceId && !manifest.spaces.some((s) => s.id === options.parentSpaceId)) {
|
|
2161
|
+
throw new Error(`Parent space "${options.parentSpaceId}" not found`);
|
|
2162
|
+
}
|
|
2163
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
2164
|
+
const memoryDir = options.memoryDir ?? path9.join(
|
|
2165
|
+
getSpacesDir(options.baseDir),
|
|
2166
|
+
id,
|
|
2167
|
+
"memory"
|
|
2168
|
+
);
|
|
2169
|
+
const space = {
|
|
2170
|
+
id,
|
|
2171
|
+
name: options.name,
|
|
2172
|
+
kind: options.kind,
|
|
2173
|
+
description: options.description,
|
|
2174
|
+
memoryDir,
|
|
2175
|
+
createdAt: now,
|
|
2176
|
+
updatedAt: now,
|
|
2177
|
+
owner: process.env.USER,
|
|
2178
|
+
parentSpaceId: options.parentSpaceId
|
|
2179
|
+
};
|
|
2180
|
+
fs8.mkdirSync(memoryDir, { recursive: true });
|
|
2181
|
+
manifest.spaces.push(space);
|
|
2182
|
+
manifest.updatedAt = now;
|
|
2183
|
+
saveManifest(manifest, options.baseDir);
|
|
2184
|
+
appendAudit({
|
|
2185
|
+
action: "space.create",
|
|
2186
|
+
sourceSpaceId: id,
|
|
2187
|
+
details: `Created ${options.kind} space "${options.name}"`
|
|
2188
|
+
}, options.baseDir);
|
|
2189
|
+
return space;
|
|
2190
|
+
}
|
|
2191
|
+
function deleteSpace(spaceId, baseDir) {
|
|
2192
|
+
const manifest = loadManifest(baseDir);
|
|
2193
|
+
if (spaceId === "personal") {
|
|
2194
|
+
throw new Error("Cannot delete the personal space");
|
|
2195
|
+
}
|
|
2196
|
+
const idx = manifest.spaces.findIndex((s) => s.id === spaceId);
|
|
2197
|
+
if (idx === -1) throw new Error(`Space "${spaceId}" not found`);
|
|
2198
|
+
if (manifest.activeSpaceId === spaceId) {
|
|
2199
|
+
manifest.activeSpaceId = "personal";
|
|
2200
|
+
}
|
|
2201
|
+
for (const space of manifest.spaces) {
|
|
2202
|
+
if (space.parentSpaceId === spaceId) {
|
|
2203
|
+
space.parentSpaceId = void 0;
|
|
2204
|
+
}
|
|
2205
|
+
}
|
|
2206
|
+
manifest.spaces.splice(idx, 1);
|
|
2207
|
+
saveManifest(manifest, baseDir);
|
|
2208
|
+
appendAudit({
|
|
2209
|
+
action: "space.delete",
|
|
2210
|
+
sourceSpaceId: spaceId,
|
|
2211
|
+
details: `Deleted space "${spaceId}"`
|
|
2212
|
+
}, baseDir);
|
|
2213
|
+
}
|
|
2214
|
+
function switchSpace(spaceId, baseDir) {
|
|
2215
|
+
const manifest = loadManifest(baseDir);
|
|
2216
|
+
const space = manifest.spaces.find((s) => s.id === spaceId);
|
|
2217
|
+
if (!space) throw new Error(`Space "${spaceId}" not found`);
|
|
2218
|
+
const previousId = manifest.activeSpaceId;
|
|
2219
|
+
manifest.activeSpaceId = spaceId;
|
|
2220
|
+
saveManifest(manifest, baseDir);
|
|
2221
|
+
appendAudit({
|
|
2222
|
+
action: "space.switch",
|
|
2223
|
+
sourceSpaceId: previousId,
|
|
2224
|
+
targetSpaceId: spaceId,
|
|
2225
|
+
details: `Switched from "${previousId}" to "${spaceId}"`
|
|
2226
|
+
}, baseDir);
|
|
2227
|
+
return {
|
|
2228
|
+
previousSpaceId: previousId,
|
|
2229
|
+
currentSpaceId: spaceId,
|
|
2230
|
+
message: `Switched to "${space.name}"`
|
|
2231
|
+
};
|
|
2232
|
+
}
|
|
2233
|
+
function pushToSpace(sourceSpaceId, targetSpaceId, options) {
|
|
2234
|
+
const startTime = Date.now();
|
|
2235
|
+
const manifest = loadManifest(options?.baseDir);
|
|
2236
|
+
const source = manifest.spaces.find((s) => s.id === sourceSpaceId);
|
|
2237
|
+
const target = manifest.spaces.find((s) => s.id === targetSpaceId);
|
|
2238
|
+
if (!source) throw new Error(`Source space "${sourceSpaceId}" not found`);
|
|
2239
|
+
if (!target) throw new Error(`Target space "${targetSpaceId}" not found`);
|
|
2240
|
+
const result = copyMemories(source.memoryDir, target.memoryDir, {
|
|
2241
|
+
filterIds: options?.memoryIds,
|
|
2242
|
+
force: options?.force
|
|
2243
|
+
});
|
|
2244
|
+
appendAudit({
|
|
2245
|
+
action: "space.push",
|
|
2246
|
+
sourceSpaceId,
|
|
2247
|
+
targetSpaceId,
|
|
2248
|
+
details: `Pushed ${result.merged} memories, ${result.conflicts.length} conflicts`
|
|
2249
|
+
}, options?.baseDir);
|
|
2250
|
+
return {
|
|
2251
|
+
sourceSpaceId,
|
|
2252
|
+
targetSpaceId,
|
|
2253
|
+
memoriesPushed: result.merged,
|
|
2254
|
+
conflicts: result.conflicts,
|
|
2255
|
+
durationMs: Date.now() - startTime
|
|
2256
|
+
};
|
|
2257
|
+
}
|
|
2258
|
+
function pullFromSpace(sourceSpaceId, targetSpaceId, options) {
|
|
2259
|
+
const startTime = Date.now();
|
|
2260
|
+
const manifest = loadManifest(options?.baseDir);
|
|
2261
|
+
const source = manifest.spaces.find((s) => s.id === sourceSpaceId);
|
|
2262
|
+
const target = manifest.spaces.find((s) => s.id === targetSpaceId);
|
|
2263
|
+
if (!source) throw new Error(`Source space "${sourceSpaceId}" not found`);
|
|
2264
|
+
if (!target) throw new Error(`Target space "${targetSpaceId}" not found`);
|
|
2265
|
+
const result = copyMemories(source.memoryDir, target.memoryDir, {
|
|
2266
|
+
filterIds: options?.memoryIds,
|
|
2267
|
+
force: options?.force
|
|
2268
|
+
});
|
|
2269
|
+
appendAudit({
|
|
2270
|
+
action: "space.pull",
|
|
2271
|
+
sourceSpaceId,
|
|
2272
|
+
targetSpaceId,
|
|
2273
|
+
details: `Pulled ${result.merged} memories, ${result.conflicts.length} conflicts`
|
|
2274
|
+
}, options?.baseDir);
|
|
2275
|
+
return {
|
|
2276
|
+
sourceSpaceId,
|
|
2277
|
+
targetSpaceId,
|
|
2278
|
+
memoriesPulled: result.merged,
|
|
2279
|
+
conflicts: result.conflicts,
|
|
2280
|
+
durationMs: Date.now() - startTime
|
|
2281
|
+
};
|
|
2282
|
+
}
|
|
2283
|
+
function shareSpace(spaceId, members, baseDir) {
|
|
2284
|
+
const manifest = loadManifest(baseDir);
|
|
2285
|
+
const space = manifest.spaces.find((s) => s.id === spaceId);
|
|
2286
|
+
if (!space) throw new Error(`Space "${spaceId}" not found`);
|
|
2287
|
+
if (space.kind === "personal") throw new Error("Cannot share personal space");
|
|
2288
|
+
space.members = [.../* @__PURE__ */ new Set([...space.members ?? [], ...members])];
|
|
2289
|
+
space.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
2290
|
+
saveManifest(manifest, baseDir);
|
|
2291
|
+
appendAudit({
|
|
2292
|
+
action: "space.share",
|
|
2293
|
+
sourceSpaceId: spaceId,
|
|
2294
|
+
details: `Shared with: ${members.join(", ")}`
|
|
2295
|
+
}, baseDir);
|
|
2296
|
+
return {
|
|
2297
|
+
spaceId,
|
|
2298
|
+
sharedWith: members,
|
|
2299
|
+
message: `Shared "${space.name}" with ${members.length} member(s)`
|
|
2300
|
+
};
|
|
2301
|
+
}
|
|
2302
|
+
function promoteSpace(sourceSpaceId, targetSpaceId, options) {
|
|
2303
|
+
const startTime = Date.now();
|
|
2304
|
+
const manifest = loadManifest(options?.baseDir);
|
|
2305
|
+
const source = manifest.spaces.find((s) => s.id === sourceSpaceId);
|
|
2306
|
+
const target = manifest.spaces.find((s) => s.id === targetSpaceId);
|
|
2307
|
+
if (!source) throw new Error(`Source space "${sourceSpaceId}" not found`);
|
|
2308
|
+
if (!target) throw new Error(`Target space "${targetSpaceId}" not found`);
|
|
2309
|
+
if (source.parentSpaceId !== targetSpaceId && target.parentSpaceId !== sourceSpaceId) {
|
|
2310
|
+
if (!options?.force) {
|
|
2311
|
+
throw new Error("Spaces must have a parent-child relationship for promotion. Use --force to override.");
|
|
2312
|
+
}
|
|
2313
|
+
}
|
|
2314
|
+
const result = copyMemories(source.memoryDir, target.memoryDir, {
|
|
2315
|
+
filterIds: options?.memoryIds,
|
|
2316
|
+
force: options?.forceOverwrite !== void 0 ? options.forceOverwrite : options?.force ?? false
|
|
2317
|
+
});
|
|
2318
|
+
appendAudit({
|
|
2319
|
+
action: "space.promote",
|
|
2320
|
+
sourceSpaceId,
|
|
2321
|
+
targetSpaceId,
|
|
2322
|
+
details: `Promoted ${result.merged} memories from "${source.name}" to "${target.name}"`
|
|
2323
|
+
}, options?.baseDir);
|
|
2324
|
+
return {
|
|
2325
|
+
sourceSpaceId,
|
|
2326
|
+
targetSpaceId,
|
|
2327
|
+
memoriesPromoted: result.merged,
|
|
2328
|
+
conflicts: result.conflicts,
|
|
2329
|
+
durationMs: Date.now() - startTime
|
|
2330
|
+
};
|
|
2331
|
+
}
|
|
2332
|
+
function mergeSpaces(sourceSpaceId, targetSpaceId, options) {
|
|
2333
|
+
const startTime = Date.now();
|
|
2334
|
+
const manifest = loadManifest(options?.baseDir);
|
|
2335
|
+
const source = manifest.spaces.find((s) => s.id === sourceSpaceId);
|
|
2336
|
+
const target = manifest.spaces.find((s) => s.id === targetSpaceId);
|
|
2337
|
+
if (!source) throw new Error(`Source space "${sourceSpaceId}" not found`);
|
|
2338
|
+
if (!target) throw new Error(`Target space "${targetSpaceId}" not found`);
|
|
2339
|
+
const result = copyMemories(source.memoryDir, target.memoryDir, {
|
|
2340
|
+
force: options?.force
|
|
2341
|
+
});
|
|
2342
|
+
appendAudit({
|
|
2343
|
+
action: "space.merge",
|
|
2344
|
+
sourceSpaceId,
|
|
2345
|
+
targetSpaceId,
|
|
2346
|
+
details: `Merged: ${result.merged} merged, ${result.conflicts.length} conflicts, ${result.skipped} skipped`
|
|
2347
|
+
}, options?.baseDir);
|
|
2348
|
+
return {
|
|
2349
|
+
...result,
|
|
2350
|
+
durationMs: Date.now() - startTime
|
|
2351
|
+
};
|
|
2352
|
+
}
|
|
2353
|
+
function getAuditLog(baseDir) {
|
|
2354
|
+
const auditPath = path9.join(getSpacesDir(baseDir), "audit.jsonl");
|
|
2355
|
+
if (!fs8.existsSync(auditPath)) return [];
|
|
2356
|
+
const lines = fs8.readFileSync(auditPath, "utf8").trim().split("\n");
|
|
2357
|
+
return lines.filter((l) => l.trim()).map((l) => JSON.parse(l));
|
|
2358
|
+
}
|
|
2359
|
+
function appendAudit(entry, baseDir) {
|
|
2360
|
+
const auditPath = path9.join(getSpacesDir(baseDir), "audit.jsonl");
|
|
2361
|
+
fs8.mkdirSync(path9.dirname(auditPath), { recursive: true });
|
|
2362
|
+
const full = {
|
|
2363
|
+
id: crypto4.randomUUID(),
|
|
2364
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2365
|
+
...entry
|
|
2366
|
+
};
|
|
2367
|
+
fs8.appendFileSync(auditPath, JSON.stringify(full) + "\n");
|
|
2368
|
+
}
|
|
2369
|
+
function copyMemories(sourceDir, targetDir, options) {
|
|
2370
|
+
let merged = 0;
|
|
2371
|
+
const conflicts = [];
|
|
2372
|
+
let skipped = 0;
|
|
2373
|
+
if (!fs8.existsSync(sourceDir)) {
|
|
2374
|
+
return { merged: 0, conflicts: [], skipped: 0 };
|
|
2375
|
+
}
|
|
2376
|
+
fs8.mkdirSync(targetDir, { recursive: true });
|
|
2377
|
+
const sourceFiles = walkMd2(sourceDir);
|
|
2378
|
+
for (const sourcePath of sourceFiles) {
|
|
2379
|
+
const content = fs8.readFileSync(sourcePath, "utf8");
|
|
2380
|
+
const relativePath = path9.relative(sourceDir, sourcePath);
|
|
2381
|
+
const targetPath = path9.join(targetDir, relativePath);
|
|
2382
|
+
const sourceHash = hashContent4(content);
|
|
2383
|
+
if (options?.filterIds?.length) {
|
|
2384
|
+
const fm = parseSimpleFrontmatter(content);
|
|
2385
|
+
if (!fm?.id || !options.filterIds.includes(fm.id)) {
|
|
2386
|
+
skipped++;
|
|
2387
|
+
continue;
|
|
2388
|
+
}
|
|
2389
|
+
}
|
|
2390
|
+
if (fs8.existsSync(targetPath) && !options?.force) {
|
|
2391
|
+
const targetContent = fs8.readFileSync(targetPath, "utf8");
|
|
2392
|
+
const targetHash = hashContent4(targetContent);
|
|
2393
|
+
if (sourceHash !== targetHash) {
|
|
2394
|
+
conflicts.push({
|
|
2395
|
+
memoryId: parseSimpleFrontmatter(content)?.id ?? relativePath,
|
|
2396
|
+
sourcePath,
|
|
2397
|
+
targetPath,
|
|
2398
|
+
conflictType: "content_mismatch",
|
|
2399
|
+
sourceHash,
|
|
2400
|
+
targetHash
|
|
2401
|
+
});
|
|
2402
|
+
continue;
|
|
2403
|
+
}
|
|
2404
|
+
skipped++;
|
|
2405
|
+
continue;
|
|
2406
|
+
}
|
|
2407
|
+
fs8.mkdirSync(path9.dirname(targetPath), { recursive: true });
|
|
2408
|
+
fs8.writeFileSync(targetPath, content);
|
|
2409
|
+
merged++;
|
|
2410
|
+
}
|
|
2411
|
+
return { merged, conflicts, skipped };
|
|
2412
|
+
}
|
|
2413
|
+
function hashContent4(content) {
|
|
2414
|
+
return crypto4.createHash("sha256").update(content).digest("hex").slice(0, 16);
|
|
2415
|
+
}
|
|
2416
|
+
function walkMd2(dir) {
|
|
2417
|
+
const results = [];
|
|
2418
|
+
function walk(d) {
|
|
2419
|
+
for (const entry of fs8.readdirSync(d, { withFileTypes: true })) {
|
|
2420
|
+
const fullPath = path9.join(d, entry.name);
|
|
2421
|
+
if (entry.isDirectory()) {
|
|
2422
|
+
walk(fullPath);
|
|
2423
|
+
} else if (entry.name.endsWith(".md")) {
|
|
2424
|
+
results.push(fullPath);
|
|
2425
|
+
}
|
|
2426
|
+
}
|
|
2427
|
+
}
|
|
2428
|
+
walk(dir);
|
|
2429
|
+
return results;
|
|
2430
|
+
}
|
|
2431
|
+
function parseSimpleFrontmatter(content) {
|
|
2432
|
+
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
2433
|
+
if (!match) return null;
|
|
2434
|
+
const fm = {};
|
|
2435
|
+
for (const line of match[1].split("\n")) {
|
|
2436
|
+
const colonIdx = line.indexOf(":");
|
|
2437
|
+
if (colonIdx === -1) continue;
|
|
2438
|
+
const key = line.slice(0, colonIdx).trim();
|
|
2439
|
+
const value = line.slice(colonIdx + 1).trim();
|
|
2440
|
+
fm[key] = value;
|
|
2441
|
+
}
|
|
2442
|
+
return fm;
|
|
2443
|
+
}
|
|
2444
|
+
export {
|
|
2445
|
+
BootstrapEngine,
|
|
2446
|
+
EngramAccessHttpServer,
|
|
2447
|
+
EngramAccessInputError,
|
|
2448
|
+
EngramAccessService,
|
|
2449
|
+
EngramMcpServer,
|
|
2450
|
+
ExtractionEngine,
|
|
2451
|
+
LanceDbBackend,
|
|
2452
|
+
MeilisearchBackend,
|
|
2453
|
+
OramaBackend,
|
|
2454
|
+
Orchestrator,
|
|
2455
|
+
QmdClient,
|
|
2456
|
+
StorageManager,
|
|
2457
|
+
buildEntityRecallSection,
|
|
2458
|
+
createSpace,
|
|
2459
|
+
curate,
|
|
2460
|
+
defaultWorkspaceDir,
|
|
2461
|
+
deleteSpace,
|
|
2462
|
+
doctorConnector,
|
|
2463
|
+
findContradictions,
|
|
2464
|
+
findDuplicates,
|
|
2465
|
+
formatZodError,
|
|
2466
|
+
generateContextTree,
|
|
2467
|
+
generateToken,
|
|
2468
|
+
getActiveSpace,
|
|
2469
|
+
getAllValidTokens,
|
|
2470
|
+
getAllValidTokensCached,
|
|
2471
|
+
getAuditLog,
|
|
2472
|
+
getManifestPath,
|
|
2473
|
+
getSpacesDir,
|
|
2474
|
+
initLogger,
|
|
2475
|
+
installConnector,
|
|
2476
|
+
isTrustZoneName,
|
|
2477
|
+
listConnectors,
|
|
2478
|
+
listReviewItems,
|
|
2479
|
+
listSpaces,
|
|
2480
|
+
listTokens,
|
|
2481
|
+
loadDaySummaryPrompt,
|
|
2482
|
+
loadManifest,
|
|
2483
|
+
loadRegistry,
|
|
2484
|
+
loadTokenStore,
|
|
2485
|
+
log,
|
|
2486
|
+
memoryStoreRequestSchema,
|
|
2487
|
+
mergeSpaces,
|
|
2488
|
+
migrateFromEngram,
|
|
2489
|
+
observeRequestSchema,
|
|
2490
|
+
onboard,
|
|
2491
|
+
parseConfig,
|
|
2492
|
+
performReview,
|
|
2493
|
+
promoteSpace,
|
|
2494
|
+
pullFromSpace,
|
|
2495
|
+
pushToSpace,
|
|
2496
|
+
recallRequestSchema,
|
|
2497
|
+
removeConnector,
|
|
2498
|
+
resolveConnectorFromToken,
|
|
2499
|
+
revokeToken,
|
|
2500
|
+
rollbackFromEngramMigration,
|
|
2501
|
+
sanitizeSessionKeyForFilename,
|
|
2502
|
+
saveManifest,
|
|
2503
|
+
saveRegistry,
|
|
2504
|
+
saveTokenStore,
|
|
2505
|
+
shareSpace,
|
|
2506
|
+
suggestionSubmitRequestSchema,
|
|
2507
|
+
switchSpace,
|
|
2508
|
+
syncChanges,
|
|
2509
|
+
validateRequest,
|
|
2510
|
+
watchForChanges
|
|
2511
|
+
};
|
|
2512
|
+
//# sourceMappingURL=index.js.map
|