@remnic/core 1.1.2 → 1.1.3
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/abort-error.js +1 -0
- package/dist/abstraction-nodes.js +1 -0
- package/dist/access-audit.js +1 -0
- package/dist/access-cli.js +70 -45
- package/dist/access-cli.js.map +1 -1
- package/dist/access-http.d.ts +50 -5
- package/dist/access-http.js +37 -15
- package/dist/access-idempotency.js +1 -0
- package/dist/access-mcp.d.ts +10 -5
- package/dist/access-mcp.js +36 -13
- package/dist/access-schema.d.ts +133 -13
- package/dist/access-schema.js +20 -1
- package/dist/access-service-_AEUMVyX.d.ts +1981 -0
- package/dist/access-service.d.ts +11 -6
- package/dist/access-service.js +38 -14
- package/dist/active-memory-bridge.js +1 -0
- package/dist/active-recall.js +1 -0
- package/dist/active-recall.js.map +1 -1
- package/dist/behavior-learner.js +1 -0
- package/dist/behavior-learner.js.map +1 -1
- package/dist/behavior-signals.js +1 -0
- package/dist/bootstrap.d.ts +6 -4
- package/dist/bootstrap.js +1 -0
- package/dist/boxes.js +1 -0
- package/dist/briefing.d.ts +9 -5
- package/dist/briefing.js +9 -6
- package/dist/buffer-surprise-report.js +1 -0
- package/dist/buffer-surprise.js +1 -0
- package/dist/buffer.d.ts +1 -1
- package/dist/buffer.js +1 -0
- package/dist/calibration.d.ts +8 -1
- package/dist/calibration.js +10 -2
- package/dist/calibration.js.map +1 -1
- package/dist/capsule-cli.d.ts +137 -0
- package/dist/capsule-cli.js +34 -0
- package/dist/capsule-crypto-5CYAGVC5.js +18 -0
- package/dist/capsule-export-NZQPOTQ4.js +17 -0
- package/dist/capsule-export-NZQPOTQ4.js.map +1 -0
- package/dist/capsule-import-SDCUXLEV.js +16 -0
- package/dist/capsule-import-SDCUXLEV.js.map +1 -0
- package/dist/capsule-merge-DI7PNQ2H.js +189 -0
- package/dist/capsule-merge-DI7PNQ2H.js.map +1 -0
- package/dist/causal-behavior.js +1 -0
- package/dist/causal-behavior.js.map +1 -1
- package/dist/causal-chain.js +1 -0
- package/dist/causal-consolidation.js +11 -8
- package/dist/causal-consolidation.js.map +1 -1
- package/dist/causal-retrieval.js +2 -1
- package/dist/causal-retrieval.js.map +1 -1
- package/dist/causal-trajectory-graph.js +4 -1
- package/dist/causal-trajectory-graph.js.map +1 -1
- package/dist/causal-trajectory.js +2 -1
- package/dist/chunk-2LSZVONP.js +67 -0
- package/dist/chunk-2LSZVONP.js.map +1 -0
- package/dist/chunk-32KD5IHZ.js +245 -0
- package/dist/chunk-32KD5IHZ.js.map +1 -0
- package/dist/{chunk-VDX363PS.js → chunk-34F3PLWZ.js} +10 -3
- package/dist/chunk-34F3PLWZ.js.map +1 -0
- package/dist/chunk-3KIS4VGT.js +228 -0
- package/dist/chunk-3KIS4VGT.js.map +1 -0
- package/dist/chunk-3LCWFNVS.js +350 -0
- package/dist/chunk-3LCWFNVS.js.map +1 -0
- package/dist/chunk-43EKP2UK.js +26 -0
- package/dist/chunk-43EKP2UK.js.map +1 -0
- package/dist/chunk-457A4P3L.js +119 -0
- package/dist/chunk-457A4P3L.js.map +1 -0
- package/dist/{chunk-TMYO7B5P.js → chunk-47WOM4YW.js} +2 -2
- package/dist/{chunk-OC5OXUQ4.js → chunk-4PLGJRBV.js} +653 -17
- package/dist/chunk-4PLGJRBV.js.map +1 -0
- package/dist/{chunk-PVICZTKG.js → chunk-55FXRRSJ.js} +5 -5
- package/dist/{chunk-PVICZTKG.js.map → chunk-55FXRRSJ.js.map} +1 -1
- package/dist/{chunk-ULYOGL6R.js → chunk-5HRY2WRF.js} +7 -3
- package/dist/chunk-5HRY2WRF.js.map +1 -0
- package/dist/chunk-6TBWYBJ3.js +236 -0
- package/dist/chunk-6TBWYBJ3.js.map +1 -0
- package/dist/chunk-74EMIVE4.js +329 -0
- package/dist/chunk-74EMIVE4.js.map +1 -0
- package/dist/chunk-74WWN7ZW.js +82 -0
- package/dist/chunk-74WWN7ZW.js.map +1 -0
- package/dist/{chunk-6YJHX2DL.js → chunk-7GCMLT7J.js} +242 -22
- package/dist/chunk-7GCMLT7J.js.map +1 -0
- package/dist/chunk-A6XUJE5D.js +126 -0
- package/dist/chunk-A6XUJE5D.js.map +1 -0
- package/dist/chunk-AJA46VX5.js +393 -0
- package/dist/chunk-AJA46VX5.js.map +1 -0
- package/dist/{chunk-UWB5LMWY.js → chunk-AKUCB2OG.js} +525 -24
- package/dist/chunk-AKUCB2OG.js.map +1 -0
- package/dist/chunk-ASIQZXYO.js +277 -0
- package/dist/chunk-ASIQZXYO.js.map +1 -0
- package/dist/{chunk-DG6YMRDC.js → chunk-B2TL6GA2.js} +2 -2
- package/dist/chunk-BJMBJZ2Y.js +290 -0
- package/dist/chunk-BJMBJZ2Y.js.map +1 -0
- package/dist/chunk-BT7NVCML.js +79 -0
- package/dist/chunk-BT7NVCML.js.map +1 -0
- package/dist/chunk-CK5NTM2S.js +454 -0
- package/dist/chunk-CK5NTM2S.js.map +1 -0
- package/dist/{chunk-AYXIPSZO.js → chunk-CRU27Q4J.js} +2 -2
- package/dist/{chunk-F5VP6YCB.js → chunk-DCE6SQLA.js} +572 -155
- package/dist/chunk-DCE6SQLA.js.map +1 -0
- package/dist/{chunk-CUPFXL3J.js → chunk-DHRQHX36.js} +4 -4
- package/dist/chunk-DHRQHX36.js.map +1 -0
- package/dist/{chunk-STGWEHYR.js → chunk-DR7MCMPS.js} +981 -61
- package/dist/chunk-DR7MCMPS.js.map +1 -0
- package/dist/chunk-FP2373TW.js +149 -0
- package/dist/chunk-FP2373TW.js.map +1 -0
- package/dist/{chunk-RBBWYEFJ.js → chunk-G2WADRQ3.js} +1 -1
- package/dist/chunk-G7D6GZ5J.js +48 -0
- package/dist/chunk-G7D6GZ5J.js.map +1 -0
- package/dist/chunk-H7XKCNR6.js +60 -0
- package/dist/chunk-H7XKCNR6.js.map +1 -0
- package/dist/{chunk-3YGHKTBF.js → chunk-IM3JSE73.js} +953 -322
- package/dist/chunk-IM3JSE73.js.map +1 -0
- package/dist/chunk-IXEJRKCZ.js +18 -0
- package/dist/chunk-IXEJRKCZ.js.map +1 -0
- package/dist/chunk-IYY4MCPG.js +275 -0
- package/dist/chunk-IYY4MCPG.js.map +1 -0
- package/dist/{chunk-BECYBZLX.js → chunk-JWSENLQI.js} +502 -22
- package/dist/chunk-JWSENLQI.js.map +1 -0
- package/dist/chunk-KNKUID7G.js +183 -0
- package/dist/chunk-KNKUID7G.js.map +1 -0
- package/dist/chunk-L2IO2QPY.js +2036 -0
- package/dist/chunk-L2IO2QPY.js.map +1 -0
- package/dist/{chunk-SPI27QT6.js → chunk-L5IIGA5V.js} +9 -4
- package/dist/chunk-L5IIGA5V.js.map +1 -0
- package/dist/{chunk-XXVWLXSG.js → chunk-LVYGDT5V.js} +56 -82
- package/dist/chunk-LVYGDT5V.js.map +1 -0
- package/dist/{chunk-ZAIM4TUE.js → chunk-LW2NMHDW.js} +46 -1
- package/dist/chunk-LW2NMHDW.js.map +1 -0
- package/dist/{chunk-3OGMS3PE.js → chunk-LZRYQK6L.js} +3 -2
- package/dist/chunk-LZRYQK6L.js.map +1 -0
- package/dist/chunk-MDYG7VI7.js +48 -0
- package/dist/chunk-MDYG7VI7.js.map +1 -0
- package/dist/chunk-MXC3AP5I.js +74 -0
- package/dist/chunk-MXC3AP5I.js.map +1 -0
- package/dist/{chunk-DIXB44VE.js → chunk-N7X62G74.js} +25 -10
- package/dist/chunk-N7X62G74.js.map +1 -0
- package/dist/chunk-NN3TS5BM.js +147 -0
- package/dist/chunk-NN3TS5BM.js.map +1 -0
- package/dist/chunk-OA3L7BFR.js +183 -0
- package/dist/chunk-OA3L7BFR.js.map +1 -0
- package/dist/chunk-OZHRDTDX.js +240 -0
- package/dist/chunk-OZHRDTDX.js.map +1 -0
- package/dist/chunk-PCUKNJAZ.js +165 -0
- package/dist/chunk-PCUKNJAZ.js.map +1 -0
- package/dist/{chunk-6PFRXT4K.js → chunk-PFV5C235.js} +11 -6
- package/dist/chunk-PFV5C235.js.map +1 -0
- package/dist/chunk-PZ5AY32C.js +10 -0
- package/dist/chunk-PZ5AY32C.js.map +1 -0
- package/dist/{chunk-Y7R2XJ5Q.js → chunk-Q7FJ5ZHM.js} +6 -2
- package/dist/chunk-Q7FJ5ZHM.js.map +1 -0
- package/dist/{chunk-NBVAS5MT.js → chunk-R2L7SUX2.js} +6 -6
- package/dist/{chunk-WCLICCGB.js → chunk-RILIVK4O.js} +91 -4
- package/dist/chunk-RILIVK4O.js.map +1 -0
- package/dist/{chunk-C2EFFULQ.js → chunk-RK2Y4XOM.js} +163 -20
- package/dist/chunk-RK2Y4XOM.js.map +1 -0
- package/dist/{chunk-TP4FZJIZ.js → chunk-RULE4VG5.js} +5 -1
- package/dist/chunk-RULE4VG5.js.map +1 -0
- package/dist/{chunk-PVPWZSSI.js → chunk-SMA4IMHV.js} +19 -3
- package/dist/chunk-SMA4IMHV.js.map +1 -0
- package/dist/{chunk-L7IXWRYE.js → chunk-SS253RXF.js} +22 -13
- package/dist/chunk-SS253RXF.js.map +1 -0
- package/dist/chunk-TUFG6VXY.js +875 -0
- package/dist/chunk-TUFG6VXY.js.map +1 -0
- package/dist/chunk-TYEOAFH3.js +251 -0
- package/dist/chunk-TYEOAFH3.js.map +1 -0
- package/dist/chunk-UKJAGEXH.js +260 -0
- package/dist/chunk-UKJAGEXH.js.map +1 -0
- package/dist/{chunk-KVBLZUKV.js → chunk-USFPPRAF.js} +93 -3
- package/dist/chunk-USFPPRAF.js.map +1 -0
- package/dist/{chunk-GA5P7RST.js → chunk-VTJVUHRK.js} +22 -36
- package/dist/chunk-VTJVUHRK.js.map +1 -0
- package/dist/chunk-WIICJPET.js +45 -0
- package/dist/chunk-WIICJPET.js.map +1 -0
- package/dist/{chunk-VBVG2M5G.js → chunk-WPGJYVUH.js} +6 -2
- package/dist/chunk-WPGJYVUH.js.map +1 -0
- package/dist/{chunk-4HQS2HPX.js → chunk-WSZIHQBK.js} +29 -9
- package/dist/{chunk-4HQS2HPX.js.map → chunk-WSZIHQBK.js.map} +1 -1
- package/dist/{chunk-NZLQTHS5.js → chunk-WW3QQF4H.js} +4 -1
- package/dist/chunk-WW3QQF4H.js.map +1 -0
- package/dist/{chunk-FVA6TGI3.js → chunk-Y3WQ4ZWK.js} +42 -2
- package/dist/chunk-Y3WQ4ZWK.js.map +1 -0
- package/dist/chunk-YNJHCGDT.js +309 -0
- package/dist/chunk-YNJHCGDT.js.map +1 -0
- package/dist/{chunk-LOIMBRDE.js → chunk-ZGXSCMQN.js} +1993 -411
- package/dist/chunk-ZGXSCMQN.js.map +1 -0
- package/dist/{chunk-W6SL7OFG.js → chunk-ZTSE2ZJ6.js} +12 -2
- package/dist/{chunk-W6SL7OFG.js.map → chunk-ZTSE2ZJ6.js.map} +1 -1
- package/dist/chunking.js +1 -0
- package/dist/cipher-GVE2GQ5H.js +28 -0
- package/dist/cipher-GVE2GQ5H.js.map +1 -0
- package/dist/citations.js +1 -0
- package/dist/{cli-BkeRaYfk.d.ts → cli-x2APT9a6.d.ts} +26 -7
- package/dist/cli.d.ts +11 -6
- package/dist/cli.js +67 -33
- package/dist/codex-thread-key.js +1 -0
- package/dist/commitment-ledger.js +1 -0
- package/dist/compression-optimizer.js +1 -0
- package/dist/config.d.ts +2 -1
- package/dist/config.js +4 -1
- package/dist/connectors-cli-DFGtY2DB.d.ts +257 -0
- package/dist/connectors-cli.d.ts +2 -0
- package/dist/connectors-cli.js +22 -0
- package/dist/connectors-cli.js.map +1 -0
- package/dist/consolidation-operator.d.ts +65 -5
- package/dist/consolidation-operator.js +6 -1
- package/dist/consolidation-provenance-check.d.ts +1 -1
- package/dist/consolidation-provenance-check.js +3 -2
- package/dist/consolidation-undo.d.ts +1 -1
- package/dist/consolidation-undo.js +1 -0
- package/dist/consolidation-undo.js.map +1 -1
- package/dist/{contradiction-review-WIUBAR52.js → contradiction-review-5LTTVDQV.js} +2 -1
- package/dist/contradiction-review-5LTTVDQV.js.map +1 -0
- package/dist/{contradiction-scan-E3GJTI4F.js → contradiction-scan-3Z6YW7YA.js} +2 -1
- package/dist/{contradiction-scan-E3GJTI4F.js.map → contradiction-scan-3Z6YW7YA.js.map} +1 -1
- package/dist/cross-namespace-budget.js +1 -0
- package/dist/cue-anchors.js +1 -0
- package/dist/dashboard-runtime.js +1 -0
- package/dist/day-summary.js +1 -0
- package/dist/delinearize.js +1 -0
- package/dist/direct-answer-wiring.js +1 -0
- package/dist/direct-answer.js +1 -0
- package/dist/dreams-ledger-LR2NBAZE.js +286 -0
- package/dist/dreams-ledger-LR2NBAZE.js.map +1 -0
- package/dist/embedding-fallback.js +1 -0
- package/dist/{engine-72LSIWQP.js → engine-ICC2DSQF.js} +10 -7
- package/dist/engine-ICC2DSQF.js.map +1 -0
- package/dist/entity-retrieval.d.ts +1 -1
- package/dist/entity-retrieval.js +9 -6
- package/dist/entity-schema.js +1 -0
- package/dist/evals.js +1 -0
- package/dist/evidence-pack.d.ts +16 -0
- package/dist/evidence-pack.js +8 -0
- package/dist/evidence-pack.js.map +1 -0
- package/dist/explicit-capture.d.ts +6 -4
- package/dist/explicit-capture.js +1 -0
- package/dist/extraction-judge-telemetry.js +1 -0
- package/dist/extraction-judge-training.js +1 -0
- package/dist/extraction-judge.js +1 -0
- package/dist/extraction.js +7 -6
- package/dist/fallback-llm.js +3 -2
- package/dist/first-start-migration-4MHQEOSD.js +263 -0
- package/dist/first-start-migration-4MHQEOSD.js.map +1 -0
- package/dist/forget-PLR6J5DN.js +69 -0
- package/dist/forget-PLR6J5DN.js.map +1 -0
- package/dist/framework-CyHYDcri.d.ts +153 -0
- package/dist/fs-utils-IRVUFB6G.js +30 -0
- package/dist/fs-utils-IRVUFB6G.js.map +1 -0
- package/dist/graph-dashboard-diff.js +1 -0
- package/dist/graph-dashboard-key.js +1 -0
- package/dist/graph-dashboard-parser.js +1 -0
- package/dist/graph-edge-decay-PWB63GRE.js +207 -0
- package/dist/graph-edge-decay-PWB63GRE.js.map +1 -0
- package/dist/graph-edge-reinforcement.d.ts +81 -0
- package/dist/graph-edge-reinforcement.js +24 -0
- package/dist/graph-edge-reinforcement.js.map +1 -0
- package/dist/graph-events.d.ts +87 -0
- package/dist/graph-events.js +14 -0
- package/dist/graph-events.js.map +1 -0
- package/dist/graph-recall.js +1 -0
- package/dist/graph-retrieval.js +1 -0
- package/dist/graph-snapshot.d.ts +112 -0
- package/dist/graph-snapshot.js +19 -0
- package/dist/graph-snapshot.js.map +1 -0
- package/dist/graph.d.ts +105 -7
- package/dist/graph.js +20 -3
- package/dist/harmonic-retrieval.js +1 -0
- package/dist/himem.js +1 -0
- package/dist/hygiene.js +1 -0
- package/dist/identity-continuity.js +1 -0
- package/dist/importance.js +1 -0
- package/dist/index.d.ts +562 -13
- package/dist/index.js +329 -67
- package/dist/index.js.map +1 -1
- package/dist/intent.js +1 -0
- package/dist/json-extract.js +1 -0
- package/dist/json-store.js +1 -0
- package/dist/kdf-7S6RWKLZ.js +26 -0
- package/dist/kdf-7S6RWKLZ.js.map +1 -0
- package/dist/legacy-hook-compat.js +1 -0
- package/dist/legacy-hook-compat.js.map +1 -1
- package/dist/lifecycle.js +1 -0
- package/dist/live-connectors-runner.d.ts +48 -0
- package/dist/live-connectors-runner.js +17 -0
- package/dist/live-connectors-runner.js.map +1 -0
- package/dist/local-llm.js +1 -0
- package/dist/logger.js +1 -0
- package/dist/memory-action-policy.js +1 -0
- package/dist/memory-cache.d.ts +2 -1
- package/dist/memory-cache.js +4 -1
- package/dist/memory-governance-KG52RITE.js +37 -0
- package/dist/memory-governance-KG52RITE.js.map +1 -0
- package/dist/memory-lifecycle-ledger-utils.d.ts +2 -1
- package/dist/memory-lifecycle-ledger-utils.js +4 -1
- package/dist/memory-projection-format.js +1 -0
- package/dist/{memory-projection-store-DeSXPh1j.d.ts → memory-projection-store-D3vBHS4J.d.ts} +1 -0
- package/dist/memory-projection-store.d.ts +1 -1
- package/dist/memory-projection-store.js +1 -0
- package/dist/memory-worth-bench.js +1 -0
- package/dist/memory-worth-bench.js.map +1 -1
- package/dist/memory-worth-filter.js +1 -0
- package/dist/memory-worth-outcomes.d.ts +1 -1
- package/dist/memory-worth-outcomes.js +1 -0
- package/dist/memory-worth.js +1 -0
- package/dist/metadata-FC3XPDRQ.js +21 -0
- package/dist/metadata-FC3XPDRQ.js.map +1 -0
- package/dist/migrate-from-identity-anchor-TTEDEJGX.js +8 -0
- package/dist/migrate-from-identity-anchor-TTEDEJGX.js.map +1 -0
- package/dist/model-registry.js +1 -0
- package/dist/models-json.js +1 -0
- package/dist/native-knowledge.js +1 -0
- package/dist/negative.js +1 -0
- package/dist/objective-state-writers.js +1 -0
- package/dist/objective-state-writers.js.map +1 -1
- package/dist/objective-state.js +1 -0
- package/dist/openai-chat-compat.js +1 -0
- package/dist/operator-toolkit.d.ts +46 -2
- package/dist/operator-toolkit.js +28 -16
- package/dist/opik-exporter.js +1 -0
- package/dist/opik-exporter.js.map +1 -1
- package/dist/{orchestrator-CmJ-NTdJ.d.ts → orchestrator-ChkesB8U.d.ts} +177 -13
- package/dist/orchestrator.d.ts +6 -4
- package/dist/orchestrator.js +55 -39
- package/dist/page-versioning.js +1 -0
- package/dist/path-RMTY5Y5A.js +9 -0
- package/dist/path-RMTY5Y5A.js.map +1 -0
- package/dist/patterns-cli.d.ts +160 -0
- package/dist/patterns-cli.js +29 -0
- package/dist/patterns-cli.js.map +1 -0
- package/dist/peers-6OSQ3NK6.js +44 -0
- package/dist/peers-6OSQ3NK6.js.map +1 -0
- package/dist/plugin-id.js +1 -0
- package/dist/policy-runtime.js +1 -0
- package/dist/{port-BADbLZU5.d.ts → port-hqGnoStS.d.ts} +6 -0
- package/dist/profiling.js +1 -0
- package/dist/purge-6ATBGT77.js +205 -0
- package/dist/purge-6ATBGT77.js.map +1 -0
- package/dist/qmd-recall-cache.d.ts +1 -1
- package/dist/qmd-recall-cache.js +1 -0
- package/dist/qmd.d.ts +2 -1
- package/dist/qmd.js +4 -3
- package/dist/reasoning-trace-recall.js +1 -0
- package/dist/reasoning-trace-types.js +1 -0
- package/dist/recall-audit-anomaly.js +1 -0
- package/dist/recall-audit.js +1 -0
- package/dist/recall-disclosure-escalation.d.ts +84 -0
- package/dist/recall-disclosure-escalation.js +14 -0
- package/dist/recall-disclosure-escalation.js.map +1 -0
- package/dist/recall-explain-renderer.js +4 -1
- package/dist/recall-mmr.js +1 -0
- package/dist/recall-qos.js +1 -0
- package/dist/recall-query-policy.js +1 -0
- package/dist/recall-state.d.ts +7 -0
- package/dist/recall-state.js +2 -1
- package/dist/recall-tag-filter.d.ts +56 -0
- package/dist/recall-tag-filter.js +14 -0
- package/dist/recall-tag-filter.js.map +1 -0
- package/dist/recall-tokenization.js +1 -0
- package/dist/recall-xray-cli.d.ts +9 -2
- package/dist/recall-xray-cli.js +9 -4
- package/dist/recall-xray-renderer.js +4 -1
- package/dist/recall-xray.d.ts +116 -2
- package/dist/recall-xray.js +9 -3
- package/dist/reconstruct.js +1 -0
- package/dist/release-changelog.js +2 -0
- package/dist/release-changelog.js.map +1 -1
- package/dist/relevance.js +1 -0
- package/dist/rerank.js +1 -0
- package/dist/{resolution-QBTDHTG7.js → resolution-YGIBORXI.js} +2 -1
- package/dist/{resolution-QBTDHTG7.js.map → resolution-YGIBORXI.js.map} +1 -1
- package/dist/resolve-auth-token.d.ts +51 -0
- package/dist/resolve-auth-token.js +12 -0
- package/dist/resolve-auth-token.js.map +1 -0
- package/dist/resolve-provider-secret.d.ts +9 -1
- package/dist/resolve-provider-secret.js +4 -1
- package/dist/resume-bundles.js +4 -3
- package/dist/retrieval-agents.d.ts +1 -1
- package/dist/retrieval-agents.js +1 -0
- package/dist/retrieval-tiers.js +1 -0
- package/dist/retrieval.js +1 -0
- package/dist/sanitize.js +1 -0
- package/dist/schemas.d.ts +37 -24
- package/dist/schemas.js +2 -1
- package/dist/sdk-compat.js +1 -0
- package/dist/sdk-compat.js.map +1 -1
- package/dist/secure-store-4R2GSO7S.js +156 -0
- package/dist/secure-store-4R2GSO7S.js.map +1 -0
- package/dist/semantic-chunking.js +1 -0
- package/dist/{semantic-consolidation-CxJU6MJk.d.ts → semantic-consolidation-ByBXb-sf.d.ts} +3 -3
- package/dist/semantic-consolidation.d.ts +2 -2
- package/dist/semantic-consolidation.js +11 -6
- package/dist/semantic-rule-promotion.d.ts +1 -1
- package/dist/semantic-rule-promotion.js +9 -6
- package/dist/semantic-rule-verifier.d.ts +1 -1
- package/dist/semantic-rule-verifier.js +9 -6
- package/dist/session-integrity.js +1 -0
- package/dist/session-observer-bands.js +1 -0
- package/dist/session-observer-state.js +1 -0
- package/dist/session-toggles.js +2 -0
- package/dist/session-toggles.js.map +1 -1
- package/dist/signal.js +1 -0
- package/dist/skills-registry.js +2 -0
- package/dist/skills-registry.js.map +1 -1
- package/dist/source-attribution.js +1 -0
- package/dist/state-NCHQ4TRG.js +8 -0
- package/dist/state-NCHQ4TRG.js.map +1 -0
- package/dist/state-store-3EH7HYIN.js +16 -0
- package/dist/state-store-3EH7HYIN.js.map +1 -0
- package/dist/storage.d.ts +76 -2
- package/dist/storage.js +8 -5
- package/dist/store-contract.js +1 -0
- package/dist/summarizer.js +5 -4
- package/dist/summary-snapshot.js +1 -0
- package/dist/temporal-index.js +1 -0
- package/dist/temporal-supersession.d.ts +1 -1
- package/dist/temporal-supersession.js +2 -1
- package/dist/temporal-validity.d.ts +52 -0
- package/dist/temporal-validity.js +14 -0
- package/dist/temporal-validity.js.map +1 -0
- package/dist/threading.js +1 -0
- package/dist/tier-migration.d.ts +2 -2
- package/dist/tier-migration.js +1 -0
- package/dist/tier-routing.js +1 -0
- package/dist/tier-stats-62ZVDFKS.js +152 -0
- package/dist/tier-stats-62ZVDFKS.js.map +1 -0
- package/dist/tmt.js +1 -0
- package/dist/tokens.js +1 -0
- package/dist/topics.js +1 -0
- package/dist/trace-C5ETWBEF.js +290 -0
- package/dist/trace-C5ETWBEF.js.map +1 -0
- package/dist/transcript.js +1 -0
- package/dist/trust-zones.js +1 -0
- package/dist/tui-RI7P6PBS.js +13 -0
- package/dist/tui-RI7P6PBS.js.map +1 -0
- package/dist/types-V3FJ26TF.js +30 -0
- package/dist/types-V3FJ26TF.js.map +1 -0
- package/dist/types.d.ts +634 -9
- package/dist/types.js +10 -3
- package/dist/utility-learner.js +1 -0
- package/dist/utility-runtime.js +1 -0
- package/dist/utility-telemetry.js +1 -0
- package/dist/verified-recall.js +9 -6
- package/dist/version-utils.js +1 -0
- package/dist/whitespace.js +1 -0
- package/dist/work-product-ledger.js +1 -0
- package/package.json +2 -1
- package/dist/access-service-Br8ZydTK.d.ts +0 -827
- package/dist/chunk-3OGMS3PE.js.map +0 -1
- package/dist/chunk-3YGHKTBF.js.map +0 -1
- package/dist/chunk-6PFRXT4K.js.map +0 -1
- package/dist/chunk-6YJHX2DL.js.map +0 -1
- package/dist/chunk-BECYBZLX.js.map +0 -1
- package/dist/chunk-C2EFFULQ.js.map +0 -1
- package/dist/chunk-CUPFXL3J.js.map +0 -1
- package/dist/chunk-DIXB44VE.js.map +0 -1
- package/dist/chunk-F5VP6YCB.js.map +0 -1
- package/dist/chunk-FVA6TGI3.js.map +0 -1
- package/dist/chunk-GA5P7RST.js.map +0 -1
- package/dist/chunk-KVBLZUKV.js.map +0 -1
- package/dist/chunk-L7IXWRYE.js.map +0 -1
- package/dist/chunk-LOIMBRDE.js.map +0 -1
- package/dist/chunk-LTCGGW2D.js +0 -14
- package/dist/chunk-LTCGGW2D.js.map +0 -1
- package/dist/chunk-NZLQTHS5.js.map +0 -1
- package/dist/chunk-OC5OXUQ4.js.map +0 -1
- package/dist/chunk-PVPWZSSI.js.map +0 -1
- package/dist/chunk-SPI27QT6.js.map +0 -1
- package/dist/chunk-STGWEHYR.js.map +0 -1
- package/dist/chunk-TP4FZJIZ.js.map +0 -1
- package/dist/chunk-ULYOGL6R.js.map +0 -1
- package/dist/chunk-UWB5LMWY.js.map +0 -1
- package/dist/chunk-VBVG2M5G.js.map +0 -1
- package/dist/chunk-VDX363PS.js.map +0 -1
- package/dist/chunk-WCLICCGB.js.map +0 -1
- package/dist/chunk-X6GF3FX2.js +0 -26
- package/dist/chunk-X6GF3FX2.js.map +0 -1
- package/dist/chunk-XXVWLXSG.js.map +0 -1
- package/dist/chunk-Y7R2XJ5Q.js.map +0 -1
- package/dist/chunk-ZAIM4TUE.js.map +0 -1
- /package/dist/{contradiction-review-WIUBAR52.js.map → capsule-cli.js.map} +0 -0
- /package/dist/{engine-72LSIWQP.js.map → capsule-crypto-5CYAGVC5.js.map} +0 -0
- /package/dist/{chunk-TMYO7B5P.js.map → chunk-47WOM4YW.js.map} +0 -0
- /package/dist/{chunk-DG6YMRDC.js.map → chunk-B2TL6GA2.js.map} +0 -0
- /package/dist/{chunk-AYXIPSZO.js.map → chunk-CRU27Q4J.js.map} +0 -0
- /package/dist/{chunk-RBBWYEFJ.js.map → chunk-G2WADRQ3.js.map} +0 -0
- /package/dist/{chunk-NBVAS5MT.js.map → chunk-R2L7SUX2.js.map} +0 -0
|
@@ -1,14 +1,26 @@
|
|
|
1
1
|
import {
|
|
2
2
|
promoteSemanticRuleFromMemory
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-34F3PLWZ.js";
|
|
4
|
+
import {
|
|
5
|
+
resolveAgentAccessAuthToken
|
|
6
|
+
} from "./chunk-MXC3AP5I.js";
|
|
4
7
|
import {
|
|
5
8
|
buildResumeBundleFromState,
|
|
6
9
|
getResumeBundleStatus,
|
|
7
10
|
recordResumeBundle
|
|
8
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-47WOM4YW.js";
|
|
9
12
|
import {
|
|
10
13
|
parseXrayCliOptions
|
|
11
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-SMA4IMHV.js";
|
|
15
|
+
import {
|
|
16
|
+
collectPatternMemories,
|
|
17
|
+
explainPatternMemory,
|
|
18
|
+
parsePatternsExplainOptions,
|
|
19
|
+
parsePatternsListOptions,
|
|
20
|
+
parseStrictCliDate,
|
|
21
|
+
renderPatternExplain,
|
|
22
|
+
renderPatternsList
|
|
23
|
+
} from "./chunk-AJA46VX5.js";
|
|
12
24
|
import {
|
|
13
25
|
listNamespaces,
|
|
14
26
|
runBenchmarkRecall,
|
|
@@ -19,7 +31,7 @@ import {
|
|
|
19
31
|
runOperatorRepair,
|
|
20
32
|
runOperatorSetup,
|
|
21
33
|
verifyNamespaces
|
|
22
|
-
} from "./chunk-
|
|
34
|
+
} from "./chunk-7GCMLT7J.js";
|
|
23
35
|
import {
|
|
24
36
|
compareVersions
|
|
25
37
|
} from "./chunk-HL4DB7TO.js";
|
|
@@ -28,14 +40,13 @@ import {
|
|
|
28
40
|
} from "./chunk-ZPKBYX2F.js";
|
|
29
41
|
import {
|
|
30
42
|
RoutingRulesStore,
|
|
31
|
-
expandTildePath,
|
|
32
43
|
isReplayRole,
|
|
33
44
|
isReplaySource,
|
|
34
45
|
normalizeReplaySessionKey,
|
|
35
46
|
parseIsoOffsetTimestamp,
|
|
36
47
|
parseIsoTimestamp,
|
|
37
48
|
validateReplayTurn
|
|
38
|
-
} from "./chunk-
|
|
49
|
+
} from "./chunk-VTJVUHRK.js";
|
|
39
50
|
import {
|
|
40
51
|
getUtilityLearningStatus,
|
|
41
52
|
learnUtilityPromotionWeights
|
|
@@ -46,18 +57,25 @@ import {
|
|
|
46
57
|
} from "./chunk-3QKK7QOS.js";
|
|
47
58
|
import {
|
|
48
59
|
searchVerifiedEpisodes
|
|
49
|
-
} from "./chunk-
|
|
60
|
+
} from "./chunk-DHRQHX36.js";
|
|
50
61
|
import {
|
|
51
62
|
ThreadingManager
|
|
52
63
|
} from "./chunk-JRNQ3RNA.js";
|
|
53
64
|
import {
|
|
54
65
|
searchVerifiedSemanticRules
|
|
55
|
-
} from "./chunk-
|
|
66
|
+
} from "./chunk-L5IIGA5V.js";
|
|
56
67
|
import {
|
|
57
68
|
getWorkProductLedgerStatus,
|
|
58
69
|
recordWorkProductLedgerEntry,
|
|
59
70
|
searchWorkProductLedgerEntries
|
|
60
71
|
} from "./chunk-CULXMQJH.js";
|
|
72
|
+
import {
|
|
73
|
+
readRuntimePolicySnapshot,
|
|
74
|
+
sanitizeRuntimePolicyValues
|
|
75
|
+
} from "./chunk-EABGC2TL.js";
|
|
76
|
+
import {
|
|
77
|
+
getObjectiveStateStoreStatus
|
|
78
|
+
} from "./chunk-LOBRX7VD.js";
|
|
61
79
|
import {
|
|
62
80
|
analyzeSessionIntegrity,
|
|
63
81
|
applySessionRepair,
|
|
@@ -68,24 +86,22 @@ import {
|
|
|
68
86
|
PLUGIN_ID
|
|
69
87
|
} from "./chunk-U66YHYC7.js";
|
|
70
88
|
import {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
89
|
+
GOOGLE_DRIVE_CONNECTOR_ID,
|
|
90
|
+
NOTION_CONNECTOR_ID,
|
|
91
|
+
createGoogleDriveConnector,
|
|
92
|
+
createNotionConnector,
|
|
93
|
+
validateGoogleDriveConfig,
|
|
94
|
+
validateNotionConfig
|
|
95
|
+
} from "./chunk-L2IO2QPY.js";
|
|
74
96
|
import {
|
|
75
|
-
|
|
76
|
-
} from "./chunk-
|
|
97
|
+
listConnectorStates
|
|
98
|
+
} from "./chunk-6TBWYBJ3.js";
|
|
77
99
|
import {
|
|
78
100
|
searchHarmonicRetrieval
|
|
79
101
|
} from "./chunk-HMDCOMYU.js";
|
|
80
102
|
import {
|
|
81
103
|
rescoreMemoryImportance
|
|
82
104
|
} from "./chunk-JXS5PDQ7.js";
|
|
83
|
-
import {
|
|
84
|
-
launchProcess
|
|
85
|
-
} from "./chunk-OR64ZGRZ.js";
|
|
86
|
-
import {
|
|
87
|
-
loadPersistedNativeKnowledgeChunks
|
|
88
|
-
} from "./chunk-7SEAZFFB.js";
|
|
89
105
|
import {
|
|
90
106
|
createEvalBaselineSnapshot,
|
|
91
107
|
getEvalHarnessStatus,
|
|
@@ -95,15 +111,23 @@ import {
|
|
|
95
111
|
runEvalStoredBaselineCiGate,
|
|
96
112
|
validateEvalBenchmarkPack
|
|
97
113
|
} from "./chunk-K6WK37A6.js";
|
|
114
|
+
import {
|
|
115
|
+
loadPersistedNativeKnowledgeChunks
|
|
116
|
+
} from "./chunk-7SEAZFFB.js";
|
|
98
117
|
import {
|
|
99
118
|
parseConfig
|
|
100
|
-
} from "./chunk-
|
|
119
|
+
} from "./chunk-JWSENLQI.js";
|
|
120
|
+
import {
|
|
121
|
+
parseConnectorsListOptions,
|
|
122
|
+
parseConnectorsRunName,
|
|
123
|
+
parseConnectorsStatusOptions,
|
|
124
|
+
renderConnectorsList,
|
|
125
|
+
renderConnectorsRunResult,
|
|
126
|
+
runConnectorPollOnce
|
|
127
|
+
} from "./chunk-OZHRDTDX.js";
|
|
101
128
|
import {
|
|
102
129
|
getCueAnchorStoreStatus
|
|
103
130
|
} from "./chunk-C6QPK5GG.js";
|
|
104
|
-
import {
|
|
105
|
-
analyzeGraphHealth
|
|
106
|
-
} from "./chunk-C2EFFULQ.js";
|
|
107
131
|
import {
|
|
108
132
|
applyCommitmentLedgerLifecycle,
|
|
109
133
|
getCommitmentLedgerStatus,
|
|
@@ -118,47 +142,60 @@ import {
|
|
|
118
142
|
} from "./chunk-NGAVDO7E.js";
|
|
119
143
|
import {
|
|
120
144
|
EngramAccessHttpServer
|
|
121
|
-
} from "./chunk-
|
|
145
|
+
} from "./chunk-AKUCB2OG.js";
|
|
122
146
|
import {
|
|
123
147
|
EngramMcpServer
|
|
124
|
-
} from "./chunk-
|
|
148
|
+
} from "./chunk-4PLGJRBV.js";
|
|
125
149
|
import {
|
|
126
150
|
EngramAccessService,
|
|
127
151
|
WorkStorage
|
|
128
|
-
} from "./chunk-
|
|
152
|
+
} from "./chunk-DR7MCMPS.js";
|
|
129
153
|
import {
|
|
130
154
|
parseRecallExplainFormat,
|
|
131
155
|
renderRecallExplain,
|
|
132
156
|
renderXray
|
|
133
|
-
} from "./chunk-
|
|
157
|
+
} from "./chunk-LW2NMHDW.js";
|
|
158
|
+
import {
|
|
159
|
+
getTrustZoneStoreStatus,
|
|
160
|
+
promoteTrustZoneRecord,
|
|
161
|
+
seedTrustZoneDemoDataset
|
|
162
|
+
} from "./chunk-EQINRHYR.js";
|
|
134
163
|
import {
|
|
135
164
|
listMemoryGovernanceRuns,
|
|
136
165
|
readMemoryGovernanceRunArtifact,
|
|
137
166
|
restoreMemoryGovernanceRun,
|
|
138
167
|
runMemoryGovernance
|
|
139
|
-
} from "./chunk-
|
|
168
|
+
} from "./chunk-LZRYQK6L.js";
|
|
140
169
|
import {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
seedTrustZoneDemoDataset
|
|
144
|
-
} from "./chunk-EQINRHYR.js";
|
|
170
|
+
expandTildePath
|
|
171
|
+
} from "./chunk-IXEJRKCZ.js";
|
|
145
172
|
import {
|
|
146
173
|
selectRouteRule,
|
|
147
174
|
validateRouteTarget
|
|
148
175
|
} from "./chunk-2LGMW3DJ.js";
|
|
176
|
+
import {
|
|
177
|
+
launchProcess
|
|
178
|
+
} from "./chunk-OR64ZGRZ.js";
|
|
179
|
+
import {
|
|
180
|
+
analyzeGraphHealth
|
|
181
|
+
} from "./chunk-RK2Y4XOM.js";
|
|
149
182
|
import {
|
|
150
183
|
getCausalTrajectoryStoreStatus
|
|
151
|
-
} from "./chunk-
|
|
184
|
+
} from "./chunk-G2WADRQ3.js";
|
|
152
185
|
import {
|
|
153
186
|
StorageManager
|
|
154
|
-
} from "./chunk-
|
|
187
|
+
} from "./chunk-DCE6SQLA.js";
|
|
188
|
+
import {
|
|
189
|
+
RECALL_DISCLOSURE_LEVELS,
|
|
190
|
+
isRecallDisclosure
|
|
191
|
+
} from "./chunk-43EKP2UK.js";
|
|
155
192
|
import {
|
|
156
193
|
MEMORY_LIFECYCLE_EVENT_SORT_ORDER,
|
|
157
194
|
buildLifecycleEventsForMemory,
|
|
158
195
|
inferMemoryStatus,
|
|
159
196
|
sortMemoryLifecycleEvents,
|
|
160
197
|
toMemoryPathRel
|
|
161
|
-
} from "./chunk-
|
|
198
|
+
} from "./chunk-RULE4VG5.js";
|
|
162
199
|
import {
|
|
163
200
|
normalizeProjectionPreview,
|
|
164
201
|
normalizeProjectionTags
|
|
@@ -178,75 +215,35 @@ import {
|
|
|
178
215
|
import {
|
|
179
216
|
resolveHomeDir
|
|
180
217
|
} from "./chunk-MARWOCVP.js";
|
|
218
|
+
import {
|
|
219
|
+
EXPORT_FORMAT,
|
|
220
|
+
EXPORT_SCHEMA_VERSION
|
|
221
|
+
} from "./chunk-IYY4MCPG.js";
|
|
222
|
+
import {
|
|
223
|
+
fileExists,
|
|
224
|
+
fromPosixRelPath,
|
|
225
|
+
listFilesRecursive,
|
|
226
|
+
readJsonFile,
|
|
227
|
+
sha256File,
|
|
228
|
+
sha256String,
|
|
229
|
+
toPosixRelPath,
|
|
230
|
+
writeJsonFile
|
|
231
|
+
} from "./chunk-457A4P3L.js";
|
|
232
|
+
import {
|
|
233
|
+
ExportBundleV1Schema
|
|
234
|
+
} from "./chunk-OA3L7BFR.js";
|
|
235
|
+
import {
|
|
236
|
+
encryptCapsuleFile
|
|
237
|
+
} from "./chunk-KNKUID7G.js";
|
|
181
238
|
|
|
182
239
|
// src/cli.ts
|
|
183
|
-
import
|
|
184
|
-
import { access as access2, readFile as
|
|
185
|
-
import { createHash as createHash2 } from "crypto";
|
|
186
|
-
|
|
187
|
-
// src/transfer/export-json.ts
|
|
188
|
-
import path2 from "path";
|
|
189
|
-
import { mkdir as mkdir2, readFile as readFile2 } from "fs/promises";
|
|
190
|
-
|
|
191
|
-
// src/transfer/constants.ts
|
|
192
|
-
var EXPORT_FORMAT = "openclaw-engram-export";
|
|
193
|
-
var EXPORT_SCHEMA_VERSION = 1;
|
|
194
|
-
|
|
195
|
-
// src/transfer/fs-utils.ts
|
|
240
|
+
import path18 from "path";
|
|
241
|
+
import { access as access2, readFile as readFile11, readdir as readdir7, unlink as unlink3 } from "fs/promises";
|
|
196
242
|
import { createHash } from "crypto";
|
|
197
|
-
import { mkdir, readdir, readFile, stat, writeFile } from "fs/promises";
|
|
198
|
-
import path from "path";
|
|
199
|
-
async function sha256File(filePath) {
|
|
200
|
-
const buf = await readFile(filePath);
|
|
201
|
-
const sha256 = createHash("sha256").update(buf).digest("hex");
|
|
202
|
-
return { sha256, bytes: buf.byteLength };
|
|
203
|
-
}
|
|
204
|
-
function sha256String(content) {
|
|
205
|
-
const buf = Buffer.from(content, "utf-8");
|
|
206
|
-
const sha256 = createHash("sha256").update(buf).digest("hex");
|
|
207
|
-
return { sha256, bytes: buf.byteLength };
|
|
208
|
-
}
|
|
209
|
-
async function writeJsonFile(filePath, value) {
|
|
210
|
-
await mkdir(path.dirname(filePath), { recursive: true });
|
|
211
|
-
await writeFile(filePath, JSON.stringify(value, null, 2) + "\n", "utf-8");
|
|
212
|
-
}
|
|
213
|
-
async function readJsonFile(filePath) {
|
|
214
|
-
const raw = await readFile(filePath, "utf-8");
|
|
215
|
-
return JSON.parse(raw);
|
|
216
|
-
}
|
|
217
|
-
async function listFilesRecursive(rootDir) {
|
|
218
|
-
const out = [];
|
|
219
|
-
async function walk(dir) {
|
|
220
|
-
const entries = await readdir(dir, { withFileTypes: true });
|
|
221
|
-
for (const ent of entries) {
|
|
222
|
-
const fp = path.join(dir, ent.name);
|
|
223
|
-
if (ent.isDirectory()) {
|
|
224
|
-
await walk(fp);
|
|
225
|
-
} else if (ent.isFile()) {
|
|
226
|
-
out.push(fp);
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
await walk(rootDir);
|
|
231
|
-
return out.sort();
|
|
232
|
-
}
|
|
233
|
-
async function fileExists(filePath) {
|
|
234
|
-
try {
|
|
235
|
-
await stat(filePath);
|
|
236
|
-
return true;
|
|
237
|
-
} catch {
|
|
238
|
-
return false;
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
function toPosixRelPath(absPath, rootDir) {
|
|
242
|
-
const rel = path.relative(rootDir, absPath);
|
|
243
|
-
return rel.split(path.sep).join("/");
|
|
244
|
-
}
|
|
245
|
-
function fromPosixRelPath(relPath) {
|
|
246
|
-
return relPath.split("/").join(path.sep);
|
|
247
|
-
}
|
|
248
243
|
|
|
249
244
|
// src/transfer/export-json.ts
|
|
245
|
+
import path from "path";
|
|
246
|
+
import { mkdir, readFile } from "fs/promises";
|
|
250
247
|
var DEFAULT_EXCLUDES = /* @__PURE__ */ new Set([
|
|
251
248
|
"node_modules",
|
|
252
249
|
".git"
|
|
@@ -259,24 +256,24 @@ function shouldExclude(relPosix, includeTranscripts) {
|
|
|
259
256
|
}
|
|
260
257
|
async function exportJsonBundle(opts) {
|
|
261
258
|
const includeTranscripts = opts.includeTranscripts === true;
|
|
262
|
-
const outDirAbs =
|
|
263
|
-
await
|
|
264
|
-
const memoryDirAbs =
|
|
259
|
+
const outDirAbs = path.resolve(opts.outDir);
|
|
260
|
+
await mkdir(outDirAbs, { recursive: true });
|
|
261
|
+
const memoryDirAbs = path.resolve(opts.memoryDir);
|
|
265
262
|
const filesAbs = await listFilesRecursive(memoryDirAbs);
|
|
266
263
|
const records = [];
|
|
267
264
|
const manifestFiles = [];
|
|
268
265
|
for (const abs of filesAbs) {
|
|
269
266
|
const relPosix = toPosixRelPath(abs, memoryDirAbs);
|
|
270
267
|
if (shouldExclude(relPosix, includeTranscripts)) continue;
|
|
271
|
-
const content = await
|
|
268
|
+
const content = await readFile(abs, "utf-8");
|
|
272
269
|
records.push({ path: relPosix, content });
|
|
273
270
|
const { sha256, bytes } = await sha256File(abs);
|
|
274
271
|
manifestFiles.push({ path: relPosix, sha256, bytes });
|
|
275
272
|
}
|
|
276
273
|
if (opts.includeWorkspaceIdentity !== false && opts.workspaceDir) {
|
|
277
|
-
const identityPath =
|
|
274
|
+
const identityPath = path.join(opts.workspaceDir, "IDENTITY.md");
|
|
278
275
|
try {
|
|
279
|
-
const content = await
|
|
276
|
+
const content = await readFile(identityPath, "utf-8");
|
|
280
277
|
const relPath = "workspace/IDENTITY.md";
|
|
281
278
|
records.push({ path: relPath, content });
|
|
282
279
|
const { sha256, bytes } = sha256String(content);
|
|
@@ -293,13 +290,13 @@ async function exportJsonBundle(opts) {
|
|
|
293
290
|
files: manifestFiles.sort((a, b) => a.path.localeCompare(b.path))
|
|
294
291
|
};
|
|
295
292
|
const bundle = { manifest, records };
|
|
296
|
-
await writeJsonFile(
|
|
297
|
-
await writeJsonFile(
|
|
293
|
+
await writeJsonFile(path.join(outDirAbs, "manifest.json"), manifest);
|
|
294
|
+
await writeJsonFile(path.join(outDirAbs, "bundle.json"), bundle);
|
|
298
295
|
}
|
|
299
296
|
|
|
300
297
|
// src/transfer/export-md.ts
|
|
301
|
-
import
|
|
302
|
-
import { mkdir as
|
|
298
|
+
import path2 from "path";
|
|
299
|
+
import { mkdir as mkdir2, readFile as readFile2, writeFile } from "fs/promises";
|
|
303
300
|
function shouldExclude2(relPosix, includeTranscripts) {
|
|
304
301
|
const parts = relPosix.split("/");
|
|
305
302
|
if (!includeTranscripts && parts[0] === "transcripts") return true;
|
|
@@ -307,18 +304,18 @@ function shouldExclude2(relPosix, includeTranscripts) {
|
|
|
307
304
|
}
|
|
308
305
|
async function exportMarkdownBundle(opts) {
|
|
309
306
|
const includeTranscripts = opts.includeTranscripts === true;
|
|
310
|
-
const outDirAbs =
|
|
311
|
-
await
|
|
312
|
-
const memDirAbs =
|
|
307
|
+
const outDirAbs = path2.resolve(opts.outDir);
|
|
308
|
+
await mkdir2(outDirAbs, { recursive: true });
|
|
309
|
+
const memDirAbs = path2.resolve(opts.memoryDir);
|
|
313
310
|
const filesAbs = await listFilesRecursive(memDirAbs);
|
|
314
311
|
const manifestFiles = [];
|
|
315
312
|
for (const abs of filesAbs) {
|
|
316
313
|
const relPosix = toPosixRelPath(abs, memDirAbs);
|
|
317
314
|
if (shouldExclude2(relPosix, includeTranscripts)) continue;
|
|
318
|
-
const dstAbs =
|
|
319
|
-
await
|
|
320
|
-
const content = await
|
|
321
|
-
await
|
|
315
|
+
const dstAbs = path2.join(outDirAbs, ...relPosix.split("/"));
|
|
316
|
+
await mkdir2(path2.dirname(dstAbs), { recursive: true });
|
|
317
|
+
const content = await readFile2(abs);
|
|
318
|
+
await writeFile(dstAbs, content);
|
|
322
319
|
const { sha256, bytes } = await sha256File(abs);
|
|
323
320
|
manifestFiles.push({ path: relPosix, sha256, bytes });
|
|
324
321
|
}
|
|
@@ -330,12 +327,12 @@ async function exportMarkdownBundle(opts) {
|
|
|
330
327
|
includesTranscripts: includeTranscripts,
|
|
331
328
|
files: manifestFiles.sort((a, b) => a.path.localeCompare(b.path))
|
|
332
329
|
};
|
|
333
|
-
await writeJsonFile(
|
|
330
|
+
await writeJsonFile(path2.join(outDirAbs, "manifest.json"), manifest);
|
|
334
331
|
}
|
|
335
332
|
async function looksLikeEngramMdExport(fromDir) {
|
|
336
|
-
const dirAbs =
|
|
333
|
+
const dirAbs = path2.resolve(fromDir);
|
|
337
334
|
try {
|
|
338
|
-
const raw = await
|
|
335
|
+
const raw = await readFile2(path2.join(dirAbs, "manifest.json"), "utf-8");
|
|
339
336
|
const parsed = JSON.parse(raw);
|
|
340
337
|
return parsed.format === EXPORT_FORMAT && parsed.schemaVersion === EXPORT_SCHEMA_VERSION;
|
|
341
338
|
} catch {
|
|
@@ -344,16 +341,52 @@ async function looksLikeEngramMdExport(fromDir) {
|
|
|
344
341
|
}
|
|
345
342
|
|
|
346
343
|
// src/transfer/backup.ts
|
|
347
|
-
import
|
|
348
|
-
import { mkdir as
|
|
344
|
+
import path3 from "path";
|
|
345
|
+
import { mkdir as mkdir3, readdir, rm, unlink, writeFile as writeFile2 } from "fs/promises";
|
|
346
|
+
import { gzipSync } from "zlib";
|
|
349
347
|
function timestampDirName(now) {
|
|
350
348
|
return now.toISOString().replace(/[:.]/g, "-");
|
|
351
349
|
}
|
|
352
350
|
async function backupMemoryDir(opts) {
|
|
353
|
-
const outDirAbs =
|
|
354
|
-
await
|
|
351
|
+
const outDirAbs = path3.resolve(opts.outDir);
|
|
352
|
+
await mkdir3(outDirAbs, { recursive: true });
|
|
355
353
|
const ts = timestampDirName(/* @__PURE__ */ new Date());
|
|
356
|
-
|
|
354
|
+
if (opts.encrypt === true) {
|
|
355
|
+
const { listFilesRecursive: listFilesRecursive3, toPosixRelPath: toPosixRelPath2 } = await import("./fs-utils-IRVUFB6G.js");
|
|
356
|
+
const { readFile: readFile12 } = await import("fs/promises");
|
|
357
|
+
const memoryDirAbs = path3.resolve(opts.memoryDir);
|
|
358
|
+
const filesAbs = await listFilesRecursive3(memoryDirAbs);
|
|
359
|
+
const includeTranscripts = opts.includeTranscripts === true;
|
|
360
|
+
const records = [];
|
|
361
|
+
for (const abs of filesAbs) {
|
|
362
|
+
const relPosix = toPosixRelPath2(abs, memoryDirAbs);
|
|
363
|
+
const parts = relPosix.split("/");
|
|
364
|
+
if (parts.some((p) => p === "node_modules" || p === ".git" || p === ".secure-store" || p === ".capsules")) continue;
|
|
365
|
+
if (!includeTranscripts && parts[0] === "transcripts") continue;
|
|
366
|
+
const content = await readFile12(abs, "utf-8");
|
|
367
|
+
records.push({ path: relPosix, content });
|
|
368
|
+
}
|
|
369
|
+
records.sort((a, b) => a.path.localeCompare(b.path));
|
|
370
|
+
const bundle = {
|
|
371
|
+
format: "remnic.backup.v1",
|
|
372
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
373
|
+
pluginVersion: opts.pluginVersion,
|
|
374
|
+
records
|
|
375
|
+
};
|
|
376
|
+
const tempGzPath = path3.join(outDirAbs, `${ts}.backup.json.gz`);
|
|
377
|
+
const gz = gzipSync(Buffer.from(JSON.stringify(bundle), "utf-8"));
|
|
378
|
+
await writeFile2(tempGzPath, gz);
|
|
379
|
+
const { encPath } = await encryptCapsuleFile({
|
|
380
|
+
sourceGzPath: tempGzPath,
|
|
381
|
+
memoryDir: opts.memoryDir
|
|
382
|
+
});
|
|
383
|
+
await unlink(tempGzPath);
|
|
384
|
+
if (opts.retentionDays && opts.retentionDays > 0) {
|
|
385
|
+
await enforceRetention(outDirAbs, opts.retentionDays);
|
|
386
|
+
}
|
|
387
|
+
return encPath;
|
|
388
|
+
}
|
|
389
|
+
const backupDir = path3.join(outDirAbs, ts);
|
|
357
390
|
await exportMarkdownBundle({
|
|
358
391
|
memoryDir: opts.memoryDir,
|
|
359
392
|
outDir: backupDir,
|
|
@@ -366,26 +399,39 @@ async function backupMemoryDir(opts) {
|
|
|
366
399
|
return backupDir;
|
|
367
400
|
}
|
|
368
401
|
async function enforceRetention(outDirAbs, retentionDays) {
|
|
369
|
-
const entries = await
|
|
402
|
+
const entries = await readdir(outDirAbs, { withFileTypes: true });
|
|
370
403
|
const cutoffMs = Date.now() - retentionDays * 24 * 60 * 60 * 1e3;
|
|
371
404
|
for (const ent of entries) {
|
|
372
|
-
if (!ent.isDirectory()) continue;
|
|
373
405
|
const name = ent.name;
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
406
|
+
if (ent.isDirectory()) {
|
|
407
|
+
const m = name.match(
|
|
408
|
+
/^(\d{4}-\d{2}-\d{2})T(\d{2})-(\d{2})-(\d{2})-(\d{3})Z$/
|
|
409
|
+
);
|
|
410
|
+
const iso = m ? `${m[1]}T${m[2]}:${m[3]}:${m[4]}.${m[5]}Z` : null;
|
|
411
|
+
const tsMs = iso ? Date.parse(iso) : NaN;
|
|
412
|
+
if (!Number.isFinite(tsMs)) continue;
|
|
413
|
+
if (tsMs < cutoffMs) {
|
|
414
|
+
await rm(path3.join(outDirAbs, name), { recursive: true, force: true });
|
|
415
|
+
}
|
|
416
|
+
continue;
|
|
417
|
+
}
|
|
418
|
+
if (ent.isFile() && name.endsWith(".backup.json.gz.enc")) {
|
|
419
|
+
const m = name.match(
|
|
420
|
+
/^(\d{4}-\d{2}-\d{2})T(\d{2})-(\d{2})-(\d{2})-(\d{3})Z/
|
|
421
|
+
);
|
|
422
|
+
const iso = m ? `${m[1]}T${m[2]}:${m[3]}:${m[4]}.${m[5]}Z` : null;
|
|
423
|
+
const tsMs = iso ? Date.parse(iso) : NaN;
|
|
424
|
+
if (!Number.isFinite(tsMs)) continue;
|
|
425
|
+
if (tsMs < cutoffMs) {
|
|
426
|
+
await rm(path3.join(outDirAbs, name), { force: true });
|
|
427
|
+
}
|
|
382
428
|
}
|
|
383
429
|
}
|
|
384
430
|
}
|
|
385
431
|
|
|
386
432
|
// src/transfer/export-sqlite.ts
|
|
387
|
-
import
|
|
388
|
-
import { readFile as
|
|
433
|
+
import path4 from "path";
|
|
434
|
+
import { readFile as readFile3 } from "fs/promises";
|
|
389
435
|
|
|
390
436
|
// src/transfer/sqlite-schema.ts
|
|
391
437
|
var SQLITE_SCHEMA_VERSION = 1;
|
|
@@ -411,8 +457,8 @@ function shouldExclude3(relPosix, includeTranscripts) {
|
|
|
411
457
|
}
|
|
412
458
|
async function exportSqlite(opts) {
|
|
413
459
|
const includeTranscripts = opts.includeTranscripts === true;
|
|
414
|
-
const memDirAbs =
|
|
415
|
-
const outAbs =
|
|
460
|
+
const memDirAbs = path4.resolve(opts.memoryDir);
|
|
461
|
+
const outAbs = path4.resolve(opts.outFile);
|
|
416
462
|
const filesAbs = await listFilesRecursive(memDirAbs);
|
|
417
463
|
const db = openBetterSqlite3(outAbs);
|
|
418
464
|
try {
|
|
@@ -433,7 +479,7 @@ async function exportSqlite(opts) {
|
|
|
433
479
|
for (const abs of filesAbs) {
|
|
434
480
|
const relPosix = toPosixRelPath(abs, memDirAbs);
|
|
435
481
|
if (shouldExclude3(relPosix, includeTranscripts)) continue;
|
|
436
|
-
const content = await
|
|
482
|
+
const content = await readFile3(abs, "utf-8");
|
|
437
483
|
const { sha256, bytes } = await sha256File(abs);
|
|
438
484
|
rows.push({ rel: relPosix, bytes, sha256, content });
|
|
439
485
|
}
|
|
@@ -444,55 +490,28 @@ async function exportSqlite(opts) {
|
|
|
444
490
|
}
|
|
445
491
|
|
|
446
492
|
// src/transfer/import-json.ts
|
|
447
|
-
import
|
|
448
|
-
import { mkdir as
|
|
449
|
-
|
|
450
|
-
// src/transfer/types.ts
|
|
451
|
-
import { z } from "zod";
|
|
452
|
-
var ExportManifestV1Schema = z.object({
|
|
453
|
-
format: z.literal("openclaw-engram-export"),
|
|
454
|
-
schemaVersion: z.literal(1),
|
|
455
|
-
createdAt: z.string(),
|
|
456
|
-
pluginVersion: z.string(),
|
|
457
|
-
includesTranscripts: z.boolean(),
|
|
458
|
-
files: z.array(
|
|
459
|
-
z.object({
|
|
460
|
-
path: z.string(),
|
|
461
|
-
sha256: z.string(),
|
|
462
|
-
bytes: z.number().int().nonnegative()
|
|
463
|
-
})
|
|
464
|
-
)
|
|
465
|
-
});
|
|
466
|
-
var ExportMemoryRecordV1Schema = z.object({
|
|
467
|
-
path: z.string(),
|
|
468
|
-
content: z.string()
|
|
469
|
-
});
|
|
470
|
-
var ExportBundleV1Schema = z.object({
|
|
471
|
-
manifest: ExportManifestV1Schema,
|
|
472
|
-
records: z.array(ExportMemoryRecordV1Schema)
|
|
473
|
-
});
|
|
474
|
-
|
|
475
|
-
// src/transfer/import-json.ts
|
|
493
|
+
import path5 from "path";
|
|
494
|
+
import { mkdir as mkdir4, writeFile as writeFile3 } from "fs/promises";
|
|
476
495
|
function normalizeForDedupe(s) {
|
|
477
496
|
return s.replace(/\s+/g, " ").trim();
|
|
478
497
|
}
|
|
479
498
|
async function importJsonBundle(opts) {
|
|
480
499
|
const conflict = opts.conflict ?? "skip";
|
|
481
|
-
const fromDirAbs =
|
|
482
|
-
const bundlePath =
|
|
500
|
+
const fromDirAbs = path5.resolve(opts.fromDir);
|
|
501
|
+
const bundlePath = path5.join(fromDirAbs, "bundle.json");
|
|
483
502
|
const bundle = ExportBundleV1Schema.parse(await readJsonFile(bundlePath));
|
|
484
|
-
const memDirAbs =
|
|
503
|
+
const memDirAbs = path5.resolve(opts.targetMemoryDir);
|
|
485
504
|
const written = [];
|
|
486
505
|
let skipped = 0;
|
|
487
506
|
for (const rec of bundle.records) {
|
|
488
507
|
const isWorkspace = rec.path.startsWith("workspace/");
|
|
489
|
-
const targetBase = isWorkspace ? opts.workspaceDir ?
|
|
508
|
+
const targetBase = isWorkspace ? opts.workspaceDir ? path5.resolve(opts.workspaceDir) : null : memDirAbs;
|
|
490
509
|
if (isWorkspace && !targetBase) {
|
|
491
510
|
skipped += 1;
|
|
492
511
|
continue;
|
|
493
512
|
}
|
|
494
513
|
const relFs = fromPosixRelPath(isWorkspace ? rec.path.replace(/^workspace\//, "") : rec.path);
|
|
495
|
-
const absTarget =
|
|
514
|
+
const absTarget = path5.join(targetBase, relFs);
|
|
496
515
|
const exists2 = await fileExists(absTarget);
|
|
497
516
|
if (exists2) {
|
|
498
517
|
if (conflict === "skip") {
|
|
@@ -516,29 +535,29 @@ async function importJsonBundle(opts) {
|
|
|
516
535
|
return { written: 0, skipped };
|
|
517
536
|
}
|
|
518
537
|
for (const w of written) {
|
|
519
|
-
await
|
|
538
|
+
await mkdir4(path5.dirname(w.abs), { recursive: true });
|
|
520
539
|
await writeFile3(w.abs, w.content, "utf-8");
|
|
521
540
|
}
|
|
522
541
|
return { written: written.length, skipped };
|
|
523
542
|
}
|
|
524
543
|
function looksLikeEngramJsonExport(fromDir) {
|
|
525
|
-
const dir =
|
|
544
|
+
const dir = path5.resolve(fromDir);
|
|
526
545
|
return Promise.all([
|
|
527
|
-
fileExists(
|
|
528
|
-
fileExists(
|
|
546
|
+
fileExists(path5.join(dir, "manifest.json")),
|
|
547
|
+
fileExists(path5.join(dir, "bundle.json"))
|
|
529
548
|
]).then(([m, b]) => m && b);
|
|
530
549
|
}
|
|
531
550
|
|
|
532
551
|
// src/transfer/import-sqlite.ts
|
|
533
|
-
import
|
|
534
|
-
import { mkdir as
|
|
552
|
+
import path6 from "path";
|
|
553
|
+
import { mkdir as mkdir5, writeFile as writeFile4 } from "fs/promises";
|
|
535
554
|
function normalizeForDedupe2(s) {
|
|
536
555
|
return s.replace(/\s+/g, " ").trim();
|
|
537
556
|
}
|
|
538
557
|
async function importSqlite(opts) {
|
|
539
558
|
const conflict = opts.conflict ?? "skip";
|
|
540
|
-
const memDirAbs =
|
|
541
|
-
const fromAbs =
|
|
559
|
+
const memDirAbs = path6.resolve(opts.targetMemoryDir);
|
|
560
|
+
const fromAbs = path6.resolve(opts.fromFile);
|
|
542
561
|
const db = openBetterSqlite3(fromAbs, { readonly: true });
|
|
543
562
|
const written = [];
|
|
544
563
|
let skipped = 0;
|
|
@@ -551,7 +570,7 @@ async function importSqlite(opts) {
|
|
|
551
570
|
const rows = db.prepare("SELECT path_rel, content FROM files").all();
|
|
552
571
|
for (const r of rows) {
|
|
553
572
|
const relFs = fromPosixRelPath(r.path_rel);
|
|
554
|
-
const absTarget =
|
|
573
|
+
const absTarget = path6.join(memDirAbs, relFs);
|
|
555
574
|
const exists2 = await fileExists(absTarget);
|
|
556
575
|
if (exists2) {
|
|
557
576
|
if (conflict === "skip") {
|
|
@@ -576,30 +595,30 @@ async function importSqlite(opts) {
|
|
|
576
595
|
}
|
|
577
596
|
if (opts.dryRun) return { written: 0, skipped };
|
|
578
597
|
for (const w of written) {
|
|
579
|
-
await
|
|
598
|
+
await mkdir5(path6.dirname(w.abs), { recursive: true });
|
|
580
599
|
await writeFile4(w.abs, w.content, "utf-8");
|
|
581
600
|
}
|
|
582
601
|
return { written: written.length, skipped };
|
|
583
602
|
}
|
|
584
603
|
|
|
585
604
|
// src/transfer/import-md.ts
|
|
586
|
-
import
|
|
587
|
-
import { mkdir as
|
|
605
|
+
import path7 from "path";
|
|
606
|
+
import { mkdir as mkdir6, readFile as readFile4, writeFile as writeFile5 } from "fs/promises";
|
|
588
607
|
function normalizeForDedupe3(s) {
|
|
589
608
|
return s.replace(/\s+/g, " ").trim();
|
|
590
609
|
}
|
|
591
610
|
async function importMarkdownBundle(opts) {
|
|
592
611
|
const conflict = opts.conflict ?? "skip";
|
|
593
|
-
const fromAbs =
|
|
594
|
-
const targetAbs =
|
|
612
|
+
const fromAbs = path7.resolve(opts.fromDir);
|
|
613
|
+
const targetAbs = path7.resolve(opts.targetMemoryDir);
|
|
595
614
|
const filesAbs = await listFilesRecursive(fromAbs);
|
|
596
615
|
const writes = [];
|
|
597
616
|
let skipped = 0;
|
|
598
617
|
for (const abs of filesAbs) {
|
|
599
618
|
const relPosix = toPosixRelPath(abs, fromAbs);
|
|
600
619
|
if (relPosix === "manifest.json") continue;
|
|
601
|
-
const dstAbs =
|
|
602
|
-
const content = await
|
|
620
|
+
const dstAbs = path7.join(targetAbs, fromPosixRelPath(relPosix));
|
|
621
|
+
const content = await readFile4(abs, "utf-8");
|
|
603
622
|
const exists2 = await fileExists(dstAbs);
|
|
604
623
|
if (exists2) {
|
|
605
624
|
if (conflict === "skip") {
|
|
@@ -621,20 +640,20 @@ async function importMarkdownBundle(opts) {
|
|
|
621
640
|
}
|
|
622
641
|
if (opts.dryRun) return { written: 0, skipped };
|
|
623
642
|
for (const w of writes) {
|
|
624
|
-
await
|
|
643
|
+
await mkdir6(path7.dirname(w.abs), { recursive: true });
|
|
625
644
|
await writeFile5(w.abs, w.content, "utf-8");
|
|
626
645
|
}
|
|
627
646
|
return { written: writes.length, skipped };
|
|
628
647
|
}
|
|
629
648
|
|
|
630
649
|
// src/transfer/autodetect.ts
|
|
631
|
-
import
|
|
632
|
-
import { stat
|
|
650
|
+
import path8 from "path";
|
|
651
|
+
import { stat } from "fs/promises";
|
|
633
652
|
async function detectImportFormat(fromPath) {
|
|
634
|
-
const abs =
|
|
653
|
+
const abs = path8.resolve(fromPath);
|
|
635
654
|
let st;
|
|
636
655
|
try {
|
|
637
|
-
st = await
|
|
656
|
+
st = await stat(abs);
|
|
638
657
|
} catch {
|
|
639
658
|
return null;
|
|
640
659
|
}
|
|
@@ -1059,8 +1078,8 @@ function gatherCandidates(input, warnings) {
|
|
|
1059
1078
|
const record = rec;
|
|
1060
1079
|
const content = typeof record.content === "string" ? record.content : null;
|
|
1061
1080
|
if (!content) continue;
|
|
1062
|
-
const
|
|
1063
|
-
if (!
|
|
1081
|
+
const path19 = typeof record.path === "string" ? record.path : "";
|
|
1082
|
+
if (!path19.startsWith("transcripts/") && !path19.includes("/transcripts/")) continue;
|
|
1064
1083
|
rows.push(...parseJsonl(content, warnings));
|
|
1065
1084
|
}
|
|
1066
1085
|
return rows;
|
|
@@ -1277,8 +1296,8 @@ async function runBulkImportPipeline(source, options = {}, processBatch) {
|
|
|
1277
1296
|
}
|
|
1278
1297
|
|
|
1279
1298
|
// src/maintenance/archive-observations.ts
|
|
1280
|
-
import
|
|
1281
|
-
import { mkdir as
|
|
1299
|
+
import path9 from "path";
|
|
1300
|
+
import { mkdir as mkdir7, readdir as readdir2, readFile as readFile5, unlink as unlink2, writeFile as writeFile6 } from "fs/promises";
|
|
1282
1301
|
var DATE_FILE_PATTERN = /^(\d{4})-(\d{2})-(\d{2})\.(jsonl|md)$/;
|
|
1283
1302
|
function normalizeRetentionDays(value) {
|
|
1284
1303
|
if (!Number.isFinite(value)) return 30;
|
|
@@ -1299,13 +1318,13 @@ async function listFilesRecursive2(root, relPrefix = "") {
|
|
|
1299
1318
|
const out = [];
|
|
1300
1319
|
let entries;
|
|
1301
1320
|
try {
|
|
1302
|
-
entries = await
|
|
1321
|
+
entries = await readdir2(root, { withFileTypes: true });
|
|
1303
1322
|
} catch {
|
|
1304
1323
|
return out;
|
|
1305
1324
|
}
|
|
1306
1325
|
for (const entry of entries) {
|
|
1307
|
-
const rel = relPrefix ?
|
|
1308
|
-
const full =
|
|
1326
|
+
const rel = relPrefix ? path9.join(relPrefix, entry.name) : entry.name;
|
|
1327
|
+
const full = path9.join(root, entry.name);
|
|
1309
1328
|
if (entry.isDirectory()) {
|
|
1310
1329
|
out.push(...await listFilesRecursive2(full, rel));
|
|
1311
1330
|
continue;
|
|
@@ -1315,19 +1334,19 @@ async function listFilesRecursive2(root, relPrefix = "") {
|
|
|
1315
1334
|
return out;
|
|
1316
1335
|
}
|
|
1317
1336
|
async function collectArchiveCandidates(memoryDir, cutoffTimeMs) {
|
|
1318
|
-
const roots = ["transcripts",
|
|
1337
|
+
const roots = ["transcripts", path9.join("state", "tool-usage"), path9.join("summaries", "hourly")];
|
|
1319
1338
|
const out = [];
|
|
1320
1339
|
for (const relRoot of roots) {
|
|
1321
|
-
const absRoot =
|
|
1340
|
+
const absRoot = path9.join(memoryDir, relRoot);
|
|
1322
1341
|
const files = await listFilesRecursive2(absRoot);
|
|
1323
1342
|
for (const fileRel of files) {
|
|
1324
|
-
const filename =
|
|
1343
|
+
const filename = path9.basename(fileRel);
|
|
1325
1344
|
const parsedDate = extractDateFromFilename(filename);
|
|
1326
1345
|
if (!parsedDate) continue;
|
|
1327
1346
|
if (parsedDate.getTime() >= cutoffTimeMs) continue;
|
|
1328
1347
|
out.push({
|
|
1329
|
-
absolutePath:
|
|
1330
|
-
relativePath:
|
|
1348
|
+
absolutePath: path9.join(absRoot, fileRel),
|
|
1349
|
+
relativePath: path9.join(relRoot, fileRel)
|
|
1331
1350
|
});
|
|
1332
1351
|
}
|
|
1333
1352
|
}
|
|
@@ -1342,7 +1361,7 @@ async function archiveObservations(options) {
|
|
|
1342
1361
|
new Date(now.getTime() - retentionDays * 24 * 60 * 60 * 1e3)
|
|
1343
1362
|
);
|
|
1344
1363
|
const stamp = now.toISOString().replace(/[-:]/g, "").replace(/\.\d{3}Z$/, "Z");
|
|
1345
|
-
const archiveRoot =
|
|
1364
|
+
const archiveRoot = path9.join(options.memoryDir, "archive", "observations", stamp);
|
|
1346
1365
|
const candidates = retentionDays === 0 ? [] : await collectArchiveCandidates(
|
|
1347
1366
|
options.memoryDir,
|
|
1348
1367
|
cutoffDayStartUtc
|
|
@@ -1351,14 +1370,14 @@ async function archiveObservations(options) {
|
|
|
1351
1370
|
let archivedBytes = 0;
|
|
1352
1371
|
const archivedRelativePaths = [];
|
|
1353
1372
|
if (!dryRun && candidates.length > 0) {
|
|
1354
|
-
await
|
|
1373
|
+
await mkdir7(archiveRoot, { recursive: true });
|
|
1355
1374
|
for (const candidate of candidates) {
|
|
1356
|
-
const archivePath =
|
|
1357
|
-
const archiveDir =
|
|
1358
|
-
await
|
|
1359
|
-
const raw = await
|
|
1375
|
+
const archivePath = path9.join(archiveRoot, candidate.relativePath);
|
|
1376
|
+
const archiveDir = path9.dirname(archivePath);
|
|
1377
|
+
await mkdir7(archiveDir, { recursive: true });
|
|
1378
|
+
const raw = await readFile5(candidate.absolutePath);
|
|
1360
1379
|
await writeFile6(archivePath, raw);
|
|
1361
|
-
await
|
|
1380
|
+
await unlink2(candidate.absolutePath);
|
|
1362
1381
|
archivedFiles += 1;
|
|
1363
1382
|
archivedBytes += raw.byteLength;
|
|
1364
1383
|
archivedRelativePaths.push(candidate.relativePath);
|
|
@@ -1378,8 +1397,8 @@ async function archiveObservations(options) {
|
|
|
1378
1397
|
}
|
|
1379
1398
|
|
|
1380
1399
|
// src/maintenance/rebuild-memory-lifecycle-ledger.ts
|
|
1381
|
-
import
|
|
1382
|
-
import { mkdir as
|
|
1400
|
+
import path10 from "path";
|
|
1401
|
+
import { mkdir as mkdir8, rename, stat as stat2, writeFile as writeFile7 } from "fs/promises";
|
|
1383
1402
|
|
|
1384
1403
|
// src/maintenance/backup-stamp.ts
|
|
1385
1404
|
function toBackupStamp(now) {
|
|
@@ -1389,11 +1408,11 @@ function toBackupStamp(now) {
|
|
|
1389
1408
|
// src/maintenance/rebuild-memory-lifecycle-ledger.ts
|
|
1390
1409
|
async function backupExistingLedger(memoryDir, outputPath, now) {
|
|
1391
1410
|
try {
|
|
1392
|
-
await
|
|
1411
|
+
await stat2(outputPath);
|
|
1393
1412
|
} catch {
|
|
1394
1413
|
return void 0;
|
|
1395
1414
|
}
|
|
1396
|
-
const backupPath =
|
|
1415
|
+
const backupPath = path10.join(
|
|
1397
1416
|
memoryDir,
|
|
1398
1417
|
"archive",
|
|
1399
1418
|
"memory-lifecycle-ledger",
|
|
@@ -1401,14 +1420,14 @@ async function backupExistingLedger(memoryDir, outputPath, now) {
|
|
|
1401
1420
|
"state",
|
|
1402
1421
|
"memory-lifecycle-ledger.jsonl"
|
|
1403
1422
|
);
|
|
1404
|
-
await
|
|
1423
|
+
await mkdir8(path10.dirname(backupPath), { recursive: true });
|
|
1405
1424
|
await rename(outputPath, backupPath);
|
|
1406
1425
|
return backupPath;
|
|
1407
1426
|
}
|
|
1408
1427
|
async function rebuildMemoryLifecycleLedger(options) {
|
|
1409
1428
|
const dryRun = options.dryRun !== false;
|
|
1410
1429
|
const now = options.now ?? /* @__PURE__ */ new Date();
|
|
1411
|
-
const outputPath =
|
|
1430
|
+
const outputPath = path10.join(options.memoryDir, "state", "memory-lifecycle-ledger.jsonl");
|
|
1412
1431
|
const storage = new StorageManager(options.memoryDir);
|
|
1413
1432
|
const allMemories = [...await storage.readAllMemories(), ...await storage.readArchivedMemories()].sort((a, b) => a.frontmatter.id.localeCompare(b.frontmatter.id));
|
|
1414
1433
|
const events = sortMemoryLifecycleEvents(
|
|
@@ -1417,7 +1436,7 @@ async function rebuildMemoryLifecycleLedger(options) {
|
|
|
1417
1436
|
let backupPath;
|
|
1418
1437
|
if (!dryRun) {
|
|
1419
1438
|
backupPath = await backupExistingLedger(options.memoryDir, outputPath, now);
|
|
1420
|
-
await
|
|
1439
|
+
await mkdir8(path10.dirname(outputPath), { recursive: true });
|
|
1421
1440
|
const payload = events.map((event) => JSON.stringify(event)).join("\n");
|
|
1422
1441
|
await writeFile7(outputPath, payload.length > 0 ? `${payload}
|
|
1423
1442
|
` : "", "utf-8");
|
|
@@ -1432,15 +1451,15 @@ async function rebuildMemoryLifecycleLedger(options) {
|
|
|
1432
1451
|
}
|
|
1433
1452
|
|
|
1434
1453
|
// src/maintenance/rebuild-memory-projection.ts
|
|
1435
|
-
import
|
|
1436
|
-
import { mkdir as
|
|
1454
|
+
import path11 from "path";
|
|
1455
|
+
import { mkdir as mkdir9, rename as rename2, rm as rm2, stat as stat3 } from "fs/promises";
|
|
1437
1456
|
async function backupExistingProjection(memoryDir, outputPath, now) {
|
|
1438
1457
|
try {
|
|
1439
|
-
await
|
|
1458
|
+
await stat3(outputPath);
|
|
1440
1459
|
} catch {
|
|
1441
1460
|
return void 0;
|
|
1442
1461
|
}
|
|
1443
|
-
const backupPath =
|
|
1462
|
+
const backupPath = path11.join(
|
|
1444
1463
|
memoryDir,
|
|
1445
1464
|
"archive",
|
|
1446
1465
|
"memory-projection",
|
|
@@ -1448,7 +1467,7 @@ async function backupExistingProjection(memoryDir, outputPath, now) {
|
|
|
1448
1467
|
"state",
|
|
1449
1468
|
"memory-projection.sqlite"
|
|
1450
1469
|
);
|
|
1451
|
-
await
|
|
1470
|
+
await mkdir9(path11.dirname(backupPath), { recursive: true });
|
|
1452
1471
|
await rename2(outputPath, backupPath);
|
|
1453
1472
|
return backupPath;
|
|
1454
1473
|
}
|
|
@@ -2132,7 +2151,7 @@ async function rebuildMemoryProjection(options) {
|
|
|
2132
2151
|
}
|
|
2133
2152
|
}
|
|
2134
2153
|
const tempPath = `${outputPath}.tmp`;
|
|
2135
|
-
await
|
|
2154
|
+
await mkdir9(path11.dirname(outputPath), { recursive: true });
|
|
2136
2155
|
await rm2(tempPath, { force: true });
|
|
2137
2156
|
writeProjectionDb(
|
|
2138
2157
|
tempPath,
|
|
@@ -2304,12 +2323,12 @@ async function repairMemoryProjection(options) {
|
|
|
2304
2323
|
}
|
|
2305
2324
|
|
|
2306
2325
|
// src/maintenance/rebuild-observations.ts
|
|
2307
|
-
import
|
|
2308
|
-
import { readdir as
|
|
2326
|
+
import path13 from "path";
|
|
2327
|
+
import { readdir as readdir3, readFile as readFile7 } from "fs/promises";
|
|
2309
2328
|
|
|
2310
2329
|
// src/maintenance/observation-ledger-utils.ts
|
|
2311
|
-
import
|
|
2312
|
-
import { mkdir as
|
|
2330
|
+
import path12 from "path";
|
|
2331
|
+
import { mkdir as mkdir10, readFile as readFile6, writeFile as writeFile8 } from "fs/promises";
|
|
2313
2332
|
function toHourBucketIso(timestamp) {
|
|
2314
2333
|
const normalized = /(?:Z|[+-]\d{2}:\d{2})$/u.test(timestamp) ? timestamp : `${timestamp}Z`;
|
|
2315
2334
|
const ms = Date.parse(normalized);
|
|
@@ -2320,16 +2339,16 @@ function toHourBucketIso(timestamp) {
|
|
|
2320
2339
|
}
|
|
2321
2340
|
async function backupAndWriteRebuiltObservations(options) {
|
|
2322
2341
|
const stamp = options.now.toISOString().replace(/[-:]/g, "").replace(/\.\d{3}Z$/, "Z");
|
|
2323
|
-
const archiveRoot =
|
|
2324
|
-
let backupPath =
|
|
2342
|
+
const archiveRoot = path12.join(options.memoryDir, "archive", "observations", stamp);
|
|
2343
|
+
let backupPath = path12.join(
|
|
2325
2344
|
archiveRoot,
|
|
2326
2345
|
"state",
|
|
2327
2346
|
"observation-ledger",
|
|
2328
2347
|
"rebuilt-observations.jsonl"
|
|
2329
2348
|
);
|
|
2330
2349
|
try {
|
|
2331
|
-
const existing = await
|
|
2332
|
-
await
|
|
2350
|
+
const existing = await readFile6(options.outputPath, "utf-8");
|
|
2351
|
+
await mkdir10(path12.dirname(backupPath), { recursive: true });
|
|
2333
2352
|
await writeFile8(backupPath, existing, "utf-8");
|
|
2334
2353
|
} catch (err) {
|
|
2335
2354
|
const code = err.code;
|
|
@@ -2346,7 +2365,7 @@ async function backupAndWriteRebuiltObservations(options) {
|
|
|
2346
2365
|
rebuiltAt
|
|
2347
2366
|
})
|
|
2348
2367
|
);
|
|
2349
|
-
await
|
|
2368
|
+
await mkdir10(path12.dirname(options.outputPath), { recursive: true });
|
|
2350
2369
|
await writeFile8(options.outputPath, lines.length > 0 ? `${lines.join("\n")}
|
|
2351
2370
|
` : "", "utf-8");
|
|
2352
2371
|
return backupPath;
|
|
@@ -2360,7 +2379,7 @@ async function listTranscriptFiles(root) {
|
|
|
2360
2379
|
const out = [];
|
|
2361
2380
|
let entries;
|
|
2362
2381
|
try {
|
|
2363
|
-
entries = await
|
|
2382
|
+
entries = await readdir3(root, { withFileTypes: true });
|
|
2364
2383
|
} catch (err) {
|
|
2365
2384
|
const code = err.code;
|
|
2366
2385
|
if (code && code === "ENOENT") return out;
|
|
@@ -2369,7 +2388,7 @@ async function listTranscriptFiles(root) {
|
|
|
2369
2388
|
for (const entry of entries) {
|
|
2370
2389
|
if (entry.name === "." || entry.name === "..") continue;
|
|
2371
2390
|
if (entry.isSymbolicLink()) continue;
|
|
2372
|
-
const full =
|
|
2391
|
+
const full = path13.join(root, entry.name);
|
|
2373
2392
|
if (entry.isDirectory()) {
|
|
2374
2393
|
out.push(...await listTranscriptFiles(full));
|
|
2375
2394
|
continue;
|
|
@@ -2429,8 +2448,8 @@ function buildLedgerRows(linesByFile) {
|
|
|
2429
2448
|
async function rebuildObservations(options) {
|
|
2430
2449
|
const dryRun = options.dryRun !== false;
|
|
2431
2450
|
const now = options.now ?? /* @__PURE__ */ new Date();
|
|
2432
|
-
const transcriptsRoot =
|
|
2433
|
-
const outputPath =
|
|
2451
|
+
const transcriptsRoot = path13.join(options.memoryDir, "transcripts");
|
|
2452
|
+
const outputPath = path13.join(
|
|
2434
2453
|
options.memoryDir,
|
|
2435
2454
|
"state",
|
|
2436
2455
|
"observation-ledger",
|
|
@@ -2440,7 +2459,7 @@ async function rebuildObservations(options) {
|
|
|
2440
2459
|
const contents = [];
|
|
2441
2460
|
for (const file of transcriptFiles) {
|
|
2442
2461
|
try {
|
|
2443
|
-
contents.push(await
|
|
2462
|
+
contents.push(await readFile7(file, "utf-8"));
|
|
2444
2463
|
} catch {
|
|
2445
2464
|
}
|
|
2446
2465
|
}
|
|
@@ -2466,8 +2485,8 @@ async function rebuildObservations(options) {
|
|
|
2466
2485
|
}
|
|
2467
2486
|
|
|
2468
2487
|
// src/maintenance/migrate-observations.ts
|
|
2469
|
-
import
|
|
2470
|
-
import { readdir as
|
|
2488
|
+
import path14 from "path";
|
|
2489
|
+
import { readdir as readdir4, readFile as readFile8 } from "fs/promises";
|
|
2471
2490
|
function toNonNegativeInt(value) {
|
|
2472
2491
|
if (typeof value !== "number" || !Number.isFinite(value)) return null;
|
|
2473
2492
|
const normalized = Math.floor(value);
|
|
@@ -2518,7 +2537,7 @@ function toCounts(row) {
|
|
|
2518
2537
|
async function listLegacyObservationFiles(root) {
|
|
2519
2538
|
let entries;
|
|
2520
2539
|
try {
|
|
2521
|
-
entries = await
|
|
2540
|
+
entries = await readdir4(root, { withFileTypes: true });
|
|
2522
2541
|
} catch (err) {
|
|
2523
2542
|
const code = err.code;
|
|
2524
2543
|
if (code && code === "ENOENT") return [];
|
|
@@ -2530,16 +2549,16 @@ async function listLegacyObservationFiles(root) {
|
|
|
2530
2549
|
async function migrateObservations(options) {
|
|
2531
2550
|
const dryRun = options.dryRun !== false;
|
|
2532
2551
|
const now = options.now ?? /* @__PURE__ */ new Date();
|
|
2533
|
-
const ledgerRoot =
|
|
2534
|
-
const outputPath =
|
|
2552
|
+
const ledgerRoot = path14.join(options.memoryDir, "state", "observation-ledger");
|
|
2553
|
+
const outputPath = path14.join(ledgerRoot, "rebuilt-observations.jsonl");
|
|
2535
2554
|
const legacyFiles = await listLegacyObservationFiles(ledgerRoot);
|
|
2536
|
-
const sourceRelativePaths = legacyFiles.map((name) =>
|
|
2555
|
+
const sourceRelativePaths = legacyFiles.map((name) => path14.join("state", "observation-ledger", name));
|
|
2537
2556
|
const byKey = /* @__PURE__ */ new Map();
|
|
2538
2557
|
let parsedRows = 0;
|
|
2539
2558
|
let malformedLines = 0;
|
|
2540
2559
|
for (const file of legacyFiles) {
|
|
2541
|
-
const full =
|
|
2542
|
-
const raw = await
|
|
2560
|
+
const full = path14.join(ledgerRoot, file);
|
|
2561
|
+
const raw = await readFile8(full, "utf-8");
|
|
2543
2562
|
for (const line of raw.split("\n")) {
|
|
2544
2563
|
if (!line.trim()) continue;
|
|
2545
2564
|
let parsed;
|
|
@@ -2616,7 +2635,7 @@ async function migrateObservations(options) {
|
|
|
2616
2635
|
}
|
|
2617
2636
|
|
|
2618
2637
|
// src/network/tailscale.ts
|
|
2619
|
-
import { stat as
|
|
2638
|
+
import { stat as stat4 } from "fs/promises";
|
|
2620
2639
|
var TailscaleHelper = class {
|
|
2621
2640
|
tailscaleBinary;
|
|
2622
2641
|
rsyncBinary;
|
|
@@ -2680,7 +2699,7 @@ var TailscaleHelper = class {
|
|
|
2680
2699
|
}
|
|
2681
2700
|
};
|
|
2682
2701
|
async function assertReadableDirectory(dir) {
|
|
2683
|
-
const info = await
|
|
2702
|
+
const info = await stat4(dir);
|
|
2684
2703
|
if (!info.isDirectory()) {
|
|
2685
2704
|
throw new Error(`sourceDir must be a directory: ${dir}`);
|
|
2686
2705
|
}
|
|
@@ -2731,10 +2750,10 @@ var defaultCommandRunner = (command, args, options) => {
|
|
|
2731
2750
|
|
|
2732
2751
|
// src/network/webdav.ts
|
|
2733
2752
|
import { createReadStream } from "fs";
|
|
2734
|
-
import { mkdir as
|
|
2753
|
+
import { mkdir as mkdir11, readdir as readdir5, realpath, stat as stat5 } from "fs/promises";
|
|
2735
2754
|
import { createServer } from "http";
|
|
2736
2755
|
import { timingSafeEqual } from "crypto";
|
|
2737
|
-
import
|
|
2756
|
+
import path15 from "path";
|
|
2738
2757
|
import { pipeline } from "stream/promises";
|
|
2739
2758
|
import { URL as URL2 } from "url";
|
|
2740
2759
|
function hostToUrlAuthority(host) {
|
|
@@ -2770,10 +2789,10 @@ var WebDavServer = class _WebDavServer {
|
|
|
2770
2789
|
const allowedRoots = [];
|
|
2771
2790
|
const aliasSet = /* @__PURE__ */ new Set();
|
|
2772
2791
|
for (const dir of options.allowlistDirs) {
|
|
2773
|
-
const resolved =
|
|
2774
|
-
await
|
|
2792
|
+
const resolved = path15.resolve(dir);
|
|
2793
|
+
await mkdir11(resolved, { recursive: true });
|
|
2775
2794
|
const canonical = await realpath(resolved);
|
|
2776
|
-
const alias =
|
|
2795
|
+
const alias = path15.basename(canonical) || "root";
|
|
2777
2796
|
if (aliasSet.has(alias)) {
|
|
2778
2797
|
throw new Error(`duplicate webdav allowlist alias: ${alias}`);
|
|
2779
2798
|
}
|
|
@@ -2929,7 +2948,7 @@ var WebDavServer = class _WebDavServer {
|
|
|
2929
2948
|
if (decodedPath.includes("\0")) {
|
|
2930
2949
|
return { ok: false, code: 400, message: "invalid path" };
|
|
2931
2950
|
}
|
|
2932
|
-
const normalized =
|
|
2951
|
+
const normalized = path15.posix.normalize(decodedPath);
|
|
2933
2952
|
const segments = normalized.split("/").filter((segment) => segment.length > 0);
|
|
2934
2953
|
if (segments.length === 0) {
|
|
2935
2954
|
return { ok: false, code: 403, message: "root listing is not allowed" };
|
|
@@ -2943,7 +2962,7 @@ var WebDavServer = class _WebDavServer {
|
|
|
2943
2962
|
if (relative.some((segment) => segment === ".." || segment.includes("\\"))) {
|
|
2944
2963
|
return { ok: false, code: 403, message: "path traversal is not allowed" };
|
|
2945
2964
|
}
|
|
2946
|
-
const candidate =
|
|
2965
|
+
const candidate = path15.resolve(root.absolute, ...relative);
|
|
2947
2966
|
if (!this.isPathInside(root.absolute, candidate)) {
|
|
2948
2967
|
return { ok: false, code: 403, message: "path escaped allowlist" };
|
|
2949
2968
|
}
|
|
@@ -2967,7 +2986,7 @@ var WebDavServer = class _WebDavServer {
|
|
|
2967
2986
|
async handleRead(method, absolutePath, res) {
|
|
2968
2987
|
let info;
|
|
2969
2988
|
try {
|
|
2970
|
-
info = await
|
|
2989
|
+
info = await stat5(absolutePath);
|
|
2971
2990
|
} catch {
|
|
2972
2991
|
res.writeHead(404, { "Content-Type": "text/plain; charset=utf-8" });
|
|
2973
2992
|
res.end("not found");
|
|
@@ -2991,7 +3010,7 @@ var WebDavServer = class _WebDavServer {
|
|
|
2991
3010
|
async handlePropfind(absolutePath, displayPath, res) {
|
|
2992
3011
|
let info;
|
|
2993
3012
|
try {
|
|
2994
|
-
info = await
|
|
3013
|
+
info = await stat5(absolutePath);
|
|
2995
3014
|
} catch {
|
|
2996
3015
|
res.writeHead(404, { "Content-Type": "text/plain; charset=utf-8" });
|
|
2997
3016
|
res.end("not found");
|
|
@@ -2999,7 +3018,7 @@ var WebDavServer = class _WebDavServer {
|
|
|
2999
3018
|
}
|
|
3000
3019
|
const entries = [];
|
|
3001
3020
|
if (info.isDirectory()) {
|
|
3002
|
-
const children = await
|
|
3021
|
+
const children = await readdir5(absolutePath, { withFileTypes: true });
|
|
3003
3022
|
for (const child of children) {
|
|
3004
3023
|
const childHref = toEncodedHref(`${displayPath.replace(/\/$/, "")}/${child.name}`);
|
|
3005
3024
|
entries.push(`
|
|
@@ -3021,10 +3040,10 @@ var WebDavServer = class _WebDavServer {
|
|
|
3021
3040
|
}
|
|
3022
3041
|
isPathInside(root, target) {
|
|
3023
3042
|
if (target === root) return true;
|
|
3024
|
-
if (root ===
|
|
3043
|
+
if (root === path15.parse(root).root) {
|
|
3025
3044
|
return target.startsWith(root);
|
|
3026
3045
|
}
|
|
3027
|
-
return target.startsWith(`${root}${
|
|
3046
|
+
return target.startsWith(`${root}${path15.sep}`);
|
|
3028
3047
|
}
|
|
3029
3048
|
};
|
|
3030
3049
|
function xmlEscape(value) {
|
|
@@ -3035,8 +3054,8 @@ function toEncodedHref(pathname) {
|
|
|
3035
3054
|
}
|
|
3036
3055
|
|
|
3037
3056
|
// src/compat/checks.ts
|
|
3038
|
-
import { access, readFile as
|
|
3039
|
-
import
|
|
3057
|
+
import { access, readFile as readFile9 } from "fs/promises";
|
|
3058
|
+
import path16 from "path";
|
|
3040
3059
|
var REQUIRED_HOOKS_LEGACY = ["before_agent_start", "agent_end"];
|
|
3041
3060
|
var REQUIRED_HOOKS_NEW = ["before_prompt_build", "agent_end"];
|
|
3042
3061
|
function isSafeCommandToken(command) {
|
|
@@ -3211,13 +3230,13 @@ function parseCurrentNodeVersion(raw) {
|
|
|
3211
3230
|
async function runCompatChecks(options) {
|
|
3212
3231
|
const checks = [];
|
|
3213
3232
|
const runner = options.runner ?? defaultRunner;
|
|
3214
|
-
const pluginJsonPath =
|
|
3215
|
-
const packageJsonPath =
|
|
3216
|
-
const indexPath =
|
|
3233
|
+
const pluginJsonPath = path16.join(options.repoRoot, "openclaw.plugin.json");
|
|
3234
|
+
const packageJsonPath = path16.join(options.repoRoot, "package.json");
|
|
3235
|
+
const indexPath = path16.join(options.repoRoot, "src", "index.ts");
|
|
3217
3236
|
let pluginRaw = "";
|
|
3218
3237
|
let pluginManifestPresent = false;
|
|
3219
3238
|
try {
|
|
3220
|
-
pluginRaw = await
|
|
3239
|
+
pluginRaw = await readFile9(pluginJsonPath, "utf-8");
|
|
3221
3240
|
pluginManifestPresent = true;
|
|
3222
3241
|
checks.push({
|
|
3223
3242
|
id: "plugin-manifest-present",
|
|
@@ -3267,7 +3286,7 @@ async function runCompatChecks(options) {
|
|
|
3267
3286
|
let packageRaw = "";
|
|
3268
3287
|
let packageJsonPresent = false;
|
|
3269
3288
|
try {
|
|
3270
|
-
packageRaw = await
|
|
3289
|
+
packageRaw = await readFile9(packageJsonPath, "utf-8");
|
|
3271
3290
|
packageJsonPresent = true;
|
|
3272
3291
|
} catch {
|
|
3273
3292
|
checks.push({
|
|
@@ -3338,7 +3357,7 @@ async function runCompatChecks(options) {
|
|
|
3338
3357
|
}
|
|
3339
3358
|
try {
|
|
3340
3359
|
await access(indexPath);
|
|
3341
|
-
const indexRaw = await
|
|
3360
|
+
const indexRaw = await readFile9(indexPath, "utf-8");
|
|
3342
3361
|
const structuralSource = stripCommentsAndStrings(indexRaw);
|
|
3343
3362
|
const hooks = parseHookRegistrations(indexRaw);
|
|
3344
3363
|
const missingLegacy = REQUIRED_HOOKS_LEGACY.filter((hook) => !hooks.has(hook));
|
|
@@ -3405,8 +3424,8 @@ async function runCompatChecks(options) {
|
|
|
3405
3424
|
}
|
|
3406
3425
|
|
|
3407
3426
|
// src/training-export/converter.ts
|
|
3408
|
-
import { lstat, readdir as
|
|
3409
|
-
import
|
|
3427
|
+
import { lstat, readdir as readdir6, readFile as readFile10, realpath as realpath2 } from "fs/promises";
|
|
3428
|
+
import path17 from "path";
|
|
3410
3429
|
function parseFrontmatter(raw) {
|
|
3411
3430
|
const match = raw.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);
|
|
3412
3431
|
if (!match) return null;
|
|
@@ -3457,13 +3476,13 @@ async function collectMarkdownFiles(dir, containmentRoot) {
|
|
|
3457
3476
|
if (dStat.isSymbolicLink()) return;
|
|
3458
3477
|
let entries;
|
|
3459
3478
|
try {
|
|
3460
|
-
entries = await
|
|
3479
|
+
entries = await readdir6(d, { withFileTypes: true });
|
|
3461
3480
|
} catch {
|
|
3462
3481
|
return;
|
|
3463
3482
|
}
|
|
3464
3483
|
const sorted = [...entries].sort((a, b) => a.name.localeCompare(b.name));
|
|
3465
3484
|
for (const entry of sorted) {
|
|
3466
|
-
const full =
|
|
3485
|
+
const full = path17.join(d, entry.name);
|
|
3467
3486
|
if (entry.isSymbolicLink()) continue;
|
|
3468
3487
|
if (entry.isDirectory()) {
|
|
3469
3488
|
await walk(full);
|
|
@@ -3477,7 +3496,7 @@ async function collectMarkdownFiles(dir, containmentRoot) {
|
|
|
3477
3496
|
if (st.nlink > 1) continue;
|
|
3478
3497
|
const real = await safeRealpath(full);
|
|
3479
3498
|
if (!real) continue;
|
|
3480
|
-
if (real !== containmentRoot && !real.startsWith(containmentRoot +
|
|
3499
|
+
if (real !== containmentRoot && !real.startsWith(containmentRoot + path17.sep)) {
|
|
3481
3500
|
continue;
|
|
3482
3501
|
}
|
|
3483
3502
|
files.push(full);
|
|
@@ -3527,11 +3546,11 @@ async function convertMemoriesToRecords(options) {
|
|
|
3527
3546
|
const { memoryDir } = options;
|
|
3528
3547
|
const containmentRoot = await safeRealpath(memoryDir);
|
|
3529
3548
|
if (!containmentRoot) return [];
|
|
3530
|
-
const factsDir =
|
|
3531
|
-
const correctionsDir =
|
|
3549
|
+
const factsDir = path17.join(memoryDir, "facts");
|
|
3550
|
+
const correctionsDir = path17.join(memoryDir, "corrections");
|
|
3532
3551
|
const dirs = [factsDir, correctionsDir];
|
|
3533
3552
|
if (options.includeEntities) {
|
|
3534
|
-
dirs.push(
|
|
3553
|
+
dirs.push(path17.join(memoryDir, "entities"));
|
|
3535
3554
|
}
|
|
3536
3555
|
const allFiles = [];
|
|
3537
3556
|
for (const dir of dirs) {
|
|
@@ -3542,7 +3561,7 @@ async function convertMemoriesToRecords(options) {
|
|
|
3542
3561
|
for (const filePath of allFiles) {
|
|
3543
3562
|
let raw;
|
|
3544
3563
|
try {
|
|
3545
|
-
raw = await
|
|
3564
|
+
raw = await readFile10(filePath, "utf-8");
|
|
3546
3565
|
} catch {
|
|
3547
3566
|
continue;
|
|
3548
3567
|
}
|
|
@@ -3580,55 +3599,6 @@ async function convertMemoriesToRecords(options) {
|
|
|
3580
3599
|
return records;
|
|
3581
3600
|
}
|
|
3582
3601
|
|
|
3583
|
-
// src/training-export/date-parse.ts
|
|
3584
|
-
var DAYS_IN_MONTH = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
|
|
3585
|
-
function isLeapYear(year) {
|
|
3586
|
-
return year % 4 === 0 && year % 100 !== 0 || year % 400 === 0;
|
|
3587
|
-
}
|
|
3588
|
-
function isCalendarDateValid(year, month, day) {
|
|
3589
|
-
if (!Number.isInteger(year) || !Number.isInteger(month) || !Number.isInteger(day)) {
|
|
3590
|
-
return false;
|
|
3591
|
-
}
|
|
3592
|
-
if (month < 1 || month > 12) return false;
|
|
3593
|
-
if (day < 1) return false;
|
|
3594
|
-
const maxDay = month === 2 && isLeapYear(year) ? 29 : DAYS_IN_MONTH[month];
|
|
3595
|
-
return day <= maxDay;
|
|
3596
|
-
}
|
|
3597
|
-
function parseStrictCliDate(value, flagName) {
|
|
3598
|
-
const shape = /^(\d{4})-(\d{2})-(\d{2})(?:T(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{1,9}))?)?(Z|[+-]\d{2}:\d{2})?)?$/;
|
|
3599
|
-
const match = value.match(shape);
|
|
3600
|
-
if (!match) {
|
|
3601
|
-
throw new Error(
|
|
3602
|
-
`Invalid ${flagName} value "${value}": expected ISO 8601 format (YYYY-MM-DD or YYYY-MM-DDTHH:mm:ss[.sss][Z|\xB1HH:MM]).`
|
|
3603
|
-
);
|
|
3604
|
-
}
|
|
3605
|
-
const year = Number(match[1]);
|
|
3606
|
-
const month = Number(match[2]);
|
|
3607
|
-
const day = Number(match[3]);
|
|
3608
|
-
if (!isCalendarDateValid(year, month, day)) {
|
|
3609
|
-
throw new Error(
|
|
3610
|
-
`Invalid ${flagName} value "${value}": date components overflow (e.g. month has fewer days). Provide a valid calendar date.`
|
|
3611
|
-
);
|
|
3612
|
-
}
|
|
3613
|
-
if (match[4] !== void 0) {
|
|
3614
|
-
const hour = Number(match[4]);
|
|
3615
|
-
const minute = Number(match[5]);
|
|
3616
|
-
const second = match[6] !== void 0 ? Number(match[6]) : 0;
|
|
3617
|
-
if (hour > 23 || minute > 59 || second > 59) {
|
|
3618
|
-
throw new Error(
|
|
3619
|
-
`Invalid ${flagName} value "${value}": time components out of range.`
|
|
3620
|
-
);
|
|
3621
|
-
}
|
|
3622
|
-
}
|
|
3623
|
-
const d = new Date(value);
|
|
3624
|
-
if (!Number.isFinite(d.getTime())) {
|
|
3625
|
-
throw new Error(
|
|
3626
|
-
`Invalid ${flagName} value "${value}". Provide an ISO 8601 date string (YYYY-MM-DD or YYYY-MM-DDTHH:mm:ss).`
|
|
3627
|
-
);
|
|
3628
|
-
}
|
|
3629
|
-
return d;
|
|
3630
|
-
}
|
|
3631
|
-
|
|
3632
3602
|
// src/training-export/registry.ts
|
|
3633
3603
|
var adapters2 = /* @__PURE__ */ new Map();
|
|
3634
3604
|
function registerTrainingExportAdapter(adapter) {
|
|
@@ -4114,6 +4084,19 @@ async function runVerifiedRecallSearchCliCommand(options) {
|
|
|
4114
4084
|
boxRecallDays: options.boxRecallDays
|
|
4115
4085
|
});
|
|
4116
4086
|
}
|
|
4087
|
+
function isNormalRetrievalVisibleMemory(memory) {
|
|
4088
|
+
return memory.frontmatter.status !== "forgotten";
|
|
4089
|
+
}
|
|
4090
|
+
async function filterNormalMemorySearchResults(results, storage) {
|
|
4091
|
+
const filtered = [];
|
|
4092
|
+
for (const result of results) {
|
|
4093
|
+
if (!result.path) continue;
|
|
4094
|
+
const memory = await storage.readMemoryByPath(result.path);
|
|
4095
|
+
if (!memory || !isNormalRetrievalVisibleMemory(memory)) continue;
|
|
4096
|
+
filtered.push(result);
|
|
4097
|
+
}
|
|
4098
|
+
return filtered;
|
|
4099
|
+
}
|
|
4117
4100
|
async function runSemanticRulePromoteCliCommand(options) {
|
|
4118
4101
|
return promoteSemanticRuleFromMemory({
|
|
4119
4102
|
memoryDir: options.memoryDir,
|
|
@@ -4123,7 +4106,7 @@ async function runSemanticRulePromoteCliCommand(options) {
|
|
|
4123
4106
|
});
|
|
4124
4107
|
}
|
|
4125
4108
|
async function runCompoundingPromoteCliCommand(options) {
|
|
4126
|
-
const { CompoundingEngine } = await import("./engine-
|
|
4109
|
+
const { CompoundingEngine } = await import("./engine-ICC2DSQF.js");
|
|
4127
4110
|
const config = parseConfig({
|
|
4128
4111
|
memoryDir: options.memoryDir,
|
|
4129
4112
|
qmdEnabled: false,
|
|
@@ -4537,10 +4520,10 @@ function effectivePolicyValuesForVersion(values, config) {
|
|
|
4537
4520
|
}
|
|
4538
4521
|
function policyVersionForValues(values, config) {
|
|
4539
4522
|
const normalized = effectivePolicyValuesForVersion(values, config);
|
|
4540
|
-
return
|
|
4523
|
+
return createHash("sha256").update(JSON.stringify(normalized)).digest("hex").slice(0, 12);
|
|
4541
4524
|
}
|
|
4542
4525
|
async function readRuntimePolicySnapshot2(config, fileName) {
|
|
4543
|
-
const filePath =
|
|
4526
|
+
const filePath = path18.join(config.memoryDir, "state", fileName);
|
|
4544
4527
|
const snapshot = await readRuntimePolicySnapshot(filePath, {
|
|
4545
4528
|
maxStaleDecayThreshold: config.lifecycleArchiveDecayThreshold
|
|
4546
4529
|
});
|
|
@@ -4568,6 +4551,38 @@ function parseSinceDurationMs(since) {
|
|
|
4568
4551
|
if (unit === "h") return amount * 60 * 60 * 1e3;
|
|
4569
4552
|
return amount * 24 * 60 * 60 * 1e3;
|
|
4570
4553
|
}
|
|
4554
|
+
function parseDurationToMs(raw) {
|
|
4555
|
+
const trimmed = raw.trim();
|
|
4556
|
+
if (/^\d+$/.test(trimmed)) {
|
|
4557
|
+
const days = Number.parseInt(trimmed, 10);
|
|
4558
|
+
return Number.isFinite(days) && days > 0 ? days * 864e5 : null;
|
|
4559
|
+
}
|
|
4560
|
+
const iso = trimmed.toUpperCase();
|
|
4561
|
+
if (!iso.startsWith("P")) return null;
|
|
4562
|
+
const match = /^P(?:(\d+)Y)?(?:(\d+)M)?(?:(\d+)W)?(?:(\d+)D)?(?:T(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)S)?)?$/.exec(iso);
|
|
4563
|
+
if (!match || match[1] === void 0 && match[2] === void 0 && match[3] === void 0 && match[4] === void 0 && match[5] === void 0 && match[6] === void 0 && match[7] === void 0) {
|
|
4564
|
+
return null;
|
|
4565
|
+
}
|
|
4566
|
+
if (iso.includes("T") && match[5] === void 0 && match[6] === void 0 && match[7] === void 0) {
|
|
4567
|
+
return null;
|
|
4568
|
+
}
|
|
4569
|
+
let totalMs = 0;
|
|
4570
|
+
if (match[1]) totalMs += Number.parseInt(match[1], 10) * 365 * 864e5;
|
|
4571
|
+
if (match[2]) totalMs += Number.parseInt(match[2], 10) * 30 * 864e5;
|
|
4572
|
+
if (match[3]) totalMs += Number.parseInt(match[3], 10) * 7 * 864e5;
|
|
4573
|
+
if (match[4]) totalMs += Number.parseInt(match[4], 10) * 864e5;
|
|
4574
|
+
if (match[5]) totalMs += Number.parseInt(match[5], 10) * 60 * 60 * 1e3;
|
|
4575
|
+
if (match[6]) totalMs += Number.parseInt(match[6], 10) * 60 * 1e3;
|
|
4576
|
+
if (match[7]) totalMs += Number.parseInt(match[7], 10) * 1e3;
|
|
4577
|
+
return Number.isFinite(totalMs) && totalMs > 0 ? totalMs : null;
|
|
4578
|
+
}
|
|
4579
|
+
var NON_FATAL_PURGE_ERROR_IDS = /* @__PURE__ */ new Set([
|
|
4580
|
+
"(purge-audit)",
|
|
4581
|
+
"(fact-hash-index)"
|
|
4582
|
+
]);
|
|
4583
|
+
function hasDestructivePurgeFailures(errors) {
|
|
4584
|
+
return errors.some((error) => !NON_FATAL_PURGE_ERROR_IDS.has(error.id));
|
|
4585
|
+
}
|
|
4571
4586
|
function resolvePolicySignalNamespaces(orchestrator) {
|
|
4572
4587
|
const names = /* @__PURE__ */ new Set([orchestrator.config.defaultNamespace]);
|
|
4573
4588
|
if (orchestrator.config.namespacesEnabled) {
|
|
@@ -5097,7 +5112,7 @@ async function withTimeout(promise, timeoutMs, timeoutMessage) {
|
|
|
5097
5112
|
}
|
|
5098
5113
|
async function runReplayCliCommand(orchestrator, options) {
|
|
5099
5114
|
const extractionIdleTimeoutMs = Number.isFinite(options.extractionIdleTimeoutMs) ? Math.max(1e3, Math.floor(options.extractionIdleTimeoutMs)) : 15 * 6e4;
|
|
5100
|
-
const inputRaw = await
|
|
5115
|
+
const inputRaw = await readFile11(options.inputPath, "utf-8");
|
|
5101
5116
|
const registry = buildReplayNormalizerRegistry([
|
|
5102
5117
|
openclawReplayNormalizer,
|
|
5103
5118
|
claudeReplayNormalizer,
|
|
@@ -5189,7 +5204,7 @@ async function runBulkImportCliCommand(opts) {
|
|
|
5189
5204
|
"Bulk import persistence is not wired: no ingestBatch callback was provided by the host CLI. Use --dry-run to validate without persisting, or invoke via `openclaw engram bulk-import` which supplies the orchestrator-backed ingestion path."
|
|
5190
5205
|
);
|
|
5191
5206
|
}
|
|
5192
|
-
const inputRaw = await
|
|
5207
|
+
const inputRaw = await readFile11(opts.file, "utf-8");
|
|
5193
5208
|
let inputParsed;
|
|
5194
5209
|
try {
|
|
5195
5210
|
inputParsed = JSON.parse(inputRaw);
|
|
@@ -5253,7 +5268,7 @@ async function runBulkImportCliCommand(opts) {
|
|
|
5253
5268
|
async function getPluginVersion() {
|
|
5254
5269
|
try {
|
|
5255
5270
|
const pkgPath = new URL("../package.json", import.meta.url);
|
|
5256
|
-
const raw = await
|
|
5271
|
+
const raw = await readFile11(pkgPath, "utf-8");
|
|
5257
5272
|
const parsed = JSON.parse(raw);
|
|
5258
5273
|
return parsed.version ?? "unknown";
|
|
5259
5274
|
} catch {
|
|
@@ -5277,24 +5292,24 @@ async function resolveMemoryDirForNamespace(orchestrator, namespace, options) {
|
|
|
5277
5292
|
}
|
|
5278
5293
|
return orchestrator.config.memoryDir;
|
|
5279
5294
|
}
|
|
5280
|
-
const candidate =
|
|
5295
|
+
const candidate = path18.join(orchestrator.config.memoryDir, "namespaces", ns);
|
|
5281
5296
|
if (ns === orchestrator.config.defaultNamespace) {
|
|
5282
5297
|
return await exists(candidate) ? candidate : orchestrator.config.memoryDir;
|
|
5283
5298
|
}
|
|
5284
5299
|
return candidate;
|
|
5285
5300
|
}
|
|
5286
5301
|
async function walkMemoryMarkdownFiles(memoryDir, visit) {
|
|
5287
|
-
const roots = [
|
|
5302
|
+
const roots = [path18.join(memoryDir, "facts"), path18.join(memoryDir, "corrections")];
|
|
5288
5303
|
const walk = async (dir) => {
|
|
5289
5304
|
let entries;
|
|
5290
5305
|
try {
|
|
5291
|
-
entries = await
|
|
5306
|
+
entries = await readdir7(dir, { withFileTypes: true });
|
|
5292
5307
|
} catch {
|
|
5293
5308
|
return;
|
|
5294
5309
|
}
|
|
5295
5310
|
for (const entry of entries) {
|
|
5296
5311
|
const entryName = typeof entry.name === "string" ? entry.name : entry.name.toString("utf-8");
|
|
5297
|
-
const fullPath =
|
|
5312
|
+
const fullPath = path18.join(dir, entryName);
|
|
5298
5313
|
if (entry.isDirectory()) {
|
|
5299
5314
|
await walk(fullPath);
|
|
5300
5315
|
continue;
|
|
@@ -5318,7 +5333,7 @@ async function readAllMemoryFiles(memoryDir) {
|
|
|
5318
5333
|
const out = [];
|
|
5319
5334
|
await walkMemoryMarkdownFiles(memoryDir, async (fullPath) => {
|
|
5320
5335
|
try {
|
|
5321
|
-
const raw = await
|
|
5336
|
+
const raw = await readFile11(fullPath, "utf-8");
|
|
5322
5337
|
const parsed = raw.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
|
|
5323
5338
|
if (!parsed) return;
|
|
5324
5339
|
const fmRaw = parsed[1];
|
|
@@ -5502,7 +5517,7 @@ function buildConversationIndexRebuildAction(orchestrator) {
|
|
|
5502
5517
|
console.log("OK");
|
|
5503
5518
|
};
|
|
5504
5519
|
}
|
|
5505
|
-
function registerCli(api, orchestrator) {
|
|
5520
|
+
function registerCli(api, orchestrator, registerOptions = {}) {
|
|
5506
5521
|
api.registerCli(
|
|
5507
5522
|
({ program }) => {
|
|
5508
5523
|
const cmd = program.command("engram").description("Engram local memory commands");
|
|
@@ -5628,59 +5643,262 @@ function registerCli(api, orchestrator) {
|
|
|
5628
5643
|
}
|
|
5629
5644
|
if (!reportHasMachineReadableOutput(options)) console.log("OK");
|
|
5630
5645
|
});
|
|
5631
|
-
cmd.command("
|
|
5646
|
+
const tierCmd = cmd.command("tier").description(
|
|
5647
|
+
"Tier-distribution visibility (issue #686). `tier list` summarizes hot/cold counts and per-status breakdown; `tier explain <id>` shows the value-score components and tier-transition decision for a single memory."
|
|
5648
|
+
);
|
|
5649
|
+
tierCmd.command("list").description("Summarize tier distribution across all memories").option("--json", "Emit machine-readable JSON only").action(async (...args) => {
|
|
5632
5650
|
const options = args[0] ?? {};
|
|
5633
|
-
const
|
|
5651
|
+
const { summarizeTiers, formatTierSummaryText } = await import("./tier-stats-62ZVDFKS.js");
|
|
5652
|
+
const summary = await summarizeTiers(orchestrator.storage);
|
|
5634
5653
|
if (reportHasMachineReadableOutput(options)) {
|
|
5635
|
-
console.log(JSON.stringify(
|
|
5654
|
+
console.log(JSON.stringify(summary, null, 2));
|
|
5636
5655
|
} else {
|
|
5637
|
-
console.log(
|
|
5656
|
+
console.log(formatTierSummaryText(summary));
|
|
5638
5657
|
}
|
|
5639
|
-
|
|
5658
|
+
});
|
|
5659
|
+
tierCmd.command("explain").description("Explain the tier-transition decision for a single memory").argument("<id>", "Memory id to explain").option("--json", "Emit machine-readable JSON only").action(async (...args) => {
|
|
5660
|
+
const idArg = typeof args[0] === "string" ? args[0] : "";
|
|
5661
|
+
const options = args[1] ?? {};
|
|
5662
|
+
const { explainTierForMemory, formatTierExplainText } = await import("./tier-stats-62ZVDFKS.js");
|
|
5663
|
+
try {
|
|
5664
|
+
const explain = await explainTierForMemory(
|
|
5665
|
+
orchestrator.storage,
|
|
5666
|
+
idArg,
|
|
5667
|
+
orchestrator.config
|
|
5668
|
+
);
|
|
5669
|
+
if (reportHasMachineReadableOutput(options)) {
|
|
5670
|
+
console.log(JSON.stringify(explain, null, 2));
|
|
5671
|
+
} else {
|
|
5672
|
+
console.log(formatTierExplainText(explain));
|
|
5673
|
+
}
|
|
5674
|
+
} catch (err) {
|
|
5675
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
5676
|
+
if (reportHasMachineReadableOutput(options)) {
|
|
5677
|
+
console.log(JSON.stringify({ ok: false, error: message }, null, 2));
|
|
5678
|
+
} else {
|
|
5679
|
+
console.error(
|
|
5680
|
+
message.startsWith("tier explain:") ? message : `tier explain: ${message}`
|
|
5681
|
+
);
|
|
5682
|
+
}
|
|
5640
5683
|
process.exitCode = 1;
|
|
5641
|
-
return;
|
|
5642
5684
|
}
|
|
5643
|
-
if (!reportHasMachineReadableOutput(options)) console.log("OK");
|
|
5644
5685
|
});
|
|
5645
|
-
cmd.command("
|
|
5646
|
-
|
|
5647
|
-
|
|
5648
|
-
|
|
5649
|
-
|
|
5650
|
-
|
|
5651
|
-
|
|
5686
|
+
cmd.command("forget").description(
|
|
5687
|
+
"Forget a memory by id (issue #686 PR 4/6). Soft-delete: sets status='forgotten' and stamps forgottenAt; the file stays on disk and the act is reversible by editing the YAML directly. Forgotten memories are excluded from recall, browse, and entity attribution."
|
|
5688
|
+
).argument("<id>", "Memory id (frontmatter `id`) to forget").option(
|
|
5689
|
+
"--reason <text>",
|
|
5690
|
+
"Optional human-readable reason captured in YAML and the lifecycle ledger"
|
|
5691
|
+
).option("--json", "Emit machine-readable JSON only").action(async (...args) => {
|
|
5692
|
+
const idArg = typeof args[0] === "string" ? args[0] : "";
|
|
5693
|
+
const options = args[1] ?? {};
|
|
5694
|
+
const reason = typeof options.reason === "string" && options.reason.trim().length > 0 ? options.reason.trim() : void 0;
|
|
5695
|
+
const { forgetMemory } = await import("./forget-PLR6J5DN.js");
|
|
5696
|
+
try {
|
|
5697
|
+
const result = await forgetMemory(orchestrator.storage, {
|
|
5698
|
+
id: idArg,
|
|
5699
|
+
...reason !== void 0 ? { reason } : {}
|
|
5700
|
+
});
|
|
5701
|
+
if (reportHasMachineReadableOutput(options)) {
|
|
5702
|
+
console.log(JSON.stringify(result, null, 2));
|
|
5703
|
+
} else {
|
|
5704
|
+
console.log(`forgot ${result.id}`);
|
|
5705
|
+
console.log(` path: ${result.path}`);
|
|
5706
|
+
console.log(` prior status: ${result.priorStatus}`);
|
|
5707
|
+
console.log(` forgotten at: ${result.forgottenAt}`);
|
|
5708
|
+
if (result.reason.length > 0) {
|
|
5709
|
+
console.log(` reason: ${result.reason}`);
|
|
5710
|
+
}
|
|
5711
|
+
console.log(
|
|
5712
|
+
"Forgotten memories are excluded from recall + browse. Edit the YAML to restore."
|
|
5713
|
+
);
|
|
5714
|
+
}
|
|
5715
|
+
} catch (err) {
|
|
5716
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
5717
|
+
if (reportHasMachineReadableOutput(options)) {
|
|
5718
|
+
console.log(JSON.stringify({ ok: false, error: message }, null, 2));
|
|
5719
|
+
} else {
|
|
5720
|
+
console.error(`forget: ${message}`);
|
|
5721
|
+
}
|
|
5722
|
+
process.exitCode = 1;
|
|
5652
5723
|
}
|
|
5653
|
-
if (!reportHasMachineReadableOutput(options)) console.log("OK");
|
|
5654
5724
|
});
|
|
5655
|
-
|
|
5656
|
-
|
|
5657
|
-
|
|
5658
|
-
|
|
5659
|
-
|
|
5725
|
+
cmd.command("purge").description(
|
|
5726
|
+
"Hard-delete memories by age + tier (issue #686 retention-completion). Removes files from disk, removes from QMD index, and logs to the observation ledger. Requires --confirm yes to execute. Defaults to --dry-run when --confirm is absent."
|
|
5727
|
+
).option(
|
|
5728
|
+
"--older-than <duration>",
|
|
5729
|
+
"Delete memories older than this duration. Accepts ISO 8601 durations (e.g. P1Y, P90D) or plain numbers of days (e.g. 365)."
|
|
5730
|
+
).option(
|
|
5731
|
+
"--tier <tier>",
|
|
5732
|
+
"Which tier to purge: 'cold' (default) or 'all'"
|
|
5733
|
+
).option(
|
|
5734
|
+
"--forgotten-only",
|
|
5735
|
+
"Only purge memories with status=forgotten"
|
|
5736
|
+
).option("--dry-run", "Report candidates without deleting (default when --confirm absent)").option(
|
|
5737
|
+
"--confirm <value>",
|
|
5738
|
+
"Must be the literal string 'yes' to execute mutations"
|
|
5739
|
+
).option("--json", "Emit machine-readable JSON only").action(async (...args) => {
|
|
5740
|
+
const options = args[0] ?? {};
|
|
5741
|
+
const olderThanRaw = options.olderThan ?? options["older-than"];
|
|
5742
|
+
if (typeof olderThanRaw !== "string" || olderThanRaw.trim().length === 0) {
|
|
5743
|
+
const msg = "purge: --older-than <duration> is required (e.g. --older-than P1Y or --older-than 365)";
|
|
5744
|
+
if (reportHasMachineReadableOutput(options)) {
|
|
5745
|
+
console.log(JSON.stringify({ ok: false, error: msg }, null, 2));
|
|
5746
|
+
} else {
|
|
5747
|
+
console.error(msg);
|
|
5748
|
+
}
|
|
5749
|
+
process.exitCode = 1;
|
|
5660
5750
|
return;
|
|
5661
5751
|
}
|
|
5662
|
-
|
|
5663
|
-
|
|
5664
|
-
|
|
5665
|
-
|
|
5666
|
-
|
|
5667
|
-
|
|
5668
|
-
|
|
5669
|
-
|
|
5670
|
-
|
|
5671
|
-
|
|
5752
|
+
const olderThanMs = parseDurationToMs(olderThanRaw.trim());
|
|
5753
|
+
if (olderThanMs === null || olderThanMs <= 0) {
|
|
5754
|
+
const msg = `purge: cannot parse duration '${olderThanRaw}'. Use ISO 8601 (P1Y, P90D, P30D) or plain days (365).`;
|
|
5755
|
+
if (reportHasMachineReadableOutput(options)) {
|
|
5756
|
+
console.log(JSON.stringify({ ok: false, error: msg }, null, 2));
|
|
5757
|
+
} else {
|
|
5758
|
+
console.error(msg);
|
|
5759
|
+
}
|
|
5760
|
+
process.exitCode = 1;
|
|
5761
|
+
return;
|
|
5672
5762
|
}
|
|
5673
|
-
|
|
5674
|
-
|
|
5675
|
-
|
|
5676
|
-
|
|
5677
|
-
|
|
5678
|
-
|
|
5679
|
-
|
|
5680
|
-
|
|
5681
|
-
|
|
5682
|
-
|
|
5683
|
-
|
|
5763
|
+
const tierRaw = typeof options.tier === "string" ? options.tier.trim() : "cold";
|
|
5764
|
+
if (tierRaw !== "cold" && tierRaw !== "all") {
|
|
5765
|
+
const msg = `purge: invalid --tier '${tierRaw}'. Valid values: cold, all`;
|
|
5766
|
+
if (reportHasMachineReadableOutput(options)) {
|
|
5767
|
+
console.log(JSON.stringify({ ok: false, error: msg }, null, 2));
|
|
5768
|
+
} else {
|
|
5769
|
+
console.error(msg);
|
|
5770
|
+
}
|
|
5771
|
+
process.exitCode = 1;
|
|
5772
|
+
return;
|
|
5773
|
+
}
|
|
5774
|
+
const confirmValue = options.confirm;
|
|
5775
|
+
const hasDryRunFlag = options.dryRun === true || options["dry-run"] === true;
|
|
5776
|
+
if (confirmValue !== void 0 && confirmValue !== "yes") {
|
|
5777
|
+
const msg = 'purge: --confirm must be exactly "yes" to execute mutations. Run with --dry-run to preview candidates without deleting.';
|
|
5778
|
+
if (reportHasMachineReadableOutput(options)) {
|
|
5779
|
+
console.log(JSON.stringify({ ok: false, error: msg }, null, 2));
|
|
5780
|
+
} else {
|
|
5781
|
+
console.error(msg);
|
|
5782
|
+
}
|
|
5783
|
+
process.exitCode = 1;
|
|
5784
|
+
return;
|
|
5785
|
+
}
|
|
5786
|
+
const confirmed = confirmValue === "yes";
|
|
5787
|
+
const dryRun = hasDryRunFlag || !confirmed;
|
|
5788
|
+
const { purgeMemories } = await import("./purge-6ATBGT77.js");
|
|
5789
|
+
try {
|
|
5790
|
+
const result = await purgeMemories({
|
|
5791
|
+
storage: orchestrator.storage,
|
|
5792
|
+
olderThanMs,
|
|
5793
|
+
tier: tierRaw,
|
|
5794
|
+
forgottenOnly: options.forgottenOnly === true || options["forgotten-only"] === true,
|
|
5795
|
+
dryRun,
|
|
5796
|
+
qmd: confirmed ? orchestrator.qmd : void 0,
|
|
5797
|
+
hotCollection: orchestrator.config.qmdCollection,
|
|
5798
|
+
coldCollection: orchestrator.config.qmdColdCollection,
|
|
5799
|
+
afterFactHashRemoval: () => orchestrator.invalidateLiveContentHashIndex()
|
|
5800
|
+
});
|
|
5801
|
+
const hasDeleteFailures = hasDestructivePurgeFailures(result.errors);
|
|
5802
|
+
if (reportHasMachineReadableOutput(options)) {
|
|
5803
|
+
console.log(JSON.stringify(result, null, 2));
|
|
5804
|
+
if (!result.dryRun && hasDeleteFailures) {
|
|
5805
|
+
process.exitCode = 1;
|
|
5806
|
+
}
|
|
5807
|
+
} else {
|
|
5808
|
+
if (result.dryRun) {
|
|
5809
|
+
console.log(`=== Purge dry-run: ${result.candidates.length} candidate(s) would be deleted ===`);
|
|
5810
|
+
} else {
|
|
5811
|
+
const absentPart = result.alreadyAbsentCount > 0 ? `, ${result.alreadyAbsentCount} already absent` : "";
|
|
5812
|
+
console.log(`=== Purge complete: ${result.purgedCount} deleted${absentPart}, ${result.errorCount} error(s) ===`);
|
|
5813
|
+
}
|
|
5814
|
+
console.log(` tier: ${result.tier}`);
|
|
5815
|
+
console.log(` older-than: ${olderThanRaw} (${Math.round(olderThanMs / 864e5)}d)`);
|
|
5816
|
+
if (result.candidates.length === 0) {
|
|
5817
|
+
console.log(" No candidates found.");
|
|
5818
|
+
} else {
|
|
5819
|
+
for (const c of result.candidates.slice(0, 20)) {
|
|
5820
|
+
console.log(` ${c.id} [${c.tier}] status=${c.status} age=${Math.round(c.ageMs / 864e5)}d ${c.path}`);
|
|
5821
|
+
}
|
|
5822
|
+
if (result.candidates.length > 20) {
|
|
5823
|
+
console.log(` ... and ${result.candidates.length - 20} more`);
|
|
5824
|
+
}
|
|
5825
|
+
}
|
|
5826
|
+
if (!result.dryRun && result.errors.length > 0) {
|
|
5827
|
+
console.error(` ${hasDeleteFailures ? "Errors" : "Warnings"} (${result.errors.length}):`);
|
|
5828
|
+
for (const e of result.errors) {
|
|
5829
|
+
console.error(` ${e.id}: ${e.error}`);
|
|
5830
|
+
}
|
|
5831
|
+
if (hasDeleteFailures) {
|
|
5832
|
+
process.exitCode = 1;
|
|
5833
|
+
}
|
|
5834
|
+
}
|
|
5835
|
+
if (result.dryRun) {
|
|
5836
|
+
console.log("\nRe-run with --confirm yes to execute.");
|
|
5837
|
+
}
|
|
5838
|
+
}
|
|
5839
|
+
} catch (err) {
|
|
5840
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
5841
|
+
if (reportHasMachineReadableOutput(options)) {
|
|
5842
|
+
console.log(JSON.stringify({ ok: false, error: message }, null, 2));
|
|
5843
|
+
} else {
|
|
5844
|
+
console.error(`purge: ${message}`);
|
|
5845
|
+
}
|
|
5846
|
+
process.exitCode = 1;
|
|
5847
|
+
}
|
|
5848
|
+
});
|
|
5849
|
+
cmd.command("config-review").description("Review Engram config defaults, recommendations, and contradictory settings").option("--json", "Emit machine-readable JSON only").action(async (...args) => {
|
|
5850
|
+
const options = args[0] ?? {};
|
|
5851
|
+
const report = await runOperatorConfigReview({ orchestrator });
|
|
5852
|
+
if (reportHasMachineReadableOutput(options)) {
|
|
5853
|
+
console.log(JSON.stringify(report, null, 2));
|
|
5854
|
+
} else {
|
|
5855
|
+
console.log(formatOperatorConfigReviewCli(report));
|
|
5856
|
+
}
|
|
5857
|
+
if (!report.ok) {
|
|
5858
|
+
process.exitCode = 1;
|
|
5859
|
+
return;
|
|
5860
|
+
}
|
|
5861
|
+
if (!reportHasMachineReadableOutput(options)) console.log("OK");
|
|
5862
|
+
});
|
|
5863
|
+
cmd.command("inventory").description("Report namespace, memory, review, and storage inventory").option("--json", "Emit machine-readable JSON only").action(async (...args) => {
|
|
5864
|
+
const options = args[0] ?? {};
|
|
5865
|
+
const report = await runOperatorInventory({ orchestrator });
|
|
5866
|
+
if (reportHasMachineReadableOutput(options)) {
|
|
5867
|
+
console.log(JSON.stringify(report, null, 2));
|
|
5868
|
+
} else {
|
|
5869
|
+
console.log(formatOperatorInventoryCli(report));
|
|
5870
|
+
}
|
|
5871
|
+
if (!reportHasMachineReadableOutput(options)) console.log("OK");
|
|
5872
|
+
});
|
|
5873
|
+
const namespacesCmd = cmd.command("namespaces").description("Manage namespace roots, migration, and verification");
|
|
5874
|
+
namespacesCmd.command("ls").description("List configured namespaces and their storage roots").action(async () => {
|
|
5875
|
+
const namespaces = await listNamespaces({ config: orchestrator.config });
|
|
5876
|
+
if (namespaces.length === 0) {
|
|
5877
|
+
console.log("No namespaces configured.");
|
|
5878
|
+
return;
|
|
5879
|
+
}
|
|
5880
|
+
console.log("=== Engram Namespaces ===\n");
|
|
5881
|
+
for (const entry of namespaces) {
|
|
5882
|
+
console.log(
|
|
5883
|
+
`${entry.namespace}
|
|
5884
|
+
root: ${entry.rootDir}
|
|
5885
|
+
exists: ${entry.exists ? "yes" : "no"}
|
|
5886
|
+
legacy-root: ${entry.usesLegacyRoot ? "yes" : "no"}
|
|
5887
|
+
has-data: ${entry.hasMemoryData ? "yes" : "no"}
|
|
5888
|
+
collection: ${entry.collection}`
|
|
5889
|
+
);
|
|
5890
|
+
}
|
|
5891
|
+
});
|
|
5892
|
+
namespacesCmd.command("verify").description("Verify namespace roots and detect legacy root drift").action(async () => {
|
|
5893
|
+
const report = await verifyNamespaces({ config: orchestrator.config });
|
|
5894
|
+
console.log("=== Namespace Verification ===\n");
|
|
5895
|
+
for (const entry of report.namespaces) {
|
|
5896
|
+
console.log(
|
|
5897
|
+
`${entry.namespace}
|
|
5898
|
+
root: ${entry.rootDir}
|
|
5899
|
+
exists: ${entry.exists ? "yes" : "no"}
|
|
5900
|
+
legacy-root: ${entry.usesLegacyRoot ? "yes" : "no"}
|
|
5901
|
+
has-data: ${entry.hasMemoryData ? "yes" : "no"}
|
|
5684
5902
|
collection: ${entry.collection}`
|
|
5685
5903
|
);
|
|
5686
5904
|
}
|
|
@@ -5712,7 +5930,7 @@ function registerCli(api, orchestrator) {
|
|
|
5712
5930
|
if (plan.moved.length > 0) {
|
|
5713
5931
|
console.log("\nEntries:");
|
|
5714
5932
|
for (const move of plan.moved) {
|
|
5715
|
-
console.log(`- ${
|
|
5933
|
+
console.log(`- ${path18.basename(move.from)}`);
|
|
5716
5934
|
}
|
|
5717
5935
|
}
|
|
5718
5936
|
if (dryRun) {
|
|
@@ -5809,12 +6027,13 @@ function registerCli(api, orchestrator) {
|
|
|
5809
6027
|
}
|
|
5810
6028
|
console.log("OK");
|
|
5811
6029
|
});
|
|
5812
|
-
cmd.command("backup").description("Create a timestamped backup of the Remnic memory directory").option("--out-dir <dir>", "Backup root directory").option("--retention-days <n>", "Delete backups older than N days", "0").option("--include-transcripts", "Include transcripts (default false)").option("--namespace <ns>", "Namespace to back up (v3.0+, default: config defaultNamespace)", "").action(async (...args) => {
|
|
6030
|
+
cmd.command("backup").description("Create a timestamped backup of the Remnic memory directory").option("--out-dir <dir>", "Backup root directory").option("--retention-days <n>", "Delete backups older than N days", "0").option("--include-transcripts", "Include transcripts (default false)").option("--namespace <ns>", "Namespace to back up (v3.0+, default: config defaultNamespace)", "").option("--encrypt", "Encrypt the backup archive with the secure-store master key (must be unlocked)").action(async (...args) => {
|
|
5813
6031
|
const options = args[0] ?? {};
|
|
5814
6032
|
const outDir = options.outDir ? String(options.outDir) : "";
|
|
5815
6033
|
const retentionDays = parseInt(String(options.retentionDays ?? "0"), 10);
|
|
5816
6034
|
const includeTranscripts = options.includeTranscripts === true;
|
|
5817
6035
|
const namespace = options.namespace ? String(options.namespace) : "";
|
|
6036
|
+
const doEncrypt = options.encrypt === true;
|
|
5818
6037
|
if (!outDir) {
|
|
5819
6038
|
console.log("Missing --out-dir. Example: openclaw engram backup --out-dir /tmp/engram-backups");
|
|
5820
6039
|
return;
|
|
@@ -5823,15 +6042,374 @@ function registerCli(api, orchestrator) {
|
|
|
5823
6042
|
const memoryDir = await resolveMemoryDirForNamespace(orchestrator, namespace, {
|
|
5824
6043
|
rejectUnsupportedOverride: true
|
|
5825
6044
|
});
|
|
5826
|
-
await backupMemoryDir({
|
|
6045
|
+
const outPath = await backupMemoryDir({
|
|
5827
6046
|
memoryDir,
|
|
5828
6047
|
outDir,
|
|
5829
6048
|
retentionDays: Number.isFinite(retentionDays) ? retentionDays : void 0,
|
|
5830
6049
|
includeTranscripts,
|
|
5831
|
-
pluginVersion
|
|
6050
|
+
pluginVersion,
|
|
6051
|
+
encrypt: doEncrypt
|
|
6052
|
+
});
|
|
6053
|
+
if (doEncrypt) {
|
|
6054
|
+
console.log(`Encrypted backup: ${outPath}`);
|
|
6055
|
+
} else {
|
|
6056
|
+
console.log(`Backup: ${outPath}`);
|
|
6057
|
+
}
|
|
6058
|
+
console.log("OK");
|
|
6059
|
+
});
|
|
6060
|
+
const capsuleCmd = cmd.command("capsule").description("Portable capsule archive export / import (issue #676, #690)");
|
|
6061
|
+
capsuleCmd.command("export").description(
|
|
6062
|
+
"Export the memory directory as a portable .capsule.json.gz archive. Pass --encrypt to seal the archive with the secure-store master key."
|
|
6063
|
+
).option("--name <id>", "Capsule id (alphanumeric + dashes, \u2264 64 chars)").option("--out-dir <dir>", "Output directory (default: <memoryDir>/.capsules)").option("--since <iso8601>", "Only include files modified on or after this date").option("--include-kinds <kinds>", "Comma-separated top-level dir allow-list (e.g. facts,entities)").option("--peer-ids <ids>", "Comma-separated peer id allow-list for the peers/ subtree").option("--include-transcripts", "Include transcripts (excluded by default)").option("--encrypt", "Encrypt the output archive with the secure-store master key (must be unlocked)").option("--namespace <ns>", "Namespace (v3.0+, default: config defaultNamespace)", "").action(async (...args) => {
|
|
6064
|
+
const options = args[0] ?? {};
|
|
6065
|
+
const name = options.name ? String(options.name) : "";
|
|
6066
|
+
if (!name) {
|
|
6067
|
+
console.error("--name is required. Example: remnic capsule export --name my-capsule");
|
|
6068
|
+
process.exitCode = 1;
|
|
6069
|
+
return;
|
|
6070
|
+
}
|
|
6071
|
+
const namespace = options.namespace ? String(options.namespace) : "";
|
|
6072
|
+
const doEncrypt = options.encrypt === true;
|
|
6073
|
+
const outDir = options.outDir ? String(options.outDir) : void 0;
|
|
6074
|
+
const since = options.since ? String(options.since) : void 0;
|
|
6075
|
+
const includeKinds = options.includeKinds ? String(options.includeKinds).split(",").map((s) => s.trim()).filter(Boolean) : void 0;
|
|
6076
|
+
const peerIds = options.peerIds ? String(options.peerIds).split(",").map((s) => s.trim()).filter(Boolean) : void 0;
|
|
6077
|
+
const includeTranscripts = options.includeTranscripts === true;
|
|
6078
|
+
const pluginVersion = await getPluginVersion();
|
|
6079
|
+
const memoryDir = await resolveMemoryDirForNamespace(orchestrator, namespace, {
|
|
6080
|
+
rejectUnsupportedOverride: true
|
|
6081
|
+
});
|
|
6082
|
+
const { exportCapsule } = await import("./capsule-export-NZQPOTQ4.js");
|
|
6083
|
+
const result = await exportCapsule({
|
|
6084
|
+
name,
|
|
6085
|
+
root: memoryDir,
|
|
6086
|
+
since,
|
|
6087
|
+
// Pass `includeKinds` only when the user explicitly provided it.
|
|
6088
|
+
// Do NOT merge transcripts into an explicit list here: doing so would
|
|
6089
|
+
// produce a hard-coded allow-list that silently drops other valid
|
|
6090
|
+
// memory dirs (peers/, forks/, etc.). Instead, use `includeTranscripts`
|
|
6091
|
+
// so the exporter adds transcripts while keeping the default "all dirs"
|
|
6092
|
+
// walk. (Cursor / #747)
|
|
6093
|
+
includeKinds,
|
|
6094
|
+
includeTranscripts,
|
|
6095
|
+
peerIds,
|
|
6096
|
+
outDir,
|
|
6097
|
+
pluginVersion,
|
|
6098
|
+
encrypt: doEncrypt,
|
|
6099
|
+
memoryDir: doEncrypt ? memoryDir : void 0
|
|
6100
|
+
});
|
|
6101
|
+
console.log(`Archive: ${result.archivePath}`);
|
|
6102
|
+
console.log(`Manifest: ${result.manifestPath}`);
|
|
6103
|
+
if (result.encryptedArchivePath) {
|
|
6104
|
+
console.log(`Encrypted: yes`);
|
|
6105
|
+
}
|
|
6106
|
+
console.log("OK");
|
|
6107
|
+
});
|
|
6108
|
+
capsuleCmd.command("import").description(
|
|
6109
|
+
"Import a capsule archive into the memory directory. Auto-detects encrypted archives (REMNIC-ENC header); requires --encrypt-key-dir or the memory dir to have an unlocked secure-store."
|
|
6110
|
+
).argument("<archive>", "Path to the .capsule.json.gz (or .enc) archive").option("--mode <mode>", "Conflict mode: skip (default), overwrite, fork", "skip").option("--namespace <ns>", "Target namespace (v3.0+, default: config defaultNamespace)", "").action(async (...args) => {
|
|
6111
|
+
const archivePath = args[0] ? String(args[0]) : "";
|
|
6112
|
+
const options = args[1] ?? {};
|
|
6113
|
+
if (!archivePath) {
|
|
6114
|
+
console.error("Usage: remnic capsule import <archive>");
|
|
6115
|
+
process.exitCode = 1;
|
|
6116
|
+
return;
|
|
6117
|
+
}
|
|
6118
|
+
const mode = options.mode ? String(options.mode) : "skip";
|
|
6119
|
+
if (mode !== "skip" && mode !== "overwrite" && mode !== "fork") {
|
|
6120
|
+
console.error(`Invalid --mode '${mode}'. Expected: skip, overwrite, fork`);
|
|
6121
|
+
process.exitCode = 1;
|
|
6122
|
+
return;
|
|
6123
|
+
}
|
|
6124
|
+
const namespace = options.namespace ? String(options.namespace) : "";
|
|
6125
|
+
const memoryDir = await resolveMemoryDirForNamespace(orchestrator, namespace, {
|
|
6126
|
+
rejectUnsupportedOverride: true
|
|
5832
6127
|
});
|
|
6128
|
+
const { importCapsule } = await import("./capsule-import-SDCUXLEV.js");
|
|
6129
|
+
const result = await importCapsule({
|
|
6130
|
+
archivePath: expandTildePath(archivePath),
|
|
6131
|
+
root: memoryDir,
|
|
6132
|
+
mode,
|
|
6133
|
+
memoryDir
|
|
6134
|
+
});
|
|
6135
|
+
console.log(`Imported: ${result.imported.length} record(s)`);
|
|
6136
|
+
if (result.skipped.length > 0) {
|
|
6137
|
+
console.log(`Skipped: ${result.skipped.length} (mode=${mode})`);
|
|
6138
|
+
}
|
|
5833
6139
|
console.log("OK");
|
|
5834
6140
|
});
|
|
6141
|
+
capsuleCmd.command("merge").description(
|
|
6142
|
+
"Three-way merge of a capsule archive into the memory directory. New files are always written; conflicts are resolved by --conflict-mode."
|
|
6143
|
+
).argument("<archive>", "Path to a .capsule.json.gz archive").option(
|
|
6144
|
+
"--conflict-mode <mode>",
|
|
6145
|
+
"Conflict mode: skip-conflicts (default) | prefer-source | prefer-local"
|
|
6146
|
+
).action(async (...args) => {
|
|
6147
|
+
const archiveArg = args[0];
|
|
6148
|
+
const opts = args[1] ?? {};
|
|
6149
|
+
const {
|
|
6150
|
+
parseCapsuleMergeOptions,
|
|
6151
|
+
defaultCapsulesDir
|
|
6152
|
+
} = await import("./capsule-cli.js");
|
|
6153
|
+
const parsed = parseCapsuleMergeOptions(archiveArg, opts);
|
|
6154
|
+
const memoryDir = expandTildePath(orchestrator.config.memoryDir);
|
|
6155
|
+
const capsulesDir = defaultCapsulesDir(memoryDir);
|
|
6156
|
+
const { stat: statMerge } = await import("fs/promises");
|
|
6157
|
+
let sourceArchive = expandTildePath(parsed.archive);
|
|
6158
|
+
const looksLikePath = sourceArchive.startsWith("/") || sourceArchive.startsWith("./") || sourceArchive.startsWith("../") || sourceArchive.includes(path18.sep);
|
|
6159
|
+
if (!looksLikePath) {
|
|
6160
|
+
const cwdResolved = path18.resolve(sourceArchive);
|
|
6161
|
+
const cwdSt = await statMerge(cwdResolved).catch(() => null);
|
|
6162
|
+
if (cwdSt && cwdSt.isFile()) {
|
|
6163
|
+
sourceArchive = cwdResolved;
|
|
6164
|
+
} else {
|
|
6165
|
+
const byId = path18.join(capsulesDir, `${sourceArchive}.capsule.json.gz`);
|
|
6166
|
+
const byIdEnc = path18.join(capsulesDir, `${sourceArchive}.capsule.json.gz.enc`);
|
|
6167
|
+
const stId = await statMerge(byId).catch(() => null);
|
|
6168
|
+
if (stId && stId.isFile()) {
|
|
6169
|
+
sourceArchive = byId;
|
|
6170
|
+
} else {
|
|
6171
|
+
const stEnc = await statMerge(byIdEnc).catch(() => null);
|
|
6172
|
+
if (stEnc && stEnc.isFile()) {
|
|
6173
|
+
sourceArchive = byIdEnc;
|
|
6174
|
+
}
|
|
6175
|
+
}
|
|
6176
|
+
}
|
|
6177
|
+
}
|
|
6178
|
+
if (sourceArchive.endsWith(".enc")) {
|
|
6179
|
+
const { isEncryptedCapsuleFile } = await import("./capsule-crypto-5CYAGVC5.js");
|
|
6180
|
+
const encDetected = await isEncryptedCapsuleFile(sourceArchive).catch(() => true);
|
|
6181
|
+
if (encDetected) {
|
|
6182
|
+
throw new Error(
|
|
6183
|
+
`capsule merge: encrypted archives (.enc) are not supported by merge. Decrypt the archive first with "remnic capsule import" (requires unlocked secure-store), then use the decrypted .capsule.json.gz.`
|
|
6184
|
+
);
|
|
6185
|
+
}
|
|
6186
|
+
}
|
|
6187
|
+
const { mergeCapsule } = await import("./capsule-merge-DI7PNQ2H.js");
|
|
6188
|
+
const result = await mergeCapsule({
|
|
6189
|
+
sourceArchive,
|
|
6190
|
+
targetRoot: memoryDir,
|
|
6191
|
+
conflictMode: parsed.conflictMode
|
|
6192
|
+
});
|
|
6193
|
+
const mergedCount = result.merged.length;
|
|
6194
|
+
const skippedCount = result.skipped.length;
|
|
6195
|
+
const conflictCount = result.conflicts.length;
|
|
6196
|
+
console.log(
|
|
6197
|
+
`Capsule merged: ${result.manifest.capsule.id}
|
|
6198
|
+
conflict-mode: ${parsed.conflictMode}
|
|
6199
|
+
merged: ${mergedCount}
|
|
6200
|
+
conflicts: ${conflictCount}
|
|
6201
|
+
skipped: ${skippedCount}`
|
|
6202
|
+
);
|
|
6203
|
+
});
|
|
6204
|
+
capsuleCmd.command("list").description(
|
|
6205
|
+
"List all capsule archives in the capsule store directory (<memoryDir>/.capsules by default). Reads the sidecar manifest.json for metadata."
|
|
6206
|
+
).option(
|
|
6207
|
+
"--dir <path>",
|
|
6208
|
+
"Override the capsule store directory to list"
|
|
6209
|
+
).option(
|
|
6210
|
+
"--format <fmt>",
|
|
6211
|
+
"Output format: text (default) | markdown | json"
|
|
6212
|
+
).action(async (...args) => {
|
|
6213
|
+
const opts = args[0] ?? {};
|
|
6214
|
+
const {
|
|
6215
|
+
parseCapsuleListOptions,
|
|
6216
|
+
renderCapsuleList,
|
|
6217
|
+
defaultCapsulesDir
|
|
6218
|
+
} = await import("./capsule-cli.js");
|
|
6219
|
+
const memoryDir = expandTildePath(orchestrator.config.memoryDir);
|
|
6220
|
+
const defaultDir = defaultCapsulesDir(memoryDir);
|
|
6221
|
+
const dirWasExplicit = typeof opts.dir === "string" && opts.dir.trim() !== "";
|
|
6222
|
+
const parsed = parseCapsuleListOptions(opts, defaultDir);
|
|
6223
|
+
const capsulesDir = expandTildePath(parsed.capsulesDir);
|
|
6224
|
+
const { readdir: readdir8, readFile: readFile12, stat: stat6 } = await import("fs/promises");
|
|
6225
|
+
let dirEntries;
|
|
6226
|
+
try {
|
|
6227
|
+
dirEntries = await readdir8(capsulesDir);
|
|
6228
|
+
} catch (err) {
|
|
6229
|
+
const code = err.code;
|
|
6230
|
+
if (dirWasExplicit) {
|
|
6231
|
+
throw new Error(
|
|
6232
|
+
`capsule list: cannot read --dir ${capsulesDir}: ${err.message}`
|
|
6233
|
+
);
|
|
6234
|
+
}
|
|
6235
|
+
if (code !== "ENOENT") {
|
|
6236
|
+
throw new Error(
|
|
6237
|
+
`capsule list: cannot read capsule store directory ${capsulesDir}: ${err.message}`
|
|
6238
|
+
);
|
|
6239
|
+
}
|
|
6240
|
+
dirEntries = [];
|
|
6241
|
+
}
|
|
6242
|
+
const archives = dirEntries.filter(
|
|
6243
|
+
(e) => e.endsWith(".capsule.json.gz") || e.endsWith(".capsule.json.gz.enc")
|
|
6244
|
+
).sort();
|
|
6245
|
+
const entries = [];
|
|
6246
|
+
for (const archiveName of archives) {
|
|
6247
|
+
const archivePath = path18.join(capsulesDir, archiveName);
|
|
6248
|
+
const id = archiveName.replace(/\.capsule\.json\.gz\.enc$/, "").replace(/\.capsule\.json\.gz$/, "");
|
|
6249
|
+
const manifestName = `${id}.manifest.json`;
|
|
6250
|
+
const manifestPath = path18.join(capsulesDir, manifestName);
|
|
6251
|
+
let createdAt = null;
|
|
6252
|
+
let pluginVersion = null;
|
|
6253
|
+
let fileCount = null;
|
|
6254
|
+
let description = null;
|
|
6255
|
+
let hasManifest = false;
|
|
6256
|
+
try {
|
|
6257
|
+
await stat6(manifestPath);
|
|
6258
|
+
hasManifest = true;
|
|
6259
|
+
} catch {
|
|
6260
|
+
}
|
|
6261
|
+
if (hasManifest) {
|
|
6262
|
+
try {
|
|
6263
|
+
const raw = await readFile12(manifestPath, "utf-8");
|
|
6264
|
+
const sidecar = JSON.parse(raw);
|
|
6265
|
+
createdAt = typeof sidecar.createdAt === "string" ? sidecar.createdAt : null;
|
|
6266
|
+
pluginVersion = typeof sidecar.pluginVersion === "string" ? sidecar.pluginVersion : null;
|
|
6267
|
+
fileCount = Array.isArray(sidecar.files) ? sidecar.files.length : null;
|
|
6268
|
+
const capsule = sidecar.capsule;
|
|
6269
|
+
if (capsule && typeof capsule.description === "string") {
|
|
6270
|
+
description = capsule.description;
|
|
6271
|
+
}
|
|
6272
|
+
} catch {
|
|
6273
|
+
}
|
|
6274
|
+
}
|
|
6275
|
+
entries.push({
|
|
6276
|
+
id,
|
|
6277
|
+
archivePath,
|
|
6278
|
+
manifestPath: hasManifest ? manifestPath : null,
|
|
6279
|
+
createdAt,
|
|
6280
|
+
pluginVersion,
|
|
6281
|
+
fileCount,
|
|
6282
|
+
description
|
|
6283
|
+
});
|
|
6284
|
+
}
|
|
6285
|
+
console.log(renderCapsuleList(entries, parsed.format));
|
|
6286
|
+
});
|
|
6287
|
+
capsuleCmd.command("inspect").description(
|
|
6288
|
+
"Show capsule archive manifest without unpacking. Reads the sidecar .manifest.json when present; otherwise decompresses the archive."
|
|
6289
|
+
).argument("<archive>", "Path to a .capsule.json.gz archive (or its id in the capsule store)").option(
|
|
6290
|
+
"--format <fmt>",
|
|
6291
|
+
"Output format: text (default) | markdown | json"
|
|
6292
|
+
).action(async (...args) => {
|
|
6293
|
+
const archiveArg = args[0];
|
|
6294
|
+
const opts = args[1] ?? {};
|
|
6295
|
+
const {
|
|
6296
|
+
parseCapsuleInspectOptions,
|
|
6297
|
+
renderCapsuleInspect,
|
|
6298
|
+
defaultCapsulesDir
|
|
6299
|
+
} = await import("./capsule-cli.js");
|
|
6300
|
+
const memoryDir = expandTildePath(orchestrator.config.memoryDir);
|
|
6301
|
+
const capsulesDir = defaultCapsulesDir(memoryDir);
|
|
6302
|
+
const parsed = parseCapsuleInspectOptions(archiveArg, opts);
|
|
6303
|
+
const { stat: stat6 } = await import("fs/promises");
|
|
6304
|
+
let archivePath = expandTildePath(parsed.archive);
|
|
6305
|
+
const looksLikePath = archivePath.startsWith("/") || archivePath.startsWith("./") || archivePath.startsWith("../") || archivePath.includes(path18.sep);
|
|
6306
|
+
if (!looksLikePath) {
|
|
6307
|
+
const cwdResolved = path18.resolve(archivePath);
|
|
6308
|
+
const cwdSt = await stat6(cwdResolved).catch(() => null);
|
|
6309
|
+
if (cwdSt && cwdSt.isFile()) {
|
|
6310
|
+
archivePath = cwdResolved;
|
|
6311
|
+
} else {
|
|
6312
|
+
const byId = path18.join(capsulesDir, `${archivePath}.capsule.json.gz`);
|
|
6313
|
+
const byIdEnc = path18.join(capsulesDir, `${archivePath}.capsule.json.gz.enc`);
|
|
6314
|
+
const st = await stat6(byId).catch(() => null);
|
|
6315
|
+
if (st && st.isFile()) {
|
|
6316
|
+
archivePath = byId;
|
|
6317
|
+
} else {
|
|
6318
|
+
const stEnc = await stat6(byIdEnc).catch(() => null);
|
|
6319
|
+
if (stEnc && stEnc.isFile()) {
|
|
6320
|
+
archivePath = byIdEnc;
|
|
6321
|
+
}
|
|
6322
|
+
}
|
|
6323
|
+
}
|
|
6324
|
+
}
|
|
6325
|
+
const isEncrypted = archivePath.endsWith(".capsule.json.gz.enc");
|
|
6326
|
+
const sidecarPath = archivePath.replace(/\.enc$/, "").replace(/\.capsule\.json\.gz$/, ".manifest.json");
|
|
6327
|
+
let sidecar = null;
|
|
6328
|
+
try {
|
|
6329
|
+
const { readFile: readFile12 } = await import("fs/promises");
|
|
6330
|
+
const raw = await readFile12(sidecarPath, "utf-8");
|
|
6331
|
+
sidecar = JSON.parse(raw);
|
|
6332
|
+
} catch {
|
|
6333
|
+
}
|
|
6334
|
+
let manifest;
|
|
6335
|
+
if (sidecar !== null) {
|
|
6336
|
+
manifest = sidecar;
|
|
6337
|
+
} else if (isEncrypted) {
|
|
6338
|
+
const { gunzipSync } = await import("zlib");
|
|
6339
|
+
const { parseExportBundle } = await import("./types-V3FJ26TF.js");
|
|
6340
|
+
let decryptedBuf;
|
|
6341
|
+
try {
|
|
6342
|
+
const { decryptCapsuleFileInMemory } = await import("./capsule-crypto-5CYAGVC5.js");
|
|
6343
|
+
decryptedBuf = await decryptCapsuleFileInMemory(archivePath, memoryDir);
|
|
6344
|
+
} catch (decErr) {
|
|
6345
|
+
const msg = decErr instanceof Error ? decErr.message : String(decErr);
|
|
6346
|
+
const isLocked = msg.includes("locked") || msg.includes("no key");
|
|
6347
|
+
process.stderr.write(
|
|
6348
|
+
isLocked ? `capsule inspect: secure-store is locked \u2014 unlock it first (remnic secure-store unlock) or provide the sidecar .manifest.json to inspect without decrypting.
|
|
6349
|
+
` : `capsule inspect: failed to decrypt archive \u2014 ${msg}
|
|
6350
|
+
`
|
|
6351
|
+
);
|
|
6352
|
+
process.exitCode = 1;
|
|
6353
|
+
return;
|
|
6354
|
+
}
|
|
6355
|
+
const json = gunzipSync(decryptedBuf).toString("utf-8");
|
|
6356
|
+
const parsed2 = parseExportBundle(JSON.parse(json));
|
|
6357
|
+
if (parsed2.capsuleVersion !== 2) {
|
|
6358
|
+
process.stderr.write(
|
|
6359
|
+
`capsule inspect: only V2 capsule archives are supported
|
|
6360
|
+
`
|
|
6361
|
+
);
|
|
6362
|
+
process.exitCode = 1;
|
|
6363
|
+
return;
|
|
6364
|
+
}
|
|
6365
|
+
manifest = parsed2.bundle.manifest;
|
|
6366
|
+
} else {
|
|
6367
|
+
const { readFile: readFile12 } = await import("fs/promises");
|
|
6368
|
+
const { gunzipSync } = await import("zlib");
|
|
6369
|
+
const { parseExportBundle } = await import("./types-V3FJ26TF.js");
|
|
6370
|
+
const buf = await readFile12(archivePath);
|
|
6371
|
+
const json = gunzipSync(buf).toString("utf-8");
|
|
6372
|
+
const parsed2 = parseExportBundle(JSON.parse(json));
|
|
6373
|
+
if (parsed2.capsuleVersion !== 2) {
|
|
6374
|
+
process.stderr.write(
|
|
6375
|
+
`capsule inspect: only V2 capsule archives are supported
|
|
6376
|
+
`
|
|
6377
|
+
);
|
|
6378
|
+
process.exitCode = 1;
|
|
6379
|
+
return;
|
|
6380
|
+
}
|
|
6381
|
+
manifest = parsed2.bundle.manifest;
|
|
6382
|
+
}
|
|
6383
|
+
const capsule = manifest.capsule ?? {};
|
|
6384
|
+
const files = Array.isArray(manifest.files) ? manifest.files : [];
|
|
6385
|
+
const TOP_N = 20;
|
|
6386
|
+
const topFiles = files.slice(0, TOP_N).map((f) => f.path ?? "");
|
|
6387
|
+
const retrievalPolicy = capsule.retrievalPolicy ?? {};
|
|
6388
|
+
const includes = capsule.includes ?? {};
|
|
6389
|
+
const data = {
|
|
6390
|
+
capsuleId: typeof capsule.id === "string" ? capsule.id : "(unknown)",
|
|
6391
|
+
version: typeof capsule.version === "string" ? capsule.version : "\u2014",
|
|
6392
|
+
schemaVersion: typeof capsule.schemaVersion === "string" ? capsule.schemaVersion : "\u2014",
|
|
6393
|
+
createdAt: typeof manifest.createdAt === "string" ? manifest.createdAt : null,
|
|
6394
|
+
pluginVersion: typeof manifest.pluginVersion === "string" ? manifest.pluginVersion : null,
|
|
6395
|
+
fileCount: files.length,
|
|
6396
|
+
includesTranscripts: manifest.includesTranscripts === true,
|
|
6397
|
+
description: typeof capsule.description === "string" ? capsule.description : "",
|
|
6398
|
+
parentCapsule: typeof capsule.parentCapsule === "string" ? capsule.parentCapsule : null,
|
|
6399
|
+
retrievalPolicy: {
|
|
6400
|
+
tierWeights: retrievalPolicy.tierWeights != null && typeof retrievalPolicy.tierWeights === "object" ? retrievalPolicy.tierWeights : {},
|
|
6401
|
+
directAnswerEnabled: retrievalPolicy.directAnswerEnabled === true
|
|
6402
|
+
},
|
|
6403
|
+
includes: {
|
|
6404
|
+
taxonomy: includes.taxonomy === true,
|
|
6405
|
+
identityAnchors: includes.identityAnchors === true,
|
|
6406
|
+
peerProfiles: includes.peerProfiles === true,
|
|
6407
|
+
procedural: includes.procedural === true
|
|
6408
|
+
},
|
|
6409
|
+
topFiles
|
|
6410
|
+
};
|
|
6411
|
+
console.log(renderCapsuleInspect(data, parsed.format));
|
|
6412
|
+
});
|
|
5835
6413
|
cmd.command("compat").description("Run local compatibility diagnostics for Engram plugin wiring").option("--json", "Emit JSON output for automation").option("--strict", "Exit non-zero when warnings or errors are present").option("--repo-root <path>", "Repository root to inspect", process.cwd()).action(async (...args) => {
|
|
5836
6414
|
const options = args[0] ?? {};
|
|
5837
6415
|
const strict = options.strict === true;
|
|
@@ -6014,6 +6592,166 @@ function registerCli(api, orchestrator) {
|
|
|
6014
6592
|
}
|
|
6015
6593
|
if (!reportHasMachineReadableOutput(options)) console.log("OK");
|
|
6016
6594
|
});
|
|
6595
|
+
cmd.command("recall").description(
|
|
6596
|
+
"Run a recall against memory. Pass --disclosure to control payload depth (chunk|section|raw). Part of #677."
|
|
6597
|
+
).argument("<query>", "Query to recall against").option(
|
|
6598
|
+
"--disclosure <level>",
|
|
6599
|
+
`Disclosure depth (one of: ${RECALL_DISCLOSURE_LEVELS.join(", ")}). Defaults to chunk.`
|
|
6600
|
+
).option(
|
|
6601
|
+
"--namespace <ns>",
|
|
6602
|
+
"Namespace to scope the recall to (defaults to configured namespace)"
|
|
6603
|
+
).option(
|
|
6604
|
+
"--session <key>",
|
|
6605
|
+
"Session key (used for session-scoped raw transcript excerpts when --disclosure=raw)"
|
|
6606
|
+
).option(
|
|
6607
|
+
"--top-k <n>",
|
|
6608
|
+
"Maximum number of memory results to include (positive integer)"
|
|
6609
|
+
).option(
|
|
6610
|
+
"--format <fmt>",
|
|
6611
|
+
"Output format: text (default) or json",
|
|
6612
|
+
"text"
|
|
6613
|
+
).option(
|
|
6614
|
+
"--as-of <iso>",
|
|
6615
|
+
"Historical recall pin (issue #680). ISO 8601 timestamp; returns the corpus as it existed at this instant."
|
|
6616
|
+
).option(
|
|
6617
|
+
"--tag <tag>",
|
|
6618
|
+
"Filter recall results by tag. Repeatable; alternatively pass a comma-separated list (issue #689).",
|
|
6619
|
+
(val, prev) => Array.isArray(prev) ? [...prev, val] : [val]
|
|
6620
|
+
).option(
|
|
6621
|
+
"--tag-match <mode>",
|
|
6622
|
+
"Tag-filter match mode: any (default) or all. Ignored when --tag is absent."
|
|
6623
|
+
).option(
|
|
6624
|
+
"--include-low-confidence",
|
|
6625
|
+
"Include graph edges below the configured graphTraversalConfidenceFloor in traversal (issue #681). Default off."
|
|
6626
|
+
).action(async (...args) => {
|
|
6627
|
+
const query = typeof args[0] === "string" ? args[0] : String(args[0] ?? "");
|
|
6628
|
+
if (!query || query.trim().length === 0) {
|
|
6629
|
+
throw new Error("missing required argument: <query>");
|
|
6630
|
+
}
|
|
6631
|
+
const options = args[1] ?? {};
|
|
6632
|
+
let disclosure;
|
|
6633
|
+
if (options.disclosure !== void 0) {
|
|
6634
|
+
if (typeof options.disclosure !== "string" || !isRecallDisclosure(options.disclosure)) {
|
|
6635
|
+
throw new Error(
|
|
6636
|
+
`invalid --disclosure value: ${String(options.disclosure)} (expected one of: ${RECALL_DISCLOSURE_LEVELS.join(", ")})`
|
|
6637
|
+
);
|
|
6638
|
+
}
|
|
6639
|
+
disclosure = options.disclosure;
|
|
6640
|
+
}
|
|
6641
|
+
let topK;
|
|
6642
|
+
if (options.topK !== void 0) {
|
|
6643
|
+
const raw = String(options.topK);
|
|
6644
|
+
if (!/^\d+$/.test(raw)) {
|
|
6645
|
+
throw new Error(`invalid --top-k value: ${raw} (expected positive integer)`);
|
|
6646
|
+
}
|
|
6647
|
+
const parsed = Number.parseInt(raw, 10);
|
|
6648
|
+
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
6649
|
+
throw new Error(`invalid --top-k value: ${raw} (expected positive integer)`);
|
|
6650
|
+
}
|
|
6651
|
+
topK = parsed;
|
|
6652
|
+
}
|
|
6653
|
+
const namespace = typeof options.namespace === "string" && options.namespace.length > 0 ? options.namespace : void 0;
|
|
6654
|
+
const sessionKey = typeof options.session === "string" && options.session.length > 0 ? options.session : void 0;
|
|
6655
|
+
let format = "text";
|
|
6656
|
+
if (options.format !== void 0) {
|
|
6657
|
+
const raw = String(options.format).toLowerCase();
|
|
6658
|
+
if (raw !== "text" && raw !== "json") {
|
|
6659
|
+
throw new Error(
|
|
6660
|
+
`invalid --format value: ${String(options.format)} (expected one of: text, json)`
|
|
6661
|
+
);
|
|
6662
|
+
}
|
|
6663
|
+
format = raw;
|
|
6664
|
+
}
|
|
6665
|
+
let asOf;
|
|
6666
|
+
if (options.asOf !== void 0) {
|
|
6667
|
+
const raw = String(options.asOf).trim();
|
|
6668
|
+
if (raw.length === 0) {
|
|
6669
|
+
throw new Error("--as-of requires a non-empty ISO 8601 timestamp");
|
|
6670
|
+
}
|
|
6671
|
+
const parsedAsOf = Date.parse(raw);
|
|
6672
|
+
if (!Number.isFinite(parsedAsOf)) {
|
|
6673
|
+
throw new Error(
|
|
6674
|
+
`invalid --as-of value: ${raw} (expected an ISO 8601 timestamp parseable by Date.parse)`
|
|
6675
|
+
);
|
|
6676
|
+
}
|
|
6677
|
+
asOf = raw;
|
|
6678
|
+
}
|
|
6679
|
+
let tags;
|
|
6680
|
+
if (options.tag !== void 0) {
|
|
6681
|
+
const raw = Array.isArray(options.tag) ? options.tag : [options.tag];
|
|
6682
|
+
const cleaned = [];
|
|
6683
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6684
|
+
for (const entry of raw) {
|
|
6685
|
+
if (typeof entry !== "string") continue;
|
|
6686
|
+
for (const part of entry.split(",")) {
|
|
6687
|
+
const trimmed = part.trim();
|
|
6688
|
+
if (trimmed.length === 0) continue;
|
|
6689
|
+
if (seen.has(trimmed)) continue;
|
|
6690
|
+
seen.add(trimmed);
|
|
6691
|
+
cleaned.push(trimmed);
|
|
6692
|
+
}
|
|
6693
|
+
}
|
|
6694
|
+
tags = cleaned.length > 0 ? cleaned : void 0;
|
|
6695
|
+
}
|
|
6696
|
+
let tagMatch;
|
|
6697
|
+
if (options.tagMatch !== void 0) {
|
|
6698
|
+
const raw = String(options.tagMatch).trim();
|
|
6699
|
+
if (raw !== "any" && raw !== "all") {
|
|
6700
|
+
throw new Error(
|
|
6701
|
+
`invalid --tag-match value: ${String(options.tagMatch)} (expected one of: any, all)`
|
|
6702
|
+
);
|
|
6703
|
+
}
|
|
6704
|
+
tagMatch = raw;
|
|
6705
|
+
}
|
|
6706
|
+
const includeLowConfidence = options.includeLowConfidence === true;
|
|
6707
|
+
const accessService2 = new EngramAccessService(orchestrator);
|
|
6708
|
+
const response = await accessService2.recall({
|
|
6709
|
+
query,
|
|
6710
|
+
...sessionKey !== void 0 ? { sessionKey } : {},
|
|
6711
|
+
...namespace !== void 0 ? { namespace } : {},
|
|
6712
|
+
...topK !== void 0 ? { topK } : {},
|
|
6713
|
+
...disclosure !== void 0 ? { disclosure } : {},
|
|
6714
|
+
...asOf !== void 0 ? { asOf } : {},
|
|
6715
|
+
...tags !== void 0 ? { tags } : {},
|
|
6716
|
+
...tagMatch !== void 0 ? { tagMatch } : {},
|
|
6717
|
+
...includeLowConfidence ? { includeLowConfidence: true } : {}
|
|
6718
|
+
});
|
|
6719
|
+
if (format === "json") {
|
|
6720
|
+
console.log(JSON.stringify(response, null, 2));
|
|
6721
|
+
return;
|
|
6722
|
+
}
|
|
6723
|
+
console.log(`=== Recall: "${query}" ===`);
|
|
6724
|
+
console.log(`namespace: ${response.namespace}`);
|
|
6725
|
+
console.log(`disclosure: ${response.disclosure}`);
|
|
6726
|
+
console.log(`results: ${response.count}`);
|
|
6727
|
+
if (response.results.length === 0) {
|
|
6728
|
+
console.log("(no results)");
|
|
6729
|
+
return;
|
|
6730
|
+
}
|
|
6731
|
+
for (const r of response.results) {
|
|
6732
|
+
console.log("");
|
|
6733
|
+
console.log(`- ${r.path}`);
|
|
6734
|
+
console.log(` category: ${r.category}`);
|
|
6735
|
+
if (r.tags.length > 0) {
|
|
6736
|
+
console.log(` tags: ${r.tags.join(", ")}`);
|
|
6737
|
+
}
|
|
6738
|
+
console.log(` preview: ${r.preview}`);
|
|
6739
|
+
if (r.content) {
|
|
6740
|
+
console.log(` content (${r.content.length} chars):`);
|
|
6741
|
+
console.log(
|
|
6742
|
+
r.content.split("\n").map((line) => ` ${line}`).join("\n")
|
|
6743
|
+
);
|
|
6744
|
+
}
|
|
6745
|
+
if (r.rawExcerpts && r.rawExcerpts.length > 0) {
|
|
6746
|
+
console.log(` raw excerpts (${r.rawExcerpts.length}):`);
|
|
6747
|
+
for (const ex of r.rawExcerpts) {
|
|
6748
|
+
console.log(
|
|
6749
|
+
` [turn ${ex.turnIndex}, ${ex.role}] ${ex.content.slice(0, 200)}`
|
|
6750
|
+
);
|
|
6751
|
+
}
|
|
6752
|
+
}
|
|
6753
|
+
}
|
|
6754
|
+
});
|
|
6017
6755
|
cmd.command("recall-explain").description(
|
|
6018
6756
|
"Show tier explain for the most recent recall (or a specific session)"
|
|
6019
6757
|
).option(
|
|
@@ -6047,6 +6785,9 @@ function registerCli(api, orchestrator) {
|
|
|
6047
6785
|
).option(
|
|
6048
6786
|
"--out <path>",
|
|
6049
6787
|
"Write the rendered snapshot to a file instead of stdout"
|
|
6788
|
+
).option(
|
|
6789
|
+
"--disclosure <level>",
|
|
6790
|
+
"Disclosure depth (chunk | section | raw). Populates the per-disclosure token-spend summary."
|
|
6050
6791
|
).action(async (...args) => {
|
|
6051
6792
|
const parsed = parseXrayCliOptions(
|
|
6052
6793
|
args[0],
|
|
@@ -6056,17 +6797,289 @@ function registerCli(api, orchestrator) {
|
|
|
6056
6797
|
const response = await xrayService.recallXray({
|
|
6057
6798
|
query: parsed.query,
|
|
6058
6799
|
...parsed.namespace ? { namespace: parsed.namespace } : {},
|
|
6059
|
-
...parsed.budget !== void 0 ? { budget: parsed.budget } : {}
|
|
6800
|
+
...parsed.budget !== void 0 ? { budget: parsed.budget } : {},
|
|
6801
|
+
...parsed.disclosure !== void 0 ? { disclosure: parsed.disclosure } : {}
|
|
6802
|
+
});
|
|
6803
|
+
const snapshot = response.snapshotFound ? response.snapshot ?? null : null;
|
|
6804
|
+
const rendered = renderXray(snapshot, parsed.format);
|
|
6805
|
+
if (parsed.outPath) {
|
|
6806
|
+
const { writeFile: fsWriteFile } = await import("fs/promises");
|
|
6807
|
+
await fsWriteFile(expandTildePath(parsed.outPath), rendered, "utf8");
|
|
6808
|
+
} else {
|
|
6809
|
+
console.log(rendered);
|
|
6810
|
+
}
|
|
6811
|
+
});
|
|
6812
|
+
const patternsCmd = cmd.command("patterns").description(
|
|
6813
|
+
"Inspect reinforced pattern memories produced by the pattern-reinforcement job (#687 PR 2/4)."
|
|
6814
|
+
);
|
|
6815
|
+
patternsCmd.command("list").description(
|
|
6816
|
+
"List memories with reinforcement_count > 0, sorted by count desc. Part of #687."
|
|
6817
|
+
).option(
|
|
6818
|
+
"--limit <N>",
|
|
6819
|
+
"Maximum number of rows to show (default 50, positive integer)"
|
|
6820
|
+
).option(
|
|
6821
|
+
"--category <list>",
|
|
6822
|
+
"Comma-separated category filter (e.g. fact,preference)"
|
|
6823
|
+
).option(
|
|
6824
|
+
"--since <ISO>",
|
|
6825
|
+
"Only include memories reinforced on or after this ISO 8601 timestamp"
|
|
6826
|
+
).option(
|
|
6827
|
+
"--format <fmt>",
|
|
6828
|
+
"Output format: text (default), markdown, or json"
|
|
6829
|
+
).action(async (...args) => {
|
|
6830
|
+
const options = args[0] ?? {};
|
|
6831
|
+
const parsed = parsePatternsListOptions(options);
|
|
6832
|
+
const memories = await orchestrator.storage.readAllMemories();
|
|
6833
|
+
const rows = collectPatternMemories(memories, parsed);
|
|
6834
|
+
console.log(renderPatternsList(rows, parsed.format));
|
|
6835
|
+
});
|
|
6836
|
+
patternsCmd.command("explain").description(
|
|
6837
|
+
"Show reinforcement detail for a single pattern canonical: count, provenance chain, and cluster members. Part of #687."
|
|
6838
|
+
).argument("<memoryId>", "ID of the canonical memory to explain").option(
|
|
6839
|
+
"--format <fmt>",
|
|
6840
|
+
"Output format: text (default), markdown, or json"
|
|
6841
|
+
).action(async (...args) => {
|
|
6842
|
+
const rawId = args[0];
|
|
6843
|
+
const options = args[1] ?? {};
|
|
6844
|
+
const parsed = parsePatternsExplainOptions(rawId, options);
|
|
6845
|
+
const memories = await orchestrator.storage.readAllMemories();
|
|
6846
|
+
const detail = explainPatternMemory(memories, parsed.id);
|
|
6847
|
+
if (detail === null) {
|
|
6848
|
+
process.stderr.write(
|
|
6849
|
+
`patterns explain: "${parsed.id}" was not found or has no reinforcement_count > 0.
|
|
6850
|
+
`
|
|
6851
|
+
);
|
|
6852
|
+
process.exitCode = 1;
|
|
6853
|
+
return;
|
|
6854
|
+
}
|
|
6855
|
+
console.log(renderPatternExplain(detail, parsed.format));
|
|
6856
|
+
});
|
|
6857
|
+
{
|
|
6858
|
+
async function buildConnectorRows() {
|
|
6859
|
+
const states = await listConnectorStates(
|
|
6860
|
+
orchestrator.config.memoryDir
|
|
6861
|
+
);
|
|
6862
|
+
const stateMap = new Map(states.map((s) => [s.id, s]));
|
|
6863
|
+
const builtIn = [
|
|
6864
|
+
{
|
|
6865
|
+
id: GOOGLE_DRIVE_CONNECTOR_ID,
|
|
6866
|
+
displayName: "Google Drive",
|
|
6867
|
+
enabled: orchestrator.config.connectors.googleDrive.enabled
|
|
6868
|
+
},
|
|
6869
|
+
{
|
|
6870
|
+
id: NOTION_CONNECTOR_ID,
|
|
6871
|
+
displayName: "Notion",
|
|
6872
|
+
enabled: orchestrator.config.connectors.notion.enabled
|
|
6873
|
+
}
|
|
6874
|
+
];
|
|
6875
|
+
return builtIn.map((c) => ({
|
|
6876
|
+
id: c.id,
|
|
6877
|
+
displayName: c.displayName,
|
|
6878
|
+
enabled: c.enabled,
|
|
6879
|
+
state: stateMap.get(c.id) ?? null
|
|
6880
|
+
}));
|
|
6881
|
+
}
|
|
6882
|
+
const connectorsCmd = cmd.command("connectors").description(
|
|
6883
|
+
"Manage live connectors (Google Drive, Notion, \u2026). Subcommands: list, status, run. See docs/live-connectors.md."
|
|
6884
|
+
);
|
|
6885
|
+
connectorsCmd.command("list").description(
|
|
6886
|
+
"List all configured live connectors with their enabled state, last poll time, and last error."
|
|
6887
|
+
).option(
|
|
6888
|
+
"--format <fmt>",
|
|
6889
|
+
"Output format: text (default), markdown, or json"
|
|
6890
|
+
).action(async (...args) => {
|
|
6891
|
+
const options = args[0] ?? {};
|
|
6892
|
+
let parsed;
|
|
6893
|
+
try {
|
|
6894
|
+
parsed = parseConnectorsListOptions(options);
|
|
6895
|
+
} catch (err) {
|
|
6896
|
+
process.stderr.write(
|
|
6897
|
+
`connectors list: ${err instanceof Error ? err.message : String(err)}
|
|
6898
|
+
`
|
|
6899
|
+
);
|
|
6900
|
+
process.exitCode = 2;
|
|
6901
|
+
return;
|
|
6902
|
+
}
|
|
6903
|
+
const rows = await buildConnectorRows();
|
|
6904
|
+
console.log(renderConnectorsList(rows, parsed.format));
|
|
6905
|
+
});
|
|
6906
|
+
connectorsCmd.command("status").description(
|
|
6907
|
+
"Print connector status. Defaults to JSON output for scripting. Use --format text|markdown to override."
|
|
6908
|
+
).option(
|
|
6909
|
+
"--format <fmt>",
|
|
6910
|
+
"Output format: json (default), text, or markdown"
|
|
6911
|
+
).action(async (...args) => {
|
|
6912
|
+
const options = args[0] ?? {};
|
|
6913
|
+
let parsed;
|
|
6914
|
+
try {
|
|
6915
|
+
parsed = parseConnectorsStatusOptions(options);
|
|
6916
|
+
} catch (err) {
|
|
6917
|
+
process.stderr.write(
|
|
6918
|
+
`connectors status: ${err instanceof Error ? err.message : String(err)}
|
|
6919
|
+
`
|
|
6920
|
+
);
|
|
6921
|
+
process.exitCode = 2;
|
|
6922
|
+
return;
|
|
6923
|
+
}
|
|
6924
|
+
const rows = await buildConnectorRows();
|
|
6925
|
+
console.log(renderConnectorsList(rows, parsed.format));
|
|
6926
|
+
});
|
|
6927
|
+
connectorsCmd.command("run").description(
|
|
6928
|
+
"Manually trigger one incremental sync pass for the named connector. Operator debug surface."
|
|
6929
|
+
).argument("<name>", "Connector id (e.g. google-drive, notion)").option(
|
|
6930
|
+
"--format <fmt>",
|
|
6931
|
+
"Output format: text (default), markdown, or json"
|
|
6932
|
+
).action(async (...args) => {
|
|
6933
|
+
const rawName = args[0];
|
|
6934
|
+
const options = args[1] ?? {};
|
|
6935
|
+
let name;
|
|
6936
|
+
try {
|
|
6937
|
+
name = parseConnectorsRunName(rawName);
|
|
6938
|
+
} catch (err) {
|
|
6939
|
+
process.stderr.write(
|
|
6940
|
+
`connectors run: ${err instanceof Error ? err.message : String(err)}
|
|
6941
|
+
`
|
|
6942
|
+
);
|
|
6943
|
+
process.exitCode = 2;
|
|
6944
|
+
return;
|
|
6945
|
+
}
|
|
6946
|
+
let format;
|
|
6947
|
+
try {
|
|
6948
|
+
format = parseConnectorsListOptions({ format: options.format }).format;
|
|
6949
|
+
} catch (err) {
|
|
6950
|
+
process.stderr.write(
|
|
6951
|
+
`connectors run: ${err instanceof Error ? err.message : String(err)}
|
|
6952
|
+
`
|
|
6953
|
+
);
|
|
6954
|
+
process.exitCode = 2;
|
|
6955
|
+
return;
|
|
6956
|
+
}
|
|
6957
|
+
const cfg = orchestrator.config.connectors;
|
|
6958
|
+
const { readConnectorState, writeConnectorState } = await import("./state-store-3EH7HYIN.js");
|
|
6959
|
+
const sharedIngestFn = async (docs) => {
|
|
6960
|
+
const fetchedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
6961
|
+
const turns = docs.map((doc) => ({
|
|
6962
|
+
role: "assistant",
|
|
6963
|
+
content: doc.title ? `# ${doc.title}
|
|
6964
|
+
|
|
6965
|
+
${doc.content}` : doc.content,
|
|
6966
|
+
timestamp: fetchedAt
|
|
6967
|
+
}));
|
|
6968
|
+
await orchestrator.ingestBulkImportBatch(turns);
|
|
6969
|
+
};
|
|
6970
|
+
const makeWriteCursorFn = (connectorName) => async ({
|
|
6971
|
+
cursor,
|
|
6972
|
+
lastSyncStatus,
|
|
6973
|
+
lastSyncError,
|
|
6974
|
+
totalDocsImported
|
|
6975
|
+
}) => {
|
|
6976
|
+
await writeConnectorState(
|
|
6977
|
+
orchestrator.config.memoryDir,
|
|
6978
|
+
connectorName,
|
|
6979
|
+
{
|
|
6980
|
+
id: connectorName,
|
|
6981
|
+
cursor,
|
|
6982
|
+
lastSyncAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6983
|
+
lastSyncStatus,
|
|
6984
|
+
...lastSyncError !== void 0 ? { lastSyncError } : {},
|
|
6985
|
+
totalDocsImported
|
|
6986
|
+
}
|
|
6987
|
+
);
|
|
6988
|
+
};
|
|
6989
|
+
let runResult;
|
|
6990
|
+
if (name === GOOGLE_DRIVE_CONNECTOR_ID) {
|
|
6991
|
+
if (!cfg.googleDrive.enabled) {
|
|
6992
|
+
process.stderr.write(
|
|
6993
|
+
`connectors run: connector "${name}" is disabled. Set connectors.googleDrive.enabled=true in config.
|
|
6994
|
+
`
|
|
6995
|
+
);
|
|
6996
|
+
process.exitCode = 1;
|
|
6997
|
+
return;
|
|
6998
|
+
}
|
|
6999
|
+
let validatedCfg;
|
|
7000
|
+
try {
|
|
7001
|
+
validatedCfg = validateGoogleDriveConfig(cfg.googleDrive);
|
|
7002
|
+
} catch (err) {
|
|
7003
|
+
process.stderr.write(
|
|
7004
|
+
`connectors run: invalid config for "${name}": ${err instanceof Error ? err.message : String(err)}
|
|
7005
|
+
`
|
|
7006
|
+
);
|
|
7007
|
+
process.exitCode = 1;
|
|
7008
|
+
return;
|
|
7009
|
+
}
|
|
7010
|
+
const connector = createGoogleDriveConnector();
|
|
7011
|
+
const state = await readConnectorState(
|
|
7012
|
+
orchestrator.config.memoryDir,
|
|
7013
|
+
name
|
|
7014
|
+
);
|
|
7015
|
+
runResult = await runConnectorPollOnce({
|
|
7016
|
+
connectorId: name,
|
|
7017
|
+
priorState: state,
|
|
7018
|
+
syncFn: (cursor) => connector.syncIncremental({
|
|
7019
|
+
cursor,
|
|
7020
|
+
// GoogleDriveConnectorConfig is narrower than ConnectorConfig
|
|
7021
|
+
// (no index signature) but is structurally compatible at
|
|
7022
|
+
// runtime. Double-cast via unknown to satisfy the interface.
|
|
7023
|
+
config: validatedCfg
|
|
7024
|
+
}),
|
|
7025
|
+
ingestFn: sharedIngestFn,
|
|
7026
|
+
writeCursorFn: makeWriteCursorFn(name)
|
|
7027
|
+
});
|
|
7028
|
+
} else if (name === NOTION_CONNECTOR_ID) {
|
|
7029
|
+
if (!cfg.notion.enabled) {
|
|
7030
|
+
process.stderr.write(
|
|
7031
|
+
`connectors run: connector "${name}" is disabled. Set connectors.notion.enabled=true in config.
|
|
7032
|
+
`
|
|
7033
|
+
);
|
|
7034
|
+
process.exitCode = 1;
|
|
7035
|
+
return;
|
|
7036
|
+
}
|
|
7037
|
+
let validatedCfg;
|
|
7038
|
+
try {
|
|
7039
|
+
validatedCfg = validateNotionConfig(cfg.notion);
|
|
7040
|
+
} catch (err) {
|
|
7041
|
+
process.stderr.write(
|
|
7042
|
+
`connectors run: invalid config for "${name}": ${err instanceof Error ? err.message : String(err)}
|
|
7043
|
+
`
|
|
7044
|
+
);
|
|
7045
|
+
process.exitCode = 1;
|
|
7046
|
+
return;
|
|
7047
|
+
}
|
|
7048
|
+
const connector = createNotionConnector();
|
|
7049
|
+
const state = await readConnectorState(
|
|
7050
|
+
orchestrator.config.memoryDir,
|
|
7051
|
+
name
|
|
7052
|
+
);
|
|
7053
|
+
runResult = await runConnectorPollOnce({
|
|
7054
|
+
connectorId: name,
|
|
7055
|
+
priorState: state,
|
|
7056
|
+
syncFn: (cursor) => connector.syncIncremental({
|
|
7057
|
+
cursor,
|
|
7058
|
+
// NotionConnectorConfig is narrower than ConnectorConfig (no
|
|
7059
|
+
// index signature) but is structurally compatible at runtime.
|
|
7060
|
+
// Double-cast via unknown to satisfy the interface boundary.
|
|
7061
|
+
config: validatedCfg
|
|
7062
|
+
}),
|
|
7063
|
+
ingestFn: sharedIngestFn,
|
|
7064
|
+
writeCursorFn: makeWriteCursorFn(name)
|
|
7065
|
+
});
|
|
7066
|
+
} else {
|
|
7067
|
+
process.stderr.write(
|
|
7068
|
+
`connectors run: unknown connector "${name}". Known connectors: ${GOOGLE_DRIVE_CONNECTOR_ID}, ${NOTION_CONNECTOR_ID}.
|
|
7069
|
+
`
|
|
7070
|
+
);
|
|
7071
|
+
process.exitCode = 1;
|
|
7072
|
+
return;
|
|
7073
|
+
}
|
|
7074
|
+
const output = renderConnectorsRunResult(name, runResult, format);
|
|
7075
|
+
if (runResult.error !== void 0) {
|
|
7076
|
+
process.stderr.write(output + "\n");
|
|
7077
|
+
process.exitCode = 1;
|
|
7078
|
+
} else {
|
|
7079
|
+
console.log(output);
|
|
7080
|
+
}
|
|
6060
7081
|
});
|
|
6061
|
-
|
|
6062
|
-
const rendered = renderXray(snapshot, parsed.format);
|
|
6063
|
-
if (parsed.outPath) {
|
|
6064
|
-
const { writeFile: fsWriteFile } = await import("fs/promises");
|
|
6065
|
-
await fsWriteFile(expandTildePath(parsed.outPath), rendered, "utf8");
|
|
6066
|
-
} else {
|
|
6067
|
-
console.log(rendered);
|
|
6068
|
-
}
|
|
6069
|
-
});
|
|
7082
|
+
}
|
|
6070
7083
|
cmd.command("benchmark-validate").description("Validate a benchmark manifest file or pack directory without importing it").argument("<path>", "Path to a benchmark manifest JSON file or a directory with manifest.json").action(async (...args) => {
|
|
6071
7084
|
const inputPath = args[0];
|
|
6072
7085
|
const summary = await runBenchmarkValidateCliCommand({
|
|
@@ -6769,12 +7782,18 @@ function registerCli(api, orchestrator) {
|
|
|
6769
7782
|
const options = args[0] ?? {};
|
|
6770
7783
|
const portRaw = parseInt(String(options.port ?? "4318"), 10);
|
|
6771
7784
|
const maxBodyBytesRaw = parseInt(String(options.maxBodyBytes ?? "131072"), 10);
|
|
7785
|
+
const cliTokenOverride = typeof options.token === "string" && options.token.trim().length > 0 ? options.token : void 0;
|
|
7786
|
+
const resolveSecretRef = registerOptions.resolveSecretRef ?? (registerOptions.loadResolveSecretRef ? await registerOptions.loadResolveSecretRef() : null);
|
|
7787
|
+
const resolvedConfigAuthToken = cliTokenOverride ? void 0 : await resolveAgentAccessAuthToken(
|
|
7788
|
+
orchestrator.config.agentAccessHttp.authToken,
|
|
7789
|
+
{ resolveSecretRef }
|
|
7790
|
+
);
|
|
6772
7791
|
const status = await runAccessHttpServeCliCommand({
|
|
6773
7792
|
service: accessService,
|
|
6774
7793
|
enabled: true,
|
|
6775
7794
|
host: typeof options.host === "string" ? options.host : "127.0.0.1",
|
|
6776
7795
|
port: Number.isFinite(portRaw) ? portRaw : 4318,
|
|
6777
|
-
authToken:
|
|
7796
|
+
authToken: cliTokenOverride ?? resolvedConfigAuthToken,
|
|
6778
7797
|
principal: resolveAccessPrincipalOverride(options.principal, orchestrator.config.agentAccessHttp.principal),
|
|
6779
7798
|
maxBodyBytes: Number.isFinite(maxBodyBytesRaw) ? maxBodyBytesRaw : 131072,
|
|
6780
7799
|
trustPrincipalHeader: options.trustPrincipalHeader === true,
|
|
@@ -7043,6 +8062,10 @@ function registerCli(api, orchestrator) {
|
|
|
7043
8062
|
const memoryDir = await resolveMemoryDirForNamespace(orchestrator, namespace, {
|
|
7044
8063
|
rejectUnsupportedOverride: true
|
|
7045
8064
|
});
|
|
8065
|
+
const deepSleep = orchestrator.config.dreamsPhases.deepSleep;
|
|
8066
|
+
if (deepSleep.enabled === false && deepSleep.enabledExplicitlySet === true) {
|
|
8067
|
+
throw new Error("memory governance is disabled by dreams.phases.deepSleep.enabled=false");
|
|
8068
|
+
}
|
|
7046
8069
|
const result = await runMemoryGovernanceCliCommand({
|
|
7047
8070
|
memoryDir,
|
|
7048
8071
|
mode,
|
|
@@ -7223,7 +8246,7 @@ function registerCli(api, orchestrator) {
|
|
|
7223
8246
|
let deleted = 0;
|
|
7224
8247
|
for (const filePath of plan.deletePaths) {
|
|
7225
8248
|
try {
|
|
7226
|
-
await
|
|
8249
|
+
await unlink3(filePath);
|
|
7227
8250
|
deleted += 1;
|
|
7228
8251
|
} catch (err) {
|
|
7229
8252
|
console.log(` failed to delete ${filePath}: ${String(err)}`);
|
|
@@ -7271,7 +8294,7 @@ function registerCli(api, orchestrator) {
|
|
|
7271
8294
|
let deleted = 0;
|
|
7272
8295
|
for (const filePath of plan.deletePaths) {
|
|
7273
8296
|
try {
|
|
7274
|
-
await
|
|
8297
|
+
await unlink3(filePath);
|
|
7275
8298
|
deleted += 1;
|
|
7276
8299
|
} catch (err) {
|
|
7277
8300
|
console.log(` failed to delete ${filePath}: ${String(err)}`);
|
|
@@ -7299,11 +8322,15 @@ function registerCli(api, orchestrator) {
|
|
|
7299
8322
|
}
|
|
7300
8323
|
await orchestrator.qmd.probe();
|
|
7301
8324
|
if (orchestrator.qmd.isAvailable()) {
|
|
7302
|
-
const
|
|
8325
|
+
const rawResults = await orchestrator.qmd.search(
|
|
7303
8326
|
query,
|
|
7304
8327
|
void 0,
|
|
7305
8328
|
maxResults
|
|
7306
8329
|
);
|
|
8330
|
+
const results = await filterNormalMemorySearchResults(
|
|
8331
|
+
rawResults,
|
|
8332
|
+
orchestrator.storage
|
|
8333
|
+
);
|
|
7307
8334
|
if (results.length === 0) {
|
|
7308
8335
|
console.log(`No results for: "${query}"`);
|
|
7309
8336
|
return;
|
|
@@ -7324,7 +8351,7 @@ function registerCli(api, orchestrator) {
|
|
|
7324
8351
|
const memories = await orchestrator.storage.readAllMemories();
|
|
7325
8352
|
const lowerQuery = query.toLowerCase();
|
|
7326
8353
|
const matches = memories.filter(
|
|
7327
|
-
(m) => m.content.toLowerCase().includes(lowerQuery) || m.frontmatter.tags.some((t) => t.includes(lowerQuery))
|
|
8354
|
+
(m) => isNormalRetrievalVisibleMemory(m) && (m.content.toLowerCase().includes(lowerQuery) || m.frontmatter.tags.some((t) => t.includes(lowerQuery)))
|
|
7328
8355
|
);
|
|
7329
8356
|
const qmdStatus = orchestrator.qmd.debugStatus();
|
|
7330
8357
|
if (matches.length === 0) {
|
|
@@ -7465,7 +8492,7 @@ Semantic consolidation complete. clusters=${result.clustersFound}, consolidated=
|
|
|
7465
8492
|
return;
|
|
7466
8493
|
}
|
|
7467
8494
|
const expandedTarget = expandTildePath(rawTarget);
|
|
7468
|
-
const targetPath =
|
|
8495
|
+
const targetPath = path18.isAbsolute(expandedTarget) ? expandedTarget : path18.join(orchestrator.config.memoryDir, expandedTarget);
|
|
7469
8496
|
const { runConsolidationUndo, formatConsolidationUndoResult } = await import("./consolidation-undo.js");
|
|
7470
8497
|
const result = await runConsolidationUndo({
|
|
7471
8498
|
storage: orchestrator.storage,
|
|
@@ -7503,7 +8530,7 @@ Semantic consolidation complete. clusters=${result.clustersFound}, consolidated=
|
|
|
7503
8530
|
}
|
|
7504
8531
|
});
|
|
7505
8532
|
cmd.command("identity").description("Show agent identity reflections").action(async () => {
|
|
7506
|
-
const workspaceDir =
|
|
8533
|
+
const workspaceDir = path18.join(resolveHomeDir(), ".openclaw", "workspace");
|
|
7507
8534
|
const identity = await orchestrator.storage.readIdentity(workspaceDir);
|
|
7508
8535
|
if (!identity) {
|
|
7509
8536
|
console.log("No identity file found.");
|
|
@@ -7726,8 +8753,8 @@ Semantic consolidation complete. clusters=${result.clustersFound}, consolidated=
|
|
|
7726
8753
|
const options = args[0] ?? {};
|
|
7727
8754
|
const threadId = options.thread;
|
|
7728
8755
|
const top = parseInt(options.top ?? "10", 10);
|
|
7729
|
-
const memoryDir =
|
|
7730
|
-
const threading = new ThreadingManager(
|
|
8756
|
+
const memoryDir = path18.join(resolveHomeDir(), ".openclaw", "workspace", "memory", "local");
|
|
8757
|
+
const threading = new ThreadingManager(path18.join(memoryDir, "threads"));
|
|
7731
8758
|
if (threadId) {
|
|
7732
8759
|
const thread = await threading.loadThread(threadId);
|
|
7733
8760
|
if (!thread) {
|
|
@@ -7889,7 +8916,7 @@ Semantic consolidation complete. clusters=${result.clustersFound}, consolidated=
|
|
|
7889
8916
|
process.exit(1);
|
|
7890
8917
|
}
|
|
7891
8918
|
const limit = parseInt(options.limit ?? "50", 10);
|
|
7892
|
-
const { listPairs } = await import("./contradiction-review-
|
|
8919
|
+
const { listPairs } = await import("./contradiction-review-5LTTVDQV.js");
|
|
7893
8920
|
const result = listPairs(orchestrator.config.memoryDir, {
|
|
7894
8921
|
filter,
|
|
7895
8922
|
namespace: options.namespace,
|
|
@@ -7916,7 +8943,7 @@ Semantic consolidation complete. clusters=${result.clustersFound}, consolidated=
|
|
|
7916
8943
|
console.error("pairId is required");
|
|
7917
8944
|
process.exit(1);
|
|
7918
8945
|
}
|
|
7919
|
-
const { readPair } = await import("./contradiction-review-
|
|
8946
|
+
const { readPair } = await import("./contradiction-review-5LTTVDQV.js");
|
|
7920
8947
|
const pair = readPair(orchestrator.config.memoryDir, pairId);
|
|
7921
8948
|
if (!pair) {
|
|
7922
8949
|
console.error(`Pair ${pairId} not found.`);
|
|
@@ -7936,7 +8963,7 @@ Semantic consolidation complete. clusters=${result.clustersFound}, consolidated=
|
|
|
7936
8963
|
console.error("--verb is required. Must be one of: keep-a, keep-b, merge, both-valid, needs-more-context");
|
|
7937
8964
|
process.exit(1);
|
|
7938
8965
|
}
|
|
7939
|
-
const { isValidResolutionVerb, executeResolution } = await import("./resolution-
|
|
8966
|
+
const { isValidResolutionVerb, executeResolution } = await import("./resolution-YGIBORXI.js");
|
|
7940
8967
|
if (!isValidResolutionVerb(verb)) {
|
|
7941
8968
|
console.error(`Invalid verb: ${verb}. Must be one of: keep-a, keep-b, merge, both-valid, needs-more-context`);
|
|
7942
8969
|
process.exit(1);
|
|
@@ -7949,7 +8976,7 @@ Semantic consolidation complete. clusters=${result.clustersFound}, consolidated=
|
|
|
7949
8976
|
});
|
|
7950
8977
|
reviewCmd.command("scan").description("Run an on-demand contradiction scan").option("--namespace <ns>", "Namespace to scan").action(async (...args) => {
|
|
7951
8978
|
const options = args[0] ?? {};
|
|
7952
|
-
const { runContradictionScan } = await import("./contradiction-scan-
|
|
8979
|
+
const { runContradictionScan } = await import("./contradiction-scan-3Z6YW7YA.js");
|
|
7953
8980
|
console.log("Running contradiction scan...");
|
|
7954
8981
|
const result = await runContradictionScan({
|
|
7955
8982
|
storage: orchestrator.storage,
|
|
@@ -7976,6 +9003,558 @@ Semantic consolidation complete. clusters=${result.clustersFound}, consolidated=
|
|
|
7976
9003
|
console.log(` Queued: ${result.queued}`);
|
|
7977
9004
|
console.log(` Cooled down: ${result.cooledDown}`);
|
|
7978
9005
|
});
|
|
9006
|
+
const dreamsCmd = cmd.command("dreams").description("Inspect and manually trigger Dreams consolidation pipeline phases");
|
|
9007
|
+
dreamsCmd.command("status").description("Show per-phase Dreams telemetry for the last N hours").option("--window-hours <n>", "Look-back window in hours (default 24)", "24").option("--format <fmt>", "Output format: text, json, markdown (default text)", "text").option("--namespace <ns>", "Namespace to inspect (default: current default namespace)").option("--principal <principal>", "Trusted principal for namespace ACLs (defaults to config/env)").action(async (...args) => {
|
|
9008
|
+
const options = args[0] ?? {};
|
|
9009
|
+
const fmt = options.format ?? "text";
|
|
9010
|
+
if (fmt !== "text" && fmt !== "json" && fmt !== "markdown") {
|
|
9011
|
+
console.error(`Invalid --format '${fmt}'. Must be one of: text, json, markdown`);
|
|
9012
|
+
process.exit(1);
|
|
9013
|
+
}
|
|
9014
|
+
const { normalizeDreamsStatusWindowHours } = await import("./dreams-ledger-LR2NBAZE.js");
|
|
9015
|
+
let windowHours;
|
|
9016
|
+
const rawWindowHours = options.windowHours;
|
|
9017
|
+
try {
|
|
9018
|
+
if (typeof rawWindowHours !== "string" || rawWindowHours.trim() === "") {
|
|
9019
|
+
throw new Error("missing window");
|
|
9020
|
+
}
|
|
9021
|
+
windowHours = normalizeDreamsStatusWindowHours(Number(rawWindowHours));
|
|
9022
|
+
} catch {
|
|
9023
|
+
console.error("--window-hours must be a positive integer");
|
|
9024
|
+
process.exit(1);
|
|
9025
|
+
}
|
|
9026
|
+
const accessService2 = new EngramAccessService(orchestrator);
|
|
9027
|
+
const result = await accessService2.dreamsStatus({
|
|
9028
|
+
windowHours,
|
|
9029
|
+
namespace: typeof options.namespace === "string" ? options.namespace : void 0,
|
|
9030
|
+
principal: resolveAccessPrincipalOverride(
|
|
9031
|
+
options.principal,
|
|
9032
|
+
orchestrator.config.agentAccessHttp.principal
|
|
9033
|
+
)
|
|
9034
|
+
});
|
|
9035
|
+
if (fmt === "json") {
|
|
9036
|
+
console.log(JSON.stringify(result, null, 2));
|
|
9037
|
+
return;
|
|
9038
|
+
}
|
|
9039
|
+
const phaseLabels = {
|
|
9040
|
+
lightSleep: "Light Sleep",
|
|
9041
|
+
rem: "REM",
|
|
9042
|
+
deepSleep: "Deep Sleep"
|
|
9043
|
+
};
|
|
9044
|
+
if (fmt === "markdown") {
|
|
9045
|
+
console.log(`## Dreams Status (last ${windowHours}h)
|
|
9046
|
+
`);
|
|
9047
|
+
console.log(`Window: ${result.windowStart} \u2192 ${result.windowEnd}
|
|
9048
|
+
`);
|
|
9049
|
+
console.log("| Phase | Runs | Total Duration | Items Processed | Last Run |");
|
|
9050
|
+
console.log("|-------|------|----------------|-----------------|----------|");
|
|
9051
|
+
for (const phase of ["lightSleep", "rem", "deepSleep"]) {
|
|
9052
|
+
const p = result.phases[phase];
|
|
9053
|
+
const lastRun = p.lastRunAt ? p.lastRunAt.slice(0, 19).replace("T", " ") : "\u2014";
|
|
9054
|
+
console.log(
|
|
9055
|
+
`| ${phaseLabels[phase]} | ${p.runCount} | ${p.totalDurationMs}ms | ${p.totalItemsProcessed} | ${lastRun} |`
|
|
9056
|
+
);
|
|
9057
|
+
}
|
|
9058
|
+
return;
|
|
9059
|
+
}
|
|
9060
|
+
console.log(`Dreams status (last ${windowHours}h):`);
|
|
9061
|
+
console.log(` Window: ${result.windowStart} \u2192 ${result.windowEnd}
|
|
9062
|
+
`);
|
|
9063
|
+
for (const phase of ["lightSleep", "rem", "deepSleep"]) {
|
|
9064
|
+
const p = result.phases[phase];
|
|
9065
|
+
const label = phaseLabels[phase];
|
|
9066
|
+
console.log(` ${label}:`);
|
|
9067
|
+
console.log(` Runs: ${p.runCount}`);
|
|
9068
|
+
console.log(` Total duration: ${p.totalDurationMs}ms`);
|
|
9069
|
+
console.log(` Items processed: ${p.totalItemsProcessed}`);
|
|
9070
|
+
console.log(` Last run: ${p.lastRunAt ?? "\u2014"}`);
|
|
9071
|
+
console.log();
|
|
9072
|
+
}
|
|
9073
|
+
});
|
|
9074
|
+
dreamsCmd.command("run").description("Manually invoke a single Dreams phase pass").requiredOption("--phase <phase>", "Phase to run: light-sleep, rem, deep-sleep").option("--dry-run", "Preview without committing writes").option("--format <fmt>", "Output format: text, json (default text)", "text").option("--namespace <ns>", "Namespace to run in (default: current default namespace)").option("--principal <principal>", "Trusted principal for namespace ACLs (defaults to config/env)").action(async (...args) => {
|
|
9075
|
+
const options = args[0] ?? {};
|
|
9076
|
+
const phaseInput = typeof options.phase === "string" ? options.phase : "";
|
|
9077
|
+
if ("dryRun" in options && options.dryRun !== void 0 && typeof options.dryRun !== "boolean") {
|
|
9078
|
+
console.error("--dry-run must be a boolean flag");
|
|
9079
|
+
process.exit(1);
|
|
9080
|
+
}
|
|
9081
|
+
const dryRun = options.dryRun === true;
|
|
9082
|
+
const fmt = typeof options.format === "string" ? options.format : "text";
|
|
9083
|
+
if (fmt !== "text" && fmt !== "json") {
|
|
9084
|
+
console.error(`Invalid --format '${fmt}'. Must be one of: text, json`);
|
|
9085
|
+
process.exit(1);
|
|
9086
|
+
}
|
|
9087
|
+
const phaseMap = {
|
|
9088
|
+
"light-sleep": "lightSleep",
|
|
9089
|
+
lightsleep: "lightSleep",
|
|
9090
|
+
lightSleep: "lightSleep",
|
|
9091
|
+
rem: "rem",
|
|
9092
|
+
REM: "rem",
|
|
9093
|
+
"deep-sleep": "deepSleep",
|
|
9094
|
+
deepsleep: "deepSleep",
|
|
9095
|
+
deepSleep: "deepSleep"
|
|
9096
|
+
};
|
|
9097
|
+
const phase = phaseMap[phaseInput];
|
|
9098
|
+
if (!phase) {
|
|
9099
|
+
console.error(
|
|
9100
|
+
`Invalid --phase '${phaseInput}'. Must be one of: light-sleep, rem, deep-sleep`
|
|
9101
|
+
);
|
|
9102
|
+
process.exit(1);
|
|
9103
|
+
}
|
|
9104
|
+
const accessService2 = new EngramAccessService(orchestrator);
|
|
9105
|
+
const result = await accessService2.dreamsRun({
|
|
9106
|
+
phase,
|
|
9107
|
+
dryRun,
|
|
9108
|
+
namespace: typeof options.namespace === "string" ? options.namespace : void 0,
|
|
9109
|
+
authenticatedPrincipal: resolveAccessPrincipalOverride(
|
|
9110
|
+
options.principal,
|
|
9111
|
+
orchestrator.config.agentAccessHttp.principal
|
|
9112
|
+
)
|
|
9113
|
+
});
|
|
9114
|
+
if (fmt === "json") {
|
|
9115
|
+
console.log(JSON.stringify(result, null, 2));
|
|
9116
|
+
return;
|
|
9117
|
+
}
|
|
9118
|
+
const phaseLabel = { lightSleep: "Light Sleep", rem: "REM", deepSleep: "Deep Sleep" }[phase];
|
|
9119
|
+
console.log(`Dreams run: ${phaseLabel}${dryRun ? " (dry-run)" : ""}`);
|
|
9120
|
+
console.log(` Duration: ${result.durationMs}ms`);
|
|
9121
|
+
console.log(` Items: ${result.itemsProcessed}`);
|
|
9122
|
+
if (result.notes) {
|
|
9123
|
+
console.log(` Notes: ${result.notes}`);
|
|
9124
|
+
}
|
|
9125
|
+
});
|
|
9126
|
+
const secureStoreCmd = cmd.command("secure-store").description(
|
|
9127
|
+
"At-rest encryption keyring (issue #690). Manage the secure-store header and the in-memory master key used by the running daemon."
|
|
9128
|
+
);
|
|
9129
|
+
secureStoreCmd.command("init").description(
|
|
9130
|
+
"Initialize a new secure-store header. Prompts for a passphrase, derives a master key via Argon2id by default, and writes the verifier to <memoryDir>/.secure-store/header.json. Refuses to overwrite an existing header."
|
|
9131
|
+
).option("--kdf <algorithm>", "KDF algorithm: argon2id (default) or scrypt", "argon2id").option("--note <text>", "Optional human-readable note recorded in metadata. Never include secrets.").option("--json", "Emit machine-readable JSON only").action(async (...args) => {
|
|
9132
|
+
const options = args[0] ?? {};
|
|
9133
|
+
const {
|
|
9134
|
+
runSecureStoreInit,
|
|
9135
|
+
createPassphraseReader,
|
|
9136
|
+
renderInitReport
|
|
9137
|
+
} = await import("./secure-store-4R2GSO7S.js");
|
|
9138
|
+
const memoryDir = expandTildePath(orchestrator.config.memoryDir);
|
|
9139
|
+
const kdf = typeof options.kdf === "string" ? options.kdf.trim() : "argon2id";
|
|
9140
|
+
if (kdf !== "argon2id" && kdf !== "scrypt") {
|
|
9141
|
+
console.error(`Invalid --kdf '${String(options.kdf)}'. Must be one of: argon2id, scrypt`);
|
|
9142
|
+
process.exit(1);
|
|
9143
|
+
}
|
|
9144
|
+
const initOpts = {
|
|
9145
|
+
memoryDir,
|
|
9146
|
+
readPassphrase: createPassphraseReader(),
|
|
9147
|
+
algorithm: kdf
|
|
9148
|
+
};
|
|
9149
|
+
if (typeof options.note === "string") initOpts.note = options.note;
|
|
9150
|
+
const report = await runSecureStoreInit(initOpts);
|
|
9151
|
+
if (options.json === true) {
|
|
9152
|
+
console.log(JSON.stringify(report, null, 2));
|
|
9153
|
+
return;
|
|
9154
|
+
}
|
|
9155
|
+
console.log(renderInitReport(report));
|
|
9156
|
+
});
|
|
9157
|
+
secureStoreCmd.command("unlock").description(
|
|
9158
|
+
"Unlock the secure-store. Prompts for the passphrase, validates it against the header verifier, and registers the master key in the daemon's in-memory keyring. The key is cleared on `lock`, daemon restart, or process exit."
|
|
9159
|
+
).option("--json", "Emit machine-readable JSON only").action(async (...args) => {
|
|
9160
|
+
const options = args[0] ?? {};
|
|
9161
|
+
const {
|
|
9162
|
+
runSecureStoreUnlock,
|
|
9163
|
+
createPassphraseReader,
|
|
9164
|
+
renderUnlockReport
|
|
9165
|
+
} = await import("./secure-store-4R2GSO7S.js");
|
|
9166
|
+
const memoryDir = expandTildePath(orchestrator.config.memoryDir);
|
|
9167
|
+
const report = await runSecureStoreUnlock({
|
|
9168
|
+
memoryDir,
|
|
9169
|
+
readPassphrase: createPassphraseReader()
|
|
9170
|
+
});
|
|
9171
|
+
if (options.json === true) {
|
|
9172
|
+
console.log(JSON.stringify(report, null, 2));
|
|
9173
|
+
} else {
|
|
9174
|
+
console.log(renderUnlockReport(report));
|
|
9175
|
+
}
|
|
9176
|
+
if (!report.ok) {
|
|
9177
|
+
process.exitCode = 1;
|
|
9178
|
+
}
|
|
9179
|
+
});
|
|
9180
|
+
secureStoreCmd.command("lock").description(
|
|
9181
|
+
"Lock the secure-store. Clears the master key from the daemon's in-memory keyring. Idempotent \u2014 succeeds even if the store is already locked."
|
|
9182
|
+
).option("--json", "Emit machine-readable JSON only").action(async (...args) => {
|
|
9183
|
+
const options = args[0] ?? {};
|
|
9184
|
+
const { runSecureStoreLock, renderLockReport } = await import("./secure-store-4R2GSO7S.js");
|
|
9185
|
+
const memoryDir = expandTildePath(orchestrator.config.memoryDir);
|
|
9186
|
+
const report = runSecureStoreLock({ memoryDir });
|
|
9187
|
+
if (options.json === true) {
|
|
9188
|
+
console.log(JSON.stringify(report, null, 2));
|
|
9189
|
+
return;
|
|
9190
|
+
}
|
|
9191
|
+
console.log(renderLockReport(report));
|
|
9192
|
+
});
|
|
9193
|
+
secureStoreCmd.command("migrate").description(
|
|
9194
|
+
"Encrypt existing plaintext storage-managed memory files in an initialized, unlocked secure-store. Idempotent; already-encrypted files are skipped."
|
|
9195
|
+
).option("--json", "Emit machine-readable JSON only").action(async (...args) => {
|
|
9196
|
+
const options = args[0] ?? {};
|
|
9197
|
+
const { runSecureStoreMigrate, renderMigrateReport } = await import("./secure-store-4R2GSO7S.js");
|
|
9198
|
+
const memoryDir = expandTildePath(orchestrator.config.memoryDir);
|
|
9199
|
+
const report = await runSecureStoreMigrate({ memoryDir });
|
|
9200
|
+
if (options.json === true) {
|
|
9201
|
+
console.log(JSON.stringify(report, null, 2));
|
|
9202
|
+
} else {
|
|
9203
|
+
console.log(renderMigrateReport(report));
|
|
9204
|
+
}
|
|
9205
|
+
if (!report.ok) {
|
|
9206
|
+
process.exitCode = 1;
|
|
9207
|
+
}
|
|
9208
|
+
});
|
|
9209
|
+
async function runSecureStoreDisableCommand(options) {
|
|
9210
|
+
const { runSecureStoreDisable, renderDisableReport } = await import("./secure-store-4R2GSO7S.js");
|
|
9211
|
+
const memoryDir = expandTildePath(orchestrator.config.memoryDir);
|
|
9212
|
+
const report = await runSecureStoreDisable({ memoryDir });
|
|
9213
|
+
if (options.json === true) {
|
|
9214
|
+
console.log(JSON.stringify(report, null, 2));
|
|
9215
|
+
} else {
|
|
9216
|
+
console.log(renderDisableReport(report));
|
|
9217
|
+
}
|
|
9218
|
+
if (!report.ok) {
|
|
9219
|
+
process.exitCode = 1;
|
|
9220
|
+
}
|
|
9221
|
+
}
|
|
9222
|
+
secureStoreCmd.command("disable").description(
|
|
9223
|
+
"Decrypt storage-managed secure-store files back to plaintext. Requires an initialized, unlocked secure-store and keeps .secure-store metadata in place."
|
|
9224
|
+
).option("--json", "Emit machine-readable JSON only").action(async (...args) => {
|
|
9225
|
+
const options = args[0] ?? {};
|
|
9226
|
+
await runSecureStoreDisableCommand(options);
|
|
9227
|
+
});
|
|
9228
|
+
secureStoreCmd.command("decrypt").description("Alias for `secure-store disable`.").option("--json", "Emit machine-readable JSON only").action(async (...args) => {
|
|
9229
|
+
const options = args[0] ?? {};
|
|
9230
|
+
await runSecureStoreDisableCommand(options);
|
|
9231
|
+
});
|
|
9232
|
+
secureStoreCmd.command("status").description(
|
|
9233
|
+
"Report secure-store status: whether a header exists, whether the daemon currently holds the key, KDF parameters, and last-unlock timestamp."
|
|
9234
|
+
).option("--json", "Emit machine-readable JSON only").action(async (...args) => {
|
|
9235
|
+
const options = args[0] ?? {};
|
|
9236
|
+
const { runSecureStoreStatus, renderStatusReport } = await import("./secure-store-4R2GSO7S.js");
|
|
9237
|
+
const memoryDir = expandTildePath(orchestrator.config.memoryDir);
|
|
9238
|
+
const report = await runSecureStoreStatus({ memoryDir });
|
|
9239
|
+
if (options.json === true) {
|
|
9240
|
+
console.log(JSON.stringify(report, null, 2));
|
|
9241
|
+
return;
|
|
9242
|
+
}
|
|
9243
|
+
console.log(renderStatusReport(report));
|
|
9244
|
+
});
|
|
9245
|
+
const peerCmd = cmd.command("peer").description("Manage the peer registry (issue #679).");
|
|
9246
|
+
peerCmd.command("list").description("List all registered peers").option("--json", "Emit machine-readable JSON only").action(async (...args) => {
|
|
9247
|
+
const options = args[0] ?? {};
|
|
9248
|
+
const { listPeers } = await import("./peers-6OSQ3NK6.js");
|
|
9249
|
+
const peers = await listPeers(orchestrator.config.memoryDir);
|
|
9250
|
+
if (options.json === true) {
|
|
9251
|
+
console.log(JSON.stringify({ peers }, null, 2));
|
|
9252
|
+
return;
|
|
9253
|
+
}
|
|
9254
|
+
if (peers.length === 0) {
|
|
9255
|
+
console.log("No peers registered.");
|
|
9256
|
+
return;
|
|
9257
|
+
}
|
|
9258
|
+
console.log(`${peers.length} peer(s):
|
|
9259
|
+
`);
|
|
9260
|
+
for (const p of peers) {
|
|
9261
|
+
console.log(` ${p.id} (${p.kind}) ${p.displayName}`);
|
|
9262
|
+
console.log(` created: ${p.createdAt} updated: ${p.updatedAt}`);
|
|
9263
|
+
}
|
|
9264
|
+
});
|
|
9265
|
+
peerCmd.command("show <id>").description("Show a peer's identity record").option("--json", "Emit machine-readable JSON only").action(async (...args) => {
|
|
9266
|
+
const id = typeof args[0] === "string" ? args[0] : "";
|
|
9267
|
+
const options = args[1] ?? {};
|
|
9268
|
+
if (!id) {
|
|
9269
|
+
console.error("peer id is required");
|
|
9270
|
+
process.exit(1);
|
|
9271
|
+
}
|
|
9272
|
+
const peersShow = await import("./peers-6OSQ3NK6.js");
|
|
9273
|
+
const validateIdShow = peersShow.assertValidPeerId;
|
|
9274
|
+
try {
|
|
9275
|
+
validateIdShow(id);
|
|
9276
|
+
} catch (err) {
|
|
9277
|
+
console.error(`Invalid peer id: ${err.message}`);
|
|
9278
|
+
process.exit(1);
|
|
9279
|
+
}
|
|
9280
|
+
const peer = await peersShow.readPeer(orchestrator.config.memoryDir, id);
|
|
9281
|
+
if (!peer) {
|
|
9282
|
+
console.error(`Peer "${id}" not found.`);
|
|
9283
|
+
process.exit(1);
|
|
9284
|
+
}
|
|
9285
|
+
if (options.json === true) {
|
|
9286
|
+
console.log(JSON.stringify(peer, null, 2));
|
|
9287
|
+
return;
|
|
9288
|
+
}
|
|
9289
|
+
console.log(`Peer: ${peer.id}`);
|
|
9290
|
+
console.log(` Kind: ${peer.kind}`);
|
|
9291
|
+
console.log(` Display name: ${peer.displayName}`);
|
|
9292
|
+
console.log(` Created: ${peer.createdAt}`);
|
|
9293
|
+
console.log(` Updated: ${peer.updatedAt}`);
|
|
9294
|
+
if (peer.notes) {
|
|
9295
|
+
console.log(` Notes:
|
|
9296
|
+
${peer.notes.split("\n").map((l) => ` ${l}`).join("\n")}`);
|
|
9297
|
+
}
|
|
9298
|
+
});
|
|
9299
|
+
peerCmd.command("set <id>").description("Create or update a peer identity record").option("--kind <kind>", "Peer kind: self | human | agent | integration (only on first write)").option("--display-name <name>", "Human-readable display name").option("--notes <text>", "Optional free-form markdown notes").option("--json", "Emit machine-readable JSON only").action(async (...args) => {
|
|
9300
|
+
const id = typeof args[0] === "string" ? args[0] : "";
|
|
9301
|
+
const options = args[1] ?? {};
|
|
9302
|
+
if (!id) {
|
|
9303
|
+
console.error("peer id is required");
|
|
9304
|
+
process.exit(1);
|
|
9305
|
+
}
|
|
9306
|
+
const peerSetService = new EngramAccessService(orchestrator);
|
|
9307
|
+
try {
|
|
9308
|
+
const result = await peerSetService.peerSet({
|
|
9309
|
+
id,
|
|
9310
|
+
...typeof options.kind === "string" ? { kind: options.kind } : {},
|
|
9311
|
+
...typeof options.displayName === "string" ? { displayName: options.displayName } : {},
|
|
9312
|
+
...typeof options.notes === "string" ? { notes: options.notes } : {}
|
|
9313
|
+
});
|
|
9314
|
+
if (options.json === true) {
|
|
9315
|
+
console.log(JSON.stringify(result, null, 2));
|
|
9316
|
+
return;
|
|
9317
|
+
}
|
|
9318
|
+
console.log(`${result.created ? "Created" : "Updated"} peer "${id}".`);
|
|
9319
|
+
} catch (err) {
|
|
9320
|
+
console.error(`Failed to set peer: ${err.message}`);
|
|
9321
|
+
process.exit(1);
|
|
9322
|
+
}
|
|
9323
|
+
});
|
|
9324
|
+
peerCmd.command("delete <id>").description("Delete a peer's identity record (idempotent; directory and profile are preserved)").option("--json", "Emit machine-readable JSON only").action(async (...args) => {
|
|
9325
|
+
const id = typeof args[0] === "string" ? args[0] : "";
|
|
9326
|
+
const options = args[1] ?? {};
|
|
9327
|
+
if (!id) {
|
|
9328
|
+
console.error("peer id is required");
|
|
9329
|
+
process.exit(1);
|
|
9330
|
+
}
|
|
9331
|
+
const peerDeleteService = new EngramAccessService(orchestrator);
|
|
9332
|
+
try {
|
|
9333
|
+
const result = await peerDeleteService.peerDelete(id);
|
|
9334
|
+
if (options.json === true) {
|
|
9335
|
+
console.log(JSON.stringify(result, null, 2));
|
|
9336
|
+
return;
|
|
9337
|
+
}
|
|
9338
|
+
console.log(result.deleted ? `Deleted peer "${id}".` : `Peer "${id}" not found (no-op).`);
|
|
9339
|
+
} catch (err) {
|
|
9340
|
+
console.error(`Failed to delete peer: ${err.message}`);
|
|
9341
|
+
process.exit(1);
|
|
9342
|
+
}
|
|
9343
|
+
});
|
|
9344
|
+
peerCmd.command("forget <id>").description(
|
|
9345
|
+
"DESTRUCTIVELY purge the entire peer directory (identity.md + profile.md + interactions.log.md and any other companion files). Requires --confirm yes. Idempotent: safe to run twice."
|
|
9346
|
+
).option(
|
|
9347
|
+
"--confirm <value>",
|
|
9348
|
+
'Confirmation guard \u2014 must be exactly "yes" to proceed'
|
|
9349
|
+
).option("--json", "Emit machine-readable JSON only").action(async (...args) => {
|
|
9350
|
+
const id = typeof args[0] === "string" ? args[0] : "";
|
|
9351
|
+
const options = args[1] ?? {};
|
|
9352
|
+
if (!id) {
|
|
9353
|
+
console.error("peer id is required");
|
|
9354
|
+
process.exit(1);
|
|
9355
|
+
}
|
|
9356
|
+
const confirm = typeof options.confirm === "string" ? options.confirm : "";
|
|
9357
|
+
if (confirm !== "yes") {
|
|
9358
|
+
console.error(
|
|
9359
|
+
`peer forget: refuses to run without --confirm yes (got ${confirm.length > 0 ? JSON.stringify(confirm) : "<not provided>"}). This operation permanently removes all peer data.`
|
|
9360
|
+
);
|
|
9361
|
+
process.exit(1);
|
|
9362
|
+
}
|
|
9363
|
+
const peerForgetService = new EngramAccessService(orchestrator);
|
|
9364
|
+
try {
|
|
9365
|
+
const result = await peerForgetService.peerForget(id, { confirm: "yes" });
|
|
9366
|
+
if (options.json === true) {
|
|
9367
|
+
console.log(JSON.stringify(result, null, 2));
|
|
9368
|
+
return;
|
|
9369
|
+
}
|
|
9370
|
+
console.log(
|
|
9371
|
+
result.purged ? `Purged all data for peer "${id}".` : `Peer "${id}" directory not found (no-op).`
|
|
9372
|
+
);
|
|
9373
|
+
} catch (err) {
|
|
9374
|
+
console.error(`Failed to forget peer: ${err.message}`);
|
|
9375
|
+
process.exit(1);
|
|
9376
|
+
}
|
|
9377
|
+
});
|
|
9378
|
+
peerCmd.command("profile <id>").description("Show the evolving cognitive profile for a peer").option("--json", "Emit machine-readable JSON only").action(async (...args) => {
|
|
9379
|
+
const id = typeof args[0] === "string" ? args[0] : "";
|
|
9380
|
+
const options = args[1] ?? {};
|
|
9381
|
+
if (!id) {
|
|
9382
|
+
console.error("peer id is required");
|
|
9383
|
+
process.exit(1);
|
|
9384
|
+
}
|
|
9385
|
+
const peersProfile = await import("./peers-6OSQ3NK6.js");
|
|
9386
|
+
const validateIdProfile = peersProfile.assertValidPeerId;
|
|
9387
|
+
try {
|
|
9388
|
+
validateIdProfile(id);
|
|
9389
|
+
} catch (err) {
|
|
9390
|
+
console.error(`Invalid peer id: ${err.message}`);
|
|
9391
|
+
process.exit(1);
|
|
9392
|
+
}
|
|
9393
|
+
const profile = await peersProfile.readPeerProfile(orchestrator.config.memoryDir, id);
|
|
9394
|
+
if (!profile) {
|
|
9395
|
+
console.error(`No profile found for peer "${id}". The profile is written by the async reasoner.`);
|
|
9396
|
+
process.exit(1);
|
|
9397
|
+
}
|
|
9398
|
+
if (options.json === true) {
|
|
9399
|
+
console.log(JSON.stringify(profile, null, 2));
|
|
9400
|
+
return;
|
|
9401
|
+
}
|
|
9402
|
+
console.log(`Profile for peer: ${id}`);
|
|
9403
|
+
console.log(` Updated: ${profile.updatedAt}`);
|
|
9404
|
+
const fieldKeys = Object.keys(profile.fields);
|
|
9405
|
+
if (fieldKeys.length === 0) {
|
|
9406
|
+
console.log(" No profile fields yet.");
|
|
9407
|
+
} else {
|
|
9408
|
+
for (const k of fieldKeys) {
|
|
9409
|
+
console.log(` ${k}:`);
|
|
9410
|
+
console.log(` ${profile.fields[k]}`);
|
|
9411
|
+
}
|
|
9412
|
+
}
|
|
9413
|
+
});
|
|
9414
|
+
peerCmd.command("migrate").description(
|
|
9415
|
+
"Migrate legacy identity-anchor data into peers/self/identity.md (issue #679 PR 5/5). Idempotent: safe to run multiple times. Use --dry-run to preview without writing."
|
|
9416
|
+
).option("--dry-run", "Preview the proposed peer record without writing anything to disk").option("--display-name <name>", 'Override the default display name for the self peer (default: "Self")').option("--json", "Emit machine-readable JSON result").action(async (...args) => {
|
|
9417
|
+
const options = args[0] ?? {};
|
|
9418
|
+
const isDryRun = options.dryRun === true;
|
|
9419
|
+
const displayName = typeof options.displayName === "string" && options.displayName.length > 0 ? options.displayName : void 0;
|
|
9420
|
+
const { migrateFromIdentityAnchor } = await import("./migrate-from-identity-anchor-TTEDEJGX.js");
|
|
9421
|
+
let result;
|
|
9422
|
+
try {
|
|
9423
|
+
result = await migrateFromIdentityAnchor({
|
|
9424
|
+
memoryDir: orchestrator.config.memoryDir,
|
|
9425
|
+
dryRun: isDryRun,
|
|
9426
|
+
...displayName !== void 0 ? { displayName } : {}
|
|
9427
|
+
});
|
|
9428
|
+
} catch (err) {
|
|
9429
|
+
console.error(`Migration failed: ${err.message}`);
|
|
9430
|
+
process.exit(1);
|
|
9431
|
+
}
|
|
9432
|
+
if (options.json === true) {
|
|
9433
|
+
console.log(JSON.stringify(result, null, 2));
|
|
9434
|
+
return;
|
|
9435
|
+
}
|
|
9436
|
+
if (result.skipped) {
|
|
9437
|
+
console.log(`Peer "self" already exists \u2014 migration skipped (idempotent).`);
|
|
9438
|
+
console.log(` peers/self/identity.md is unchanged.`);
|
|
9439
|
+
return;
|
|
9440
|
+
}
|
|
9441
|
+
if (result.dryRun) {
|
|
9442
|
+
console.log(`[dry-run] Migration preview \u2014 nothing was written.`);
|
|
9443
|
+
console.log(` Proposed peer id: ${result.peer.id}`);
|
|
9444
|
+
console.log(` Proposed kind: ${result.peer.kind}`);
|
|
9445
|
+
console.log(` Proposed name: ${result.peer.displayName}`);
|
|
9446
|
+
if (result.identityAnchorSource) {
|
|
9447
|
+
console.log(` Would read anchor: ${result.identityAnchorSource}`);
|
|
9448
|
+
}
|
|
9449
|
+
if (result.identityMdSource) {
|
|
9450
|
+
console.log(` Would read identity:${result.identityMdSource}`);
|
|
9451
|
+
}
|
|
9452
|
+
if (!result.identityAnchorSource && !result.identityMdSource) {
|
|
9453
|
+
console.log(` No legacy source files found \u2014 self peer would be created with no notes.`);
|
|
9454
|
+
}
|
|
9455
|
+
return;
|
|
9456
|
+
}
|
|
9457
|
+
console.log(`Migrated identity-anchor data to peers/self/identity.md.`);
|
|
9458
|
+
if (result.identityAnchorSource) {
|
|
9459
|
+
console.log(` Read anchor: ${result.identityAnchorSource}`);
|
|
9460
|
+
}
|
|
9461
|
+
if (result.identityMdSource) {
|
|
9462
|
+
console.log(` Read identity:${result.identityMdSource}`);
|
|
9463
|
+
}
|
|
9464
|
+
if (!result.identityAnchorSource && !result.identityMdSource) {
|
|
9465
|
+
console.log(` No legacy source files found \u2014 self peer created with no notes.`);
|
|
9466
|
+
}
|
|
9467
|
+
console.log(`
|
|
9468
|
+
Legacy identity-anchor files are untouched. Verify the migration result`);
|
|
9469
|
+
console.log(`with \`remnic peer show self\` before archiving legacy files.`);
|
|
9470
|
+
});
|
|
9471
|
+
cmd.command("console").description(
|
|
9472
|
+
"Operator console (issue #688). With no flags: launches the interactive TUI. With --state-only: prints a single JSON snapshot. With --record-trace <path>: appends every snapshot to a JSONL file. With --trace <path>: replays a recorded trace at the original cadence (or --speed N)."
|
|
9473
|
+
).option(
|
|
9474
|
+
"--state-only",
|
|
9475
|
+
"Print a single console-state snapshot as JSON and exit"
|
|
9476
|
+
).option(
|
|
9477
|
+
"--record-trace <path>",
|
|
9478
|
+
"Append every snapshot to <path> as JSONL while the TUI runs"
|
|
9479
|
+
).option(
|
|
9480
|
+
"--trace <path>",
|
|
9481
|
+
"Replay a recorded JSONL trace file frame-by-frame at the original cadence"
|
|
9482
|
+
).option(
|
|
9483
|
+
"--speed <multiplier>",
|
|
9484
|
+
"Replay speed multiplier (default 1.0). 2.0 = twice as fast; 0.5 = half speed."
|
|
9485
|
+
).action(async (...args) => {
|
|
9486
|
+
const options = args[0] ?? {};
|
|
9487
|
+
if (options.stateOnly === true) {
|
|
9488
|
+
const { gatherConsoleState } = await import("./state-NCHQ4TRG.js");
|
|
9489
|
+
const snapshot = await gatherConsoleState(orchestrator);
|
|
9490
|
+
console.log(JSON.stringify(snapshot, null, 2));
|
|
9491
|
+
return;
|
|
9492
|
+
}
|
|
9493
|
+
if (typeof options.trace === "string" && options.trace.length > 0) {
|
|
9494
|
+
const { replayTrace, parseSpeedFlag } = await import("./trace-C5ETWBEF.js");
|
|
9495
|
+
const { expandTildePath: expandTildePath2 } = await import("./path-RMTY5Y5A.js");
|
|
9496
|
+
const tracePath = expandTildePath2(options.trace);
|
|
9497
|
+
let speed;
|
|
9498
|
+
try {
|
|
9499
|
+
speed = parseSpeedFlag(options.speed);
|
|
9500
|
+
} catch (err) {
|
|
9501
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
9502
|
+
console.error(`remnic console: ${msg}`);
|
|
9503
|
+
process.exitCode = 2;
|
|
9504
|
+
return;
|
|
9505
|
+
}
|
|
9506
|
+
const replayAbort = new AbortController();
|
|
9507
|
+
const replaySigintHandler = () => replayAbort.abort();
|
|
9508
|
+
process.on("SIGINT", replaySigintHandler);
|
|
9509
|
+
try {
|
|
9510
|
+
await replayTrace(tracePath, {
|
|
9511
|
+
speed,
|
|
9512
|
+
signal: replayAbort.signal
|
|
9513
|
+
});
|
|
9514
|
+
} finally {
|
|
9515
|
+
try {
|
|
9516
|
+
process.removeListener("SIGINT", replaySigintHandler);
|
|
9517
|
+
} catch {
|
|
9518
|
+
}
|
|
9519
|
+
}
|
|
9520
|
+
return;
|
|
9521
|
+
}
|
|
9522
|
+
const { runConsoleTui } = await import("./tui-RI7P6PBS.js");
|
|
9523
|
+
let recorder = null;
|
|
9524
|
+
if (typeof options.recordTrace === "string" && options.recordTrace.length > 0) {
|
|
9525
|
+
const { openTraceRecorder } = await import("./trace-C5ETWBEF.js");
|
|
9526
|
+
const { expandTildePath: expandTildePath2 } = await import("./path-RMTY5Y5A.js");
|
|
9527
|
+
recorder = await openTraceRecorder(
|
|
9528
|
+
expandTildePath2(options.recordTrace)
|
|
9529
|
+
);
|
|
9530
|
+
}
|
|
9531
|
+
const handle = runConsoleTui(orchestrator, {
|
|
9532
|
+
traceRecorder: recorder ?? void 0
|
|
9533
|
+
});
|
|
9534
|
+
try {
|
|
9535
|
+
await handle.done;
|
|
9536
|
+
} finally {
|
|
9537
|
+
if (recorder) {
|
|
9538
|
+
const CLOSE_TIMEOUT_MS = 2e3;
|
|
9539
|
+
const { flushWithTimeout } = await import("./trace-C5ETWBEF.js");
|
|
9540
|
+
const flushResult = await flushWithTimeout(
|
|
9541
|
+
(signal) => recorder.close(signal),
|
|
9542
|
+
CLOSE_TIMEOUT_MS
|
|
9543
|
+
);
|
|
9544
|
+
if (flushResult.timedOut) {
|
|
9545
|
+
console.warn(
|
|
9546
|
+
`[remnic console] trace flush timed out after ${CLOSE_TIMEOUT_MS}ms; some final frames may be lost`
|
|
9547
|
+
);
|
|
9548
|
+
}
|
|
9549
|
+
if (flushResult.error != null) {
|
|
9550
|
+
const msg = flushResult.error instanceof Error ? flushResult.error.message : String(flushResult.error);
|
|
9551
|
+
console.warn(
|
|
9552
|
+
`[remnic console] trace flush error: ${msg}`
|
|
9553
|
+
);
|
|
9554
|
+
}
|
|
9555
|
+
}
|
|
9556
|
+
}
|
|
9557
|
+
});
|
|
7979
9558
|
},
|
|
7980
9559
|
{ commands: ["engram"] }
|
|
7981
9560
|
);
|
|
@@ -8007,7 +9586,6 @@ export {
|
|
|
8007
9586
|
formatBatchTranscript,
|
|
8008
9587
|
runBulkImportPipeline,
|
|
8009
9588
|
convertMemoriesToRecords,
|
|
8010
|
-
parseStrictCliDate,
|
|
8011
9589
|
registerTrainingExportAdapter,
|
|
8012
9590
|
getTrainingExportAdapter,
|
|
8013
9591
|
listTrainingExportAdapters,
|
|
@@ -8046,6 +9624,8 @@ export {
|
|
|
8046
9624
|
runCueAnchorStatusCliCommand,
|
|
8047
9625
|
runHarmonicSearchCliCommand,
|
|
8048
9626
|
runVerifiedRecallSearchCliCommand,
|
|
9627
|
+
isNormalRetrievalVisibleMemory,
|
|
9628
|
+
filterNormalMemorySearchResults,
|
|
8049
9629
|
runSemanticRulePromoteCliCommand,
|
|
8050
9630
|
runCompoundingPromoteCliCommand,
|
|
8051
9631
|
runSemanticRuleVerifyCliCommand,
|
|
@@ -8073,7 +9653,9 @@ export {
|
|
|
8073
9653
|
runMigrateRescoreImportanceCliCommand,
|
|
8074
9654
|
runMigrateRechunkCliCommand,
|
|
8075
9655
|
runMigrateReextractCliCommand,
|
|
8076
|
-
parseStrictCliDate2,
|
|
9656
|
+
parseStrictCliDate2 as parseStrictCliDate,
|
|
9657
|
+
parseDurationToMs,
|
|
9658
|
+
hasDestructivePurgeFailures,
|
|
8077
9659
|
runPolicyStatusCliCommand,
|
|
8078
9660
|
runPolicyDiffCliCommand,
|
|
8079
9661
|
runPolicyRollbackCliCommand,
|
|
@@ -8098,4 +9680,4 @@ export {
|
|
|
8098
9680
|
resolveMemoryDirForNamespace,
|
|
8099
9681
|
registerCli
|
|
8100
9682
|
};
|
|
8101
|
-
//# sourceMappingURL=chunk-
|
|
9683
|
+
//# sourceMappingURL=chunk-ZGXSCMQN.js.map
|