@remnic/core 9.65.1 → 9.65.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 (576) hide show
  1. package/dist/access-admin-ops-surface.d.ts +44 -44
  2. package/dist/access-admin-ops-surface.js +36 -35
  3. package/dist/access-authorization-probe.d.ts +39 -40
  4. package/dist/access-authorization-probe.js +37 -36
  5. package/dist/access-boundary.d.ts +41 -185
  6. package/dist/access-boundary.js +36 -35
  7. package/dist/access-cli.js +110 -107
  8. package/dist/access-cli.js.map +1 -1
  9. package/dist/access-coding-context-resolution.d.ts +3 -1
  10. package/dist/access-extraction-force-flush.d.ts +25 -25
  11. package/dist/access-extraction-force-flush.js +36 -35
  12. package/dist/access-health-types.d.ts +3 -1
  13. package/dist/access-http-lcm-compaction.d.ts +39 -39
  14. package/dist/access-http-lifecycle-flush.d.ts +40 -41
  15. package/dist/access-http-offline-stream.d.ts +25 -25
  16. package/dist/access-http-query.d.ts +4 -2
  17. package/dist/access-http-query.js +38 -37
  18. package/dist/access-http.d.ts +51 -44
  19. package/dist/access-http.js +57 -56
  20. package/dist/access-identity-continuity-surface.d.ts +12 -12
  21. package/dist/access-identity-continuity-surface.js +36 -35
  22. package/dist/access-lcm-surface.d.ts +27 -27
  23. package/dist/access-lcm-surface.js +36 -35
  24. package/dist/access-mcp-admin-tools.d.ts +9 -1
  25. package/dist/access-mcp-admin-tools.js +3 -1
  26. package/dist/access-mcp-output-schemas.js +1 -1
  27. package/dist/access-mcp.d.ts +39 -39
  28. package/dist/access-mcp.js +50 -47
  29. package/dist/access-memory-search-fanout.d.ts +4 -2
  30. package/dist/{access-namespace-preflight-BKUnKsBv.d.ts → access-namespace-preflight-B7Usyz-K.d.ts} +1 -1
  31. package/dist/access-namespace-preflight.d.ts +5 -3
  32. package/dist/access-namespace-preflight.js +36 -35
  33. package/dist/access-observe-write-surface.d.ts +39 -39
  34. package/dist/access-observe-write-surface.js +36 -35
  35. package/dist/access-offline-manifest.d.ts +12 -12
  36. package/dist/access-offline-manifest.js +5 -5
  37. package/dist/access-operations-batch.js +41 -40
  38. package/dist/access-operations.d.ts +46 -47
  39. package/dist/access-operations.js +44 -43
  40. package/dist/access-recall-concurrency.d.ts +40 -40
  41. package/dist/access-recall-concurrency.js +36 -35
  42. package/dist/access-recall-response.d.ts +24 -24
  43. package/dist/access-recall-response.js +36 -35
  44. package/dist/access-recall-surface.d.ts +24 -24
  45. package/dist/access-recall-surface.js +36 -35
  46. package/dist/access-schema.d.ts +139 -139
  47. package/dist/access-schema.js +3 -3
  48. package/dist/{access-service-B1Lbb-nQ.d.ts → access-service-DkaIG3n8.d.ts} +688 -140
  49. package/dist/access-service-helpers.d.ts +40 -40
  50. package/dist/access-service.d.ts +47 -47
  51. package/dist/access-service.js +36 -35
  52. package/dist/access-surface-catalog.d.ts +41 -42
  53. package/dist/access-surface-catalog.js +44 -37
  54. package/dist/access-surface-catalog.js.map +1 -1
  55. package/dist/access-wearables-meetings-surface.d.ts +5 -3
  56. package/dist/action-confidence.d.ts +3 -1
  57. package/dist/active-memory-bridge.d.ts +3 -1
  58. package/dist/active-recall.d.ts +3 -1
  59. package/dist/active-recall.js +11 -1
  60. package/dist/active-recall.js.map +1 -1
  61. package/dist/adapters/index.js +4 -4
  62. package/dist/adapters/registry.js +2 -2
  63. package/dist/ambient-provenance.d.ts +3 -1
  64. package/dist/artifact-search.d.ts +3 -1
  65. package/dist/{auto-sync-5L7EUZ27.js → auto-sync-H64ZCNIR.js} +13 -5
  66. package/dist/{auto-sync-5L7EUZ27.js.map → auto-sync-H64ZCNIR.js.map} +1 -1
  67. package/dist/behavior-learner.d.ts +3 -1
  68. package/dist/behavior-signals.d.ts +3 -1
  69. package/dist/bootstrap.d.ts +12 -12
  70. package/dist/briefing-window.d.ts +4 -2
  71. package/dist/briefing.d.ts +4 -2
  72. package/dist/briefing.js +16 -15
  73. package/dist/buffer-surprise-report.d.ts +3 -1
  74. package/dist/buffer-turn-helpers.d.ts +3 -1
  75. package/dist/buffer.d.ts +4 -2
  76. package/dist/buffer.js +4 -4
  77. package/dist/bulk-import/index.d.ts +5 -3
  78. package/dist/calibration.d.ts +3 -1
  79. package/dist/calibration.js +1 -1
  80. package/dist/capabilities.d.ts +3 -1
  81. package/dist/{capsule-crypto-7FJQINUR.js → capsule-crypto-YO5QJ6L3.js} +2 -2
  82. package/dist/{catalog-DjVhJoRM.d.ts → catalog-CX2BZEJh.d.ts} +1 -1
  83. package/dist/causal-behavior.d.ts +1 -1
  84. package/dist/causal-consolidation.d.ts +3 -1
  85. package/dist/causal-consolidation.js +20 -19
  86. package/dist/causal-consolidation.js.map +1 -1
  87. package/dist/causal-trajectory-graph.d.ts +1 -1
  88. package/dist/{chunk-MIBKEW7A.js → chunk-2VXWFYJE.js} +3 -3
  89. package/dist/{chunk-3YTTAGPB.js → chunk-3DVBKTSO.js} +2 -2
  90. package/dist/{chunk-EIR5VLIH.js → chunk-4K7IW3F7.js} +2 -2
  91. package/dist/chunk-4K7IW3F7.js.map +1 -0
  92. package/dist/{chunk-JTSVMJHV.js → chunk-4XDGYCZI.js} +3 -3
  93. package/dist/chunk-573TEZCD.js +88 -0
  94. package/dist/chunk-573TEZCD.js.map +1 -0
  95. package/dist/{chunk-HQSBYI5X.js → chunk-57HVIG5U.js} +2 -2
  96. package/dist/{chunk-PMVPCZJZ.js → chunk-6433HV72.js} +2 -2
  97. package/dist/{chunk-N6TRHP72.js → chunk-6TAX66IA.js} +2 -2
  98. package/dist/{chunk-AGKIG3YA.js → chunk-6VALIZKG.js} +2 -2
  99. package/dist/{chunk-YQ3CBLL4.js → chunk-76PL4XLG.js} +512 -8
  100. package/dist/chunk-76PL4XLG.js.map +1 -0
  101. package/dist/{chunk-4NZHHGVL.js → chunk-7BDZTALN.js} +4 -1
  102. package/dist/chunk-7BDZTALN.js.map +1 -0
  103. package/dist/{chunk-NS5ETDYD.js → chunk-7BEPVIH3.js} +3 -3
  104. package/dist/{chunk-JG22O53B.js → chunk-7CBKAQIG.js} +2 -1
  105. package/dist/chunk-7CBKAQIG.js.map +1 -0
  106. package/dist/{chunk-LYIZXQYY.js → chunk-7KFIMGMP.js} +2 -2
  107. package/dist/{chunk-LWVO2QZV.js → chunk-7QOO4LGC.js} +56 -56
  108. package/dist/chunk-AAXJNINV.js +55 -0
  109. package/dist/chunk-AAXJNINV.js.map +1 -0
  110. package/dist/{chunk-56BSXSHC.js → chunk-AB3A7EFH.js} +31 -2
  111. package/dist/{chunk-56BSXSHC.js.map → chunk-AB3A7EFH.js.map} +1 -1
  112. package/dist/{chunk-CCTVAVTT.js → chunk-AUO2LJ3K.js} +2 -2
  113. package/dist/{chunk-ALCJRQ72.js → chunk-AYDDB3XI.js} +2 -2
  114. package/dist/{chunk-3TMYV3LP.js → chunk-AYYGRVRP.js} +5 -5
  115. package/dist/{chunk-W6TSGWYS.js → chunk-AZAA5DNP.js} +2 -2
  116. package/dist/{chunk-WTOE7CW4.js → chunk-BKYPJUQL.js} +122 -16
  117. package/dist/chunk-BKYPJUQL.js.map +1 -0
  118. package/dist/{chunk-6JJT5AKI.js → chunk-BQUEAVNW.js} +2 -2
  119. package/dist/{chunk-2NLLXCJG.js → chunk-BXLOS5AJ.js} +2 -2
  120. package/dist/{chunk-CEH2AFXG.js → chunk-C24UZSFW.js} +6 -6
  121. package/dist/{chunk-ZPN7W3OP.js → chunk-CDUUDBWJ.js} +3 -3
  122. package/dist/{chunk-35NN3ZFA.js → chunk-CTVWELNK.js} +21 -3
  123. package/dist/chunk-CTVWELNK.js.map +1 -0
  124. package/dist/{chunk-Y23B2QXP.js → chunk-D27J626P.js} +2 -2
  125. package/dist/{chunk-2572MRP2.js → chunk-DHTQP334.js} +2 -2
  126. package/dist/{chunk-HJQZQUPC.js → chunk-DJZWNKFO.js} +5 -5
  127. package/dist/{chunk-X7Y7WX73.js → chunk-DQEMWVMT.js} +1 -1
  128. package/dist/{chunk-VJ6ECBIP.js → chunk-E4MVQQVX.js} +2 -2
  129. package/dist/{chunk-SYJ6EKKE.js → chunk-EIVIB73I.js} +2 -2
  130. package/dist/{chunk-HUNSEO5U.js → chunk-EV3YFLCB.js} +2 -2
  131. package/dist/{chunk-GEULB2VI.js → chunk-FC7TIRFS.js} +21 -1
  132. package/dist/chunk-FC7TIRFS.js.map +1 -0
  133. package/dist/{chunk-VPGRXEAB.js → chunk-G57LQRP6.js} +2 -2
  134. package/dist/{chunk-BC4QD3FM.js → chunk-GN55KU2P.js} +2 -2
  135. package/dist/{chunk-4W6INNXO.js → chunk-GUXS322H.js} +2 -2
  136. package/dist/{chunk-DBXZZIDU.js → chunk-H5FW4S5Q.js} +434 -693
  137. package/dist/chunk-H5FW4S5Q.js.map +1 -0
  138. package/dist/chunk-I32NKXE2.js +879 -0
  139. package/dist/chunk-I32NKXE2.js.map +1 -0
  140. package/dist/{chunk-3MADV4YC.js → chunk-IQSC3V2E.js} +2 -2
  141. package/dist/{chunk-UYCIS6V5.js → chunk-JCWY73FK.js} +2 -2
  142. package/dist/{chunk-T42L3S6A.js → chunk-LBWQ65SX.js} +4 -4
  143. package/dist/{chunk-MSTNSVXI.js → chunk-LDBFXD4F.js} +2 -1
  144. package/dist/chunk-LDBFXD4F.js.map +1 -0
  145. package/dist/{chunk-CEQF6L5K.js → chunk-LUNJ3WFO.js} +9 -7
  146. package/dist/chunk-LUNJ3WFO.js.map +1 -0
  147. package/dist/{chunk-256FBCVX.js → chunk-M4AHBM72.js} +7 -7
  148. package/dist/{chunk-YEQEGSJA.js → chunk-MBDJJTAT.js} +3 -3
  149. package/dist/{chunk-IAY7YBXS.js → chunk-MRTUN665.js} +2 -2
  150. package/dist/{chunk-JFJ3MHGV.js → chunk-NXKJHSDN.js} +1 -1
  151. package/dist/chunk-NXKJHSDN.js.map +1 -0
  152. package/dist/{chunk-R3AAOKR2.js → chunk-NZWEEALH.js} +2 -2
  153. package/dist/{chunk-I2HTKOOP.js → chunk-ODZG724P.js} +2 -2
  154. package/dist/{chunk-7QFBLYFP.js → chunk-OJD4WS2E.js} +3 -3
  155. package/dist/{chunk-CUS6S7PN.js → chunk-OLWTCWQ2.js} +9 -9
  156. package/dist/chunk-OLWTCWQ2.js.map +1 -0
  157. package/dist/{chunk-53ENM6F6.js → chunk-P4DHENRE.js} +2 -2
  158. package/dist/{chunk-DEFI2QBT.js → chunk-PAYGC3BD.js} +52 -22
  159. package/dist/chunk-PAYGC3BD.js.map +1 -0
  160. package/dist/{chunk-KPBLJCCV.js → chunk-PDVQ5JU3.js} +2 -2
  161. package/dist/{chunk-7BY7V4YX.js → chunk-Q4WONDMJ.js} +4 -3
  162. package/dist/{chunk-7BY7V4YX.js.map → chunk-Q4WONDMJ.js.map} +1 -1
  163. package/dist/{chunk-ESCQ6LY7.js → chunk-QFMO32TO.js} +3 -3
  164. package/dist/{chunk-HQSPXTQO.js → chunk-QXIQPCCN.js} +1 -1
  165. package/dist/{chunk-CFRBTATE.js → chunk-R47WINCY.js} +3 -3
  166. package/dist/{chunk-G72IPMR7.js → chunk-R4OCGPSH.js} +2 -2
  167. package/dist/{chunk-LCU5R6TQ.js → chunk-RAIUTAZZ.js} +22 -3
  168. package/dist/chunk-RAIUTAZZ.js.map +1 -0
  169. package/dist/chunk-RIAM7DND.js +167 -0
  170. package/dist/chunk-RIAM7DND.js.map +1 -0
  171. package/dist/{chunk-VZVP2W4O.js → chunk-RK4WXUI2.js} +2 -2
  172. package/dist/{chunk-JBPKEARU.js → chunk-RKNJBZ55.js} +4 -4
  173. package/dist/{chunk-6L27N6YI.js → chunk-S7Q5CM7E.js} +2 -2
  174. package/dist/{chunk-CTQRPANJ.js → chunk-SVSRPG6M.js} +2 -2
  175. package/dist/{chunk-GXWDWOWP.js → chunk-TDKSCV62.js} +2 -2
  176. package/dist/{chunk-S2VBSTTA.js → chunk-THG4GYIE.js} +2 -2
  177. package/dist/{chunk-IXRC7EQG.js → chunk-TR7DGXGI.js} +2 -2
  178. package/dist/{chunk-63FHSH7E.js → chunk-TYUS5TLG.js} +4 -4
  179. package/dist/{chunk-7PWWGYGO.js → chunk-URHCUXKI.js} +2 -2
  180. package/dist/{chunk-Z54TXZ2F.js → chunk-VA5KMSAE.js} +16 -7
  181. package/dist/chunk-VA5KMSAE.js.map +1 -0
  182. package/dist/{chunk-KQAFEZQX.js → chunk-VDX2J7OX.js} +2 -2
  183. package/dist/{chunk-MUJ4QFUQ.js → chunk-W4BMEGQA.js} +4 -4
  184. package/dist/{chunk-5HK3CJAR.js → chunk-W675UJCZ.js} +2 -2
  185. package/dist/{chunk-3PXVYJMC.js → chunk-WN5FSGLE.js} +2077 -215
  186. package/dist/chunk-WN5FSGLE.js.map +1 -0
  187. package/dist/{chunk-3RHFGGI5.js → chunk-YF6UHWOV.js} +30 -10
  188. package/dist/chunk-YF6UHWOV.js.map +1 -0
  189. package/dist/{chunk-X5SDZMO7.js → chunk-YHCBJULX.js} +2 -2
  190. package/dist/{chunk-5UYSCYR7.js → chunk-Z4RPXHJH.js} +4 -4
  191. package/dist/{cli-Pulnz-qm.d.ts → cli-ChKeYMZv.d.ts} +5 -5
  192. package/dist/cli.d.ts +25 -25
  193. package/dist/cli.js +81 -78
  194. package/dist/coding/pre-action-gate.d.ts +2 -60
  195. package/dist/compounding/engine.d.ts +4 -2
  196. package/dist/compounding/engine.js +17 -16
  197. package/dist/compounding/preference-consolidator.d.ts +3 -1
  198. package/dist/compression-optimizer.d.ts +3 -1
  199. package/dist/config.d.ts +3 -1
  200. package/dist/config.js +11 -1
  201. package/dist/connectors/codex-materialize-runner.d.ts +3 -1
  202. package/dist/connectors/codex-materialize-runner.js +16 -15
  203. package/dist/connectors/codex-materialize.d.ts +3 -1
  204. package/dist/connectors/index.d.ts +3 -1
  205. package/dist/connectors/index.js +16 -15
  206. package/dist/consolidation-provenance-check.d.ts +4 -2
  207. package/dist/consolidation-undo.d.ts +4 -2
  208. package/dist/contradiction/index.d.ts +10 -270
  209. package/dist/contradiction/index.js +20 -7
  210. package/dist/{contradiction-review-QKJH5DKD.js → contradiction-review-WRVLRWHS.js} +6 -2
  211. package/dist/{contradiction-scan-VOTQRRSX.js → contradiction-scan-AKUWPX5N.js} +5 -3
  212. package/dist/converge-config.d.ts +3 -1
  213. package/dist/convergence-refresh.d.ts +4 -2
  214. package/dist/convergence-refresh.js +18 -17
  215. package/dist/conversation-index/backend.d.ts +3 -1
  216. package/dist/conversation-index/chunker.d.ts +3 -1
  217. package/dist/conversation-index/faiss-adapter.d.ts +3 -1
  218. package/dist/conversation-index/indexer.d.ts +3 -1
  219. package/dist/conversation-index/search.d.ts +3 -1
  220. package/dist/corpus-watermark.d.ts +3 -1
  221. package/dist/corpus-watermark.js +18 -17
  222. package/dist/cross-lingual-recall.d.ts +3 -1
  223. package/dist/day-summary.d.ts +3 -1
  224. package/dist/delinearize.d.ts +3 -1
  225. package/dist/dependency-propagation-config.d.ts +3 -1
  226. package/dist/{dependency-propagation-delivery-Co17gxYb.d.ts → dependency-propagation-delivery-B8ZMBBCY.d.ts} +1 -1
  227. package/dist/direct-answer-wiring.d.ts +3 -1
  228. package/dist/direct-answer.d.ts +3 -1
  229. package/dist/embedding-fallback.d.ts +3 -1
  230. package/dist/enrichment/index.d.ts +3 -1
  231. package/dist/entity-origin-fields.d.ts +3 -1
  232. package/dist/entity-retrieval.d.ts +4 -2
  233. package/dist/entity-retrieval.js +16 -15
  234. package/dist/entity-schema.d.ts +3 -1
  235. package/dist/episodic-context.d.ts +3 -1
  236. package/dist/explicit-capture.d.ts +12 -12
  237. package/dist/explicit-capture.js +7 -6
  238. package/dist/external-wiki-access.d.ts +41 -42
  239. package/dist/external-wiki-access.js +37 -36
  240. package/dist/external-wiki-collection-registration.d.ts +3 -1
  241. package/dist/external-wiki-collection.d.ts +3 -1
  242. package/dist/external-wiki-mcp-tools.d.ts +40 -40
  243. package/dist/extraction-error-classification.d.ts +3 -1
  244. package/dist/extraction-faithfulness.d.ts +3 -1
  245. package/dist/extraction-judge-telemetry.d.ts +3 -1
  246. package/dist/extraction-judge-training.d.ts +3 -1
  247. package/dist/extraction-judge.d.ts +3 -1
  248. package/dist/extraction-judge.js +2 -2
  249. package/dist/extraction-liveness.d.ts +3 -1
  250. package/dist/extraction-normalization.d.ts +3 -1
  251. package/dist/extraction-normalization.js +2 -2
  252. package/dist/extraction-prompt.d.ts +4 -2
  253. package/dist/extraction-prompt.js +1 -1
  254. package/dist/extraction-source-grounding-rules.d.ts +3 -1
  255. package/dist/extraction-source-grounding.d.ts +3 -1
  256. package/dist/extraction.d.ts +3 -1
  257. package/dist/extraction.js +22 -21
  258. package/dist/fallback-llm.d.ts +3 -1
  259. package/dist/graph-dashboard-diff.d.ts +3 -1
  260. package/dist/graph-dashboard-key.d.ts +3 -1
  261. package/dist/graph-dashboard-parser.d.ts +3 -1
  262. package/dist/graph-edge-reinforcement.d.ts +3 -1
  263. package/dist/graph-path-reconstruction.d.ts +3 -1
  264. package/dist/graph-path-scoring.d.ts +3 -1
  265. package/dist/graph-snapshot.d.ts +3 -1
  266. package/dist/graph.d.ts +3 -1
  267. package/dist/harmonic-retrieval.js +1 -1
  268. package/dist/importance.d.ts +3 -1
  269. package/dist/importers/index.d.ts +3 -1
  270. package/dist/in-flight-reads.d.ts +3 -1
  271. package/dist/index-CexDrJzC.d.ts +284 -0
  272. package/dist/index.d.ts +946 -707
  273. package/dist/index.js +253 -151
  274. package/dist/intent.d.ts +3 -1
  275. package/dist/lcm/engine.d.ts +3 -1
  276. package/dist/lcm/engine.js +3 -3
  277. package/dist/lcm/index.d.ts +3 -1
  278. package/dist/lcm/index.js +6 -6
  279. package/dist/lcm/tools.d.ts +3 -1
  280. package/dist/lifecycle.d.ts +3 -1
  281. package/dist/live-connectors-runner.d.ts +3 -1
  282. package/dist/local-llm.d.ts +3 -1
  283. package/dist/local-model-endpoint.d.ts +3 -1
  284. package/dist/maintenance/memory-governance.d.ts +3 -1
  285. package/dist/maintenance/memory-governance.js +16 -15
  286. package/dist/maintenance/rebuild-memory-lifecycle-ledger.d.ts +4 -2
  287. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +16 -15
  288. package/dist/maintenance/rebuild-memory-projection.d.ts +4 -2
  289. package/dist/maintenance/rebuild-memory-projection.js +17 -16
  290. package/dist/{maintenance-DiSLtVN7.d.ts → maintenance-nkdtSrVr.d.ts} +3 -3
  291. package/dist/mcp-memory-inspector-app.d.ts +37 -37
  292. package/dist/mcp-read-only-tools.js +1 -1
  293. package/dist/memory-action-policy.d.ts +3 -1
  294. package/dist/memory-cache.d.ts +3 -1
  295. package/dist/memory-lifecycle-ledger-utils.d.ts +3 -1
  296. package/dist/memory-projection-store.d.ts +3 -1
  297. package/dist/memory-provenance.d.ts +3 -1
  298. package/dist/memory-snapshot.d.ts +3 -1
  299. package/dist/memory-subject-cli.d.ts +177 -0
  300. package/dist/memory-subject-cli.js +16 -0
  301. package/dist/memory-subject.d.ts +128 -0
  302. package/dist/memory-subject.js +44 -0
  303. package/dist/memory-subject.js.map +1 -0
  304. package/dist/memory-worth-outcomes.d.ts +7 -4
  305. package/dist/memory-worth-outcomes.js +1 -1
  306. package/dist/models-json.d.ts +3 -1
  307. package/dist/namespaces/migrate.d.ts +5 -3
  308. package/dist/namespaces/migrate.js +17 -16
  309. package/dist/namespaces/principal.d.ts +3 -1
  310. package/dist/namespaces/search.d.ts +3 -1
  311. package/dist/namespaces/search.js +6 -6
  312. package/dist/namespaces/storage.d.ts +5 -3
  313. package/dist/namespaces/storage.js +16 -15
  314. package/dist/native-knowledge.d.ts +3 -1
  315. package/dist/offline-sync-impression-drain.d.ts +3 -1
  316. package/dist/operator-doctor-corpus.d.ts +3 -1
  317. package/dist/operator-doctor-corpus.js +19 -18
  318. package/dist/operator-doctor-replica.d.ts +3 -1
  319. package/dist/operator-toolkit.d.ts +5 -3
  320. package/dist/operator-toolkit.js +29 -24
  321. package/dist/orchestration/compression-guideline-coordinator.d.ts +4 -2
  322. package/dist/orchestration/maintenance.d.ts +6 -4
  323. package/dist/orchestration/maintenance.js +22 -21
  324. package/dist/{orchestrator-DzCaxNS4.d.ts → orchestrator-Bvq1-RQs.d.ts} +23 -9
  325. package/dist/orchestrator.d.ts +12 -12
  326. package/dist/orchestrator.js +111 -108
  327. package/dist/patterns-cli.d.ts +3 -1
  328. package/dist/{pipeline-HJ8DKbFl.d.ts → pipeline-C8vfIiTX.d.ts} +1 -1
  329. package/dist/policy-runtime.d.ts +3 -1
  330. package/dist/proactive-contention.d.ts +3 -1
  331. package/dist/provenance.d.ts +3 -1
  332. package/dist/{public-http-DwXauTX3.d.ts → public-http-Cy0aYbys.d.ts} +1 -1
  333. package/dist/{qmd-BzxluoLt.d.ts → qmd-B9p1SZTZ.d.ts} +1 -1
  334. package/dist/qmd-preflight.d.ts +4 -2
  335. package/dist/qmd-recall-cache.d.ts +3 -1
  336. package/dist/qmd.d.ts +4 -2
  337. package/dist/qmd.js +4 -4
  338. package/dist/recall-concurrency-config.d.ts +3 -1
  339. package/dist/recall-disclosure-escalation.d.ts +3 -1
  340. package/dist/recall-explain-renderer.d.ts +3 -1
  341. package/dist/recall-explain-renderer.js +3 -3
  342. package/dist/recall-memory-map.d.ts +3 -1
  343. package/dist/recall-planner-llm.d.ts +3 -1
  344. package/dist/recall-state.d.ts +3 -1
  345. package/dist/recall-tag-filter.d.ts +3 -1
  346. package/dist/recall-timings.d.ts +3 -1
  347. package/dist/recall-xray-cli.d.ts +3 -1
  348. package/dist/recall-xray-cli.js +4 -4
  349. package/dist/recall-xray-renderer.d.ts +3 -1
  350. package/dist/recall-xray-renderer.js +3 -3
  351. package/dist/recall-xray.d.ts +3 -1
  352. package/dist/recall-xray.js +2 -2
  353. package/dist/reconcile/cursor.d.ts +3 -1
  354. package/dist/reconcile/manifest.d.ts +3 -1
  355. package/dist/reconcile/manifest.js +3 -3
  356. package/dist/reconcile/plan.d.ts +3 -1
  357. package/dist/replay/normalizers/chatgpt.d.ts +3 -1
  358. package/dist/replay/normalizers/claude.d.ts +3 -1
  359. package/dist/replay/normalizers/openclaw.d.ts +3 -1
  360. package/dist/replay/normalizers/shared.d.ts +3 -1
  361. package/dist/replay/runner.d.ts +3 -1
  362. package/dist/replay/types.d.ts +3 -1
  363. package/dist/replica-divergence.d.ts +3 -1
  364. package/dist/replica-peers-config.d.ts +3 -1
  365. package/dist/resolution-4552BNRV.js +36 -0
  366. package/dist/resolution-4552BNRV.js.map +1 -0
  367. package/dist/resolve-auth-token.d.ts +3 -1
  368. package/dist/resume-bundles.js +9 -2
  369. package/dist/retrieval-agents.d.ts +4 -2
  370. package/dist/retrieval-tiers.d.ts +3 -1
  371. package/dist/routing/engine.d.ts +3 -1
  372. package/dist/routing/store.d.ts +3 -1
  373. package/dist/salvage-envelope.d.ts +3 -1
  374. package/dist/salvage-envelope.js +10 -2
  375. package/dist/schemas.d.ts +130 -116
  376. package/dist/schemas.js +1 -1
  377. package/dist/{scope-profiles-CEMZz0t5.d.ts → scope-profiles-DLrRxFWR.d.ts} +1 -1
  378. package/dist/search/embed-helper.d.ts +3 -1
  379. package/dist/search/factory.d.ts +3 -1
  380. package/dist/search/factory.js +5 -5
  381. package/dist/search/index.d.ts +3 -1
  382. package/dist/search/index.js +9 -9
  383. package/dist/search/lancedb-backend.d.ts +3 -1
  384. package/dist/search/meilisearch-backend.d.ts +3 -1
  385. package/dist/search/noop-backend.d.ts +3 -1
  386. package/dist/search/orama-backend.d.ts +3 -1
  387. package/dist/search/port.d.ts +3 -1
  388. package/dist/search/remote-backend.d.ts +3 -1
  389. package/dist/{semantic-TddhF0y7.d.ts → semantic-BalR6EXU.d.ts} +1 -1
  390. package/dist/{semantic-consolidation-D9dYj6vu.d.ts → semantic-consolidation-DlN6xe20.d.ts} +1 -1
  391. package/dist/semantic-consolidation.d.ts +4 -2
  392. package/dist/semantic-consolidation.js +17 -16
  393. package/dist/semantic-rule-promotion.js +16 -15
  394. package/dist/semantic-rule-verifier.d.ts +3 -1
  395. package/dist/semantic-rule-verifier.js +16 -15
  396. package/dist/{service-_qgST_0y.d.ts → service-GkYyVfm9.d.ts} +2 -2
  397. package/dist/session-observer-bands.d.ts +3 -1
  398. package/dist/session-observer-state.d.ts +3 -1
  399. package/dist/shared-context/manager.d.ts +13 -11
  400. package/dist/signal.d.ts +3 -1
  401. package/dist/source-agent-qualifier.d.ts +3 -1
  402. package/dist/source-agent-qualifier.js +18 -17
  403. package/dist/{storage-B9lbNTYE.d.ts → storage-BIDzuKIn.d.ts} +3 -2
  404. package/dist/storage.d.ts +4 -2
  405. package/dist/storage.js +18 -17
  406. package/dist/subject-config.d.ts +40 -0
  407. package/dist/subject-config.js +20 -0
  408. package/dist/subject-config.js.map +1 -0
  409. package/dist/summarizer.d.ts +3 -1
  410. package/dist/summary-snapshot.d.ts +3 -1
  411. package/dist/support-passport/index.d.ts +43 -43
  412. package/dist/support-passport/index.js +39 -38
  413. package/dist/temporal-supersession.d.ts +4 -2
  414. package/dist/temporal-timeline-recall.d.ts +3 -1
  415. package/dist/temporal-validity.d.ts +3 -1
  416. package/dist/threading.d.ts +3 -1
  417. package/dist/tier-migration.d.ts +4 -2
  418. package/dist/tier-routing.d.ts +3 -1
  419. package/dist/topics.d.ts +3 -1
  420. package/dist/transcript.d.ts +3 -1
  421. package/dist/transfer/backup.js +2 -2
  422. package/dist/transfer/capsule-export.js +2 -2
  423. package/dist/transfer/capsule-import.js +2 -2
  424. package/dist/transfer/types.d.ts +86 -86
  425. package/dist/trust-score-stage.d.ts +3 -1
  426. package/dist/trust-score.d.ts +3 -1
  427. package/dist/{types-BrEzuxPA.d.ts → types-BxAcOl5Q.d.ts} +360 -32
  428. package/dist/types.d.ts +3 -1
  429. package/dist/types.js +1 -1
  430. package/dist/utility-runtime.d.ts +3 -1
  431. package/dist/verified-recall.js +16 -15
  432. package/dist/who-knows-cli.d.ts +40 -40
  433. package/dist/who-knows-cli.js +17 -16
  434. package/dist/who-knows.d.ts +42 -42
  435. package/dist/who-knows.js +16 -15
  436. package/dist/write-envelope.d.ts +7 -2
  437. package/dist/write-envelope.js +10 -1
  438. package/package.json +2 -2
  439. package/scripts/build-with-heap.mjs +1 -1
  440. package/src/access-boundary.ts +6 -0
  441. package/src/access-http.ts +6 -5
  442. package/src/access-mcp-admin-tools.ts +38 -0
  443. package/src/access-mcp-output-schemas.ts +20 -0
  444. package/src/access-mcp.ts +8 -8
  445. package/src/access-operations-batch.ts +13 -0
  446. package/src/access-service.ts +112 -0
  447. package/src/access-surface-catalog.test.ts +24 -0
  448. package/src/access-surface-catalog.ts +6 -0
  449. package/src/coding/action-gate.test.ts +341 -0
  450. package/src/coding/action-gate.ts +556 -0
  451. package/src/config.ts +15 -17
  452. package/src/contradiction/contradiction-review.ts +50 -4
  453. package/src/contradiction/contradiction-scan.ts +14 -3
  454. package/src/contradiction/resolution.ts +50 -2
  455. package/src/extraction-prompt.ts +1 -0
  456. package/src/extraction.ts +4 -1
  457. package/src/index.ts +9 -9
  458. package/src/mcp-read-only-tools.ts +1 -0
  459. package/src/memory-subject-cli.ts +135 -0
  460. package/src/memory-subject.test.ts +48 -0
  461. package/src/memory-subject.ts +314 -0
  462. package/src/memory-worth-outcomes.test.ts +6 -2
  463. package/src/memory-worth-outcomes.ts +11 -7
  464. package/src/operator-toolkit.ts +1 -1
  465. package/src/orchestration/extraction-persist.ts +48 -48
  466. package/src/orchestration/recall-internal.ts +6 -5
  467. package/src/orchestration/recall-rerank-coordinator.ts +123 -4
  468. package/src/orchestration/recall-result-formatter.ts +6 -2
  469. package/src/orchestration/recall-search-pipeline.ts +14 -1
  470. package/src/preferences/drift-config.ts +118 -0
  471. package/src/preferences/drift-recall.ts +133 -0
  472. package/src/preferences/drift-types.ts +87 -0
  473. package/src/preferences/index.ts +12 -0
  474. package/src/preferences/preference-drift.test.ts +690 -0
  475. package/src/preferences/preference-drift.ts +724 -0
  476. package/src/procedural/library-maintenance.test.ts +582 -0
  477. package/src/procedural/library-maintenance.ts +546 -0
  478. package/src/procedural/maintenance-config.ts +78 -0
  479. package/src/procedural/procedure-recall.ts +29 -1
  480. package/src/procedural/procedure-stats.ts +20 -0
  481. package/src/review/review-deck-access.test.ts +325 -0
  482. package/src/review/review-deck-http-base.ts +133 -0
  483. package/src/review/review-deck-mutation.test.ts +417 -0
  484. package/src/review/review-deck-mutation.ts +677 -0
  485. package/src/review/review-deck-snapshot.ts +196 -0
  486. package/src/review/review-deck-surface.ts +117 -0
  487. package/src/review/review-deck.test.ts +347 -0
  488. package/src/review/review-deck.ts +311 -0
  489. package/src/schemas.ts +7 -0
  490. package/src/spaces/index.ts +38 -2
  491. package/src/storage.ts +10 -8
  492. package/src/subject-config.ts +80 -0
  493. package/src/types.ts +33 -32
  494. package/src/write-envelope.test.ts +14 -0
  495. package/src/write-envelope.ts +24 -3
  496. package/dist/chunk-35NN3ZFA.js.map +0 -1
  497. package/dist/chunk-3PXVYJMC.js.map +0 -1
  498. package/dist/chunk-3RHFGGI5.js.map +0 -1
  499. package/dist/chunk-4NZHHGVL.js.map +0 -1
  500. package/dist/chunk-CEQF6L5K.js.map +0 -1
  501. package/dist/chunk-CUS6S7PN.js.map +0 -1
  502. package/dist/chunk-DBXZZIDU.js.map +0 -1
  503. package/dist/chunk-DEFI2QBT.js.map +0 -1
  504. package/dist/chunk-EIR5VLIH.js.map +0 -1
  505. package/dist/chunk-GEULB2VI.js.map +0 -1
  506. package/dist/chunk-JFJ3MHGV.js.map +0 -1
  507. package/dist/chunk-JG22O53B.js.map +0 -1
  508. package/dist/chunk-LCU5R6TQ.js.map +0 -1
  509. package/dist/chunk-MDVBCPOS.js +0 -402
  510. package/dist/chunk-MDVBCPOS.js.map +0 -1
  511. package/dist/chunk-MSTNSVXI.js.map +0 -1
  512. package/dist/chunk-WTOE7CW4.js.map +0 -1
  513. package/dist/chunk-YQ3CBLL4.js.map +0 -1
  514. package/dist/chunk-Z54TXZ2F.js.map +0 -1
  515. package/dist/resolution-DKMBPXHI.js +0 -18
  516. /package/dist/{capsule-crypto-7FJQINUR.js.map → capsule-crypto-YO5QJ6L3.js.map} +0 -0
  517. /package/dist/{chunk-MIBKEW7A.js.map → chunk-2VXWFYJE.js.map} +0 -0
  518. /package/dist/{chunk-3YTTAGPB.js.map → chunk-3DVBKTSO.js.map} +0 -0
  519. /package/dist/{chunk-JTSVMJHV.js.map → chunk-4XDGYCZI.js.map} +0 -0
  520. /package/dist/{chunk-HQSBYI5X.js.map → chunk-57HVIG5U.js.map} +0 -0
  521. /package/dist/{chunk-PMVPCZJZ.js.map → chunk-6433HV72.js.map} +0 -0
  522. /package/dist/{chunk-N6TRHP72.js.map → chunk-6TAX66IA.js.map} +0 -0
  523. /package/dist/{chunk-AGKIG3YA.js.map → chunk-6VALIZKG.js.map} +0 -0
  524. /package/dist/{chunk-NS5ETDYD.js.map → chunk-7BEPVIH3.js.map} +0 -0
  525. /package/dist/{chunk-LYIZXQYY.js.map → chunk-7KFIMGMP.js.map} +0 -0
  526. /package/dist/{chunk-LWVO2QZV.js.map → chunk-7QOO4LGC.js.map} +0 -0
  527. /package/dist/{chunk-CCTVAVTT.js.map → chunk-AUO2LJ3K.js.map} +0 -0
  528. /package/dist/{chunk-ALCJRQ72.js.map → chunk-AYDDB3XI.js.map} +0 -0
  529. /package/dist/{chunk-3TMYV3LP.js.map → chunk-AYYGRVRP.js.map} +0 -0
  530. /package/dist/{chunk-W6TSGWYS.js.map → chunk-AZAA5DNP.js.map} +0 -0
  531. /package/dist/{chunk-6JJT5AKI.js.map → chunk-BQUEAVNW.js.map} +0 -0
  532. /package/dist/{chunk-2NLLXCJG.js.map → chunk-BXLOS5AJ.js.map} +0 -0
  533. /package/dist/{chunk-CEH2AFXG.js.map → chunk-C24UZSFW.js.map} +0 -0
  534. /package/dist/{chunk-ZPN7W3OP.js.map → chunk-CDUUDBWJ.js.map} +0 -0
  535. /package/dist/{chunk-Y23B2QXP.js.map → chunk-D27J626P.js.map} +0 -0
  536. /package/dist/{chunk-2572MRP2.js.map → chunk-DHTQP334.js.map} +0 -0
  537. /package/dist/{chunk-HJQZQUPC.js.map → chunk-DJZWNKFO.js.map} +0 -0
  538. /package/dist/{chunk-X7Y7WX73.js.map → chunk-DQEMWVMT.js.map} +0 -0
  539. /package/dist/{chunk-VJ6ECBIP.js.map → chunk-E4MVQQVX.js.map} +0 -0
  540. /package/dist/{chunk-SYJ6EKKE.js.map → chunk-EIVIB73I.js.map} +0 -0
  541. /package/dist/{chunk-HUNSEO5U.js.map → chunk-EV3YFLCB.js.map} +0 -0
  542. /package/dist/{chunk-VPGRXEAB.js.map → chunk-G57LQRP6.js.map} +0 -0
  543. /package/dist/{chunk-BC4QD3FM.js.map → chunk-GN55KU2P.js.map} +0 -0
  544. /package/dist/{chunk-4W6INNXO.js.map → chunk-GUXS322H.js.map} +0 -0
  545. /package/dist/{chunk-3MADV4YC.js.map → chunk-IQSC3V2E.js.map} +0 -0
  546. /package/dist/{chunk-UYCIS6V5.js.map → chunk-JCWY73FK.js.map} +0 -0
  547. /package/dist/{chunk-T42L3S6A.js.map → chunk-LBWQ65SX.js.map} +0 -0
  548. /package/dist/{chunk-256FBCVX.js.map → chunk-M4AHBM72.js.map} +0 -0
  549. /package/dist/{chunk-YEQEGSJA.js.map → chunk-MBDJJTAT.js.map} +0 -0
  550. /package/dist/{chunk-IAY7YBXS.js.map → chunk-MRTUN665.js.map} +0 -0
  551. /package/dist/{chunk-R3AAOKR2.js.map → chunk-NZWEEALH.js.map} +0 -0
  552. /package/dist/{chunk-I2HTKOOP.js.map → chunk-ODZG724P.js.map} +0 -0
  553. /package/dist/{chunk-7QFBLYFP.js.map → chunk-OJD4WS2E.js.map} +0 -0
  554. /package/dist/{chunk-53ENM6F6.js.map → chunk-P4DHENRE.js.map} +0 -0
  555. /package/dist/{chunk-KPBLJCCV.js.map → chunk-PDVQ5JU3.js.map} +0 -0
  556. /package/dist/{chunk-ESCQ6LY7.js.map → chunk-QFMO32TO.js.map} +0 -0
  557. /package/dist/{chunk-HQSPXTQO.js.map → chunk-QXIQPCCN.js.map} +0 -0
  558. /package/dist/{chunk-CFRBTATE.js.map → chunk-R47WINCY.js.map} +0 -0
  559. /package/dist/{chunk-G72IPMR7.js.map → chunk-R4OCGPSH.js.map} +0 -0
  560. /package/dist/{chunk-VZVP2W4O.js.map → chunk-RK4WXUI2.js.map} +0 -0
  561. /package/dist/{chunk-JBPKEARU.js.map → chunk-RKNJBZ55.js.map} +0 -0
  562. /package/dist/{chunk-6L27N6YI.js.map → chunk-S7Q5CM7E.js.map} +0 -0
  563. /package/dist/{chunk-CTQRPANJ.js.map → chunk-SVSRPG6M.js.map} +0 -0
  564. /package/dist/{chunk-GXWDWOWP.js.map → chunk-TDKSCV62.js.map} +0 -0
  565. /package/dist/{chunk-S2VBSTTA.js.map → chunk-THG4GYIE.js.map} +0 -0
  566. /package/dist/{chunk-IXRC7EQG.js.map → chunk-TR7DGXGI.js.map} +0 -0
  567. /package/dist/{chunk-63FHSH7E.js.map → chunk-TYUS5TLG.js.map} +0 -0
  568. /package/dist/{chunk-7PWWGYGO.js.map → chunk-URHCUXKI.js.map} +0 -0
  569. /package/dist/{chunk-KQAFEZQX.js.map → chunk-VDX2J7OX.js.map} +0 -0
  570. /package/dist/{chunk-MUJ4QFUQ.js.map → chunk-W4BMEGQA.js.map} +0 -0
  571. /package/dist/{chunk-5HK3CJAR.js.map → chunk-W675UJCZ.js.map} +0 -0
  572. /package/dist/{chunk-X5SDZMO7.js.map → chunk-YHCBJULX.js.map} +0 -0
  573. /package/dist/{chunk-5UYSCYR7.js.map → chunk-Z4RPXHJH.js.map} +0 -0
  574. /package/dist/{contradiction-review-QKJH5DKD.js.map → contradiction-review-WRVLRWHS.js.map} +0 -0
  575. /package/dist/{contradiction-scan-VOTQRRSX.js.map → contradiction-scan-AKUWPX5N.js.map} +0 -0
  576. /package/dist/{resolution-DKMBPXHI.js.map → memory-subject-cli.js.map} +0 -0
@@ -0,0 +1,546 @@
1
+ /**
2
+ * Procedure library health maintenance (issue #2370).
3
+ *
4
+ * The library-health loop the agent-memory survey describes: consume the
5
+ * telemetry Remnic already records (Memory Worth counters, access
6
+ * timestamps, causal trajectories) and propose merge / repair-flag /
7
+ * retire transitions for ACTIVE procedure memories.
8
+ *
9
+ * Shadow-first contract (mirrors `memory_governance_run`): the default run
10
+ * mode produces a JSON report and writes NOTHING — not even the run
11
+ * marker. Applying requires `apply: true` AND
12
+ * `procedural.maintenance.enabled: true`.
13
+ *
14
+ * Actions, evaluated in this order per run:
15
+ * 1. Merge — cluster active procedures by normalized trigger phrase +
16
+ * step signature; most-recently-updated member becomes the
17
+ * canonical, the rest are superseded pointing at it. The
18
+ * canonical is stamped with the issue-#687 frontmatter
19
+ * contract (`reinforcement_count`, `last_reinforced_at`,
20
+ * `derived_via`, `derived_from`) so `patterns explain` reads
21
+ * procedure canonicals unchanged. A user-edited body never
22
+ * merges — the cluster is flagged instead.
23
+ * 2. Repair — flag (never rewrite) procedures whose `ProcedureStep`
24
+ * toolCall tools no longer appear in recent causal
25
+ * trajectories, via `structuredAttributes.needsRepair`.
26
+ * 3. Retire — demote to `archived` when failure-dominant past the
27
+ * configured thresholds, or idle past `retireIdleDays` with
28
+ * zero recorded outcomes. Demotion, never deletion; page
29
+ * versioning snapshots every overwrite. User-edited
30
+ * procedures are exempt and flagged instead.
31
+ *
32
+ * Deliberately NOT part of `runMemoryGovernance` — same isolation decision
33
+ * as procedure mining (docs/procedural-memory.md).
34
+ */
35
+
36
+ import path from "node:path";
37
+ import type { MemoryFile, PluginConfig } from "../types.js";
38
+ import { isActiveMemoryStatus } from "../memory-lifecycle-ledger-utils.js";
39
+ import { bumpMemoryCorpusVersionForDir } from "../memory-corpus-version.js";
40
+ import {
41
+ buildProcedurePersistBody,
42
+ parseProcedureStepsFromBody,
43
+ type ProcedureStep,
44
+ } from "./procedure-types.js";
45
+ import {
46
+ filterTrajectoriesByLookbackDays,
47
+ readCausalTrajectoryRecords,
48
+ type CausalTrajectoryRecord,
49
+ } from "../causal-trajectory.js";
50
+ import { readJsonFile, writeJsonFileAtomic } from "../json-store.js";
51
+ import { log } from "../logger.js";
52
+
53
+ type ProcedureLibraryStorage = {
54
+ readAllMemories: () => Promise<MemoryFile[]>;
55
+ writeMemoryFrontmatter: (
56
+ memory: MemoryFile,
57
+ patch: Record<string, unknown>,
58
+ extras?: Record<string, unknown>,
59
+ ) => Promise<unknown>;
60
+ archiveMemory: (
61
+ memory: MemoryFile,
62
+ opts: {
63
+ at: Date;
64
+ actor: string;
65
+ reasonCode: string;
66
+ ruleVersion?: string;
67
+ relatedMemoryIds?: string[];
68
+ },
69
+ ) => Promise<string | null>;
70
+ };
71
+
72
+ const MAINTENANCE_ACTOR = "procedure-library-maintenance";
73
+ const MAINTENANCE_RULE_VERSION = "procedure-library-maintenance:1";
74
+
75
+ export type ProcedureMaintenanceActionKind =
76
+ | "merge"
77
+ | "retire"
78
+ | "flag_repair"
79
+ | "flag_user_edited";
80
+
81
+ export type ProcedureMaintenanceReasonCode =
82
+ | "merge_duplicate_signature"
83
+ | "retire_failure_dominant"
84
+ | "retire_idle"
85
+ | "needs_repair_stale_tools"
86
+ | "user_edited_protected";
87
+
88
+ export interface ProcedureMaintenanceEvidence {
89
+ memoryId: string;
90
+ mwSuccess: number;
91
+ mwFail: number;
92
+ lastAccessed: string | null;
93
+ updated: string | null;
94
+ }
95
+
96
+ export interface ProcedureMaintenanceAction {
97
+ action: ProcedureMaintenanceActionKind;
98
+ reasonCode: ProcedureMaintenanceReasonCode;
99
+ /** Canonical first for merges; otherwise the single targeted memory. */
100
+ memoryIds: string[];
101
+ canonicalId?: string;
102
+ reason: string;
103
+ evidence: ProcedureMaintenanceEvidence[];
104
+ }
105
+
106
+ export interface ProcedureLibraryMaintenanceReport {
107
+ schemaVersion: 1;
108
+ generatedAt: string;
109
+ mode: "shadow" | "apply";
110
+ scannedProcedures: number;
111
+ proposed: ProcedureMaintenanceAction[];
112
+ applied: ProcedureMaintenanceAction[];
113
+ appliedCount: number;
114
+ skippedReason?: "procedural_disabled" | "maintenance_disabled";
115
+ }
116
+
117
+ export interface ProcedureMaintenanceMarker {
118
+ schemaVersion: 1;
119
+ lastRunAt: string;
120
+ lastApplyAt: string | null;
121
+ appliedCount: number;
122
+ }
123
+
124
+ function maintenanceMarkerPath(memoryDir: string): string {
125
+ return path.join(memoryDir, "state", "procedure-maintenance.json");
126
+ }
127
+
128
+ /** Read the last-run marker. Absent marker (or shadow-only history) → null apply timestamp. */
129
+ export async function readProcedureMaintenanceMarker(
130
+ memoryDir: string,
131
+ ): Promise<ProcedureMaintenanceMarker | null> {
132
+ try {
133
+ const raw = await readJsonFile(maintenanceMarkerPath(memoryDir));
134
+ if (raw === null || typeof raw !== "object" || Array.isArray(raw)) return null;
135
+ const m = raw as Record<string, unknown>;
136
+ if (typeof m.lastRunAt !== "string") return null;
137
+ return {
138
+ schemaVersion: 1,
139
+ lastRunAt: m.lastRunAt,
140
+ lastApplyAt: typeof m.lastApplyAt === "string" ? m.lastApplyAt : null,
141
+ appliedCount: typeof m.appliedCount === "number" ? m.appliedCount : 0,
142
+ };
143
+ } catch {
144
+ return null;
145
+ }
146
+ }
147
+
148
+ function evidenceFor(m: MemoryFile): ProcedureMaintenanceEvidence {
149
+ return {
150
+ memoryId: m.frontmatter.id,
151
+ mwSuccess: m.frontmatter.mw_success ?? 0,
152
+ mwFail: m.frontmatter.mw_fail ?? 0,
153
+ lastAccessed: m.frontmatter.lastAccessed ?? null,
154
+ updated: m.frontmatter.updated ?? null,
155
+ };
156
+ }
157
+
158
+ function tsMs(value: unknown): number | null {
159
+ if (typeof value !== "string") return null;
160
+ const ms = Date.parse(value);
161
+ return Number.isFinite(ms) ? ms : null;
162
+ }
163
+
164
+ /** Title line of a procedure body — everything before the first `## Step N` header. */
165
+ function procedureTitle(content: string): string {
166
+ const text = content.replace(/\r\n/g, "\n").trim();
167
+ const idx = text.search(/^##\s+Step\s+\d+\s*$/im);
168
+ return (idx === -1 ? text : text.slice(0, idx)).trim();
169
+ }
170
+
171
+ function normalizePhrase(s: string): string {
172
+ return s
173
+ .toLowerCase()
174
+ .replace(/[^a-z0-9]+/g, " ")
175
+ .trim();
176
+ }
177
+
178
+ /** Ordered (intent, tool) signature — the machine-mined shape of a procedure. */
179
+ function stepSignature(steps: ProcedureStep[] | null): string {
180
+ if (steps === null) return "<unparsed>";
181
+ return steps
182
+ .map(
183
+ (s) =>
184
+ `${s.order}|${normalizePhrase(s.intent)}|${s.toolCall?.kind ?? ""}|${s.toolCall?.signature ?? ""}`,
185
+ )
186
+ .join(";;");
187
+ }
188
+
189
+ /**
190
+ * A procedure is user-edited when its body no longer round-trips through the
191
+ * miner's own serializer for its parsed steps — the stateless equivalent of
192
+ * "body hash differs from last mined write". Freeform bodies with no step
193
+ * headers count as user-authored.
194
+ */
195
+ export function isUserEditedProcedure(content: string): boolean {
196
+ const steps = parseProcedureStepsFromBody(content);
197
+ if (steps === null) return true;
198
+ const rebuilt = buildProcedurePersistBody(procedureTitle(content), steps);
199
+ return rebuilt.trim() !== content.replace(/\r\n/g, "\n").trim();
200
+ }
201
+
202
+ /** Most-recently-updated wins; total comparator with stable id tiebreak (§12). */
203
+ function compareCanonical(a: MemoryFile, b: MemoryFile): number {
204
+ const aMs = tsMs(a.frontmatter.updated) ?? tsMs(a.frontmatter.created) ?? 0;
205
+ const bMs = tsMs(b.frontmatter.updated) ?? tsMs(b.frontmatter.created) ?? 0;
206
+ if (aMs !== bMs) return aMs > bMs ? -1 : 1;
207
+ const aId = a.frontmatter.id ?? "";
208
+ const bId = b.frontmatter.id ?? "";
209
+ if (aId !== bId) return aId < bId ? -1 : 1;
210
+ return 0;
211
+ }
212
+
213
+ function recentTrajectoryToolText(
214
+ trajectories: readonly CausalTrajectoryRecord[],
215
+ ): string {
216
+ return trajectories.map((r) => r.actionSummary).join("\n").toLowerCase();
217
+ }
218
+
219
+ /**
220
+ * Run one library-health maintenance pass over the procedures in a storage.
221
+ * Shadow mode performs NO writes (not even the state marker).
222
+ */
223
+ export async function runProcedureLibraryMaintenance(options: {
224
+ storage: ProcedureLibraryStorage,
225
+ memoryDir: string;
226
+ config: PluginConfig;
227
+ apply?: boolean;
228
+ now?: Date;
229
+ }): Promise<ProcedureLibraryMaintenanceReport> {
230
+ const now = options.now ?? new Date();
231
+ const nowIso = now.toISOString();
232
+ const mode: "shadow" | "apply" = options.apply === true ? "apply" : "shadow";
233
+ const cfg = options.config.procedural;
234
+ if (cfg?.enabled !== true || cfg.maintenance?.enabled !== true) {
235
+ return {
236
+ schemaVersion: 1,
237
+ generatedAt: nowIso,
238
+ mode,
239
+ scannedProcedures: 0,
240
+ proposed: [],
241
+ applied: [],
242
+ appliedCount: 0,
243
+ skippedReason: cfg?.enabled !== true ? "procedural_disabled" : "maintenance_disabled",
244
+ };
245
+ }
246
+ const maintenance = cfg.maintenance;
247
+
248
+ const all = await options.storage.readAllMemories();
249
+ const byId = new Map<string, MemoryFile>();
250
+ for (const m of all) {
251
+ if (m.frontmatter.category !== "procedure") continue;
252
+ // Only ACTIVE procedures are maintenance candidates. pending_review,
253
+ // rejected, quarantined, superseded, and archived are never merge or
254
+ // retire candidates (§41) — archived files live outside readAllMemories
255
+ // entirely.
256
+ if (!isActiveMemoryStatus(m.frontmatter.status)) continue;
257
+ if (typeof m.frontmatter.id === "string" && m.frontmatter.id.length > 0) {
258
+ byId.set(m.frontmatter.id, m);
259
+ }
260
+ }
261
+ const activeProcedures = [...byId.values()];
262
+
263
+ const report: ProcedureLibraryMaintenanceReport = {
264
+ schemaVersion: 1,
265
+ generatedAt: nowIso,
266
+ mode,
267
+ scannedProcedures: activeProcedures.length,
268
+ proposed: [],
269
+ applied: [],
270
+ appliedCount: 0,
271
+ };
272
+ // Empty library: nothing to propose. Shadow returns immediately; an apply
273
+ // run still falls through so the run marker records the pass.
274
+ if (activeProcedures.length === 0 && mode === "shadow") return report;
275
+
276
+
277
+ // --- 1. Merge -------------------------------------------------------------
278
+ const mergeConsumed = new Set<string>();
279
+ if (maintenance.mergeEnabled) {
280
+ const clusters = new Map<string, MemoryFile[]>();
281
+ for (const m of activeProcedures) {
282
+ const steps = parseProcedureStepsFromBody(m.content);
283
+ const key = `${normalizePhrase(procedureTitle(m.content))}\n@@\n${stepSignature(steps)}`;
284
+ const bucket = clusters.get(key);
285
+ if (bucket) bucket.push(m);
286
+ else clusters.set(key, [m]);
287
+ }
288
+ for (const cluster of clusters.values()) {
289
+ if (cluster.length < 2) continue;
290
+ const sortedCluster = [...cluster].sort(compareCanonical);
291
+ const userEdited = sortedCluster.filter((m) => isUserEditedProcedure(m.content));
292
+ if (userEdited.length > 0) {
293
+ report.proposed.push({
294
+ action: "flag_user_edited",
295
+ reasonCode: "user_edited_protected",
296
+ memoryIds: sortedCluster.map((m) => m.frontmatter.id),
297
+ reason:
298
+ "duplicate-signature cluster contains user-edited bodies; merge skipped for manual review",
299
+ evidence: sortedCluster.map(evidenceFor),
300
+ });
301
+ continue;
302
+ }
303
+ const canonical = sortedCluster[0]!;
304
+ const duplicates = sortedCluster.slice(1);
305
+ for (const m of sortedCluster) mergeConsumed.add(m.frontmatter.id);
306
+ report.proposed.push({
307
+ action: "merge",
308
+ reasonCode: "merge_duplicate_signature",
309
+ memoryIds: [canonical.frontmatter.id, ...duplicates.map((m) => m.frontmatter.id)],
310
+ canonicalId: canonical.frontmatter.id,
311
+ reason: `near-identical trigger phrase + step signature across ${sortedCluster.length} active procedures`,
312
+ evidence: sortedCluster.map(evidenceFor),
313
+ });
314
+ }
315
+ }
316
+
317
+ // --- 2. Repair flag -------------------------------------------------------
318
+ // Only meaningful when the lookback window holds trajectory evidence: an
319
+ // empty window proves nothing about tool freshness.
320
+ const trajectoryDir =
321
+ typeof options.config.causalTrajectoryStoreDir === "string" &&
322
+ options.config.causalTrajectoryStoreDir.trim().length > 0
323
+ ? options.config.causalTrajectoryStoreDir.trim()
324
+ : undefined;
325
+ const { trajectories } = await readCausalTrajectoryRecords({
326
+ memoryDir: options.memoryDir,
327
+ causalTrajectoryStoreDir: trajectoryDir,
328
+ });
329
+ const recentTrajectories = filterTrajectoriesByLookbackDays(
330
+ trajectories,
331
+ cfg.lookbackDays,
332
+ now.getTime(),
333
+ );
334
+ const repairFlags: ProcedureMaintenanceAction[] = [];
335
+ const staleToolsByProcedure = new Map<string, string[]>();
336
+ if (recentTrajectories.length > 0) {
337
+ const toolText = recentTrajectoryToolText(recentTrajectories);
338
+ for (const m of activeProcedures) {
339
+ if (mergeConsumed.has(m.frontmatter.id)) continue;
340
+ const steps = parseProcedureStepsFromBody(m.content);
341
+ if (steps === null) continue;
342
+ const tools = [
343
+ ...new Set(
344
+ steps
345
+ .map((s) => s.toolCall?.kind)
346
+ .filter((t): t is string => typeof t === "string" && t.length > 0),
347
+ ),
348
+ ];
349
+ if (tools.length === 0) continue;
350
+ const stale = tools.filter((t) => !toolText.includes(t.toLowerCase()));
351
+ if (stale.length === 0) continue;
352
+ staleToolsByProcedure.set(m.frontmatter.id, stale);
353
+ repairFlags.push({
354
+ action: "flag_repair",
355
+ reasonCode: "needs_repair_stale_tools",
356
+ memoryIds: [m.frontmatter.id],
357
+ reason: `tools absent from last ${cfg.lookbackDays}d of trajectories: ${stale.join(", ")}`,
358
+ evidence: [evidenceFor(m)],
359
+ });
360
+ }
361
+ }
362
+
363
+ // --- 3. Retire ------------------------------------------------------------
364
+ const retireActions: ProcedureMaintenanceAction[] = [];
365
+ const retireIds = new Set<string>();
366
+ const idleMs = maintenance.retireIdleDays * 24 * 60 * 60 * 1000;
367
+ for (const m of activeProcedures) {
368
+ if (mergeConsumed.has(m.frontmatter.id)) continue;
369
+ const mwSuccess = m.frontmatter.mw_success ?? 0;
370
+ const mwFail = m.frontmatter.mw_fail ?? 0;
371
+ const failureDominant =
372
+ mwFail >= maintenance.retireMinOutcomes &&
373
+ mwFail > mwSuccess * maintenance.retireFailRatio;
374
+ // Half-open idle window (§23): fresh means last signal in
375
+ // [now - idleMs, now); idle means strictly older than the window start.
376
+ const lastSignalMs =
377
+ tsMs(m.frontmatter.lastAccessed) ?? tsMs(m.frontmatter.updated);
378
+ const idle =
379
+ maintenance.retireIdleDays > 0 &&
380
+ mwSuccess + mwFail === 0 &&
381
+ lastSignalMs !== null &&
382
+ lastSignalMs < now.getTime() - idleMs;
383
+ const reasonCode: ProcedureMaintenanceReasonCode | null = failureDominant
384
+ ? "retire_failure_dominant"
385
+ : idle
386
+ ? "retire_idle"
387
+ : null;
388
+ if (reasonCode === null) continue;
389
+ if (isUserEditedProcedure(m.content)) {
390
+ report.proposed.push({
391
+ action: "flag_user_edited",
392
+ reasonCode: "user_edited_protected",
393
+ memoryIds: [m.frontmatter.id],
394
+ reason: `user-edited body exempt from automatic retirement (${reasonCode} waived)`,
395
+ evidence: [evidenceFor(m)],
396
+ });
397
+ continue;
398
+ }
399
+ retireIds.add(m.frontmatter.id);
400
+ retireActions.push({
401
+ action: "retire",
402
+ reasonCode,
403
+ memoryIds: [m.frontmatter.id],
404
+ reason:
405
+ reasonCode === "retire_failure_dominant"
406
+ ? `mw_fail ${mwFail} >= ${maintenance.retireMinOutcomes} and > mw_success ${mwSuccess} * ${maintenance.retireFailRatio}`
407
+ : `no access signal for ${maintenance.retireIdleDays}d and zero recorded outcomes`,
408
+ evidence: [evidenceFor(m)],
409
+ });
410
+ }
411
+
412
+ // Repair flags after merge/retire exclusions land in the report in
413
+ // evaluation order (merge → repair → retire).
414
+ for (const flag of repairFlags) {
415
+ if (retireIds.has(flag.memoryIds[0]!)) continue;
416
+ report.proposed.push(flag);
417
+ }
418
+ report.proposed.push(...retireActions);
419
+
420
+ if (mode === "shadow") return report;
421
+
422
+ // --- Apply ----------------------------------------------------------------
423
+ const applied = report.proposed;
424
+ let writes = 0;
425
+ for (const action of applied) {
426
+ try {
427
+ if (action.action === "merge") {
428
+ const canonicalId = action.canonicalId;
429
+ const canonical = canonicalId !== undefined ? byId.get(canonicalId) : undefined;
430
+ if (!canonical || canonicalId === undefined) continue;
431
+ const memberIds = [...action.memoryIds].sort();
432
+ const previousCount = canonical.frontmatter.reinforcement_count ?? 0;
433
+ const newCount = Math.max(previousCount, memberIds.length);
434
+ if (
435
+ newCount !== canonical.frontmatter.reinforcement_count ||
436
+ canonical.frontmatter.derived_via !== "pattern-reinforcement"
437
+ ) {
438
+ await options.storage.writeMemoryFrontmatter(
439
+ canonical,
440
+ {
441
+ reinforcement_count: newCount,
442
+ last_reinforced_at: nowIso,
443
+ derived_via: "pattern-reinforcement",
444
+ derived_from: memberIds,
445
+ updated: nowIso,
446
+ },
447
+ {
448
+ actor: MAINTENANCE_ACTOR,
449
+ reasonCode: action.reasonCode,
450
+ ruleVersion: MAINTENANCE_RULE_VERSION,
451
+ relatedMemoryIds: memberIds,
452
+ },
453
+ );
454
+ writes += 1;
455
+ }
456
+ for (const memberId of action.memoryIds) {
457
+ if (memberId === canonicalId) continue;
458
+ const member = byId.get(memberId);
459
+ if (!member) continue;
460
+ await options.storage.writeMemoryFrontmatter(
461
+ member,
462
+ {
463
+ status: "superseded",
464
+ supersededBy: canonicalId,
465
+ supersededAt: nowIso,
466
+ updated: nowIso,
467
+ },
468
+ {
469
+ actor: MAINTENANCE_ACTOR,
470
+ reasonCode: action.reasonCode,
471
+ ruleVersion: MAINTENANCE_RULE_VERSION,
472
+ relatedMemoryIds: [canonicalId],
473
+ },
474
+ );
475
+ writes += 1;
476
+ }
477
+ } else if (action.action === "retire") {
478
+ const memory = byId.get(action.memoryIds[0]!);
479
+ if (!memory) continue;
480
+ const archivedPath = await options.storage.archiveMemory(memory, {
481
+ at: now,
482
+ actor: `${MAINTENANCE_ACTOR}.apply`,
483
+ reasonCode: action.reasonCode,
484
+ ruleVersion: MAINTENANCE_RULE_VERSION,
485
+ relatedMemoryIds: [],
486
+ });
487
+ if (archivedPath !== null) writes += 1;
488
+ } else if (action.action === "flag_repair") {
489
+ const memory = byId.get(action.memoryIds[0]!);
490
+ if (!memory) continue;
491
+ const existing = memory.frontmatter.structuredAttributes ?? {};
492
+ const prior = existing.needsRepair;
493
+ let priorReason: string | null = null;
494
+ if (typeof prior === "string") {
495
+ try {
496
+ const parsed = JSON.parse(prior) as { reason?: unknown };
497
+ if (typeof parsed.reason === "string") priorReason = parsed.reason;
498
+ } catch {
499
+ priorReason = prior;
500
+ }
501
+ }
502
+ if (priorReason === action.reason) continue;
503
+ const stamp = JSON.stringify({ reason: action.reason, detectedAt: nowIso });
504
+ await options.storage.writeMemoryFrontmatter(
505
+ memory,
506
+ {
507
+ structuredAttributes: { ...existing, needsRepair: stamp },
508
+ updated: nowIso,
509
+ },
510
+ {
511
+ actor: MAINTENANCE_ACTOR,
512
+ reasonCode: action.reasonCode,
513
+ ruleVersion: MAINTENANCE_RULE_VERSION,
514
+ },
515
+ );
516
+ writes += 1;
517
+ }
518
+ // flag_user_edited writes nothing — flags are report-only by design.
519
+ report.applied.push(action);
520
+ } catch (err) {
521
+ log.warn(
522
+ `procedure-library-maintenance: action ${action.reasonCode} on ${action.memoryIds.join(",")} failed: ${err instanceof Error ? err.message : String(err)}`,
523
+ );
524
+ }
525
+ }
526
+ report.appliedCount = report.applied.length;
527
+
528
+ if (writes > 0) {
529
+ // Out-of-band corpus bump + marker so hot caches and the stats surface
530
+ // observe the pass (§25/§31 — direct writes must not leave stale views).
531
+ bumpMemoryCorpusVersionForDir(options.memoryDir);
532
+ }
533
+ try {
534
+ await writeJsonFileAtomic(maintenanceMarkerPath(options.memoryDir), {
535
+ schemaVersion: 1,
536
+ lastRunAt: nowIso,
537
+ lastApplyAt: nowIso,
538
+ appliedCount: report.appliedCount,
539
+ } satisfies ProcedureMaintenanceMarker);
540
+ } catch (err) {
541
+ log.warn(
542
+ `procedure-library-maintenance: failed to persist run marker: ${err instanceof Error ? err.message : String(err)}`,
543
+ );
544
+ }
545
+ return report;
546
+ }
@@ -0,0 +1,78 @@
1
+ import { coerceBool, coerceNumber } from "../connectors/coerce.js";
2
+
3
+ export interface ProceduralMaintenanceConfig {
4
+ enabled: boolean;
5
+ retireIdleDays: number;
6
+ retireMinOutcomes: number;
7
+ retireFailRatio: number;
8
+ mergeEnabled: boolean;
9
+ }
10
+
11
+ export function parseProceduralMaintenanceConfig(
12
+ raw: unknown,
13
+ ): ProceduralMaintenanceConfig {
14
+ if (raw !== undefined && (raw === null || typeof raw !== "object" || Array.isArray(raw))) {
15
+ throw new Error(
16
+ `procedural.maintenance must be an object (got ${JSON.stringify(raw)}). Omit the key to keep maintenance disabled (issue #2370).`,
17
+ );
18
+ }
19
+ const rawMaintenance = raw && typeof raw === "object" ? (raw as Record<string, unknown>) : {};
20
+ let enabled = false;
21
+ if (rawMaintenance.enabled !== undefined) {
22
+ const coerced = coerceBool(rawMaintenance.enabled);
23
+ if (coerced === undefined) {
24
+ throw new Error(
25
+ `procedural.maintenance.enabled must be a boolean or one of "true"/"false"/"1"/"0"/"yes"/"no"/"on"/"off" (got ${JSON.stringify(rawMaintenance.enabled)}).`,
26
+ );
27
+ }
28
+ enabled = coerced;
29
+ }
30
+ const parseInteger = (key: string, fallback: number, min: number, max: number): number => {
31
+ const value = rawMaintenance[key];
32
+ if (value === undefined) return fallback;
33
+ const coerced = coerceNumber(value);
34
+ if (coerced === undefined || !Number.isFinite(coerced)) {
35
+ throw new Error(
36
+ `procedural.maintenance.${key} must be a finite number (got ${JSON.stringify(value)}).`,
37
+ );
38
+ }
39
+ if (!Number.isInteger(coerced)) {
40
+ throw new Error(
41
+ `procedural.maintenance.${key} must be an integer (got ${JSON.stringify(value)}).`,
42
+ );
43
+ }
44
+ if (coerced < min || coerced > max) {
45
+ throw new Error(
46
+ `procedural.maintenance.${key} must be between ${min} and ${max} (got ${JSON.stringify(value)}).`,
47
+ );
48
+ }
49
+ return coerced;
50
+ };
51
+ let retireFailRatio = 2;
52
+ if (rawMaintenance.retireFailRatio !== undefined) {
53
+ const coerced = coerceNumber(rawMaintenance.retireFailRatio);
54
+ if (coerced === undefined || !Number.isFinite(coerced) || coerced <= 0) {
55
+ throw new Error(
56
+ `procedural.maintenance.retireFailRatio must be a positive finite number (got ${JSON.stringify(rawMaintenance.retireFailRatio)}).`,
57
+ );
58
+ }
59
+ retireFailRatio = coerced;
60
+ }
61
+ let mergeEnabled = true;
62
+ if (rawMaintenance.mergeEnabled !== undefined) {
63
+ const coerced = coerceBool(rawMaintenance.mergeEnabled);
64
+ if (coerced === undefined) {
65
+ throw new Error(
66
+ `procedural.maintenance.mergeEnabled must be a boolean or one of "true"/"false"/"1"/"0"/"yes"/"no"/"on"/"off" (got ${JSON.stringify(rawMaintenance.mergeEnabled)}).`,
67
+ );
68
+ }
69
+ mergeEnabled = coerced;
70
+ }
71
+ return {
72
+ enabled,
73
+ retireIdleDays: parseInteger("retireIdleDays", 90, 0, 36_500),
74
+ retireMinOutcomes: parseInteger("retireMinOutcomes", 5, 1, 100_000),
75
+ retireFailRatio,
76
+ mergeEnabled,
77
+ };
78
+ }
@@ -47,7 +47,18 @@ export async function buildProcedureRecallSection(
47
47
  storage: StorageManager,
48
48
  prompt: string,
49
49
  config: PluginConfig,
50
- options?: { partitionToolScoped?: boolean; requestingConnector?: string },
50
+ options?: {
51
+ partitionToolScoped?: boolean;
52
+ requestingConnector?: string;
53
+ /**
54
+ * Out-param (issue #2370): populated with the injected procedures
55
+ * (id + path, in injection order) so the recall pipeline can fold them
56
+ * into the same per-recall bookkeeping as QMD-served memories —
57
+ * access tracking and `LastRecallSnapshot.memoryIds`. Only populated
58
+ * when a section is returned.
59
+ */
60
+ injectedMemories?: Array<{ id: string; path: string; namespace?: string }>;
61
+ },
51
62
  ): Promise<string | null> {
52
63
  if (config.procedural?.enabled !== true) return null;
53
64
  const trimmed = typeof prompt === "string" ? prompt.trim() : "";
@@ -87,6 +98,12 @@ export async function buildProcedureRecallSection(
87
98
 
88
99
  if (scored.length === 0) return null;
89
100
 
101
+ if (options?.injectedMemories) {
102
+ for (const { m } of scored) {
103
+ options.injectedMemories.push({ id: m.frontmatter.id, path: m.path });
104
+ }
105
+ }
106
+
90
107
  // #1955: procedure bodies are model-visible instructions by nature — an
91
108
  // untrusted-origin procedure must render inside the data-only authority
92
109
  // fence like every other recall surface.
@@ -105,3 +122,14 @@ export async function buildProcedureRecallSection(
105
122
 
106
123
  return `## Relevant procedures\n\n${blocks.join("\n\n")}`;
107
124
  }
125
+
126
+ export function mergeProcedureInjections<T extends { id: string }>(existing: T[], injected: T[]): T[] {
127
+ if (injected.length === 0) return existing;
128
+ const seen = new Set(existing.map((memory) => memory.id));
129
+ const extra = injected.filter((memory) => {
130
+ if (seen.has(memory.id)) return false;
131
+ seen.add(memory.id);
132
+ return true;
133
+ });
134
+ return extra.length === 0 ? existing : [...existing, ...extra];
135
+ }