@remnic/core 1.1.1 → 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.
Files changed (497) hide show
  1. package/dist/abort-error.js +1 -0
  2. package/dist/abstraction-nodes.js +1 -0
  3. package/dist/access-audit.js +1 -0
  4. package/dist/access-cli.js +76 -51
  5. package/dist/access-cli.js.map +1 -1
  6. package/dist/access-http.d.ts +50 -5
  7. package/dist/access-http.js +38 -16
  8. package/dist/access-idempotency.js +1 -0
  9. package/dist/access-mcp.d.ts +10 -5
  10. package/dist/access-mcp.js +37 -14
  11. package/dist/access-schema.d.ts +133 -13
  12. package/dist/access-schema.js +20 -1
  13. package/dist/access-service-_AEUMVyX.d.ts +1981 -0
  14. package/dist/access-service.d.ts +11 -6
  15. package/dist/access-service.js +39 -14
  16. package/dist/active-memory-bridge.js +1 -0
  17. package/dist/active-recall.js +1 -0
  18. package/dist/active-recall.js.map +1 -1
  19. package/dist/behavior-learner.js +1 -0
  20. package/dist/behavior-learner.js.map +1 -1
  21. package/dist/behavior-signals.js +1 -0
  22. package/dist/bootstrap.d.ts +6 -4
  23. package/dist/bootstrap.js +1 -0
  24. package/dist/boxes.js +1 -0
  25. package/dist/briefing.d.ts +9 -5
  26. package/dist/briefing.js +10 -6
  27. package/dist/buffer-surprise-report.js +1 -0
  28. package/dist/buffer-surprise.js +1 -0
  29. package/dist/buffer.d.ts +1 -1
  30. package/dist/buffer.js +1 -0
  31. package/dist/calibration.d.ts +8 -1
  32. package/dist/calibration.js +10 -2
  33. package/dist/calibration.js.map +1 -1
  34. package/dist/capsule-cli.d.ts +137 -0
  35. package/dist/capsule-cli.js +34 -0
  36. package/dist/capsule-crypto-5CYAGVC5.js +18 -0
  37. package/dist/capsule-export-NZQPOTQ4.js +17 -0
  38. package/dist/capsule-export-NZQPOTQ4.js.map +1 -0
  39. package/dist/capsule-import-SDCUXLEV.js +16 -0
  40. package/dist/capsule-import-SDCUXLEV.js.map +1 -0
  41. package/dist/capsule-merge-DI7PNQ2H.js +189 -0
  42. package/dist/capsule-merge-DI7PNQ2H.js.map +1 -0
  43. package/dist/causal-behavior.js +1 -0
  44. package/dist/causal-behavior.js.map +1 -1
  45. package/dist/causal-chain.js +1 -0
  46. package/dist/causal-consolidation.js +12 -9
  47. package/dist/causal-consolidation.js.map +1 -1
  48. package/dist/causal-retrieval.js +2 -1
  49. package/dist/causal-retrieval.js.map +1 -1
  50. package/dist/causal-trajectory-graph.js +4 -1
  51. package/dist/causal-trajectory-graph.js.map +1 -1
  52. package/dist/causal-trajectory.js +2 -1
  53. package/dist/chunk-2LSZVONP.js +67 -0
  54. package/dist/chunk-2LSZVONP.js.map +1 -0
  55. package/dist/chunk-32KD5IHZ.js +245 -0
  56. package/dist/chunk-32KD5IHZ.js.map +1 -0
  57. package/dist/{chunk-VDX363PS.js → chunk-34F3PLWZ.js} +10 -3
  58. package/dist/chunk-34F3PLWZ.js.map +1 -0
  59. package/dist/chunk-3KIS4VGT.js +228 -0
  60. package/dist/chunk-3KIS4VGT.js.map +1 -0
  61. package/dist/chunk-3LCWFNVS.js +350 -0
  62. package/dist/chunk-3LCWFNVS.js.map +1 -0
  63. package/dist/chunk-43EKP2UK.js +26 -0
  64. package/dist/chunk-43EKP2UK.js.map +1 -0
  65. package/dist/chunk-457A4P3L.js +119 -0
  66. package/dist/chunk-457A4P3L.js.map +1 -0
  67. package/dist/{chunk-KUB6JU6H.js → chunk-47WOM4YW.js} +2 -2
  68. package/dist/{chunk-HK3FGIEW.js → chunk-4PLGJRBV.js} +656 -20
  69. package/dist/chunk-4PLGJRBV.js.map +1 -0
  70. package/dist/{chunk-BGJGXLZ7.js → chunk-55FXRRSJ.js} +11 -8
  71. package/dist/chunk-55FXRRSJ.js.map +1 -0
  72. package/dist/{chunk-ULYOGL6R.js → chunk-5HRY2WRF.js} +7 -3
  73. package/dist/chunk-5HRY2WRF.js.map +1 -0
  74. package/dist/chunk-6TBWYBJ3.js +236 -0
  75. package/dist/chunk-6TBWYBJ3.js.map +1 -0
  76. package/dist/chunk-74EMIVE4.js +329 -0
  77. package/dist/chunk-74EMIVE4.js.map +1 -0
  78. package/dist/chunk-74WWN7ZW.js +82 -0
  79. package/dist/chunk-74WWN7ZW.js.map +1 -0
  80. package/dist/{chunk-B5WXLVDY.js → chunk-7GCMLT7J.js} +245 -25
  81. package/dist/chunk-7GCMLT7J.js.map +1 -0
  82. package/dist/chunk-A6XUJE5D.js +126 -0
  83. package/dist/chunk-A6XUJE5D.js.map +1 -0
  84. package/dist/chunk-AJA46VX5.js +393 -0
  85. package/dist/chunk-AJA46VX5.js.map +1 -0
  86. package/dist/{chunk-DFTTJYSO.js → chunk-AKUCB2OG.js} +525 -24
  87. package/dist/chunk-AKUCB2OG.js.map +1 -0
  88. package/dist/chunk-ASIQZXYO.js +277 -0
  89. package/dist/chunk-ASIQZXYO.js.map +1 -0
  90. package/dist/{chunk-ZEM3OK2K.js → chunk-B2TL6GA2.js} +3 -3
  91. package/dist/chunk-BJMBJZ2Y.js +290 -0
  92. package/dist/chunk-BJMBJZ2Y.js.map +1 -0
  93. package/dist/chunk-BT7NVCML.js +79 -0
  94. package/dist/chunk-BT7NVCML.js.map +1 -0
  95. package/dist/chunk-CK5NTM2S.js +454 -0
  96. package/dist/chunk-CK5NTM2S.js.map +1 -0
  97. package/dist/{chunk-3GXCSUXR.js → chunk-CRU27Q4J.js} +2 -2
  98. package/dist/{chunk-F5VP6YCB.js → chunk-DCE6SQLA.js} +572 -155
  99. package/dist/chunk-DCE6SQLA.js.map +1 -0
  100. package/dist/{chunk-CUPFXL3J.js → chunk-DHRQHX36.js} +4 -4
  101. package/dist/chunk-DHRQHX36.js.map +1 -0
  102. package/dist/{chunk-GKFXUTJ2.js → chunk-DR7MCMPS.js} +981 -61
  103. package/dist/chunk-DR7MCMPS.js.map +1 -0
  104. package/dist/chunk-FP2373TW.js +149 -0
  105. package/dist/chunk-FP2373TW.js.map +1 -0
  106. package/dist/{chunk-RBBWYEFJ.js → chunk-G2WADRQ3.js} +1 -1
  107. package/dist/chunk-G7D6GZ5J.js +48 -0
  108. package/dist/chunk-G7D6GZ5J.js.map +1 -0
  109. package/dist/chunk-H7XKCNR6.js +60 -0
  110. package/dist/chunk-H7XKCNR6.js.map +1 -0
  111. package/dist/{chunk-VYM3VWOF.js → chunk-IM3JSE73.js} +966 -329
  112. package/dist/chunk-IM3JSE73.js.map +1 -0
  113. package/dist/chunk-IXEJRKCZ.js +18 -0
  114. package/dist/chunk-IXEJRKCZ.js.map +1 -0
  115. package/dist/chunk-IYY4MCPG.js +275 -0
  116. package/dist/chunk-IYY4MCPG.js.map +1 -0
  117. package/dist/{chunk-BK2EFTE2.js → chunk-JWSENLQI.js} +508 -28
  118. package/dist/chunk-JWSENLQI.js.map +1 -0
  119. package/dist/chunk-KNKUID7G.js +183 -0
  120. package/dist/chunk-KNKUID7G.js.map +1 -0
  121. package/dist/chunk-L2IO2QPY.js +2036 -0
  122. package/dist/chunk-L2IO2QPY.js.map +1 -0
  123. package/dist/{chunk-SPI27QT6.js → chunk-L5IIGA5V.js} +9 -4
  124. package/dist/chunk-L5IIGA5V.js.map +1 -0
  125. package/dist/{chunk-RGLL5SPU.js → chunk-LVYGDT5V.js} +56 -82
  126. package/dist/chunk-LVYGDT5V.js.map +1 -0
  127. package/dist/{chunk-ZAIM4TUE.js → chunk-LW2NMHDW.js} +46 -1
  128. package/dist/chunk-LW2NMHDW.js.map +1 -0
  129. package/dist/{chunk-3OGMS3PE.js → chunk-LZRYQK6L.js} +3 -2
  130. package/dist/chunk-LZRYQK6L.js.map +1 -0
  131. package/dist/chunk-MDYG7VI7.js +48 -0
  132. package/dist/chunk-MDYG7VI7.js.map +1 -0
  133. package/dist/chunk-MXC3AP5I.js +74 -0
  134. package/dist/chunk-MXC3AP5I.js.map +1 -0
  135. package/dist/{chunk-S3EEFKNY.js → chunk-N7X62G74.js} +26 -11
  136. package/dist/chunk-N7X62G74.js.map +1 -0
  137. package/dist/chunk-NN3TS5BM.js +147 -0
  138. package/dist/chunk-NN3TS5BM.js.map +1 -0
  139. package/dist/chunk-OA3L7BFR.js +183 -0
  140. package/dist/chunk-OA3L7BFR.js.map +1 -0
  141. package/dist/{chunk-LK6SGL53.js → chunk-OR64ZGRZ.js} +3 -2
  142. package/dist/chunk-OR64ZGRZ.js.map +1 -0
  143. package/dist/chunk-OZHRDTDX.js +240 -0
  144. package/dist/chunk-OZHRDTDX.js.map +1 -0
  145. package/dist/chunk-PCUKNJAZ.js +165 -0
  146. package/dist/chunk-PCUKNJAZ.js.map +1 -0
  147. package/dist/{chunk-6PFRXT4K.js → chunk-PFV5C235.js} +11 -6
  148. package/dist/chunk-PFV5C235.js.map +1 -0
  149. package/dist/chunk-PZ5AY32C.js +10 -0
  150. package/dist/chunk-PZ5AY32C.js.map +1 -0
  151. package/dist/{chunk-XZ2TIKGC.js → chunk-Q7FJ5ZHM.js} +30 -10
  152. package/dist/chunk-Q7FJ5ZHM.js.map +1 -0
  153. package/dist/{chunk-7I7FKFZH.js → chunk-R2L7SUX2.js} +6 -6
  154. package/dist/{chunk-JL2PU6AI.js → chunk-R2XRID2N.js} +2 -2
  155. package/dist/{chunk-WCLICCGB.js → chunk-RILIVK4O.js} +91 -4
  156. package/dist/chunk-RILIVK4O.js.map +1 -0
  157. package/dist/{chunk-C2EFFULQ.js → chunk-RK2Y4XOM.js} +163 -20
  158. package/dist/chunk-RK2Y4XOM.js.map +1 -0
  159. package/dist/{chunk-TP4FZJIZ.js → chunk-RULE4VG5.js} +5 -1
  160. package/dist/chunk-RULE4VG5.js.map +1 -0
  161. package/dist/{chunk-PVPWZSSI.js → chunk-SMA4IMHV.js} +19 -3
  162. package/dist/chunk-SMA4IMHV.js.map +1 -0
  163. package/dist/{chunk-WVVA7F5A.js → chunk-SS253RXF.js} +30 -16
  164. package/dist/chunk-SS253RXF.js.map +1 -0
  165. package/dist/chunk-TUFG6VXY.js +875 -0
  166. package/dist/chunk-TUFG6VXY.js.map +1 -0
  167. package/dist/chunk-TYEOAFH3.js +251 -0
  168. package/dist/chunk-TYEOAFH3.js.map +1 -0
  169. package/dist/chunk-UKJAGEXH.js +260 -0
  170. package/dist/chunk-UKJAGEXH.js.map +1 -0
  171. package/dist/{chunk-KVBLZUKV.js → chunk-USFPPRAF.js} +93 -3
  172. package/dist/chunk-USFPPRAF.js.map +1 -0
  173. package/dist/{chunk-EPQJM2GC.js → chunk-VTJVUHRK.js} +22 -36
  174. package/dist/chunk-VTJVUHRK.js.map +1 -0
  175. package/dist/{chunk-O5ETUNBT.js → chunk-VTU2B4VF.js} +7 -3
  176. package/dist/chunk-VTU2B4VF.js.map +1 -0
  177. package/dist/chunk-WIICJPET.js +45 -0
  178. package/dist/chunk-WIICJPET.js.map +1 -0
  179. package/dist/{chunk-VBVG2M5G.js → chunk-WPGJYVUH.js} +6 -2
  180. package/dist/chunk-WPGJYVUH.js.map +1 -0
  181. package/dist/{chunk-YNQKWQT4.js → chunk-WSZIHQBK.js} +31 -11
  182. package/dist/{chunk-YNQKWQT4.js.map → chunk-WSZIHQBK.js.map} +1 -1
  183. package/dist/{chunk-NZLQTHS5.js → chunk-WW3QQF4H.js} +4 -1
  184. package/dist/chunk-WW3QQF4H.js.map +1 -0
  185. package/dist/{chunk-FVA6TGI3.js → chunk-Y3WQ4ZWK.js} +42 -2
  186. package/dist/chunk-Y3WQ4ZWK.js.map +1 -0
  187. package/dist/chunk-YNJHCGDT.js +309 -0
  188. package/dist/chunk-YNJHCGDT.js.map +1 -0
  189. package/dist/{chunk-ALXMCZEU.js → chunk-Z2E7VW55.js} +6 -3
  190. package/dist/chunk-Z2E7VW55.js.map +1 -0
  191. package/dist/{chunk-INXV5JBT.js → chunk-ZGXSCMQN.js} +1992 -410
  192. package/dist/chunk-ZGXSCMQN.js.map +1 -0
  193. package/dist/{chunk-W6SL7OFG.js → chunk-ZTSE2ZJ6.js} +12 -2
  194. package/dist/{chunk-W6SL7OFG.js.map → chunk-ZTSE2ZJ6.js.map} +1 -1
  195. package/dist/chunking.js +1 -0
  196. package/dist/cipher-GVE2GQ5H.js +28 -0
  197. package/dist/cipher-GVE2GQ5H.js.map +1 -0
  198. package/dist/citations.js +1 -0
  199. package/dist/{cli-BkeRaYfk.d.ts → cli-x2APT9a6.d.ts} +26 -7
  200. package/dist/cli.d.ts +11 -6
  201. package/dist/cli.js +68 -34
  202. package/dist/codex-thread-key.js +1 -0
  203. package/dist/commitment-ledger.js +1 -0
  204. package/dist/compression-optimizer.js +1 -0
  205. package/dist/config.d.ts +2 -1
  206. package/dist/config.js +5 -2
  207. package/dist/connectors-cli-DFGtY2DB.d.ts +257 -0
  208. package/dist/connectors-cli.d.ts +2 -0
  209. package/dist/connectors-cli.js +22 -0
  210. package/dist/connectors-cli.js.map +1 -0
  211. package/dist/consolidation-operator.d.ts +65 -5
  212. package/dist/consolidation-operator.js +6 -1
  213. package/dist/consolidation-provenance-check.d.ts +1 -1
  214. package/dist/consolidation-provenance-check.js +3 -2
  215. package/dist/consolidation-undo.d.ts +1 -1
  216. package/dist/consolidation-undo.js +1 -0
  217. package/dist/consolidation-undo.js.map +1 -1
  218. package/dist/{contradiction-review-WIUBAR52.js → contradiction-review-5LTTVDQV.js} +2 -1
  219. package/dist/contradiction-review-5LTTVDQV.js.map +1 -0
  220. package/dist/{contradiction-scan-E3GJTI4F.js → contradiction-scan-3Z6YW7YA.js} +2 -1
  221. package/dist/{contradiction-scan-E3GJTI4F.js.map → contradiction-scan-3Z6YW7YA.js.map} +1 -1
  222. package/dist/cross-namespace-budget.js +1 -0
  223. package/dist/cue-anchors.js +1 -0
  224. package/dist/dashboard-runtime.js +1 -0
  225. package/dist/day-summary.js +1 -0
  226. package/dist/delinearize.js +1 -0
  227. package/dist/direct-answer-wiring.js +1 -0
  228. package/dist/direct-answer.js +1 -0
  229. package/dist/dreams-ledger-LR2NBAZE.js +286 -0
  230. package/dist/dreams-ledger-LR2NBAZE.js.map +1 -0
  231. package/dist/embedding-fallback.js +3 -1
  232. package/dist/{engine-F3GOXGE5.js → engine-ICC2DSQF.js} +10 -7
  233. package/dist/engine-ICC2DSQF.js.map +1 -0
  234. package/dist/entity-retrieval.d.ts +1 -1
  235. package/dist/entity-retrieval.js +9 -6
  236. package/dist/entity-schema.js +1 -0
  237. package/dist/evals.js +1 -0
  238. package/dist/evidence-pack.d.ts +16 -0
  239. package/dist/evidence-pack.js +8 -0
  240. package/dist/evidence-pack.js.map +1 -0
  241. package/dist/explicit-capture.d.ts +6 -4
  242. package/dist/explicit-capture.js +1 -0
  243. package/dist/extraction-judge-telemetry.js +1 -0
  244. package/dist/extraction-judge-training.js +1 -0
  245. package/dist/extraction-judge.js +1 -0
  246. package/dist/extraction.js +9 -8
  247. package/dist/fallback-llm.js +3 -2
  248. package/dist/first-start-migration-4MHQEOSD.js +263 -0
  249. package/dist/first-start-migration-4MHQEOSD.js.map +1 -0
  250. package/dist/forget-PLR6J5DN.js +69 -0
  251. package/dist/forget-PLR6J5DN.js.map +1 -0
  252. package/dist/framework-CyHYDcri.d.ts +153 -0
  253. package/dist/fs-utils-IRVUFB6G.js +30 -0
  254. package/dist/fs-utils-IRVUFB6G.js.map +1 -0
  255. package/dist/graph-dashboard-diff.js +1 -0
  256. package/dist/graph-dashboard-key.js +1 -0
  257. package/dist/graph-dashboard-parser.js +1 -0
  258. package/dist/graph-edge-decay-PWB63GRE.js +207 -0
  259. package/dist/graph-edge-decay-PWB63GRE.js.map +1 -0
  260. package/dist/graph-edge-reinforcement.d.ts +81 -0
  261. package/dist/graph-edge-reinforcement.js +24 -0
  262. package/dist/graph-edge-reinforcement.js.map +1 -0
  263. package/dist/graph-events.d.ts +87 -0
  264. package/dist/graph-events.js +14 -0
  265. package/dist/graph-events.js.map +1 -0
  266. package/dist/graph-recall.js +1 -0
  267. package/dist/graph-retrieval.js +1 -0
  268. package/dist/graph-snapshot.d.ts +112 -0
  269. package/dist/graph-snapshot.js +19 -0
  270. package/dist/graph-snapshot.js.map +1 -0
  271. package/dist/graph.d.ts +105 -7
  272. package/dist/graph.js +20 -3
  273. package/dist/harmonic-retrieval.js +1 -0
  274. package/dist/himem.js +1 -0
  275. package/dist/hygiene.js +1 -0
  276. package/dist/identity-continuity.js +1 -0
  277. package/dist/importance.js +1 -0
  278. package/dist/index.d.ts +562 -13
  279. package/dist/index.js +365 -96
  280. package/dist/index.js.map +1 -1
  281. package/dist/intent.js +1 -0
  282. package/dist/json-extract.js +1 -0
  283. package/dist/json-store.js +1 -0
  284. package/dist/kdf-7S6RWKLZ.js +26 -0
  285. package/dist/kdf-7S6RWKLZ.js.map +1 -0
  286. package/dist/legacy-hook-compat.js +1 -0
  287. package/dist/legacy-hook-compat.js.map +1 -1
  288. package/dist/lifecycle.js +1 -0
  289. package/dist/live-connectors-runner.d.ts +48 -0
  290. package/dist/live-connectors-runner.js +17 -0
  291. package/dist/live-connectors-runner.js.map +1 -0
  292. package/dist/local-llm.js +3 -2
  293. package/dist/logger.js +1 -0
  294. package/dist/memory-action-policy.js +1 -0
  295. package/dist/memory-cache.d.ts +2 -1
  296. package/dist/memory-cache.js +4 -1
  297. package/dist/memory-governance-KG52RITE.js +37 -0
  298. package/dist/memory-governance-KG52RITE.js.map +1 -0
  299. package/dist/memory-lifecycle-ledger-utils.d.ts +2 -1
  300. package/dist/memory-lifecycle-ledger-utils.js +4 -1
  301. package/dist/memory-projection-format.js +1 -0
  302. package/dist/{memory-projection-store-DeSXPh1j.d.ts → memory-projection-store-D3vBHS4J.d.ts} +1 -0
  303. package/dist/memory-projection-store.d.ts +1 -1
  304. package/dist/memory-projection-store.js +1 -0
  305. package/dist/memory-worth-bench.js +1 -0
  306. package/dist/memory-worth-bench.js.map +1 -1
  307. package/dist/memory-worth-filter.js +1 -0
  308. package/dist/memory-worth-outcomes.d.ts +1 -1
  309. package/dist/memory-worth-outcomes.js +1 -0
  310. package/dist/memory-worth.js +1 -0
  311. package/dist/metadata-FC3XPDRQ.js +21 -0
  312. package/dist/metadata-FC3XPDRQ.js.map +1 -0
  313. package/dist/migrate-from-identity-anchor-TTEDEJGX.js +8 -0
  314. package/dist/migrate-from-identity-anchor-TTEDEJGX.js.map +1 -0
  315. package/dist/model-registry.js +1 -0
  316. package/dist/models-json.js +1 -0
  317. package/dist/native-knowledge.js +1 -0
  318. package/dist/negative.js +1 -0
  319. package/dist/objective-state-writers.js +1 -0
  320. package/dist/objective-state-writers.js.map +1 -1
  321. package/dist/objective-state.js +1 -0
  322. package/dist/openai-chat-compat.js +1 -0
  323. package/dist/operator-toolkit.d.ts +46 -2
  324. package/dist/operator-toolkit.js +29 -17
  325. package/dist/opik-exporter.js +1 -0
  326. package/dist/opik-exporter.js.map +1 -1
  327. package/dist/{orchestrator-CmJ-NTdJ.d.ts → orchestrator-ChkesB8U.d.ts} +177 -13
  328. package/dist/orchestrator.d.ts +6 -4
  329. package/dist/orchestrator.js +58 -42
  330. package/dist/page-versioning.js +1 -0
  331. package/dist/path-RMTY5Y5A.js +9 -0
  332. package/dist/path-RMTY5Y5A.js.map +1 -0
  333. package/dist/patterns-cli.d.ts +160 -0
  334. package/dist/patterns-cli.js +29 -0
  335. package/dist/patterns-cli.js.map +1 -0
  336. package/dist/peers-6OSQ3NK6.js +44 -0
  337. package/dist/peers-6OSQ3NK6.js.map +1 -0
  338. package/dist/plugin-id.js +1 -0
  339. package/dist/policy-runtime.js +1 -0
  340. package/dist/{port-BADbLZU5.d.ts → port-hqGnoStS.d.ts} +6 -0
  341. package/dist/profiling.js +1 -0
  342. package/dist/purge-6ATBGT77.js +205 -0
  343. package/dist/purge-6ATBGT77.js.map +1 -0
  344. package/dist/qmd-recall-cache.d.ts +1 -1
  345. package/dist/qmd-recall-cache.js +1 -0
  346. package/dist/qmd.d.ts +2 -1
  347. package/dist/qmd.js +4 -3
  348. package/dist/reasoning-trace-recall.js +1 -0
  349. package/dist/reasoning-trace-types.js +1 -0
  350. package/dist/recall-audit-anomaly.js +1 -0
  351. package/dist/recall-audit.js +1 -0
  352. package/dist/recall-disclosure-escalation.d.ts +84 -0
  353. package/dist/recall-disclosure-escalation.js +14 -0
  354. package/dist/recall-disclosure-escalation.js.map +1 -0
  355. package/dist/recall-explain-renderer.js +4 -1
  356. package/dist/recall-mmr.js +1 -0
  357. package/dist/recall-qos.js +1 -0
  358. package/dist/recall-query-policy.js +1 -0
  359. package/dist/recall-state.d.ts +7 -0
  360. package/dist/recall-state.js +2 -1
  361. package/dist/recall-tag-filter.d.ts +56 -0
  362. package/dist/recall-tag-filter.js +14 -0
  363. package/dist/recall-tag-filter.js.map +1 -0
  364. package/dist/recall-tokenization.js +1 -0
  365. package/dist/recall-xray-cli.d.ts +9 -2
  366. package/dist/recall-xray-cli.js +9 -4
  367. package/dist/recall-xray-renderer.js +4 -1
  368. package/dist/recall-xray.d.ts +116 -2
  369. package/dist/recall-xray.js +9 -3
  370. package/dist/reconstruct.js +1 -0
  371. package/dist/release-changelog.js +2 -0
  372. package/dist/release-changelog.js.map +1 -1
  373. package/dist/relevance.js +1 -0
  374. package/dist/rerank.js +1 -0
  375. package/dist/{resolution-QBTDHTG7.js → resolution-YGIBORXI.js} +2 -1
  376. package/dist/{resolution-QBTDHTG7.js.map → resolution-YGIBORXI.js.map} +1 -1
  377. package/dist/resolve-auth-token.d.ts +51 -0
  378. package/dist/resolve-auth-token.js +12 -0
  379. package/dist/resolve-auth-token.js.map +1 -0
  380. package/dist/resolve-provider-secret.d.ts +13 -1
  381. package/dist/resolve-provider-secret.js +6 -1
  382. package/dist/resume-bundles.js +5 -4
  383. package/dist/retrieval-agents.d.ts +1 -1
  384. package/dist/retrieval-agents.js +1 -0
  385. package/dist/retrieval-tiers.js +1 -0
  386. package/dist/retrieval.js +1 -0
  387. package/dist/sanitize.js +1 -0
  388. package/dist/schemas.d.ts +15 -2
  389. package/dist/schemas.js +2 -1
  390. package/dist/sdk-compat.js +1 -0
  391. package/dist/sdk-compat.js.map +1 -1
  392. package/dist/secure-store-4R2GSO7S.js +156 -0
  393. package/dist/secure-store-4R2GSO7S.js.map +1 -0
  394. package/dist/semantic-chunking.js +1 -0
  395. package/dist/{semantic-consolidation-CxJU6MJk.d.ts → semantic-consolidation-ByBXb-sf.d.ts} +3 -3
  396. package/dist/semantic-consolidation.d.ts +2 -2
  397. package/dist/semantic-consolidation.js +12 -6
  398. package/dist/semantic-rule-promotion.d.ts +1 -1
  399. package/dist/semantic-rule-promotion.js +9 -6
  400. package/dist/semantic-rule-verifier.d.ts +1 -1
  401. package/dist/semantic-rule-verifier.js +9 -6
  402. package/dist/session-integrity.js +1 -0
  403. package/dist/session-observer-bands.js +1 -0
  404. package/dist/session-observer-state.js +1 -0
  405. package/dist/session-toggles.js +2 -0
  406. package/dist/session-toggles.js.map +1 -1
  407. package/dist/signal.js +1 -0
  408. package/dist/skills-registry.js +2 -0
  409. package/dist/skills-registry.js.map +1 -1
  410. package/dist/source-attribution.js +1 -0
  411. package/dist/state-NCHQ4TRG.js +8 -0
  412. package/dist/state-NCHQ4TRG.js.map +1 -0
  413. package/dist/state-store-3EH7HYIN.js +16 -0
  414. package/dist/state-store-3EH7HYIN.js.map +1 -0
  415. package/dist/storage.d.ts +76 -2
  416. package/dist/storage.js +8 -5
  417. package/dist/store-contract.js +1 -0
  418. package/dist/summarizer.js +6 -5
  419. package/dist/summary-snapshot.js +1 -0
  420. package/dist/temporal-index.js +1 -0
  421. package/dist/temporal-supersession.d.ts +1 -1
  422. package/dist/temporal-supersession.js +2 -1
  423. package/dist/temporal-validity.d.ts +52 -0
  424. package/dist/temporal-validity.js +14 -0
  425. package/dist/temporal-validity.js.map +1 -0
  426. package/dist/threading.js +1 -0
  427. package/dist/tier-migration.d.ts +2 -2
  428. package/dist/tier-migration.js +1 -0
  429. package/dist/tier-routing.js +1 -0
  430. package/dist/tier-stats-62ZVDFKS.js +152 -0
  431. package/dist/tier-stats-62ZVDFKS.js.map +1 -0
  432. package/dist/tmt.js +1 -0
  433. package/dist/tokens.js +3 -1
  434. package/dist/topics.js +1 -0
  435. package/dist/trace-C5ETWBEF.js +290 -0
  436. package/dist/trace-C5ETWBEF.js.map +1 -0
  437. package/dist/transcript.js +1 -0
  438. package/dist/trust-zones.js +1 -0
  439. package/dist/tui-RI7P6PBS.js +13 -0
  440. package/dist/tui-RI7P6PBS.js.map +1 -0
  441. package/dist/types-V3FJ26TF.js +30 -0
  442. package/dist/types-V3FJ26TF.js.map +1 -0
  443. package/dist/types.d.ts +634 -9
  444. package/dist/types.js +10 -3
  445. package/dist/utility-learner.js +1 -0
  446. package/dist/utility-runtime.js +1 -0
  447. package/dist/utility-telemetry.js +1 -0
  448. package/dist/verified-recall.js +9 -6
  449. package/dist/version-utils.js +1 -0
  450. package/dist/whitespace.js +1 -0
  451. package/dist/work-product-ledger.js +1 -0
  452. package/package.json +2 -1
  453. package/dist/access-service-Br8ZydTK.d.ts +0 -827
  454. package/dist/chunk-3OGMS3PE.js.map +0 -1
  455. package/dist/chunk-6PFRXT4K.js.map +0 -1
  456. package/dist/chunk-ALXMCZEU.js.map +0 -1
  457. package/dist/chunk-B5WXLVDY.js.map +0 -1
  458. package/dist/chunk-BGJGXLZ7.js.map +0 -1
  459. package/dist/chunk-BK2EFTE2.js.map +0 -1
  460. package/dist/chunk-C2EFFULQ.js.map +0 -1
  461. package/dist/chunk-CUPFXL3J.js.map +0 -1
  462. package/dist/chunk-DFTTJYSO.js.map +0 -1
  463. package/dist/chunk-EPQJM2GC.js.map +0 -1
  464. package/dist/chunk-F5VP6YCB.js.map +0 -1
  465. package/dist/chunk-FVA6TGI3.js.map +0 -1
  466. package/dist/chunk-GKFXUTJ2.js.map +0 -1
  467. package/dist/chunk-HK3FGIEW.js.map +0 -1
  468. package/dist/chunk-INXV5JBT.js.map +0 -1
  469. package/dist/chunk-KVBLZUKV.js.map +0 -1
  470. package/dist/chunk-LK6SGL53.js.map +0 -1
  471. package/dist/chunk-LTCGGW2D.js +0 -14
  472. package/dist/chunk-LTCGGW2D.js.map +0 -1
  473. package/dist/chunk-NZLQTHS5.js.map +0 -1
  474. package/dist/chunk-O5ETUNBT.js.map +0 -1
  475. package/dist/chunk-PVPWZSSI.js.map +0 -1
  476. package/dist/chunk-RGLL5SPU.js.map +0 -1
  477. package/dist/chunk-S3EEFKNY.js.map +0 -1
  478. package/dist/chunk-SPI27QT6.js.map +0 -1
  479. package/dist/chunk-TP4FZJIZ.js.map +0 -1
  480. package/dist/chunk-ULYOGL6R.js.map +0 -1
  481. package/dist/chunk-VBVG2M5G.js.map +0 -1
  482. package/dist/chunk-VDX363PS.js.map +0 -1
  483. package/dist/chunk-VYM3VWOF.js.map +0 -1
  484. package/dist/chunk-WCLICCGB.js.map +0 -1
  485. package/dist/chunk-WVVA7F5A.js.map +0 -1
  486. package/dist/chunk-X6GF3FX2.js +0 -26
  487. package/dist/chunk-X6GF3FX2.js.map +0 -1
  488. package/dist/chunk-XZ2TIKGC.js.map +0 -1
  489. package/dist/chunk-ZAIM4TUE.js.map +0 -1
  490. /package/dist/{contradiction-review-WIUBAR52.js.map → capsule-cli.js.map} +0 -0
  491. /package/dist/{engine-F3GOXGE5.js.map → capsule-crypto-5CYAGVC5.js.map} +0 -0
  492. /package/dist/{chunk-KUB6JU6H.js.map → chunk-47WOM4YW.js.map} +0 -0
  493. /package/dist/{chunk-ZEM3OK2K.js.map → chunk-B2TL6GA2.js.map} +0 -0
  494. /package/dist/{chunk-3GXCSUXR.js.map → chunk-CRU27Q4J.js.map} +0 -0
  495. /package/dist/{chunk-RBBWYEFJ.js.map → chunk-G2WADRQ3.js.map} +0 -0
  496. /package/dist/{chunk-7I7FKFZH.js.map → chunk-R2L7SUX2.js.map} +0 -0
  497. /package/dist/{chunk-JL2PU6AI.js.map → chunk-R2XRID2N.js.map} +0 -0
@@ -1,14 +1,26 @@
1
1
  import {
2
2
  promoteSemanticRuleFromMemory
3
- } from "./chunk-VDX363PS.js";
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-KUB6JU6H.js";
11
+ } from "./chunk-47WOM4YW.js";
9
12
  import {
10
13
  parseXrayCliOptions
11
- } from "./chunk-PVPWZSSI.js";
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-B5WXLVDY.js";
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-EPQJM2GC.js";
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-CUPFXL3J.js";
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-SPI27QT6.js";
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
- readRuntimePolicySnapshot,
72
- sanitizeRuntimePolicyValues
73
- } from "./chunk-EABGC2TL.js";
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
- getObjectiveStateStoreStatus
76
- } from "./chunk-LOBRX7VD.js";
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-LK6SGL53.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-BK2EFTE2.js";
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,50 +142,60 @@ import {
118
142
  } from "./chunk-NGAVDO7E.js";
119
143
  import {
120
144
  EngramAccessHttpServer
121
- } from "./chunk-DFTTJYSO.js";
145
+ } from "./chunk-AKUCB2OG.js";
122
146
  import {
123
147
  EngramMcpServer
124
- } from "./chunk-HK3FGIEW.js";
125
- import {
126
- resolveHomeDir
127
- } from "./chunk-MARWOCVP.js";
148
+ } from "./chunk-4PLGJRBV.js";
128
149
  import {
129
150
  EngramAccessService,
130
151
  WorkStorage
131
- } from "./chunk-GKFXUTJ2.js";
152
+ } from "./chunk-DR7MCMPS.js";
132
153
  import {
133
154
  parseRecallExplainFormat,
134
155
  renderRecallExplain,
135
156
  renderXray
136
- } from "./chunk-ZAIM4TUE.js";
157
+ } from "./chunk-LW2NMHDW.js";
158
+ import {
159
+ getTrustZoneStoreStatus,
160
+ promoteTrustZoneRecord,
161
+ seedTrustZoneDemoDataset
162
+ } from "./chunk-EQINRHYR.js";
137
163
  import {
138
164
  listMemoryGovernanceRuns,
139
165
  readMemoryGovernanceRunArtifact,
140
166
  restoreMemoryGovernanceRun,
141
167
  runMemoryGovernance
142
- } from "./chunk-3OGMS3PE.js";
168
+ } from "./chunk-LZRYQK6L.js";
143
169
  import {
144
- getTrustZoneStoreStatus,
145
- promoteTrustZoneRecord,
146
- seedTrustZoneDemoDataset
147
- } from "./chunk-EQINRHYR.js";
170
+ expandTildePath
171
+ } from "./chunk-IXEJRKCZ.js";
148
172
  import {
149
173
  selectRouteRule,
150
174
  validateRouteTarget
151
175
  } from "./chunk-2LGMW3DJ.js";
176
+ import {
177
+ launchProcess
178
+ } from "./chunk-OR64ZGRZ.js";
179
+ import {
180
+ analyzeGraphHealth
181
+ } from "./chunk-RK2Y4XOM.js";
152
182
  import {
153
183
  getCausalTrajectoryStoreStatus
154
- } from "./chunk-RBBWYEFJ.js";
184
+ } from "./chunk-G2WADRQ3.js";
155
185
  import {
156
186
  StorageManager
157
- } from "./chunk-F5VP6YCB.js";
187
+ } from "./chunk-DCE6SQLA.js";
188
+ import {
189
+ RECALL_DISCLOSURE_LEVELS,
190
+ isRecallDisclosure
191
+ } from "./chunk-43EKP2UK.js";
158
192
  import {
159
193
  MEMORY_LIFECYCLE_EVENT_SORT_ORDER,
160
194
  buildLifecycleEventsForMemory,
161
195
  inferMemoryStatus,
162
196
  sortMemoryLifecycleEvents,
163
197
  toMemoryPathRel
164
- } from "./chunk-TP4FZJIZ.js";
198
+ } from "./chunk-RULE4VG5.js";
165
199
  import {
166
200
  normalizeProjectionPreview,
167
201
  normalizeProjectionTags
@@ -178,75 +212,38 @@ import {
178
212
  readProjectedGovernanceRecord,
179
213
  readProjectedNativeKnowledgeChunks
180
214
  } from "./chunk-BOUYNNYD.js";
215
+ import {
216
+ resolveHomeDir
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 path19 from "path";
184
- import { access as access2, readFile as readFile12, readdir as readdir8, unlink as unlink2 } from "fs/promises";
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 = path2.resolve(opts.outDir);
263
- await mkdir2(outDirAbs, { recursive: true });
264
- const memoryDirAbs = path2.resolve(opts.memoryDir);
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 readFile2(abs, "utf-8");
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 = path2.join(opts.workspaceDir, "IDENTITY.md");
274
+ const identityPath = path.join(opts.workspaceDir, "IDENTITY.md");
278
275
  try {
279
- const content = await readFile2(identityPath, "utf-8");
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(path2.join(outDirAbs, "manifest.json"), manifest);
297
- await writeJsonFile(path2.join(outDirAbs, "bundle.json"), bundle);
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 path3 from "path";
302
- import { mkdir as mkdir3, readFile as readFile3, writeFile as writeFile2 } from "fs/promises";
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 = path3.resolve(opts.outDir);
311
- await mkdir3(outDirAbs, { recursive: true });
312
- const memDirAbs = path3.resolve(opts.memoryDir);
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 = path3.join(outDirAbs, ...relPosix.split("/"));
319
- await mkdir3(path3.dirname(dstAbs), { recursive: true });
320
- const content = await readFile3(abs);
321
- await writeFile2(dstAbs, content);
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(path3.join(outDirAbs, "manifest.json"), manifest);
330
+ await writeJsonFile(path2.join(outDirAbs, "manifest.json"), manifest);
334
331
  }
335
332
  async function looksLikeEngramMdExport(fromDir) {
336
- const dirAbs = path3.resolve(fromDir);
333
+ const dirAbs = path2.resolve(fromDir);
337
334
  try {
338
- const raw = await readFile3(path3.join(dirAbs, "manifest.json"), "utf-8");
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 path4 from "path";
348
- import { mkdir as mkdir4, readdir as readdir2, rm } from "fs/promises";
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 = path4.resolve(opts.outDir);
354
- await mkdir4(outDirAbs, { recursive: true });
351
+ const outDirAbs = path3.resolve(opts.outDir);
352
+ await mkdir3(outDirAbs, { recursive: true });
355
353
  const ts = timestampDirName(/* @__PURE__ */ new Date());
356
- const backupDir = path4.join(outDirAbs, ts);
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 readdir2(outDirAbs, { withFileTypes: true });
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
- const m = name.match(
375
- /^(\d{4}-\d{2}-\d{2})T(\d{2})-(\d{2})-(\d{2})-(\d{3})Z$/
376
- );
377
- const iso = m ? `${m[1]}T${m[2]}:${m[3]}:${m[4]}.${m[5]}Z` : null;
378
- const tsMs = iso ? Date.parse(iso) : NaN;
379
- if (!Number.isFinite(tsMs)) continue;
380
- if (tsMs < cutoffMs) {
381
- await rm(path4.join(outDirAbs, name), { recursive: true, force: true });
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 path5 from "path";
388
- import { readFile as readFile4 } from "fs/promises";
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 = path5.resolve(opts.memoryDir);
415
- const outAbs = path5.resolve(opts.outFile);
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 readFile4(abs, "utf-8");
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 path6 from "path";
448
- import { mkdir as mkdir5, writeFile as writeFile3 } from "fs/promises";
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 = path6.resolve(opts.fromDir);
482
- const bundlePath = path6.join(fromDirAbs, "bundle.json");
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 = path6.resolve(opts.targetMemoryDir);
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 ? path6.resolve(opts.workspaceDir) : null : memDirAbs;
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 = path6.join(targetBase, relFs);
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 mkdir5(path6.dirname(w.abs), { recursive: true });
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 = path6.resolve(fromDir);
544
+ const dir = path5.resolve(fromDir);
526
545
  return Promise.all([
527
- fileExists(path6.join(dir, "manifest.json")),
528
- fileExists(path6.join(dir, "bundle.json"))
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 path7 from "path";
534
- import { mkdir as mkdir6, writeFile as writeFile4 } from "fs/promises";
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 = path7.resolve(opts.targetMemoryDir);
541
- const fromAbs = path7.resolve(opts.fromFile);
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 = path7.join(memDirAbs, relFs);
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 mkdir6(path7.dirname(w.abs), { recursive: true });
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 path8 from "path";
587
- import { mkdir as mkdir7, readFile as readFile5, writeFile as writeFile5 } from "fs/promises";
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 = path8.resolve(opts.fromDir);
594
- const targetAbs = path8.resolve(opts.targetMemoryDir);
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 = path8.join(targetAbs, fromPosixRelPath(relPosix));
602
- const content = await readFile5(abs, "utf-8");
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 mkdir7(path8.dirname(w.abs), { recursive: true });
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 path9 from "path";
632
- import { stat as stat2 } from "fs/promises";
650
+ import path8 from "path";
651
+ import { stat } from "fs/promises";
633
652
  async function detectImportFormat(fromPath) {
634
- const abs = path9.resolve(fromPath);
653
+ const abs = path8.resolve(fromPath);
635
654
  let st;
636
655
  try {
637
- st = await stat2(abs);
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 path20 = typeof record.path === "string" ? record.path : "";
1063
- if (!path20.startsWith("transcripts/") && !path20.includes("/transcripts/")) continue;
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 path10 from "path";
1281
- import { mkdir as mkdir8, readdir as readdir3, readFile as readFile6, unlink, writeFile as writeFile6 } from "fs/promises";
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 readdir3(root, { withFileTypes: true });
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 ? path10.join(relPrefix, entry.name) : entry.name;
1308
- const full = path10.join(root, entry.name);
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", path10.join("state", "tool-usage"), path10.join("summaries", "hourly")];
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 = path10.join(memoryDir, relRoot);
1340
+ const absRoot = path9.join(memoryDir, relRoot);
1322
1341
  const files = await listFilesRecursive2(absRoot);
1323
1342
  for (const fileRel of files) {
1324
- const filename = path10.basename(fileRel);
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: path10.join(absRoot, fileRel),
1330
- relativePath: path10.join(relRoot, fileRel)
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 = path10.join(options.memoryDir, "archive", "observations", stamp);
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 mkdir8(archiveRoot, { recursive: true });
1373
+ await mkdir7(archiveRoot, { recursive: true });
1355
1374
  for (const candidate of candidates) {
1356
- const archivePath = path10.join(archiveRoot, candidate.relativePath);
1357
- const archiveDir = path10.dirname(archivePath);
1358
- await mkdir8(archiveDir, { recursive: true });
1359
- const raw = await readFile6(candidate.absolutePath);
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 unlink(candidate.absolutePath);
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 path11 from "path";
1382
- import { mkdir as mkdir9, rename, stat as stat3, writeFile as writeFile7 } from "fs/promises";
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 stat3(outputPath);
1411
+ await stat2(outputPath);
1393
1412
  } catch {
1394
1413
  return void 0;
1395
1414
  }
1396
- const backupPath = path11.join(
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 mkdir9(path11.dirname(backupPath), { recursive: true });
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 = path11.join(options.memoryDir, "state", "memory-lifecycle-ledger.jsonl");
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 mkdir9(path11.dirname(outputPath), { recursive: true });
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 path12 from "path";
1436
- import { mkdir as mkdir10, rename as rename2, rm as rm2, stat as stat4 } from "fs/promises";
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 stat4(outputPath);
1458
+ await stat3(outputPath);
1440
1459
  } catch {
1441
1460
  return void 0;
1442
1461
  }
1443
- const backupPath = path12.join(
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 mkdir10(path12.dirname(backupPath), { recursive: true });
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 mkdir10(path12.dirname(outputPath), { recursive: true });
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 path14 from "path";
2308
- import { readdir as readdir4, readFile as readFile8 } from "fs/promises";
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 path13 from "path";
2312
- import { mkdir as mkdir11, readFile as readFile7, writeFile as writeFile8 } from "fs/promises";
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 = path13.join(options.memoryDir, "archive", "observations", stamp);
2324
- let backupPath = path13.join(
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 readFile7(options.outputPath, "utf-8");
2332
- await mkdir11(path13.dirname(backupPath), { recursive: true });
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 mkdir11(path13.dirname(options.outputPath), { recursive: true });
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 readdir4(root, { withFileTypes: true });
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 = path14.join(root, entry.name);
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 = path14.join(options.memoryDir, "transcripts");
2433
- const outputPath = path14.join(
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 readFile8(file, "utf-8"));
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 path15 from "path";
2470
- import { readdir as readdir5, readFile as readFile9 } from "fs/promises";
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 readdir5(root, { withFileTypes: true });
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 = path15.join(options.memoryDir, "state", "observation-ledger");
2534
- const outputPath = path15.join(ledgerRoot, "rebuilt-observations.jsonl");
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) => path15.join("state", "observation-ledger", 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 = path15.join(ledgerRoot, file);
2542
- const raw = await readFile9(full, "utf-8");
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 stat5 } from "fs/promises";
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 stat5(dir);
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 mkdir12, readdir as readdir6, realpath, stat as stat6 } from "fs/promises";
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 path16 from "path";
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 = path16.resolve(dir);
2774
- await mkdir12(resolved, { recursive: true });
2792
+ const resolved = path15.resolve(dir);
2793
+ await mkdir11(resolved, { recursive: true });
2775
2794
  const canonical = await realpath(resolved);
2776
- const alias = path16.basename(canonical) || "root";
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 = path16.posix.normalize(decodedPath);
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 = path16.resolve(root.absolute, ...relative);
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 stat6(absolutePath);
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 stat6(absolutePath);
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 readdir6(absolutePath, { withFileTypes: true });
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 === path16.parse(root).root) {
3043
+ if (root === path15.parse(root).root) {
3025
3044
  return target.startsWith(root);
3026
3045
  }
3027
- return target.startsWith(`${root}${path16.sep}`);
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 readFile10 } from "fs/promises";
3039
- import path17 from "path";
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 = path17.join(options.repoRoot, "openclaw.plugin.json");
3215
- const packageJsonPath = path17.join(options.repoRoot, "package.json");
3216
- const indexPath = path17.join(options.repoRoot, "src", "index.ts");
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 readFile10(pluginJsonPath, "utf-8");
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 readFile10(packageJsonPath, "utf-8");
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 readFile10(indexPath, "utf-8");
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 readdir7, readFile as readFile11, realpath as realpath2 } from "fs/promises";
3409
- import path18 from "path";
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 readdir7(d, { withFileTypes: true });
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 = path18.join(d, entry.name);
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 + path18.sep)) {
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 = path18.join(memoryDir, "facts");
3531
- const correctionsDir = path18.join(memoryDir, "corrections");
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(path18.join(memoryDir, "entities"));
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 readFile11(filePath, "utf-8");
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-F3GOXGE5.js");
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 createHash2("sha256").update(JSON.stringify(normalized)).digest("hex").slice(0, 12);
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 = path19.join(config.memoryDir, "state", fileName);
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 readFile12(options.inputPath, "utf-8");
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 readFile12(opts.file, "utf-8");
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 readFile12(pkgPath, "utf-8");
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 = path19.join(orchestrator.config.memoryDir, "namespaces", ns);
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 = [path19.join(memoryDir, "facts"), path19.join(memoryDir, "corrections")];
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 readdir8(dir, { withFileTypes: true });
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 = path19.join(dir, entryName);
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 readFile12(fullPath, "utf-8");
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,55 +5643,258 @@ function registerCli(api, orchestrator) {
5628
5643
  }
5629
5644
  if (!reportHasMachineReadableOutput(options)) console.log("OK");
5630
5645
  });
5631
- cmd.command("config-review").description("Review Engram config defaults, recommendations, and contradictory settings").option("--json", "Emit machine-readable JSON only").action(async (...args) => {
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 report = await runOperatorConfigReview({ orchestrator });
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(report, null, 2));
5654
+ console.log(JSON.stringify(summary, null, 2));
5636
5655
  } else {
5637
- console.log(formatOperatorConfigReviewCli(report));
5656
+ console.log(formatTierSummaryText(summary));
5638
5657
  }
5639
- if (!report.ok) {
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("inventory").description("Report namespace, memory, review, and storage inventory").option("--json", "Emit machine-readable JSON only").action(async (...args) => {
5646
- const options = args[0] ?? {};
5647
- const report = await runOperatorInventory({ orchestrator });
5648
- if (reportHasMachineReadableOutput(options)) {
5649
- console.log(JSON.stringify(report, null, 2));
5650
- } else {
5651
- console.log(formatOperatorInventoryCli(report));
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
- const namespacesCmd = cmd.command("namespaces").description("Manage namespace roots, migration, and verification");
5656
- namespacesCmd.command("ls").description("List configured namespaces and their storage roots").action(async () => {
5657
- const namespaces = await listNamespaces({ config: orchestrator.config });
5658
- if (namespaces.length === 0) {
5659
- console.log("No namespaces configured.");
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
- console.log("=== Engram Namespaces ===\n");
5663
- for (const entry of namespaces) {
5664
- console.log(
5665
- `${entry.namespace}
5666
- root: ${entry.rootDir}
5667
- exists: ${entry.exists ? "yes" : "no"}
5668
- legacy-root: ${entry.usesLegacyRoot ? "yes" : "no"}
5669
- has-data: ${entry.hasMemoryData ? "yes" : "no"}
5670
- collection: ${entry.collection}`
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
- namespacesCmd.command("verify").description("Verify namespace roots and detect legacy root drift").action(async () => {
5675
- const report = await verifyNamespaces({ config: orchestrator.config });
5676
- console.log("=== Namespace Verification ===\n");
5677
- for (const entry of report.namespaces) {
5678
- console.log(
5679
- `${entry.namespace}
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}
5680
5898
  root: ${entry.rootDir}
5681
5899
  exists: ${entry.exists ? "yes" : "no"}
5682
5900
  legacy-root: ${entry.usesLegacyRoot ? "yes" : "no"}
@@ -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(`- ${path19.basename(move.from)}`);
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
5832
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
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
- const snapshot = response.snapshotFound ? response.snapshot ?? null : null;
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: typeof options.token === "string" && options.token.trim().length > 0 ? options.token : orchestrator.config.agentAccessHttp.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 unlink2(filePath);
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 unlink2(filePath);
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 results = await orchestrator.qmd.search(
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 = path19.isAbsolute(expandedTarget) ? expandedTarget : path19.join(orchestrator.config.memoryDir, expandedTarget);
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 = path19.join(resolveHomeDir(), ".openclaw", "workspace");
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 = path19.join(resolveHomeDir(), ".openclaw", "workspace", "memory", "local");
7730
- const threading = new ThreadingManager(path19.join(memoryDir, "threads"));
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-WIUBAR52.js");
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-WIUBAR52.js");
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-QBTDHTG7.js");
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-E3GJTI4F.js");
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-INXV5JBT.js.map
9683
+ //# sourceMappingURL=chunk-ZGXSCMQN.js.map