@remnic/core 9.30.1 → 9.32.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (504) hide show
  1. package/dist/access-admin-ops-surface.d.ts +10 -10
  2. package/dist/access-admin-ops-surface.js +55 -44
  3. package/dist/access-authorization-probe.d.ts +10 -10
  4. package/dist/access-authorization-probe.js +56 -45
  5. package/dist/access-boundary.d.ts +13 -11
  6. package/dist/access-boundary.js +55 -44
  7. package/dist/access-cli.js +170 -126
  8. package/dist/access-cli.js.map +1 -1
  9. package/dist/access-extraction-force-flush.d.ts +119 -0
  10. package/dist/access-extraction-force-flush.js +171 -0
  11. package/dist/access-health-types.d.ts +1 -1
  12. package/dist/access-http-lcm-compaction.d.ts +47 -13
  13. package/dist/access-http-lcm-compaction.js +7 -3
  14. package/dist/access-http-lifecycle-flush.d.ts +132 -0
  15. package/dist/access-http-lifecycle-flush.js +9 -0
  16. package/dist/access-http-lifecycle-flush.js.map +1 -0
  17. package/dist/access-http.d.ts +11 -10
  18. package/dist/access-http.js +71 -59
  19. package/dist/access-identity-continuity-surface.d.ts +8 -8
  20. package/dist/access-identity-continuity-surface.js +55 -44
  21. package/dist/access-lcm-surface.d.ts +10 -10
  22. package/dist/access-lcm-surface.js +55 -44
  23. package/dist/access-mcp-output-schemas.js +1 -1
  24. package/dist/access-mcp.d.ts +16 -10
  25. package/dist/access-mcp.js +63 -52
  26. package/dist/access-memory-search-fanout.d.ts +2 -2
  27. package/dist/{access-namespace-preflight-VfXssvoI.d.ts → access-namespace-preflight-COhbXBqS.d.ts} +1 -1
  28. package/dist/access-namespace-preflight.d.ts +3 -3
  29. package/dist/access-namespace-preflight.js +55 -44
  30. package/dist/access-observe-helpers.d.ts +22 -0
  31. package/dist/access-observe-helpers.js +10 -0
  32. package/dist/access-observe-helpers.js.map +1 -0
  33. package/dist/access-observe-write-surface.d.ts +51 -47
  34. package/dist/access-observe-write-surface.js +55 -44
  35. package/dist/access-operations-batch.js +58 -47
  36. package/dist/access-operations.d.ts +11 -11
  37. package/dist/access-operations.js +60 -49
  38. package/dist/access-recall-concurrency.d.ts +10 -10
  39. package/dist/access-recall-concurrency.js +55 -44
  40. package/dist/access-recall-response.d.ts +10 -10
  41. package/dist/access-recall-response.js +55 -44
  42. package/dist/access-recall-surface.d.ts +10 -10
  43. package/dist/access-recall-surface.js +55 -44
  44. package/dist/access-schema.d.ts +37 -7
  45. package/dist/access-schema.js +5 -3
  46. package/dist/{access-service-B5RwVsTV.d.ts → access-service-BmBTtEKO.d.ts} +44 -20
  47. package/dist/access-service-helpers.d.ts +113 -0
  48. package/dist/access-service-helpers.js +8 -0
  49. package/dist/access-service-helpers.js.map +1 -0
  50. package/dist/access-service.d.ts +10 -10
  51. package/dist/access-service.js +55 -44
  52. package/dist/access-surface-catalog.d.ts +10 -10
  53. package/dist/access-surface-catalog.js +2 -0
  54. package/dist/access-surface-catalog.js.map +1 -1
  55. package/dist/access-wearables-meetings-surface.d.ts +3 -3
  56. package/dist/action-confidence.d.ts +1 -1
  57. package/dist/active-memory-bridge.d.ts +1 -1
  58. package/dist/active-recall.d.ts +1 -1
  59. package/dist/active-recall.js +2 -2
  60. package/dist/adapters/index.js +7 -7
  61. package/dist/adapters/registry.js +3 -3
  62. package/dist/behavior-learner.d.ts +1 -1
  63. package/dist/behavior-signals.d.ts +1 -1
  64. package/dist/bootstrap.d.ts +8 -8
  65. package/dist/briefing.d.ts +2 -2
  66. package/dist/briefing.js +14 -14
  67. package/dist/buffer-surprise-report.d.ts +1 -1
  68. package/dist/buffer-turn-helpers.d.ts +5 -0
  69. package/dist/buffer-turn-helpers.js +24 -0
  70. package/dist/buffer-turn-helpers.js.map +1 -0
  71. package/dist/buffer.d.ts +17 -4
  72. package/dist/buffer.js +21 -1
  73. package/dist/bulk-import/index.d.ts +3 -3
  74. package/dist/calibration.d.ts +1 -1
  75. package/dist/capabilities.d.ts +1 -1
  76. package/dist/{capsule-crypto-GWVG7LGC.js → capsule-crypto-7FJQINUR.js} +2 -2
  77. package/dist/capsule-crypto-7FJQINUR.js.map +1 -0
  78. package/dist/{capsule-merge-5KKJQBWQ.js → capsule-merge-2H2IUTBT.js} +4 -4
  79. package/dist/{catalog-V7inUQdp.d.ts → catalog-Dm-DvNBY.d.ts} +1 -1
  80. package/dist/causal-behavior.d.ts +1 -1
  81. package/dist/causal-behavior.js +2 -2
  82. package/dist/causal-chain.js +2 -2
  83. package/dist/causal-consolidation.d.ts +1 -1
  84. package/dist/causal-consolidation.js +21 -22
  85. package/dist/causal-consolidation.js.map +1 -1
  86. package/dist/causal-retrieval.js +2 -2
  87. package/dist/causal-trajectory-graph.d.ts +1 -1
  88. package/dist/causal-trajectory.js +1 -1
  89. package/dist/{chunk-LEPOP46W.js → chunk-227UFSEQ.js} +4 -4
  90. package/dist/{chunk-I5NLEENJ.js → chunk-27HHNYSQ.js} +3 -3
  91. package/dist/{chunk-2SA56WMI.js → chunk-2LTDWSR6.js} +4 -4
  92. package/dist/{chunk-OWHERGF2.js → chunk-2NLLXCJG.js} +2 -2
  93. package/dist/{chunk-SPJXKAVF.js → chunk-2NTGBZLZ.js} +14 -13
  94. package/dist/chunk-2NTGBZLZ.js.map +1 -0
  95. package/dist/{chunk-P5PXWTW7.js → chunk-2Q4JJ3FZ.js} +3 -3
  96. package/dist/{chunk-G5R3D5UP.js → chunk-2QIMTVEJ.js} +6 -5
  97. package/dist/chunk-2QIMTVEJ.js.map +1 -0
  98. package/dist/{chunk-H5CPS5JP.js → chunk-35IVNNRK.js} +3 -3
  99. package/dist/{chunk-LBOD4U5B.js → chunk-3EQ2XB3W.js} +6 -6
  100. package/dist/{chunk-YTSNAUXN.js → chunk-3F2LKUMU.js} +22 -8
  101. package/dist/chunk-3F2LKUMU.js.map +1 -0
  102. package/dist/chunk-3QL24R5Y.js +9 -0
  103. package/dist/chunk-3QL24R5Y.js.map +1 -0
  104. package/dist/chunk-4RNZMRAV.js +60 -0
  105. package/dist/chunk-4RNZMRAV.js.map +1 -0
  106. package/dist/chunk-5IVLTFOV.js +65 -0
  107. package/dist/chunk-5IVLTFOV.js.map +1 -0
  108. package/dist/{chunk-2EUVEDF5.js → chunk-5WZVQRHV.js} +2 -2
  109. package/dist/{chunk-ALSGMEJR.js → chunk-65ZPVYTA.js} +7 -7
  110. package/dist/{chunk-GIBMDSJ2.js → chunk-6P7MTSU5.js} +2 -2
  111. package/dist/{chunk-5VQJBH2G.js → chunk-6TAUHL33.js} +2 -2
  112. package/dist/{chunk-WVO4G37W.js → chunk-7TEZUUGM.js} +3 -3
  113. package/dist/{chunk-MJCGLM25.js → chunk-7VUAG236.js} +5 -5
  114. package/dist/{chunk-CZRYLSSW.js → chunk-AJL6NNX6.js} +2 -2
  115. package/dist/{chunk-LGHKJABJ.js → chunk-AQEJE3WO.js} +40 -18
  116. package/dist/chunk-AQEJE3WO.js.map +1 -0
  117. package/dist/{chunk-66772WBP.js → chunk-AQWVJURR.js} +5 -5
  118. package/dist/{chunk-RKNJBZ55.js → chunk-AU7Q3LSC.js} +7 -7
  119. package/dist/{chunk-IYZ5K7MU.js → chunk-BUE5E2HL.js} +4 -187
  120. package/dist/chunk-BUE5E2HL.js.map +1 -0
  121. package/dist/{chunk-NHWB6HG2.js → chunk-CE5355TT.js} +21 -5
  122. package/dist/chunk-CE5355TT.js.map +1 -0
  123. package/dist/{chunk-M3C2V3PV.js → chunk-CJDNT45S.js} +12 -12
  124. package/dist/{chunk-D2ANTDGO.js → chunk-E6BMSH7U.js} +2 -2
  125. package/dist/{chunk-CKMO4RDY.js → chunk-EMDLM3LW.js} +4 -4
  126. package/dist/chunk-ER7W6H4T.js +112 -0
  127. package/dist/chunk-ER7W6H4T.js.map +1 -0
  128. package/dist/{chunk-RGIWINDN.js → chunk-FHBITMRY.js} +30 -30
  129. package/dist/{chunk-6FUPCJUL.js → chunk-FMFLGS5Z.js} +54 -54
  130. package/dist/chunk-FMFLGS5Z.js.map +1 -0
  131. package/dist/{chunk-FDAMS4PK.js → chunk-G2YQ57YO.js} +4 -4
  132. package/dist/{chunk-6U7F52DE.js → chunk-HFQQWAMS.js} +62 -62
  133. package/dist/{chunk-5W4ZLBEZ.js → chunk-HKPJPOW7.js} +2 -2
  134. package/dist/{chunk-JCBWCYEJ.js → chunk-IGWFKW4B.js} +2 -2
  135. package/dist/{chunk-AITCS2RC.js → chunk-IJ7HK452.js} +4 -4
  136. package/dist/{chunk-4WKA6I65.js → chunk-J3ZGPYXB.js} +1135 -311
  137. package/dist/chunk-J3ZGPYXB.js.map +1 -0
  138. package/dist/{chunk-D3LMYTBV.js → chunk-J7WZUL2K.js} +9 -9
  139. package/dist/{chunk-5W7CTZ2E.js → chunk-KQAFEZQX.js} +4 -4
  140. package/dist/{chunk-YNQBRLC5.js → chunk-LUQ443JP.js} +520 -2011
  141. package/dist/chunk-LUQ443JP.js.map +1 -0
  142. package/dist/{chunk-Z54EM5YZ.js → chunk-MAXVH44E.js} +7 -7
  143. package/dist/{chunk-WZFAPHIK.js → chunk-MU7ZHSZE.js} +2 -2
  144. package/dist/chunk-N5Z4EVOR.js +123 -0
  145. package/dist/chunk-N5Z4EVOR.js.map +1 -0
  146. package/dist/{chunk-AZ5BTEKX.js → chunk-NQUF7XKR.js} +2 -2
  147. package/dist/{chunk-W4FBGYGK.js → chunk-NRV4Y3PM.js} +1 -1
  148. package/dist/{chunk-62U4J2GN.js → chunk-ODGOP7P2.js} +2 -2
  149. package/dist/{chunk-QJAQNXWI.js → chunk-ONHRRJZM.js} +6 -6
  150. package/dist/{chunk-ACXPX4AG.js → chunk-OPBTPRGY.js} +2 -2
  151. package/dist/{chunk-XOZ4ALGB.js → chunk-QDTZ2HF7.js} +3 -3
  152. package/dist/{chunk-GBJ4RDFR.js → chunk-QIHIHZYC.js} +66 -91
  153. package/dist/chunk-QIHIHZYC.js.map +1 -0
  154. package/dist/{chunk-ZPSVBSOF.js → chunk-QMWFQBIL.js} +3 -3
  155. package/dist/{chunk-W5EG6LE3.js → chunk-THCPRMRF.js} +3 -3
  156. package/dist/{chunk-4A6YGWQN.js → chunk-TL4TO3EA.js} +115 -120
  157. package/dist/chunk-TL4TO3EA.js.map +1 -0
  158. package/dist/{chunk-VI2JQPNQ.js → chunk-U7QYBSQJ.js} +2 -2
  159. package/dist/chunk-ULARSG5Z.js +203 -0
  160. package/dist/chunk-ULARSG5Z.js.map +1 -0
  161. package/dist/{chunk-TH2LSRMG.js → chunk-UORKJ34C.js} +2 -2
  162. package/dist/{chunk-4Z4XNEWZ.js → chunk-VCD4PSK2.js} +56 -12
  163. package/dist/chunk-VCD4PSK2.js.map +1 -0
  164. package/dist/{chunk-K5GB36ME.js → chunk-VMZ56EE3.js} +2 -2
  165. package/dist/{chunk-HUHX2OCX.js → chunk-VVDPPDDF.js} +1 -1
  166. package/dist/chunk-VVDPPDDF.js.map +1 -0
  167. package/dist/{chunk-RMMVQQA6.js → chunk-WDISJRMG.js} +2 -2
  168. package/dist/{chunk-B6JDYXL7.js → chunk-WWUVONGW.js} +7 -1
  169. package/dist/chunk-WWUVONGW.js.map +1 -0
  170. package/dist/{chunk-UVYI6VIX.js → chunk-X7Y7WX73.js} +1 -1
  171. package/dist/{chunk-CVILPI77.js → chunk-XOQSEF7X.js} +6 -6
  172. package/dist/{chunk-RPW2NOU6.js → chunk-YIAA2X3D.js} +41 -1
  173. package/dist/chunk-YIAA2X3D.js.map +1 -0
  174. package/dist/chunk-YPC7W6GA.js +1604 -0
  175. package/dist/chunk-YPC7W6GA.js.map +1 -0
  176. package/dist/{chunk-YTQNQ4KB.js → chunk-YX5LN6JR.js} +3 -3
  177. package/dist/{chunk-IC6CBHCA.js → chunk-Z7XKUWYS.js} +2 -2
  178. package/dist/{chunk-PHWUFPCO.js → chunk-ZCPP5OW6.js} +61 -53
  179. package/dist/chunk-ZCPP5OW6.js.map +1 -0
  180. package/dist/{cli-C4GbETPC.d.ts → cli-DRJLv1Xt.d.ts} +5 -5
  181. package/dist/cli.d.ts +12 -12
  182. package/dist/cli.js +96 -86
  183. package/dist/compounding/engine.d.ts +2 -2
  184. package/dist/compounding/engine.js +14 -14
  185. package/dist/compounding/preference-consolidator.d.ts +1 -1
  186. package/dist/compression-optimizer.d.ts +1 -1
  187. package/dist/config.d.ts +1 -1
  188. package/dist/config.js +2 -2
  189. package/dist/connectors/codex-materialize-runner.d.ts +1 -1
  190. package/dist/connectors/codex-materialize-runner.js +14 -15
  191. package/dist/connectors/codex-materialize.d.ts +1 -1
  192. package/dist/connectors/index.d.ts +3 -2
  193. package/dist/connectors/index.js +24 -23
  194. package/dist/consolidation-provenance-check.d.ts +2 -2
  195. package/dist/consolidation-provenance-check.js +5 -5
  196. package/dist/consolidation-undo.d.ts +2 -2
  197. package/dist/consolidation-undo.js +3 -3
  198. package/dist/contradiction/index.d.ts +2 -2
  199. package/dist/contradiction/index.js +4 -4
  200. package/dist/conversation-index/backend.d.ts +1 -1
  201. package/dist/conversation-index/backend.js +2 -2
  202. package/dist/conversation-index/chunker.d.ts +1 -1
  203. package/dist/conversation-index/faiss-adapter.d.ts +1 -1
  204. package/dist/conversation-index/indexer.d.ts +1 -1
  205. package/dist/conversation-index/search.d.ts +1 -1
  206. package/dist/corpus-watermark.d.ts +1 -1
  207. package/dist/corpus-watermark.js +26 -26
  208. package/dist/day-summary.d.ts +1 -1
  209. package/dist/delinearize.d.ts +1 -1
  210. package/dist/direct-answer-wiring.d.ts +1 -1
  211. package/dist/direct-answer.d.ts +1 -1
  212. package/dist/embedding-fallback.d.ts +1 -1
  213. package/dist/enrichment/index.d.ts +1 -1
  214. package/dist/entity-retrieval.d.ts +2 -2
  215. package/dist/entity-retrieval.js +14 -14
  216. package/dist/entity-schema.d.ts +1 -1
  217. package/dist/explicit-capture.d.ts +8 -8
  218. package/dist/extraction-error-classification.d.ts +1 -1
  219. package/dist/extraction-faithfulness.d.ts +1 -1
  220. package/dist/extraction-judge-telemetry.d.ts +1 -1
  221. package/dist/extraction-judge-training.d.ts +1 -1
  222. package/dist/extraction-judge.d.ts +1 -1
  223. package/dist/extraction-liveness.d.ts +1 -1
  224. package/dist/extraction-source-grounding-rules.d.ts +1 -1
  225. package/dist/extraction-source-grounding.d.ts +15 -2
  226. package/dist/extraction-source-grounding.js +10 -1
  227. package/dist/extraction.d.ts +2 -15
  228. package/dist/extraction.js +5 -4
  229. package/dist/fallback-llm.d.ts +1 -1
  230. package/dist/graph-dashboard-diff.d.ts +1 -1
  231. package/dist/graph-dashboard-key.d.ts +1 -1
  232. package/dist/graph-dashboard-parser.d.ts +1 -1
  233. package/dist/graph-edge-reinforcement.d.ts +1 -1
  234. package/dist/graph-snapshot.d.ts +1 -1
  235. package/dist/graph.d.ts +1 -1
  236. package/dist/importance.d.ts +1 -1
  237. package/dist/importers/index.d.ts +1 -1
  238. package/dist/in-flight-reads.d.ts +1 -1
  239. package/dist/index.d.ts +19 -19
  240. package/dist/index.js +253 -246
  241. package/dist/intent.d.ts +1 -1
  242. package/dist/lcm/engine.d.ts +1 -1
  243. package/dist/lcm/engine.js +3 -3
  244. package/dist/lcm/index.d.ts +1 -1
  245. package/dist/lcm/index.js +6 -6
  246. package/dist/lcm/tools.d.ts +1 -1
  247. package/dist/lifecycle.d.ts +1 -1
  248. package/dist/live-connectors-runner.d.ts +1 -1
  249. package/dist/local-llm-helpers.d.ts +7 -0
  250. package/dist/local-llm-helpers.js +16 -0
  251. package/dist/local-llm-helpers.js.map +1 -0
  252. package/dist/local-llm.d.ts +3 -6
  253. package/dist/local-llm.js +2 -1
  254. package/dist/local-model-endpoint.d.ts +1 -1
  255. package/dist/maintenance/memory-governance.d.ts +1 -1
  256. package/dist/maintenance/memory-governance.js +14 -14
  257. package/dist/maintenance/rebuild-memory-lifecycle-ledger.d.ts +2 -2
  258. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +14 -14
  259. package/dist/maintenance/rebuild-memory-projection.d.ts +2 -2
  260. package/dist/maintenance/rebuild-memory-projection.js +15 -15
  261. package/dist/{maintenance-CL30NWtc.d.ts → maintenance-C6Pffz30.d.ts} +3 -3
  262. package/dist/mcp-memory-inspector-app.d.ts +10 -10
  263. package/dist/memory-action-policy.d.ts +1 -1
  264. package/dist/memory-cache.d.ts +1 -1
  265. package/dist/memory-corpus-version.js +2 -2
  266. package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
  267. package/dist/memory-projection-store.d.ts +1 -1
  268. package/dist/memory-provenance.d.ts +1 -1
  269. package/dist/memory-worth-outcomes.d.ts +2 -2
  270. package/dist/models-json.d.ts +1 -1
  271. package/dist/namespaces/migrate.d.ts +3 -3
  272. package/dist/namespaces/migrate.js +24 -24
  273. package/dist/namespaces/principal.d.ts +1 -1
  274. package/dist/namespaces/search.d.ts +1 -1
  275. package/dist/namespaces/search.js +9 -9
  276. package/dist/namespaces/storage.d.ts +3 -3
  277. package/dist/namespaces/storage.js +14 -14
  278. package/dist/native-knowledge.d.ts +1 -1
  279. package/dist/offline-sync-impression-drain.d.ts +1 -1
  280. package/dist/offline-sync-impression-drain.js +6 -5
  281. package/dist/operator-doctor-corpus.d.ts +1 -1
  282. package/dist/operator-doctor-corpus.js +29 -29
  283. package/dist/operator-doctor-replica.d.ts +1 -1
  284. package/dist/operator-doctor-replica.js +3 -3
  285. package/dist/operator-toolkit.d.ts +3 -3
  286. package/dist/operator-toolkit.js +39 -38
  287. package/dist/orchestration/compression-guideline-coordinator.d.ts +2 -2
  288. package/dist/orchestration/maintenance.d.ts +4 -4
  289. package/dist/orchestration/maintenance.js +22 -21
  290. package/dist/{orchestrator-CKTCRwWV.d.ts → orchestrator-eQlmasno.d.ts} +72 -34
  291. package/dist/orchestrator.d.ts +8 -8
  292. package/dist/orchestrator.js +169 -162
  293. package/dist/page-versioning.js +3 -3
  294. package/dist/patterns-cli.d.ts +1 -1
  295. package/dist/{pipeline-B7wj4rRZ.d.ts → pipeline-CZGmAMQ2.d.ts} +1 -1
  296. package/dist/policy-runtime.d.ts +1 -1
  297. package/dist/proactive-contention.d.ts +1 -1
  298. package/dist/provenance.d.ts +1 -1
  299. package/dist/{qmd-q9tg4dHp.d.ts → qmd-DBj4MF8T.d.ts} +1 -1
  300. package/dist/qmd-preflight.d.ts +2 -2
  301. package/dist/qmd-recall-cache.d.ts +1 -1
  302. package/dist/qmd.d.ts +2 -2
  303. package/dist/qmd.js +4 -4
  304. package/dist/recall-concurrency-config.d.ts +1 -1
  305. package/dist/recall-disclosure-escalation.d.ts +1 -1
  306. package/dist/recall-explain-renderer.d.ts +1 -1
  307. package/dist/recall-explain-renderer.js +3 -3
  308. package/dist/recall-memory-map.d.ts +1 -1
  309. package/dist/recall-planner-llm.d.ts +1 -1
  310. package/dist/recall-state.d.ts +1 -1
  311. package/dist/recall-tag-filter.d.ts +1 -1
  312. package/dist/recall-timings.d.ts +1 -1
  313. package/dist/recall-xray-cli.d.ts +1 -1
  314. package/dist/recall-xray-cli.js +4 -4
  315. package/dist/recall-xray-renderer.d.ts +1 -1
  316. package/dist/recall-xray-renderer.js +3 -3
  317. package/dist/recall-xray.d.ts +1 -1
  318. package/dist/recall-xray.js +2 -2
  319. package/dist/replay/normalizers/chatgpt.d.ts +1 -1
  320. package/dist/replay/normalizers/claude.d.ts +1 -1
  321. package/dist/replay/normalizers/openclaw.d.ts +1 -1
  322. package/dist/replay/normalizers/shared.d.ts +1 -1
  323. package/dist/replay/runner.d.ts +1 -1
  324. package/dist/replay/types.d.ts +1 -1
  325. package/dist/replica-divergence.d.ts +1 -1
  326. package/dist/replica-divergence.js +2 -2
  327. package/dist/replica-peers-config.d.ts +1 -1
  328. package/dist/resolve-auth-token.d.ts +1 -1
  329. package/dist/resume-bundles.js +2 -2
  330. package/dist/retrieval-agents.d.ts +2 -2
  331. package/dist/retrieval-tiers.d.ts +1 -1
  332. package/dist/routing/engine.d.ts +1 -1
  333. package/dist/routing/store.d.ts +1 -1
  334. package/dist/salvage-envelope.d.ts +1 -1
  335. package/dist/{scope-profiles-CWDyglPM.d.ts → scope-profiles-S85lrsUn.d.ts} +1 -1
  336. package/dist/search/embed-helper.d.ts +1 -1
  337. package/dist/search/factory.d.ts +1 -1
  338. package/dist/search/factory.js +8 -8
  339. package/dist/search/index.d.ts +1 -1
  340. package/dist/search/index.js +12 -12
  341. package/dist/search/lancedb-backend.d.ts +1 -1
  342. package/dist/search/meilisearch-backend.d.ts +1 -1
  343. package/dist/search/noop-backend.d.ts +1 -1
  344. package/dist/search/orama-backend.d.ts +1 -1
  345. package/dist/search/port.d.ts +1 -1
  346. package/dist/search/remote-backend.d.ts +1 -1
  347. package/dist/{semantic-consolidation-BUE3deLn.d.ts → semantic-consolidation-DVzDcV6x.d.ts} +1 -1
  348. package/dist/semantic-consolidation.d.ts +2 -2
  349. package/dist/semantic-consolidation.js +17 -18
  350. package/dist/semantic-rule-promotion.js +14 -14
  351. package/dist/semantic-rule-verifier.d.ts +1 -1
  352. package/dist/semantic-rule-verifier.js +14 -14
  353. package/dist/{service-CXgM0bQG.d.ts → service-C2M-wD4W.d.ts} +2 -2
  354. package/dist/session-observer-bands.d.ts +1 -1
  355. package/dist/session-observer-state.d.ts +1 -1
  356. package/dist/shared-context/manager.d.ts +1 -1
  357. package/dist/signal.d.ts +1 -1
  358. package/dist/{storage-DysJq-XH.d.ts → storage-dyBC3Q84.d.ts} +1 -1
  359. package/dist/storage.d.ts +2 -2
  360. package/dist/storage.js +13 -13
  361. package/dist/summarizer.d.ts +1 -1
  362. package/dist/summarizer.js +3 -2
  363. package/dist/summary-snapshot.d.ts +1 -1
  364. package/dist/temporal-supersession.d.ts +2 -2
  365. package/dist/temporal-timeline-recall.d.ts +1 -1
  366. package/dist/temporal-validity.d.ts +1 -1
  367. package/dist/threading.d.ts +1 -1
  368. package/dist/tier-migration.d.ts +2 -2
  369. package/dist/tier-routing.d.ts +1 -1
  370. package/dist/tokens.js +2 -2
  371. package/dist/topics.d.ts +1 -1
  372. package/dist/transcript.d.ts +1 -1
  373. package/dist/transfer/backup.js +2 -2
  374. package/dist/transfer/capsule-export.js +2 -2
  375. package/dist/transfer/capsule-import.js +5 -5
  376. package/dist/trust-score-stage.d.ts +1 -1
  377. package/dist/trust-score.d.ts +1 -1
  378. package/dist/{types-aPPzhnjT.d.ts → types-D63ZI--P.d.ts} +23 -2
  379. package/dist/types.d.ts +1 -1
  380. package/dist/types.js +1 -1
  381. package/dist/utility-runtime.d.ts +1 -1
  382. package/dist/verified-recall.js +14 -14
  383. package/dist/write-envelope.d.ts +1 -1
  384. package/package.json +2 -2
  385. package/src/access-boundary.ts +3 -0
  386. package/src/access-cli.test.ts +93 -0
  387. package/src/access-cli.ts +56 -2
  388. package/src/access-extraction-force-flush.ts +177 -0
  389. package/src/access-http-extraction-force-flush.test.ts +132 -0
  390. package/src/access-http-lcm-compaction.ts +99 -22
  391. package/src/access-http-lifecycle-flush.ts +81 -0
  392. package/src/access-http.test.ts +227 -0
  393. package/src/access-http.ts +33 -40
  394. package/src/access-mcp-output-schemas.ts +6 -0
  395. package/src/access-mcp.test.ts +40 -0
  396. package/src/access-mcp.ts +32 -1
  397. package/src/access-observe-helpers.ts +180 -0
  398. package/src/access-observe-write-surface.ts +78 -19
  399. package/src/access-operations-batch.ts +2 -1
  400. package/src/access-schema-pi.test.ts +17 -0
  401. package/src/access-schema.ts +28 -11
  402. package/src/access-service-helpers.ts +46 -0
  403. package/src/access-service-observe-lcm-parity.test.ts +781 -31
  404. package/src/access-service-observe-scope.test.ts +88 -0
  405. package/src/access-service.ts +46 -128
  406. package/src/access-surface-catalog.test.ts +32 -0
  407. package/src/access-surface-catalog.ts +2 -0
  408. package/src/buffer-session.test.ts +148 -0
  409. package/src/buffer-turn-helpers.ts +152 -0
  410. package/src/buffer.ts +126 -201
  411. package/src/connectors/index.ts +1 -1
  412. package/src/connectors/label.ts +18 -0
  413. package/src/correction/correction-access-wiring.ts +79 -27
  414. package/src/correction/correction-executor.test.ts +542 -1
  415. package/src/correction/correction-executor.ts +309 -89
  416. package/src/correction/correction-planner.test.ts +35 -1
  417. package/src/correction/correction-planner.ts +50 -3
  418. package/src/correction/correction-service.ts +12 -7
  419. package/src/correction/correction-storage-integration.test.ts +172 -1
  420. package/src/correction/passive-capture.test.ts +35 -0
  421. package/src/correction/passive-capture.ts +17 -3
  422. package/src/extraction-source-grounding.ts +55 -1
  423. package/src/extraction-timeout.test.ts +51 -0
  424. package/src/extraction.ts +64 -90
  425. package/src/local-llm-headers-timeout.test.ts +48 -0
  426. package/src/local-llm-helpers.ts +58 -0
  427. package/src/local-llm.ts +62 -58
  428. package/src/orchestration/extraction-run-helpers.ts +309 -0
  429. package/src/orchestration/extraction-run.test.ts +350 -7
  430. package/src/orchestration/extraction-run.ts +327 -250
  431. package/src/orchestration/recall-result-formatter.ts +21 -2
  432. package/src/orchestration/recall-search-pipeline.test.ts +34 -0
  433. package/src/orchestration/recall-search-pipeline.ts +9 -1
  434. package/src/orchestration/session-context.ts +193 -18
  435. package/src/orchestration/turn-ingestion.ts +61 -11
  436. package/src/orchestrator-flush.test.ts +511 -5
  437. package/src/orchestrator.ts +8 -6
  438. package/src/recall-source-connector-label.test.ts +300 -0
  439. package/src/types.ts +3 -3
  440. package/dist/chunk-3UXOZBHV.js +0 -20
  441. package/dist/chunk-3UXOZBHV.js.map +0 -1
  442. package/dist/chunk-4A6YGWQN.js.map +0 -1
  443. package/dist/chunk-4WKA6I65.js.map +0 -1
  444. package/dist/chunk-4Z4XNEWZ.js.map +0 -1
  445. package/dist/chunk-6FUPCJUL.js.map +0 -1
  446. package/dist/chunk-B6JDYXL7.js.map +0 -1
  447. package/dist/chunk-G5R3D5UP.js.map +0 -1
  448. package/dist/chunk-GBJ4RDFR.js.map +0 -1
  449. package/dist/chunk-HUHX2OCX.js.map +0 -1
  450. package/dist/chunk-IYZ5K7MU.js.map +0 -1
  451. package/dist/chunk-LGHKJABJ.js.map +0 -1
  452. package/dist/chunk-NHWB6HG2.js.map +0 -1
  453. package/dist/chunk-PHWUFPCO.js.map +0 -1
  454. package/dist/chunk-RPW2NOU6.js.map +0 -1
  455. package/dist/chunk-SPJXKAVF.js.map +0 -1
  456. package/dist/chunk-YNQBRLC5.js.map +0 -1
  457. package/dist/chunk-YTSNAUXN.js.map +0 -1
  458. /package/dist/{capsule-crypto-GWVG7LGC.js.map → access-extraction-force-flush.js.map} +0 -0
  459. /package/dist/{capsule-merge-5KKJQBWQ.js.map → capsule-merge-2H2IUTBT.js.map} +0 -0
  460. /package/dist/{chunk-LEPOP46W.js.map → chunk-227UFSEQ.js.map} +0 -0
  461. /package/dist/{chunk-I5NLEENJ.js.map → chunk-27HHNYSQ.js.map} +0 -0
  462. /package/dist/{chunk-2SA56WMI.js.map → chunk-2LTDWSR6.js.map} +0 -0
  463. /package/dist/{chunk-OWHERGF2.js.map → chunk-2NLLXCJG.js.map} +0 -0
  464. /package/dist/{chunk-P5PXWTW7.js.map → chunk-2Q4JJ3FZ.js.map} +0 -0
  465. /package/dist/{chunk-H5CPS5JP.js.map → chunk-35IVNNRK.js.map} +0 -0
  466. /package/dist/{chunk-LBOD4U5B.js.map → chunk-3EQ2XB3W.js.map} +0 -0
  467. /package/dist/{chunk-2EUVEDF5.js.map → chunk-5WZVQRHV.js.map} +0 -0
  468. /package/dist/{chunk-ALSGMEJR.js.map → chunk-65ZPVYTA.js.map} +0 -0
  469. /package/dist/{chunk-GIBMDSJ2.js.map → chunk-6P7MTSU5.js.map} +0 -0
  470. /package/dist/{chunk-5VQJBH2G.js.map → chunk-6TAUHL33.js.map} +0 -0
  471. /package/dist/{chunk-WVO4G37W.js.map → chunk-7TEZUUGM.js.map} +0 -0
  472. /package/dist/{chunk-MJCGLM25.js.map → chunk-7VUAG236.js.map} +0 -0
  473. /package/dist/{chunk-CZRYLSSW.js.map → chunk-AJL6NNX6.js.map} +0 -0
  474. /package/dist/{chunk-66772WBP.js.map → chunk-AQWVJURR.js.map} +0 -0
  475. /package/dist/{chunk-RKNJBZ55.js.map → chunk-AU7Q3LSC.js.map} +0 -0
  476. /package/dist/{chunk-M3C2V3PV.js.map → chunk-CJDNT45S.js.map} +0 -0
  477. /package/dist/{chunk-D2ANTDGO.js.map → chunk-E6BMSH7U.js.map} +0 -0
  478. /package/dist/{chunk-CKMO4RDY.js.map → chunk-EMDLM3LW.js.map} +0 -0
  479. /package/dist/{chunk-RGIWINDN.js.map → chunk-FHBITMRY.js.map} +0 -0
  480. /package/dist/{chunk-FDAMS4PK.js.map → chunk-G2YQ57YO.js.map} +0 -0
  481. /package/dist/{chunk-6U7F52DE.js.map → chunk-HFQQWAMS.js.map} +0 -0
  482. /package/dist/{chunk-5W4ZLBEZ.js.map → chunk-HKPJPOW7.js.map} +0 -0
  483. /package/dist/{chunk-JCBWCYEJ.js.map → chunk-IGWFKW4B.js.map} +0 -0
  484. /package/dist/{chunk-AITCS2RC.js.map → chunk-IJ7HK452.js.map} +0 -0
  485. /package/dist/{chunk-D3LMYTBV.js.map → chunk-J7WZUL2K.js.map} +0 -0
  486. /package/dist/{chunk-5W7CTZ2E.js.map → chunk-KQAFEZQX.js.map} +0 -0
  487. /package/dist/{chunk-Z54EM5YZ.js.map → chunk-MAXVH44E.js.map} +0 -0
  488. /package/dist/{chunk-WZFAPHIK.js.map → chunk-MU7ZHSZE.js.map} +0 -0
  489. /package/dist/{chunk-AZ5BTEKX.js.map → chunk-NQUF7XKR.js.map} +0 -0
  490. /package/dist/{chunk-W4FBGYGK.js.map → chunk-NRV4Y3PM.js.map} +0 -0
  491. /package/dist/{chunk-62U4J2GN.js.map → chunk-ODGOP7P2.js.map} +0 -0
  492. /package/dist/{chunk-QJAQNXWI.js.map → chunk-ONHRRJZM.js.map} +0 -0
  493. /package/dist/{chunk-ACXPX4AG.js.map → chunk-OPBTPRGY.js.map} +0 -0
  494. /package/dist/{chunk-XOZ4ALGB.js.map → chunk-QDTZ2HF7.js.map} +0 -0
  495. /package/dist/{chunk-ZPSVBSOF.js.map → chunk-QMWFQBIL.js.map} +0 -0
  496. /package/dist/{chunk-W5EG6LE3.js.map → chunk-THCPRMRF.js.map} +0 -0
  497. /package/dist/{chunk-VI2JQPNQ.js.map → chunk-U7QYBSQJ.js.map} +0 -0
  498. /package/dist/{chunk-TH2LSRMG.js.map → chunk-UORKJ34C.js.map} +0 -0
  499. /package/dist/{chunk-K5GB36ME.js.map → chunk-VMZ56EE3.js.map} +0 -0
  500. /package/dist/{chunk-RMMVQQA6.js.map → chunk-WDISJRMG.js.map} +0 -0
  501. /package/dist/{chunk-UVYI6VIX.js.map → chunk-X7Y7WX73.js.map} +0 -0
  502. /package/dist/{chunk-CVILPI77.js.map → chunk-XOQSEF7X.js.map} +0 -0
  503. /package/dist/{chunk-YTQNQ4KB.js.map → chunk-YX5LN6JR.js.map} +0 -0
  504. /package/dist/{chunk-IC6CBHCA.js.map → chunk-Z7XKUWYS.js.map} +0 -0
@@ -7,22 +7,22 @@ import {
7
7
  syncWearableSource,
8
8
  wearableSourceLabel
9
9
  } from "./chunk-UV72DEZD.js";
10
- import {
11
- runPeerProfileReasoner
12
- } from "./chunk-I74SUMNI.js";
13
10
  import {
14
11
  CompressionGuidelineCoordinator
15
12
  } from "./chunk-6LKEUCEM.js";
16
13
  import {
17
14
  ActivityStore,
18
15
  MaintenanceScheduler
19
- } from "./chunk-LBOD4U5B.js";
16
+ } from "./chunk-3EQ2XB3W.js";
17
+ import {
18
+ runPeerProfileReasoner
19
+ } from "./chunk-I74SUMNI.js";
20
20
  import {
21
21
  migrateFromEngram
22
22
  } from "./chunk-7HYPN2GC.js";
23
23
  import {
24
24
  LcmEngine
25
- } from "./chunk-Z54EM5YZ.js";
25
+ } from "./chunk-MAXVH44E.js";
26
26
  import {
27
27
  chunkTranscriptEntries
28
28
  } from "./chunk-TECVW3JP.js";
@@ -32,7 +32,7 @@ import {
32
32
  import {
33
33
  CompoundingEngine,
34
34
  defaultTierMigrationCycleBudget
35
- } from "./chunk-VI2JQPNQ.js";
35
+ } from "./chunk-U7QYBSQJ.js";
36
36
  import {
37
37
  SharedContextManager
38
38
  } from "./chunk-AS7YMSL6.js";
@@ -41,9 +41,6 @@ import {
41
41
  applyUtilityRankingRuntimeDelta,
42
42
  loadUtilityRuntimeValues
43
43
  } from "./chunk-LXOM6IQU.js";
44
- import {
45
- CODEX_THREAD_KEY_PREFIX
46
- } from "./chunk-4EX5WZ4M.js";
47
44
  import {
48
45
  TierMigrationExecutor
49
46
  } from "./chunk-VOUOLGIP.js";
@@ -56,16 +53,19 @@ import {
56
53
  import {
57
54
  extractTopics
58
55
  } from "./chunk-UHGBNIOS.js";
59
- import {
60
- buildTargetedFactRecallSection,
61
- shouldRecallTargetedFactEvidence
62
- } from "./chunk-T67LUYCR.js";
63
56
  import {
64
57
  buildTemporalTimelineRecallSection
65
58
  } from "./chunk-I6WYQSX4.js";
59
+ import {
60
+ CODEX_THREAD_KEY_PREFIX
61
+ } from "./chunk-4EX5WZ4M.js";
66
62
  import {
67
63
  HourlySummarizer
68
- } from "./chunk-AZ5BTEKX.js";
64
+ } from "./chunk-NQUF7XKR.js";
65
+ import {
66
+ buildTargetedFactRecallSection,
67
+ shouldRecallTargetedFactEvidence
68
+ } from "./chunk-T67LUYCR.js";
69
69
  import {
70
70
  SessionObserverState
71
71
  } from "./chunk-QFN4U7AG.js";
@@ -108,9 +108,6 @@ import {
108
108
  reorderByRankedKeys,
109
109
  rerankLocalOrNoop
110
110
  } from "./chunk-LUDXM7MD.js";
111
- import {
112
- createRecallSectionMetricRecorder
113
- } from "./chunk-C3AKM55W.js";
114
111
  import {
115
112
  LastRecallStore,
116
113
  RecallHandleHistoryStore,
@@ -128,6 +125,9 @@ import {
128
125
  import {
129
126
  reorderRecallResultsWithMmr
130
127
  } from "./chunk-YDBIWGNI.js";
128
+ import {
129
+ createRecallSectionMetricRecorder
130
+ } from "./chunk-C3AKM55W.js";
131
131
  import {
132
132
  applyReasoningTraceBoost
133
133
  } from "./chunk-ZZTOURJI.js";
@@ -147,35 +147,13 @@ import {
147
147
  import {
148
148
  runLiveConnectorsOnce
149
149
  } from "./chunk-HTIIXNJQ.js";
150
- import {
151
- hasBroadGraphIntent,
152
- inferIntentFromText,
153
- intentCompatibilityScore,
154
- isTaskInitiationIntent,
155
- planRecallMode
156
- } from "./chunk-PD6O7AXF.js";
157
150
  import {
158
151
  classifyMemoryKind
159
152
  } from "./chunk-YAZNBMNF.js";
160
- import {
161
- ExtractionEngine
162
- } from "./chunk-GBJ4RDFR.js";
163
- import {
164
- parseMemoryActionEligibilityContext
165
- } from "./chunk-TGTTESJS.js";
166
- import {
167
- ModelRegistry
168
- } from "./chunk-WLZYGLJ4.js";
169
- import {
170
- LocalLlmClient
171
- } from "./chunk-PHWUFPCO.js";
172
153
  import {
173
154
  buildFocusedListRecallSection,
174
155
  shouldRecallFocusedListEvidence
175
156
  } from "./chunk-OH7QLI6W.js";
176
- import {
177
- recordJudgeTrainingPair
178
- } from "./chunk-PWFCHOB3.js";
179
157
  import {
180
158
  createDeferCountMap,
181
159
  createVerdictCache,
@@ -188,9 +166,17 @@ import {
188
166
  loadRedactionRules
189
167
  } from "./chunk-LTHVM4XN.js";
190
168
  import {
191
- buildEventOrderRecallSection,
192
- shouldRecallEventOrderEvidence
193
- } from "./chunk-DEOYTFA6.js";
169
+ ExtractionEngine
170
+ } from "./chunk-QIHIHZYC.js";
171
+ import {
172
+ parseMemoryActionEligibilityContext
173
+ } from "./chunk-TGTTESJS.js";
174
+ import {
175
+ ModelRegistry
176
+ } from "./chunk-WLZYGLJ4.js";
177
+ import {
178
+ LocalLlmClient
179
+ } from "./chunk-ZCPP5OW6.js";
194
180
  import {
195
181
  pickFactEventTimeAnchor,
196
182
  resolveFactEventTime
@@ -199,8 +185,8 @@ import {
199
185
  buildExplicitCueRecallSection
200
186
  } from "./chunk-TVIVY7KU.js";
201
187
  import {
202
- tryDirectAnswer
203
- } from "./chunk-Q6IP2ARR.js";
188
+ recordJudgeTrainingPair
189
+ } from "./chunk-PWFCHOB3.js";
204
190
  import {
205
191
  EmbeddingFallback
206
192
  } from "./chunk-E6EE5B67.js";
@@ -208,33 +194,40 @@ import {
208
194
  buildEntityRecallSection,
209
195
  entityRecentTranscriptLookbackHours,
210
196
  readRecentEntityTranscriptEntries
211
- } from "./chunk-66772WBP.js";
197
+ } from "./chunk-AQWVJURR.js";
198
+ import {
199
+ buildEventOrderRecallSection,
200
+ shouldRecallEventOrderEvidence
201
+ } from "./chunk-DEOYTFA6.js";
212
202
  import {
213
203
  formatDaySummaryMemories
214
204
  } from "./chunk-RPSYDM6C.js";
205
+ import {
206
+ tryDirectAnswer
207
+ } from "./chunk-Q6IP2ARR.js";
215
208
  import {
216
209
  builtInConnectorPackageSpecifier,
217
210
  ensureBuiltInWearableConnectors,
218
211
  getWearableConnector,
219
212
  listWearableConnectors
220
- } from "./chunk-6U7F52DE.js";
221
- import {
222
- normalizeReplaySessionKey
223
- } from "./chunk-AJVLDJU6.js";
213
+ } from "./chunk-HFQQWAMS.js";
224
214
  import {
225
215
  RoutingRulesStore
226
216
  } from "./chunk-XL24QQ63.js";
217
+ import {
218
+ normalizeReplaySessionKey
219
+ } from "./chunk-AJVLDJU6.js";
227
220
  import {
228
221
  compareVerifiedEpisodeResults,
229
222
  searchVerifiedEpisodes
230
- } from "./chunk-2EUVEDF5.js";
223
+ } from "./chunk-5WZVQRHV.js";
231
224
  import {
232
225
  ThreadingManager
233
226
  } from "./chunk-OJP3N7UK.js";
234
227
  import {
235
228
  compareVerifiedSemanticRuleResults,
236
229
  searchVerifiedSemanticRules
237
- } from "./chunk-TH2LSRMG.js";
230
+ } from "./chunk-UORKJ34C.js";
238
231
  import {
239
232
  searchWorkProductLedgerEntries
240
233
  } from "./chunk-ZRWB5D4H.js";
@@ -247,11 +240,11 @@ import {
247
240
  import {
248
241
  runNamespaceMaintenanceFanout,
249
242
  summarizeNamespaceMaintenanceHealth
250
- } from "./chunk-M3C2V3PV.js";
243
+ } from "./chunk-CJDNT45S.js";
251
244
  import {
252
245
  NamespaceCatalog,
253
246
  planNamespaceMaintenance
254
- } from "./chunk-H5CPS5JP.js";
247
+ } from "./chunk-35IVNNRK.js";
255
248
  import {
256
249
  isAboveImportanceThreshold,
257
250
  scoreImportance
@@ -263,20 +256,20 @@ import {
263
256
  EXTRACTION_JUDGE_VERDICT_CATEGORY,
264
257
  recordJudgeVerdict
265
258
  } from "./chunk-OZKOPQCM.js";
266
- import {
267
- recordEvalShadowRecall
268
- } from "./chunk-3PY7VHV7.js";
269
259
  import {
270
260
  collectNativeKnowledgeChunks,
271
261
  formatNativeKnowledgeSection,
272
262
  searchNativeKnowledge
273
263
  } from "./chunk-2DQ2XREU.js";
264
+ import {
265
+ recordEvalShadowRecall
266
+ } from "./chunk-3PY7VHV7.js";
274
267
  import {
275
268
  applyCommitmentLedgerLifecycle
276
269
  } from "./chunk-LMDRGRJ2.js";
277
270
  import {
278
- buildCompressionGuidelinesMarkdown
279
- } from "./chunk-OD4FM2U7.js";
271
+ SmartBuffer
272
+ } from "./chunk-TL4TO3EA.js";
280
273
  import {
281
274
  buildConsolidationPrompt,
282
275
  buildExtensionsBlockForConsolidation,
@@ -286,16 +279,26 @@ import {
286
279
  materializeAfterSemanticConsolidation,
287
280
  parseConsolidationResponse,
288
281
  parseOperatorAwareConsolidationResponse
289
- } from "./chunk-FDAMS4PK.js";
282
+ } from "./chunk-G2YQ57YO.js";
283
+ import {
284
+ buildBehaviorSignalsForMemory,
285
+ dedupeBehaviorSignalsByMemoryAndHash
286
+ } from "./chunk-KD3QD3A5.js";
287
+ import {
288
+ BootstrapEngine
289
+ } from "./chunk-MYVPLJOO.js";
290
+ import {
291
+ isDisagreementPrompt
292
+ } from "./chunk-H3FZVNRN.js";
293
+ import {
294
+ BoxBuilder
295
+ } from "./chunk-B7RWBZXW.js";
290
296
  import {
291
297
  semanticChunkContent
292
298
  } from "./chunk-P4BC54KI.js";
293
299
  import {
294
300
  chunkContent
295
301
  } from "./chunk-UQ7RN5HK.js";
296
- import {
297
- SmartBuffer
298
- } from "./chunk-4A6YGWQN.js";
299
302
  import {
300
303
  detectMeetings
301
304
  } from "./chunk-IB26HVAJ.js";
@@ -313,22 +316,9 @@ import {
313
316
  import {
314
317
  buildRecallQueryPolicy
315
318
  } from "./chunk-LBJBNWS2.js";
316
- import {
317
- buildBehaviorSignalsForMemory,
318
- dedupeBehaviorSignalsByMemoryAndHash
319
- } from "./chunk-KD3QD3A5.js";
320
- import {
321
- BootstrapEngine
322
- } from "./chunk-MYVPLJOO.js";
323
- import {
324
- isDisagreementPrompt
325
- } from "./chunk-H3FZVNRN.js";
326
- import {
327
- BoxBuilder
328
- } from "./chunk-B7RWBZXW.js";
329
319
  import {
330
320
  MeetingsInputError
331
- } from "./chunk-6FUPCJUL.js";
321
+ } from "./chunk-FMFLGS5Z.js";
332
322
  import {
333
323
  WearablesInputError,
334
324
  describeErrorForOperator
@@ -342,17 +332,21 @@ import {
342
332
  } from "./chunk-CEN6DW6X.js";
343
333
  import {
344
334
  RecallResultFormatter,
335
+ SessionContextCoordinator,
345
336
  capturePassiveCorrections,
346
337
  clusterByKey,
347
- createCorrectionService,
348
338
  detectPassiveCorrections
349
- } from "./chunk-4WKA6I65.js";
339
+ } from "./chunk-J3ZGPYXB.js";
350
340
  import {
351
341
  importCapsule
352
- } from "./chunk-ALSGMEJR.js";
342
+ } from "./chunk-65ZPVYTA.js";
353
343
  import {
354
344
  isCodingGraphInstalled
355
345
  } from "./chunk-VQ7B2Q6M.js";
346
+ import {
347
+ listTrustZoneRecords,
348
+ searchTrustZoneRecords
349
+ } from "./chunk-JGSKJHF7.js";
356
350
  import {
357
351
  applyTrustScoreStage,
358
352
  buildTrustSignalsForRerank,
@@ -361,9 +355,8 @@ import {
361
355
  trustResultKey
362
356
  } from "./chunk-GNVZQ5JN.js";
363
357
  import {
364
- listTrustZoneRecords,
365
- searchTrustZoneRecords
366
- } from "./chunk-JGSKJHF7.js";
358
+ buildXraySnapshot
359
+ } from "./chunk-OPBTPRGY.js";
367
360
  import {
368
361
  boundRecallContextComposition,
369
362
  composeRecallContext,
@@ -371,21 +364,15 @@ import {
371
364
  formatCuriosityFooter,
372
365
  selectCuriosityQuestion
373
366
  } from "./chunk-AHVEHR6K.js";
374
- import {
375
- buildXraySnapshot
376
- } from "./chunk-ACXPX4AG.js";
377
367
  import {
378
368
  objectiveStateStoreOverrideForNamespace,
379
369
  searchObjectiveStateSnapshots
380
370
  } from "./chunk-6HMYUWXR.js";
381
371
  import {
382
- combineNamespaces,
383
372
  getConfiguredNamespaces,
384
- resolveCodingNamespaceOverlay,
385
373
  resolveNamespaceFromStorageDir,
386
- resolveScopePlan,
387
- resolveScopeProfilePlan
388
- } from "./chunk-IYZ5K7MU.js";
374
+ resolveScopePlan
375
+ } from "./chunk-ULARSG5Z.js";
389
376
  import {
390
377
  ProfilingCollector
391
378
  } from "./chunk-NLE6TSLG.js";
@@ -398,29 +385,80 @@ import {
398
385
  import {
399
386
  NamespaceSearchRouter,
400
387
  namespaceCollectionName
401
- } from "./chunk-D2ANTDGO.js";
388
+ } from "./chunk-E6BMSH7U.js";
402
389
  import {
403
390
  createConversationIndexRuntime,
404
391
  createSearchBackend
405
- } from "./chunk-D3LMYTBV.js";
392
+ } from "./chunk-J7WZUL2K.js";
406
393
  import {
407
394
  NoopSearchBackend
408
395
  } from "./chunk-CYEPCZN5.js";
409
396
  import {
410
397
  NamespaceStorageRouter
411
- } from "./chunk-IC6CBHCA.js";
398
+ } from "./chunk-Z7XKUWYS.js";
412
399
  import {
413
400
  writeConversationChunks
414
401
  } from "./chunk-72A4L5JJ.js";
415
- import {
416
- parseQmdExplain
417
- } from "./chunk-QJAQNXWI.js";
418
402
  import {
419
403
  GraphIndex
420
404
  } from "./chunk-L2DPF4DF.js";
405
+ import {
406
+ BulkImportBatchPartialFailureError,
407
+ COMPACTION_SIGNAL_MAX_AGE_MS,
408
+ ExtractionDeadlineError,
409
+ ExtractionRunCoordinator,
410
+ abortRecallError,
411
+ appendMemoryToGraphContext,
412
+ applyQueryAwareCandidateFilter,
413
+ buildMemoryPathById,
414
+ buildQmdIntentHint,
415
+ computeArtifactCandidateFetchLimit,
416
+ computeArtifactRecallLimit,
417
+ computeQmdHybridFetchLimit,
418
+ defaultWorkspaceDir,
419
+ filterHourlySummaryMarkdownForLocalDay,
420
+ formatDateInTimeZone,
421
+ isActivityDigestPath,
422
+ isArtifactMemoryPath,
423
+ isMeetingRecordPath,
424
+ lifecycleRecallScoreAdjustment,
425
+ mapRecallSourceToXrayServedBy,
426
+ mergeArtifactRecallCandidates,
427
+ normalizeIanaTimeZone,
428
+ parseFiniteDate,
429
+ parseGraphRecallRankedResults,
430
+ parseMemoryIntentSnapshot,
431
+ parseQmdRecallResults,
432
+ qmdStartupCollectionCheckWithTimeout,
433
+ raceRecallAbort,
434
+ resolvePersistedMemoryRelativePath,
435
+ resolveRecallModeDecision,
436
+ resolveRecallModeDecisionAsync,
437
+ resolveRecentThreadMemoryPaths,
438
+ sanitizeSessionKeyForFilename,
439
+ shouldFilterLifecycleRecallCandidate,
440
+ splitTurnsBySourceValidAt,
441
+ summarizeGraphShadowComparison,
442
+ targetSourceValidAtSortMs,
443
+ throwIfRecallAborted,
444
+ tokenizeRecallQuery,
445
+ utcDateKeysForLocalDay
446
+ } from "./chunk-YPC7W6GA.js";
447
+ import {
448
+ resolveCodingNamespaceOverlay
449
+ } from "./chunk-BUE5E2HL.js";
450
+ import {
451
+ inferIntentFromText,
452
+ intentCompatibilityScore,
453
+ isTaskInitiationIntent,
454
+ planRecallMode
455
+ } from "./chunk-PD6O7AXF.js";
456
+ import {
457
+ searchCausalTrajectories
458
+ } from "./chunk-NRV4Y3PM.js";
421
459
  import {
422
460
  buildChainFollowupGenerator
423
- } from "./chunk-CZRYLSSW.js";
461
+ } from "./chunk-AJL6NNX6.js";
424
462
  import {
425
463
  QmdResultResolver,
426
464
  StorageManager,
@@ -439,7 +477,7 @@ import {
439
477
  reconstructFusionInputs,
440
478
  selfDeps,
441
479
  serializeFusionDay
442
- } from "./chunk-RGIWINDN.js";
480
+ } from "./chunk-FHBITMRY.js";
443
481
  import {
444
482
  bodyIsEscaped,
445
483
  decodeTranscriptBody,
@@ -470,28 +508,23 @@ import {
470
508
  } from "./chunk-J6A3CX5N.js";
471
509
  import {
472
510
  confidenceTier
473
- } from "./chunk-HUHX2OCX.js";
511
+ } from "./chunk-VVDPPDDF.js";
474
512
  import {
475
513
  namespaceIdentityFromToken,
476
514
  namespaceIdentityToken,
477
515
  normalizeNamespaceIdentity
478
516
  } from "./chunk-EGGE52UU.js";
479
- import {
480
- assertPathInsideRoot
481
- } from "./chunk-GCASGYIO.js";
482
517
  import {
483
518
  inferMemoryStatus,
484
519
  isActiveMemoryStatus
485
520
  } from "./chunk-ILGC6JH6.js";
521
+ import {
522
+ assertPathInsideRoot
523
+ } from "./chunk-GCASGYIO.js";
486
524
  import {
487
525
  lintWorkspaceFiles,
488
526
  rotateMarkdownFileToArchive
489
527
  } from "./chunk-DM2T26WE.js";
490
- import {
491
- applyFaithfulnessVerdict,
492
- createFaithfulnessCounters,
493
- runFaithfulnessGateBatch
494
- } from "./chunk-JYIJNNN3.js";
495
528
  import {
496
529
  ContentHashIndex
497
530
  } from "./chunk-FBUE6PD3.js";
@@ -507,9 +540,14 @@ import {
507
540
  import {
508
541
  normalizeTags
509
542
  } from "./chunk-BT7NVCML.js";
543
+ import {
544
+ applyFaithfulnessVerdict,
545
+ createFaithfulnessCounters,
546
+ runFaithfulnessGateBatch
547
+ } from "./chunk-JYIJNNN3.js";
510
548
  import {
511
549
  bumpMemoryCorpusVersionForDir
512
- } from "./chunk-AITCS2RC.js";
550
+ } from "./chunk-IJ7HK452.js";
513
551
  import {
514
552
  buildQmdRecallCacheKey,
515
553
  getCachedQmdRecall,
@@ -520,9 +558,6 @@ import {
520
558
  fallbackLlmRuntimeContextFromConfig,
521
559
  gatewayTaskChainOptions
522
560
  } from "./chunk-C23BYTJV.js";
523
- import {
524
- searchCausalTrajectories
525
- } from "./chunk-W4FBGYGK.js";
526
561
  import {
527
562
  sanitizeMemoryContent
528
563
  } from "./chunk-5GKPFL3S.js";
@@ -557,14 +592,9 @@ import {
557
592
  assertIsDirectoryNotSymlink,
558
593
  assertRealpathInsideRoot
559
594
  } from "./chunk-GCGJW34D.js";
560
- import {
561
- parseFlexibleIsoTimestamp
562
- } from "./chunk-P7FMDTKL.js";
563
595
  import {
564
596
  canReadNamespace,
565
- canWriteNamespace,
566
597
  defaultNamespaceForPrincipal,
567
- recallNamespacesForPrincipal,
568
598
  resolvePrincipal
569
599
  } from "./chunk-3GD2HFR6.js";
570
600
  import {
@@ -608,7 +638,6 @@ import {
608
638
  ALL_CATEGORY_DIRS,
609
639
  ALL_CATEGORY_KEYS,
610
640
  RECALL_FALLBACK_DIRS,
611
- categoryDirName,
612
641
  getCategoryDir
613
642
  } from "./chunk-VS2IYZRU.js";
614
643
  import {
@@ -616,8 +645,8 @@ import {
616
645
  } from "./chunk-3WCASNQZ.js";
617
646
 
618
647
  // src/orchestrator.ts
619
- import path17 from "path";
620
- import { createHash as createHash8 } from "crypto";
648
+ import path16 from "path";
649
+ import { createHash as createHash6 } from "crypto";
621
650
 
622
651
  // src/orchestration/tier-migration-coordinator.ts
623
652
  import path from "path";
@@ -2108,7 +2137,7 @@ var RecallRerankCoordinator = class _RecallRerankCoordinator {
2108
2137
  namespaces,
2109
2138
  {
2110
2139
  readNamespaceMemories: async (ns) => (await this.getStorage(ns)).readAllMemories(),
2111
- readMemoryFrontmatter: async (path32, preferredNamespace) => {
2140
+ readMemoryFrontmatter: async (path31, preferredNamespace) => {
2112
2141
  if (!fallbackReader) {
2113
2142
  for (const ns of namespaces) {
2114
2143
  try {
@@ -2120,7 +2149,7 @@ var RecallRerankCoordinator = class _RecallRerankCoordinator {
2120
2149
  }
2121
2150
  if (!fallbackReader) return null;
2122
2151
  const memory = await this.readQmdResultMemory(
2123
- path32,
2152
+ path31,
2124
2153
  fallbackReader,
2125
2154
  namespaces,
2126
2155
  preferredNamespace
@@ -2721,1313 +2750,60 @@ var ContradictionLinkingCoordinator = class {
2721
2750
  );
2722
2751
  }
2723
2752
  } catch (err) {
2724
- log.warn(
2725
- `contradiction auto-resolve supersede failed for ${contradiction.supersededId}: ${err}`
2726
- );
2727
- }
2728
- }
2729
- // ---------------------------------------------------------------------------
2730
- // Memory Linking (Phase 3A)
2731
- // ---------------------------------------------------------------------------
2732
- /**
2733
- * Suggest links for a new memory based on similar existing memories.
2734
- */
2735
- async suggestLinksForMemory(content, category, namespaceScope) {
2736
- if (!this.isSearchAvailable()) return [];
2737
- const results = await this.searchAcrossNamespaces({
2738
- query: content,
2739
- namespaces: [namespaceScope],
2740
- maxResults: 5,
2741
- mode: "search"
2742
- });
2743
- if (results.length === 0) return [];
2744
- const candidates = [];
2745
- for (const result of results) {
2746
- const memoryId = this.extractMemoryIdsFromResults([result])[0];
2747
- if (!memoryId) continue;
2748
- const resultNamespace = this.namespaceFromPath(result.path);
2749
- if (resultNamespace !== namespaceScope) continue;
2750
- const resultStorage = await this.storageForNamespace(resultNamespace);
2751
- const memory = await resultStorage.getMemoryById(memoryId);
2752
- if (memory && memory.frontmatter.status !== "superseded" && memory.frontmatter.status !== "forgotten") {
2753
- candidates.push({
2754
- id: memory.frontmatter.id,
2755
- content: memory.content,
2756
- category: memory.frontmatter.category
2757
- });
2758
- }
2759
- }
2760
- if (candidates.length === 0) return [];
2761
- const extraction = this.getExtraction();
2762
- const suggestions = await extraction.suggestLinks(
2763
- { content, category },
2764
- candidates
2765
- );
2766
- if (!suggestions || suggestions.links.length === 0) return [];
2767
- return suggestions.links.map((link) => ({
2768
- targetId: link.targetId,
2769
- linkType: link.linkType,
2770
- strength: link.strength,
2771
- reason: link.reason || void 0
2772
- }));
2773
- }
2774
- };
2775
-
2776
- // src/orchestration/extraction-run.ts
2777
- import { createHash as createHash3 } from "crypto";
2778
-
2779
- // src/orchestration/orchestrator-helpers.ts
2780
- import { createHash as createHash2 } from "crypto";
2781
- import os from "os";
2782
- import path4 from "path";
2783
- var BulkImportBatchPartialFailureError = class extends Error {
2784
- partialResult;
2785
- originalError;
2786
- constructor(message, partialResult, originalError) {
2787
- super(message);
2788
- this.name = "BulkImportBatchPartialFailureError";
2789
- this.partialResult = partialResult;
2790
- this.originalError = originalError;
2791
- }
2792
- };
2793
- function mapRecallSourceToXrayServedBy(source) {
2794
- switch (source) {
2795
- case "recent_scan":
2796
- return "recent-scan";
2797
- case "hot_qmd":
2798
- case "hot_embedding":
2799
- case "cold_fallback":
2800
- case "none":
2801
- return "hybrid";
2802
- }
2803
- const _exhaustive = source;
2804
- void _exhaustive;
2805
- return "hybrid";
2806
- }
2807
- var abortRecallError = abortError;
2808
- function throwIfRecallAborted(signal, message = "recall aborted") {
2809
- throwIfAborted(signal, message);
2810
- }
2811
- async function raceRecallAbort(promise, signal, message = "recall aborted") {
2812
- throwIfRecallAborted(signal, message);
2813
- if (!signal) return promise;
2814
- let onAbort = null;
2815
- const abortPromise = new Promise((_resolve, reject) => {
2816
- onAbort = () => reject(abortRecallError(message));
2817
- signal.addEventListener("abort", onAbort, { once: true });
2818
- });
2819
- try {
2820
- return await Promise.race([promise, abortPromise]);
2821
- } finally {
2822
- if (onAbort) {
2823
- signal.removeEventListener("abort", onAbort);
2824
- }
2825
- }
2826
- }
2827
- var COMPACTION_SIGNAL_MAX_AGE_MS = 60 * 60 * 1e3;
2828
- var DEFAULT_QMD_STARTUP_COLLECTION_CHECK_TIMEOUT_MS = 1e4;
2829
- function normalizeIanaTimeZone(value) {
2830
- if (typeof value !== "string") return void 0;
2831
- const trimmed = value.trim();
2832
- if (!trimmed) return void 0;
2833
- try {
2834
- Intl.DateTimeFormat(void 0, { timeZone: trimmed });
2835
- return trimmed;
2836
- } catch {
2837
- return void 0;
2838
- }
2839
- }
2840
- function formatDateInTimeZone(date, timeZone) {
2841
- const parts = new Intl.DateTimeFormat("en-US", {
2842
- timeZone,
2843
- year: "numeric",
2844
- month: "2-digit",
2845
- day: "2-digit"
2846
- }).formatToParts(date);
2847
- const get = (type) => parts.find((part) => part.type === type)?.value ?? "";
2848
- return `${get("year")}-${get("month")}-${get("day")}`;
2849
- }
2850
- function utcDateKey(date) {
2851
- return date.toISOString().slice(0, 10);
2852
- }
2853
- function utcDateKeysAround(date) {
2854
- const dayMs = 864e5;
2855
- const keys = [
2856
- utcDateKey(new Date(date.getTime() - dayMs)),
2857
- utcDateKey(date),
2858
- utcDateKey(new Date(date.getTime() + dayMs))
2859
- ];
2860
- return keys.filter((value, index, array) => array.indexOf(value) === index);
2861
- }
2862
- function utcDateKeysForLocalDay(date, timeZone) {
2863
- const targetLocalDate = formatDateInTimeZone(date, timeZone);
2864
- const keys = /* @__PURE__ */ new Set();
2865
- const hourMs = 36e5;
2866
- const scanStart = date.getTime() - 48 * hourMs;
2867
- const scanEnd = date.getTime() + 48 * hourMs;
2868
- for (let ms = scanStart; ms <= scanEnd; ms += hourMs) {
2869
- const candidate = new Date(ms);
2870
- if (formatDateInTimeZone(candidate, timeZone) === targetLocalDate) {
2871
- keys.add(utcDateKey(candidate));
2872
- }
2873
- }
2874
- return keys.size > 0 ? [...keys].sort() : utcDateKeysAround(date);
2875
- }
2876
- function parseFiniteDate(value) {
2877
- if (typeof value !== "string" || value.trim().length === 0) return null;
2878
- const parsed = new Date(value);
2879
- return Number.isFinite(parsed.getTime()) ? parsed : null;
2880
- }
2881
- function filterHourlySummaryMarkdownForLocalDay(raw, utcDate, timeZone, targetLocalDate) {
2882
- const hourHeaderPattern = /^## ([01]\d|2[0-3]):00[ \t]*$/gm;
2883
- const matches = Array.from(raw.matchAll(hourHeaderPattern));
2884
- if (matches.length === 0) return null;
2885
- const firstSectionStart = matches[0]?.index ?? 0;
2886
- const preamble = raw.slice(0, firstSectionStart).trim();
2887
- const sections = [];
2888
- for (let index = 0; index < matches.length; index += 1) {
2889
- const match = matches[index];
2890
- const hour = match[1];
2891
- if (!hour) continue;
2892
- const sectionTimestamp = parseFiniteDate(`${utcDate}T${hour}:00:00.000Z`);
2893
- if (!sectionTimestamp || formatDateInTimeZone(sectionTimestamp, timeZone) !== targetLocalDate) {
2894
- continue;
2895
- }
2896
- const sectionStart = match.index ?? 0;
2897
- const sectionEnd = matches[index + 1]?.index ?? raw.length;
2898
- const section = raw.slice(sectionStart, sectionEnd).trim();
2899
- if (section.length > 0) sections.push(section);
2900
- }
2901
- if (sections.length === 0) return null;
2902
- return [preamble, ...sections].filter((section) => section.length > 0).join("\n\n");
2903
- }
2904
- function qmdStartupCollectionCheckTimeoutMs() {
2905
- const raw = process.env.REMNIC_QMD_STARTUP_COLLECTION_CHECK_TIMEOUT_MS ?? process.env.ENGRAM_QMD_STARTUP_COLLECTION_CHECK_TIMEOUT_MS;
2906
- if (raw === void 0) return DEFAULT_QMD_STARTUP_COLLECTION_CHECK_TIMEOUT_MS;
2907
- const parsed = Number(raw);
2908
- return Number.isFinite(parsed) && parsed >= 1e3 ? Math.floor(parsed) : DEFAULT_QMD_STARTUP_COLLECTION_CHECK_TIMEOUT_MS;
2909
- }
2910
- async function qmdStartupCollectionCheckWithTimeout(promise, controller, label) {
2911
- const timeoutMs = qmdStartupCollectionCheckTimeoutMs();
2912
- let timer;
2913
- let settled = false;
2914
- const timeoutPromise = new Promise((resolve) => {
2915
- timer = setTimeout(() => {
2916
- if (settled) return;
2917
- controller.abort();
2918
- log.warn(
2919
- `QMD startup collection check for ${label} timed out after ${timeoutMs}ms; keeping search enabled fail-open`
2920
- );
2921
- resolve("unknown");
2922
- }, timeoutMs);
2923
- timer.unref?.();
2924
- });
2925
- const checkedPromise = promise.catch((err) => {
2926
- log.warn(
2927
- `QMD startup collection check for ${label} failed; keeping search enabled fail-open: ${err}`
2928
- );
2929
- return "unknown";
2930
- }).finally(() => {
2931
- settled = true;
2932
- if (timer) clearTimeout(timer);
2933
- });
2934
- return await Promise.race([checkedPromise, timeoutPromise]);
2935
- }
2936
- function defaultWorkspaceDir() {
2937
- return path4.join(os.homedir(), ".openclaw", "workspace");
2938
- }
2939
- function sanitizeSessionKeyForFilename(sessionKey) {
2940
- const readable = sessionKey.replace(/[^a-zA-Z0-9._-]/g, "_");
2941
- const hash = createHash2("sha256").update(sessionKey).digest("hex").slice(0, 12);
2942
- return `${readable}-${hash}`;
2943
- }
2944
- function sourceValidAtMs(turn) {
2945
- if (typeof turn.sourceValidAt !== "string") return null;
2946
- return parseFlexibleIsoTimestamp(turn.sourceValidAt.trim());
2947
- }
2948
- var SOURCE_VALID_AT_CONTEXT_TURNS = 2;
2949
- function sourceValidAtSliceKey(turn, index) {
2950
- const validAtMs = sourceValidAtMs(turn);
2951
- return validAtMs === null ? `unknown:${index}` : String(validAtMs);
2952
- }
2953
- function asExtractionContextTurn(turn) {
2954
- return { ...turn, extractionContextOnly: true };
2955
- }
2956
- function asExtractionTargetTurn(turn) {
2957
- const { extractionContextOnly: _contextOnly, ...targetTurn } = turn;
2958
- return targetTurn;
2959
- }
2960
- function sourceValidAtContextTurns(turns, targetStart, targetEnd, targetValidAtMs) {
2961
- if (targetValidAtMs === null) return [];
2962
- return turns.flatMap((turn, index) => {
2963
- if (index >= targetStart && index < targetEnd) return [];
2964
- const contextValidAtMs = sourceValidAtMs(turn);
2965
- if (contextValidAtMs === null || contextValidAtMs > targetValidAtMs) {
2966
- return [];
2967
- }
2968
- return [{ turn, index, validAtMs: contextValidAtMs }];
2969
- }).sort((a, b) => {
2970
- if (a.validAtMs < b.validAtMs) return -1;
2971
- if (a.validAtMs > b.validAtMs) return 1;
2972
- if (a.index === b.index) return 0;
2973
- return a.index < b.index ? -1 : 1;
2974
- }).slice(-SOURCE_VALID_AT_CONTEXT_TURNS).map(({ turn }) => asExtractionContextTurn(turn));
2975
- }
2976
- function targetSourceValidAtSortMs(turns) {
2977
- let latestMs = null;
2978
- for (const turn of turns) {
2979
- if (turn.extractionContextOnly === true) continue;
2980
- const validAtMs = sourceValidAtMs(turn);
2981
- if (validAtMs === null) continue;
2982
- if (latestMs === null || validAtMs > latestMs) {
2983
- latestMs = validAtMs;
2984
- }
2985
- }
2986
- return latestMs ?? Number.POSITIVE_INFINITY;
2987
- }
2988
- function sortSourceValidAtSlicesChronologically(slices) {
2989
- return slices.map((turns, order) => ({
2990
- turns,
2991
- order,
2992
- targetValidAtMs: targetSourceValidAtSortMs(turns)
2993
- })).sort((a, b) => {
2994
- if (a.targetValidAtMs < b.targetValidAtMs) return -1;
2995
- if (a.targetValidAtMs > b.targetValidAtMs) return 1;
2996
- if (a.order === b.order) return 0;
2997
- return a.order < b.order ? -1 : 1;
2998
- }).map((slice) => slice.turns);
2999
- }
3000
- function splitTurnsBySourceValidAt(turns, options = {}) {
3001
- if (turns.length === 0) return [];
3002
- if (!turns.some((turn) => sourceValidAtMs(turn) !== null)) {
3003
- return [[...turns]];
3004
- }
3005
- const slices = [];
3006
- let start = 0;
3007
- while (start < turns.length) {
3008
- const targetValidAtMs = sourceValidAtMs(turns[start]);
3009
- const activeKey = sourceValidAtSliceKey(turns[start], start);
3010
- let end = start + 1;
3011
- while (end < turns.length && sourceValidAtSliceKey(turns[end], end) === activeKey) {
3012
- end += 1;
3013
- }
3014
- const contextTurns = options.includeContext === false ? [] : sourceValidAtContextTurns(turns, start, end, targetValidAtMs);
3015
- slices.push([
3016
- ...contextTurns,
3017
- ...turns.slice(start, end).map(asExtractionTargetTurn)
3018
- ]);
3019
- start = end;
3020
- }
3021
- return sortSourceValidAtSlicesChronologically(slices);
3022
- }
3023
- function isArtifactMemoryPath(filePath) {
3024
- return /(?:^|[\\/])artifacts(?:[\\/]|$)/i.test(filePath);
3025
- }
3026
- function isMeetingRecordPath(filePath) {
3027
- return /(?:^|[\\/])meetings[\\/]\d{4}-\d{2}-\d{2}[\\/]mtg-\d{4}-\d{2}-\d{2}-[0-9a-f]{8}\.md$/i.test(filePath);
3028
- }
3029
- var ACTIVITY_DIGEST_TOPLEVEL = /^activity[\\/]\d{4}-\d{2}-\d{2}\.md$/i;
3030
- var ACTIVITY_DIGEST_ANYWHERE = /(?:^|[\\/])activity[\\/]\d{4}-\d{2}-\d{2}\.md$/i;
3031
- function isActivityDigestPath(filePath, memoryRoot) {
3032
- if (memoryRoot !== void 0 && memoryRoot.length > 0) {
3033
- const relative = path4.relative(memoryRoot, path4.resolve(memoryRoot, filePath));
3034
- return ACTIVITY_DIGEST_TOPLEVEL.test(relative);
3035
- }
3036
- return ACTIVITY_DIGEST_ANYWHERE.test(filePath);
3037
- }
3038
- function buildCompressionGuidelinesMarkdown2(events, generatedAtIso = (/* @__PURE__ */ new Date()).toISOString()) {
3039
- return buildCompressionGuidelinesMarkdown(events, generatedAtIso);
3040
- }
3041
- function applyQueryAwareCandidateFilter(candidates, candidatePaths) {
3042
- if (!candidatePaths) return candidates;
3043
- if (candidatePaths.size === 0) return [];
3044
- const filtered = candidates.filter(
3045
- (candidate) => candidatePaths.has(candidate.path)
3046
- );
3047
- return filtered.length > 0 ? filtered : candidates;
3048
- }
3049
- function tokenizeRecallQuery(prompt) {
3050
- return prompt.toLowerCase().split(/[^a-z0-9]+/i).map((t) => t.trim()).filter((t) => t.length >= 3);
3051
- }
3052
- function hasLifecycleMetadata(frontmatter) {
3053
- return frontmatter.lifecycleState !== void 0 || frontmatter.verificationState !== void 0 || frontmatter.policyClass !== void 0 || frontmatter.lastValidatedAt !== void 0 || frontmatter.decayScore !== void 0 || frontmatter.heatScore !== void 0;
3054
- }
3055
- function shouldFilterLifecycleRecallCandidate(frontmatter, options) {
3056
- if (!options.lifecyclePolicyEnabled || !options.lifecycleFilterStaleEnabled)
3057
- return false;
3058
- if (!hasLifecycleMetadata(frontmatter)) return false;
3059
- const lifecycleState = resolveLifecycleState(frontmatter);
3060
- return lifecycleState === "stale" || lifecycleState === "archived";
3061
- }
3062
- function lifecycleRecallScoreAdjustment(frontmatter, options) {
3063
- if (!options.lifecyclePolicyEnabled) return 0;
3064
- if (!hasLifecycleMetadata(frontmatter)) return 0;
3065
- let delta = 0;
3066
- const lifecycleState = resolveLifecycleState(frontmatter);
3067
- switch (lifecycleState) {
3068
- case "active":
3069
- delta += 0.05;
3070
- break;
3071
- case "validated":
3072
- delta += 0.03;
3073
- break;
3074
- case "candidate":
3075
- delta -= 0.01;
3076
- break;
3077
- case "stale":
3078
- delta -= 0.06;
3079
- break;
3080
- case "archived":
3081
- delta -= 0.08;
3082
- break;
3083
- }
3084
- if (frontmatter.verificationState === "disputed") {
3085
- delta -= 0.12;
3086
- }
3087
- return delta;
3088
- }
3089
- function computeArtifactRecallLimit(recallMode, recallResultLimit, verbatimArtifactsMaxRecall) {
3090
- if (recallMode === "no_recall") return 0;
3091
- if (Math.max(0, recallResultLimit) === 0) return 0;
3092
- const base = Math.max(0, verbatimArtifactsMaxRecall);
3093
- if (recallMode === "minimal") {
3094
- return Math.min(base, Math.max(0, recallResultLimit));
3095
- }
3096
- return base;
3097
- }
3098
- function resolveEffectiveRecallMode(options) {
3099
- return resolveRecallModeDecision(options).effectiveMode;
3100
- }
3101
- function finalizeRecallModeDecision(plannedModeRaw, options) {
3102
- let plannedMode = plannedModeRaw;
3103
- const graphExpandedIntentDetected = options.plannerEnabled && options.graphExpandedIntentEnabled === true && hasBroadGraphIntent(options.prompt);
3104
- if (plannedMode !== "graph_mode" && graphExpandedIntentDetected) {
3105
- plannedMode = "graph_mode";
3106
- }
3107
- if (plannedMode === "graph_mode" && (!options.graphRecallEnabled || !options.multiGraphMemoryEnabled)) {
3108
- return {
3109
- plannedMode,
3110
- effectiveMode: "full",
3111
- graphExpandedIntentDetected,
3112
- graphReason: !options.graphRecallEnabled ? "graph recall disabled by config" : "multi-graph memory disabled by config"
3113
- };
3114
- }
3115
- return {
3116
- plannedMode,
3117
- effectiveMode: plannedMode,
3118
- graphExpandedIntentDetected
3119
- };
3120
- }
3121
- function resolveRecallModeDecision(options) {
3122
- const plannedMode = options.plannerEnabled ? planRecallMode(options.prompt) : "full";
3123
- return finalizeRecallModeDecision(plannedMode, options);
3124
- }
3125
- async function resolveRecallModeDecisionAsync(options) {
3126
- const heuristicDecision = resolveRecallModeDecision(options);
3127
- const plannerLlmEnabled = options.caps.recallPlannerLlm;
3128
- if (!options.plannerEnabled || !plannerLlmEnabled) {
3129
- return heuristicDecision;
3130
- }
3131
- const { planRecallModeLLM } = await import("./recall-planner-llm.js");
3132
- const planned = await planRecallModeLLM(
3133
- options.prompt,
3134
- options.hints,
3135
- options.config,
3136
- options.caps,
3137
- options.llm,
3138
- options.signal
3139
- );
3140
- if (options.config.recallPlannerShadowMode) {
3141
- return {
3142
- ...heuristicDecision,
3143
- plannerSource: planned.source,
3144
- plannerReason: `shadow:${planned.reason}`,
3145
- plannerLatencyMs: planned.latencyMs,
3146
- plannerFallbackUsed: planned.fallbackUsed,
3147
- plannerModelUsed: planned.modelUsed,
3148
- plannerHeuristicMode: planned.heuristicMode,
3149
- shadowLlmMode: planned.mode
3150
- };
3151
- }
3152
- const llmDecision = finalizeRecallModeDecision(planned.mode, options);
3153
- return {
3154
- ...llmDecision,
3155
- plannerSource: planned.source,
3156
- plannerReason: planned.reason,
3157
- plannerLatencyMs: planned.latencyMs,
3158
- plannerFallbackUsed: planned.fallbackUsed,
3159
- plannerModelUsed: planned.modelUsed,
3160
- plannerHeuristicMode: planned.heuristicMode
3161
- };
3162
- }
3163
- function computeArtifactCandidateFetchLimit(targetCount) {
3164
- const cappedTarget = Math.max(0, targetCount);
3165
- if (cappedTarget === 0) return 0;
3166
- const headroom = Math.max(8, cappedTarget * 4);
3167
- return Math.min(200, cappedTarget + headroom);
3168
- }
3169
- function computeQmdHybridFetchLimit(recallFetchLimit, artifactsEnabled, maxArtifactRecall) {
3170
- const cappedRecallLimit = Math.max(0, recallFetchLimit);
3171
- if (cappedRecallLimit === 0) return 0;
3172
- if (!artifactsEnabled) return cappedRecallLimit;
3173
- const artifactHeadroom = Math.max(20, Math.max(0, maxArtifactRecall) * 8);
3174
- return Math.min(400, cappedRecallLimit + artifactHeadroom);
3175
- }
3176
- function summarizeGraphShadowComparison(baseline, merged, topN) {
3177
- const limit = Math.max(0, Math.floor(topN));
3178
- const baselineTop = limit > 0 ? baseline.slice(0, limit) : [];
3179
- const graphTop = limit > 0 ? merged.slice(0, limit) : [];
3180
- const baselineByPath = new Map(
3181
- baselineTop.map((item) => [item.path, item.score])
3182
- );
3183
- const graphByPath = new Map(graphTop.map((item) => [item.path, item.score]));
3184
- let overlapCount = 0;
3185
- let overlapDeltaSum = 0;
3186
- for (const [p, baselineScore] of baselineByPath.entries()) {
3187
- const graphScore = graphByPath.get(p);
3188
- if (typeof graphScore !== "number") continue;
3189
- overlapCount += 1;
3190
- overlapDeltaSum += graphScore - baselineScore;
3191
- }
3192
- const baselineCount = baselineTop.length;
3193
- return {
3194
- baselineCount,
3195
- graphCount: graphTop.length,
3196
- overlapCount,
3197
- overlapRatio: baselineCount > 0 ? overlapCount / baselineCount : 0,
3198
- averageOverlapDelta: overlapCount > 0 ? overlapDeltaSum / overlapCount : 0
3199
- };
3200
- }
3201
- function parseGraphRecallRankedResults(value) {
3202
- if (!Array.isArray(value)) return [];
3203
- const parsed = [];
3204
- for (const entry of value) {
3205
- if (!entry || typeof entry !== "object") continue;
3206
- const candidate = entry;
3207
- if (typeof candidate.path !== "string" || typeof candidate.score !== "number")
3208
- continue;
3209
- parsed.push({
3210
- path: candidate.path,
3211
- score: candidate.score,
3212
- docid: typeof candidate.docid === "string" ? candidate.docid : void 0,
3213
- sourceLabels: Array.isArray(candidate.sourceLabels) ? candidate.sourceLabels.filter(
3214
- (item) => typeof item === "string"
3215
- ) : []
3216
- });
3217
- }
3218
- return parsed.slice(0, 64);
3219
- }
3220
- function parseMemoryIntentSnapshot(value) {
3221
- const candidate = value && typeof value === "object" ? value : {};
3222
- return {
3223
- goal: typeof candidate.goal === "string" ? candidate.goal : "unknown",
3224
- actionType: typeof candidate.actionType === "string" ? candidate.actionType : "unknown",
3225
- entityTypes: Array.isArray(candidate.entityTypes) ? candidate.entityTypes.filter(
3226
- (item) => typeof item === "string"
3227
- ) : [],
3228
- taskInitiation: candidate.taskInitiation === true
3229
- };
3230
- }
3231
- function buildQmdIntentHint(intent) {
3232
- const parts = [];
3233
- if (intent.goal !== "unknown") {
3234
- parts.push(`goal:${intent.goal.replace(/_/g, " ")}`);
3235
- }
3236
- if (intent.actionType !== "unknown") {
3237
- parts.push(`action:${intent.actionType.replace(/_/g, " ")}`);
3238
- }
3239
- if (intent.entityTypes.length > 0) {
3240
- parts.push(`entities:${intent.entityTypes.join(",")}`);
3241
- }
3242
- if (intent.taskInitiation === true) {
3243
- parts.push("task_initiation");
3244
- }
3245
- return parts.length > 0 ? parts.join(" ") : void 0;
3246
- }
3247
- function parseQmdRecallResults(value) {
3248
- if (!Array.isArray(value)) return [];
3249
- const parsed = [];
3250
- for (const entry of value) {
3251
- if (!entry || typeof entry !== "object") continue;
3252
- const candidate = entry;
3253
- if (typeof candidate.path !== "string" || typeof candidate.score !== "number")
3254
- continue;
3255
- parsed.push({
3256
- docid: typeof candidate.docid === "string" ? candidate.docid : "",
3257
- path: candidate.path,
3258
- snippet: typeof candidate.snippet === "string" ? candidate.snippet : "",
3259
- score: candidate.score,
3260
- explain: parseQmdExplain(candidate.explain),
3261
- transport: candidate.transport === "daemon" || candidate.transport === "subprocess" || candidate.transport === "hybrid" || candidate.transport === "scoped_prefilter" ? candidate.transport : void 0
3262
- });
3263
- }
3264
- return parsed.slice(0, 32);
3265
- }
3266
- function mergeArtifactRecallCandidates(candidatesByNamespace, limit) {
3267
- const cappedLimit = Math.max(0, limit);
3268
- if (cappedLimit === 0) return [];
3269
- const out = [];
3270
- const seen = /* @__PURE__ */ new Set();
3271
- let offset = 0;
3272
- while (out.length < cappedLimit) {
3273
- let hasAnyCandidateAtOffset = false;
3274
- for (const list of candidatesByNamespace) {
3275
- if (offset >= list.length) continue;
3276
- hasAnyCandidateAtOffset = true;
3277
- const item = list[offset];
3278
- const dedupeKey = `${item.frontmatter.id}:${item.frontmatter.sourceMemoryId ?? ""}:${item.content}`;
3279
- if (seen.has(dedupeKey)) continue;
3280
- seen.add(dedupeKey);
3281
- out.push(item);
3282
- if (out.length >= cappedLimit) break;
3283
- }
3284
- if (!hasAnyCandidateAtOffset) break;
3285
- offset += 1;
3286
- }
3287
- return out;
3288
- }
3289
- function resolveRecentThreadMemoryPaths(options) {
3290
- const maxRecent = Math.max(0, options.maxRecent);
3291
- if (options.threadEpisodeIds.length === 0 || maxRecent === 0) return [];
3292
- const pathById = options.pathById ?? buildMemoryPathById(options.allMemsForGraph, options.storageDir);
3293
- if (pathById.size === 0) return [];
3294
- const pendingReviewIds = new Set(
3295
- (options.allMemsForGraph ?? []).filter((m) => m.frontmatter.status === "pending_review" && m.frontmatter.id).map((m) => m.frontmatter.id)
3296
- );
3297
- return options.threadEpisodeIds.filter((id) => id !== options.currentMemoryId).filter((id) => !pendingReviewIds.has(id)).slice(-maxRecent).map((id) => pathById.get(id)).filter((p) => typeof p === "string" && p.length > 0);
3298
- }
3299
- function buildMemoryPathById(allMemsForGraph, storageDir) {
3300
- const pathById = /* @__PURE__ */ new Map();
3301
- for (const mem of allMemsForGraph ?? []) {
3302
- const id = mem.frontmatter.id;
3303
- if (!id) continue;
3304
- pathById.set(id, path4.relative(storageDir, mem.path));
3305
- }
3306
- return pathById;
3307
- }
3308
- function appendMemoryToGraphContext(options) {
3309
- if (!Array.isArray(options.allMemsForGraph)) return;
3310
- const nowIso = (/* @__PURE__ */ new Date()).toISOString();
3311
- options.allMemsForGraph.push({
3312
- path: path4.join(options.storageDir, options.memoryRelPath),
3313
- content: options.content,
3314
- frontmatter: {
3315
- id: options.memoryId,
3316
- category: options.category,
3317
- created: nowIso,
3318
- updated: nowIso,
3319
- source: "extraction",
3320
- confidence: 0.8,
3321
- confidenceTier: "implied",
3322
- tags: [],
3323
- entityRef: options.entityRef,
3324
- status: "active"
3325
- }
3326
- });
3327
- }
3328
- function resolvePersistedMemoryRelativePath(options) {
3329
- const persisted = options.pathById.get(options.memoryId);
3330
- if (persisted) return persisted;
3331
- if (options.category === "correction") {
3332
- return path4.join("corrections", `${options.memoryId}.md`);
3333
- }
3334
- const subtree = categoryDirName(options.category);
3335
- const idParts = options.memoryId.split("-");
3336
- const maybeTimestamp = Number(idParts[1]);
3337
- if (Number.isFinite(maybeTimestamp) && maybeTimestamp > 0) {
3338
- const day = new Date(maybeTimestamp).toISOString().slice(0, 10);
3339
- return path4.join(subtree, day, `${options.memoryId}.md`);
3340
- }
3341
- return path4.join(subtree, `${options.memoryId}.md`);
3342
- }
3343
-
3344
- // src/orchestration/extraction-run.ts
3345
- function deriveTopicsFromExtraction(result) {
3346
- const topics = /* @__PURE__ */ new Set();
3347
- for (const fact of result.facts ?? []) {
3348
- for (const tag of fact.tags ?? []) {
3349
- if (tag && tag.length >= 2) topics.add(tag.toLowerCase());
3350
- }
3351
- if (fact.entityRef) topics.add(fact.entityRef.toLowerCase());
3352
- if (fact.category) topics.add(fact.category);
3353
- }
3354
- for (const entity of result.entities ?? []) {
3355
- if (typeof entity.name === "string" && entity.name.length >= 2) {
3356
- topics.add(entity.name.toLowerCase());
3357
- }
3358
- }
3359
- return [...topics].slice(0, 16);
3360
- }
3361
- var EXTRACTION_RETRY_STATE_MAX_ENTRIES = 500;
3362
- function computeExtractionRetryNextEligibleMs(attempts, scheduleMs, maxBackoffMs, jitterRatio, now, rng = Math.random) {
3363
- const cap = Number.isFinite(maxBackoffMs) && maxBackoffMs > 0 ? maxBackoffMs : 0;
3364
- if (!Array.isArray(scheduleMs) || scheduleMs.length === 0) {
3365
- return now + cap;
3366
- }
3367
- const idx = Math.min(Math.max(attempts - 1, 0), scheduleMs.length - 1);
3368
- const step = scheduleMs[idx];
3369
- const base = Math.min(typeof step === "number" && step > 0 ? step : cap, cap);
3370
- const jitter = 1 + (rng() * 2 - 1) * jitterRatio;
3371
- return now + Math.max(0, Math.round(base * jitter));
3372
- }
3373
- function capExtractionRetryStateEntries(entries, maxEntries) {
3374
- if (maxEntries <= 0) return [];
3375
- const sorted = [...entries].sort((a, b) => a.firstFailedAt.localeCompare(b.firstFailedAt));
3376
- return sorted.slice(-maxEntries);
3377
- }
3378
- var ExtractionRunCoordinator = class {
3379
- constructor(deps) {
3380
- this.deps = deps;
3381
- }
3382
- deps;
3383
- recentExtractionFingerprints = /* @__PURE__ */ new Map();
3384
- // Per-fingerprint extraction retry/backoff state (extraction hot-loop
3385
- // hardening). Outer key = namespace, inner key = fingerprint. Hydrated lazily
3386
- // from namespace-scoped meta so the hot path is a Map lookup; persisted back
3387
- // to meta on change (restart-safe, cross-process coherent via the shared
3388
- // meta.json). The breaker below is intentionally per-process in-memory
3389
- // (mirrors local-llm.cooldownUntilMs); a restart clears it but the persisted
3390
- // backoff still throttles, so a restart can't resurrect the hot loop.
3391
- extractionRetryState = /* @__PURE__ */ new Map();
3392
- hydratedRetryNamespaces = /* @__PURE__ */ new Set();
3393
- providerBreaker = { consecutiveFailures: 0, openUntilMs: 0, state: "closed", lastReason: "" };
3394
- get config() {
3395
- return this.deps.config;
3396
- }
3397
- // -------------------------------------------------------------------------
3398
- // Source-valid-at helpers (moved from orchestrator.ts module scope)
3399
- // -------------------------------------------------------------------------
3400
- latestSourceValidAtFromTurns(turns) {
3401
- let latestMs = null;
3402
- for (const turn of turns) {
3403
- if (turn.extractionContextOnly === true) continue;
3404
- if (typeof turn.sourceValidAt !== "string") continue;
3405
- const parsed = parseFlexibleIsoTimestamp(turn.sourceValidAt.trim());
3406
- if (parsed === null) continue;
3407
- if (latestMs === null || parsed > latestMs) {
3408
- latestMs = parsed;
3409
- }
3410
- }
3411
- return latestMs === null ? void 0 : new Date(latestMs).toISOString();
3412
- }
3413
- // -------------------------------------------------------------------------
3414
- // Extraction dedupe fingerprint helpers
3415
- // -------------------------------------------------------------------------
3416
- normalizeExtractionFingerprintTurns(turns) {
3417
- if (!Array.isArray(turns) || turns.length === 0) return [];
3418
- return turns.filter((turn) => turn.role === "user" || turn.role === "assistant").map((turn) => {
3419
- if (typeof turn.turnFingerprint === "string" && turn.turnFingerprint.length > 0) {
3420
- return `fp:${turn.turnFingerprint}`;
3421
- }
3422
- return `${turn.role}:${(turn.content ?? "").replace(/\s+/g, " ").trim().slice(0, this.config.extractionMaxTurnChars)}`;
3423
- }).filter((value) => value.length > 0);
3424
- }
3425
- buildExtractionFingerprint(turns, bufferKey) {
3426
- const normalized = this.normalizeExtractionFingerprintTurns(turns).join("\n");
3427
- if (!normalized) return null;
3428
- return createHash3("sha256").update(`${bufferKey}
3429
- ${normalized}`).digest("hex");
3430
- }
3431
- shouldQueueExtraction(turns, options = {}) {
3432
- const lifecycleCaps = resolveMemoryLifecycleCapabilities(this.config);
3433
- if (!lifecycleCaps.extractionDedupe) return true;
3434
- if (!Array.isArray(turns) || turns.length === 0) return false;
3435
- const bufferKey = options.bufferKey ?? turns[0]?.sessionKey ?? "default";
3436
- const fingerprint = this.buildExtractionFingerprint(turns, bufferKey);
3437
- if (!fingerprint) return false;
3438
- const now = Date.now();
3439
- const seenAt = this.recentExtractionFingerprints.get(fingerprint);
3440
- if (seenAt && now - seenAt < this.config.extractionDedupeWindowMs) {
3441
- log.debug("extraction dedupe: skipped duplicate buffered turn set");
3442
- return false;
3443
- }
3444
- if (options.commit !== false) {
3445
- this.recentExtractionFingerprints.set(fingerprint, now);
3446
- }
3447
- if (options.commit !== false && this.recentExtractionFingerprints.size > 200) {
3448
- const entries = Array.from(this.recentExtractionFingerprints.entries()).sort((a, b) => a[1] - b[1]);
3449
- for (const [key] of entries.slice(0, entries.length - 200)) {
3450
- this.recentExtractionFingerprints.delete(key);
3451
- }
3452
- }
3453
- return true;
3454
- }
3455
- // -------------------------------------------------------------------------
3456
- // Processed-fingerprint recording
3457
- // -------------------------------------------------------------------------
3458
- async recordProcessedExtractionFingerprint(storage, fingerprint, preloadedMeta) {
3459
- const meta = preloadedMeta ?? await storage.loadMeta();
3460
- const observedAt = (/* @__PURE__ */ new Date()).toISOString();
3461
- const seen = new Map(
3462
- (meta.processedExtractionFingerprints ?? []).map((entry) => [entry.fingerprint, entry.observedAt])
3463
- );
3464
- seen.set(fingerprint, observedAt);
3465
- meta.processedExtractionFingerprints = Array.from(seen.entries()).map(([value, at2]) => ({ fingerprint: value, observedAt: at2 })).sort((left, right) => left.observedAt.localeCompare(right.observedAt)).slice(-500);
3466
- if (!preloadedMeta) {
3467
- await storage.saveMeta(meta);
3468
- }
3469
- }
3470
- // -------------------------------------------------------------------------
3471
- // Extraction retry/backoff + circuit breaker (extraction hot-loop hardening)
3472
- // -------------------------------------------------------------------------
3473
- /** Lazily hydrate the in-memory retry-state mirror for a namespace from meta.
3474
- * One-time per namespace per coordinator; the hot path is then a Map lookup.
3475
- * Cross-process coherence: a fresh coordinator hydrates from the shared
3476
- * meta.json, so a failure persisted by another process is honored here. */
3477
- hydrateRetryStateFromMeta(namespace, meta) {
3478
- if (this.hydratedRetryNamespaces.has(namespace)) return;
3479
- this.hydratedRetryNamespaces.add(namespace);
3480
- const nsMap = this.extractionRetryState.get(namespace) ?? /* @__PURE__ */ new Map();
3481
- for (const entry of meta.extractionRetryState ?? []) {
3482
- const nextEligibleAtMs = Date.parse(entry.nextEligibleAt);
3483
- const firstFailedAtMs = Date.parse(entry.firstFailedAt);
3484
- nsMap.set(entry.fingerprint, {
3485
- attempts: entry.attempts,
3486
- nextEligibleAtMs: Number.isFinite(nextEligibleAtMs) ? nextEligibleAtMs : 0,
3487
- firstFailedAtMs: Number.isFinite(firstFailedAtMs) ? firstFailedAtMs : Date.now(),
3488
- lastFailureClass: entry.lastFailureClass
3489
- });
3490
- }
3491
- this.extractionRetryState.set(namespace, nsMap);
3492
- }
3493
- logBreakerTransition(state) {
3494
- log.warn("extraction: provider circuit breaker transition", {
3495
- state,
3496
- consecutiveFailures: this.providerBreaker.consecutiveFailures,
3497
- lastReason: this.providerBreaker.lastReason,
3498
- openUntilMs: this.providerBreaker.openUntilMs
3499
- });
3500
- }
3501
- /** True while the breaker suppresses non-forced attempts. Flips an expired
3502
- * `open` breaker to `half_open`, which allows exactly one probe (the next
3503
- * non-forced attempt) because the extraction queue is a serial drain. */
3504
- isProviderBreakerOpen(now) {
3505
- if (now < this.providerBreaker.openUntilMs) return true;
3506
- if (this.providerBreaker.state === "open") {
3507
- this.providerBreaker.state = "half_open";
3508
- this.logBreakerTransition("half_open");
3509
- }
3510
- return false;
3511
- }
3512
- onProviderFailure(cls, now) {
3513
- this.providerBreaker.consecutiveFailures += 1;
3514
- const trip = cls === "auth_config" || // A failed half-open probe re-opens immediately (standard breaker
3515
- // semantics). Without this, an auth_config-opened breaker (which trips
3516
- // below the threshold) would get stuck half_open after a transient
3517
- // probe failure and stop suppressing (cursor review).
3518
- this.providerBreaker.state === "half_open" || this.providerBreaker.consecutiveFailures >= this.config.extractionBreakerFailureThreshold;
3519
- if (!trip) return;
3520
- const cooldown = cls === "auth_config" ? this.config.extractionBreakerAuthCooldownMs : this.config.extractionBreakerCooldownMs;
3521
- this.providerBreaker.openUntilMs = now + Math.max(0, cooldown);
3522
- this.providerBreaker.lastReason = cls;
3523
- if (this.providerBreaker.state !== "open") {
3524
- this.providerBreaker.state = "open";
3525
- this.logBreakerTransition("open");
3526
- }
3527
- }
3528
- resetProviderBreakerOnSuccess() {
3529
- const wasDisturbed = this.providerBreaker.state !== "closed" || this.providerBreaker.consecutiveFailures > 0 || this.providerBreaker.openUntilMs > 0;
3530
- if (!wasDisturbed) return;
3531
- const wasOpen = this.providerBreaker.state !== "closed";
3532
- this.providerBreaker.consecutiveFailures = 0;
3533
- this.providerBreaker.openUntilMs = 0;
3534
- this.providerBreaker.lastReason = "";
3535
- this.providerBreaker.state = "closed";
3536
- if (wasOpen) this.logBreakerTransition("closed");
3537
- }
3538
- /** Rebuild `meta.extractionRetryState` from the in-memory namespace mirror,
3539
- * bounded to the newest entries, and prune the mirror to match. */
3540
- persistRetryStateToMeta(namespace, meta) {
3541
- const nsMap = this.extractionRetryState.get(namespace);
3542
- const entries = nsMap ? Array.from(nsMap.entries()).map(([fingerprint, st]) => ({
3543
- fingerprint,
3544
- attempts: st.attempts,
3545
- nextEligibleAt: new Date(st.nextEligibleAtMs).toISOString(),
3546
- firstFailedAt: new Date(st.firstFailedAtMs).toISOString(),
3547
- lastFailureClass: st.lastFailureClass
3548
- })) : [];
3549
- const capped = capExtractionRetryStateEntries(entries, EXTRACTION_RETRY_STATE_MAX_ENTRIES);
3550
- meta.extractionRetryState = capped;
3551
- if (nsMap && capped.length < nsMap.size) {
3552
- const kept = new Set(capped.map((e) => e.fingerprint));
3553
- for (const key of Array.from(nsMap.keys())) {
3554
- if (!kept.has(key)) nsMap.delete(key);
3555
- }
3556
- }
3557
- }
3558
- /** Record an extraction failure into per-fingerprint backoff state + breaker,
3559
- * persisting to namespace meta. Fail-open: never throws upward. */
3560
- async recordExtractionFailure(storage, namespace, fingerprint, cls, meta, now) {
3561
- try {
3562
- this.hydrateRetryStateFromMeta(namespace, meta);
3563
- const nsMap = this.extractionRetryState.get(namespace) ?? /* @__PURE__ */ new Map();
3564
- const prev = nsMap.get(fingerprint);
3565
- const attempts = (prev?.attempts ?? 0) + 1;
3566
- const firstFailedAtMs = prev?.firstFailedAtMs ?? now;
3567
- let nextEligibleAtMs;
3568
- if (cls === "parse_empty" && attempts > this.config.extractionParseEmptyMaxAttempts) {
3569
- nextEligibleAtMs = now + Math.max(0, this.config.extractionRetryMaxBackoffMs);
3570
- } else {
3571
- nextEligibleAtMs = computeExtractionRetryNextEligibleMs(
3572
- attempts,
3573
- this.config.extractionRetryScheduleMs,
3574
- this.config.extractionRetryMaxBackoffMs,
3575
- this.config.extractionRetryJitterRatio,
3576
- now
3577
- );
3578
- }
3579
- nsMap.set(fingerprint, { attempts, nextEligibleAtMs, firstFailedAtMs, lastFailureClass: cls });
3580
- this.extractionRetryState.set(namespace, nsMap);
3581
- this.onProviderFailure(cls, now);
3582
- this.persistRetryStateToMeta(namespace, meta);
3583
- await storage.saveMeta(meta);
3584
- } catch (err) {
3585
- log.warn("runExtraction: failed to record extraction retry state (non-fatal)", err);
3586
- }
3587
- }
3588
- /** Delete a fingerprint's retry entry from the mirror + meta. Returns whether
3589
- * meta changed (so the caller can decide to persist). Does not touch the
3590
- * breaker — callers pair this with `resetProviderBreakerOnSuccess`. */
3591
- clearExtractionRetryEntry(namespace, fingerprint, meta) {
3592
- const nsMap = this.extractionRetryState.get(namespace);
3593
- if (!nsMap?.has(fingerprint)) return false;
3594
- nsMap.delete(fingerprint);
3595
- this.persistRetryStateToMeta(namespace, meta);
3596
- return true;
3597
- }
3598
- /** Live in-process resilience snapshot (breaker + backoff population). */
3599
- getExtractionResilienceStatus() {
3600
- let backoffFingerprintCount = 0;
3601
- for (const nsMap of this.extractionRetryState.values()) {
3602
- backoffFingerprintCount += nsMap.size;
3603
- }
3604
- return {
3605
- breaker: {
3606
- state: this.providerBreaker.state,
3607
- openUntilMs: this.providerBreaker.openUntilMs,
3608
- consecutiveFailures: this.providerBreaker.consecutiveFailures,
3609
- lastReason: this.providerBreaker.lastReason
3610
- },
3611
- backoffFingerprintCount
3612
- };
3613
- }
3614
- // -------------------------------------------------------------------------
3615
- // Main extraction pipeline
3616
- // -------------------------------------------------------------------------
3617
- async runExtraction(turns, options = {}) {
3618
- log.debug(`running extraction on ${turns.length} turns`);
3619
- const clearBufferAfterExtraction = options.clearBufferAfterExtraction ?? true;
3620
- const skipCharThreshold = options.skipCharThreshold ?? false;
3621
- const skipUserTurnThreshold = options.skipUserTurnThreshold ?? false;
3622
- const deadlineMs = typeof options.deadlineMs === "number" && Number.isFinite(options.deadlineMs) ? options.deadlineMs : void 0;
3623
- const bufferKey = options.bufferKey ?? turns[0]?.sessionKey ?? "default";
3624
- const throwIfDeadlineExceeded = (stage) => {
3625
- if (typeof deadlineMs === "number" && Date.now() > deadlineMs) {
3626
- throw new Error(`replay extraction deadline exceeded (${stage})`);
3627
- }
3628
- };
3629
- const throwIfAborted2 = (stage) => {
3630
- throwIfRecallAborted(options.abortSignal, `extraction aborted (${stage})`);
3631
- };
3632
- const clearBuffer = async (options2) => {
3633
- if (options2?.ignoreAbort !== true) {
3634
- throwIfAborted2("before_clear_buffer");
3635
- }
3636
- if (clearBufferAfterExtraction) {
3637
- await this.deps.getBuffer().clearAfterExtraction(bufferKey, turns);
3638
- }
3639
- };
3640
- const sessionKey = turns[0]?.sessionKey ?? "";
3641
- if (sessionKey.includes(":cron:")) {
3642
- log.debug(`skipping extraction for cron session: ${sessionKey}`);
3643
- await clearBuffer();
3644
- return {
3645
- status: "skipped",
3646
- reason: "cron_session",
3647
- persistedCount: 0,
3648
- durableOutputCount: 0
3649
- };
3650
- }
3651
- const normalizedTurns = turns.filter((t) => (t.role === "user" || t.role === "assistant") && typeof t.content === "string").map((t) => ({
3652
- ...t,
3653
- content: t.content.trim().slice(0, this.config.extractionMaxTurnChars)
3654
- })).filter((t) => t.content.length > 0);
3655
- const targetTurns = normalizedTurns.filter((turn) => turn.extractionContextOnly !== true);
3656
- if (targetTurns.length === 0) {
3657
- log.debug("skipping extraction: no non-context turns after normalization");
3658
- if (normalizedTurns.length > 0) {
3659
- await this.deps.maybeCapturePassiveCorrections(normalizedTurns, {
3660
- sessionKey,
3661
- principal: resolvePrincipal(sessionKey, this.config),
3662
- namespace: this.deps.resolveSelfNamespace(sessionKey),
3663
- bufferKey,
3664
- isLiveSession: clearBufferAfterExtraction
3665
- });
3666
- }
3667
- await clearBuffer();
3668
- return { status: "skipped", reason: "empty_normalized_turns", persistedCount: 0, durableOutputCount: 0 };
3669
- }
3670
- const sourceValidAt = this.latestSourceValidAtFromTurns(targetTurns);
3671
- throwIfDeadlineExceeded("before_extract");
3672
- throwIfAborted2("before_extract");
3673
- const userTurns = targetTurns.filter((t) => t.role === "user");
3674
- const totalChars = targetTurns.reduce((sum, t) => sum + t.content.length, 0);
3675
- const belowCharThreshold = totalChars < this.config.extractionMinChars;
3676
- const belowUserTurnThreshold = !skipUserTurnThreshold && userTurns.length < this.config.extractionMinUserTurns;
3677
- if (!skipCharThreshold && belowCharThreshold || belowUserTurnThreshold) {
3678
- log.debug(`skipping extraction: below threshold (totalChars=${totalChars}, userTurns=${userTurns.length})`);
3679
- await clearBuffer();
3680
- {
3681
- const capturePrincipal = typeof options.principalOverride === "string" && options.principalOverride.length > 0 ? options.principalOverride : resolvePrincipal(sessionKey, this.config);
3682
- const captureWO = typeof options.writeNamespaceOverride === "string" && options.writeNamespaceOverride.length > 0 ? options.writeNamespaceOverride : void 0;
3683
- const captureCodingCtx = sessionKey ? this.deps.getCodingContextForSession(sessionKey) : null;
3684
- const captureCodingOv = resolveCodingNamespaceOverlay(
3685
- captureCodingCtx,
3686
- this.config.codingMode,
3687
- this.config.defaultNamespace
3688
- );
3689
- const captureScopePlan = resolveScopeProfilePlan({
3690
- config: this.config,
3691
- principal: capturePrincipal,
3692
- codingContext: captureCodingCtx,
3693
- codingOverlay: captureCodingOv
3694
- });
3695
- const captureNamespace = captureWO ?? captureScopePlan?.writeNamespace ?? this.deps.resolveSelfNamespace(sessionKey);
3696
- await this.deps.maybeCapturePassiveCorrections(normalizedTurns, {
3697
- sessionKey,
3698
- principal: capturePrincipal,
3699
- namespace: captureNamespace,
3700
- bufferKey,
3701
- isLiveSession: clearBufferAfterExtraction
3702
- });
3703
- }
3704
- return {
3705
- status: "skipped",
3706
- reason: "below_threshold",
3707
- persistedCount: 0,
3708
- durableOutputCount: 0
3709
- };
3710
- }
3711
- const principal = typeof options.principalOverride === "string" && options.principalOverride.length > 0 ? options.principalOverride : resolvePrincipal(sessionKey, this.config);
3712
- const explicitWriteNamespace = typeof options.writeNamespaceOverride === "string" && options.writeNamespaceOverride.length > 0 ? options.writeNamespaceOverride : void 0;
3713
- const codingContextForWrite = sessionKey ? this.deps.getCodingContextForSession(sessionKey) : null;
3714
- const codingOverlayForWrite = resolveCodingNamespaceOverlay(
3715
- codingContextForWrite,
3716
- this.config.codingMode,
3717
- this.config.defaultNamespace
3718
- );
3719
- const scopeProfileGatePlan = resolveScopeProfilePlan({
3720
- config: this.config,
3721
- principal,
3722
- codingContext: codingContextForWrite,
3723
- codingOverlay: codingOverlayForWrite
3724
- });
3725
- const scopeProfileWritePlan = explicitWriteNamespace ? null : scopeProfileGatePlan;
3726
- if (scopeProfileWritePlan) {
3727
- const selectedLayer = scopeProfileWritePlan.layers.find((layer) => layer.id === scopeProfileWritePlan.writeLayer);
3728
- const writeNamespaceReadable = scopeProfileWritePlan.readNamespaces.includes(
3729
- scopeProfileWritePlan.writeNamespace
3730
- );
3731
- if (!selectedLayer?.writable || !writeNamespaceReadable) {
3732
- log.warn(
3733
- `runExtraction: skipping scope profile ${scopeProfileWritePlan.profileId} because write layer ${scopeProfileWritePlan.writeLayer} is not writable inside the profile read stack`
3734
- );
3735
- await clearBuffer();
3736
- return {
3737
- status: "skipped",
3738
- reason: "scope_profile_no_writable_layer",
3739
- persistedCount: 0,
3740
- durableOutputCount: 0
3741
- };
3742
- }
3743
- }
3744
- const selfNamespace = explicitWriteNamespace ?? scopeProfileWritePlan?.writeNamespace ?? this.deps.applyCodingNamespaceOverlay(sessionKey, defaultNamespaceForPrincipal(principal, this.config));
3745
- const storage = await this.deps.getStorageRouter().storageFor(selfNamespace);
3746
- const shouldPersistProcessedFingerprint = targetTurns.some((turn) => turn.persistProcessedFingerprint === true);
3747
- const extractionFingerprint = this.buildExtractionFingerprint(targetTurns, bufferKey);
3748
- let meta = extractionFingerprint && shouldPersistProcessedFingerprint ? await storage.loadMeta() : null;
3749
- if (extractionFingerprint && shouldPersistProcessedFingerprint && (meta?.processedExtractionFingerprints ?? []).some((entry) => entry.fingerprint === extractionFingerprint)) {
3750
- log.debug(`runExtraction: skipping already-processed extraction fingerprint for ${bufferKey}`);
3751
- await clearBuffer();
3752
- return {
3753
- status: "skipped",
3754
- reason: "processed_fingerprint",
3755
- persistedCount: 0,
3756
- durableOutputCount: 0
3757
- };
3758
- }
3759
- const forcedExtractionAttempt = options.failOnExtractionFailure === true || options.forceExtractionAttempt === true;
3760
- const extractionRetryEnabled = resolveMemoryLifecycleCapabilities(this.config).extractionRetry;
3761
- if (extractionFingerprint && !forcedExtractionAttempt && extractionRetryEnabled) {
3762
- try {
3763
- meta ??= await storage.loadMeta();
3764
- this.hydrateRetryStateFromMeta(selfNamespace, meta);
3765
- const nowMs = Date.now();
3766
- let suppressReason = null;
3767
- if (this.isProviderBreakerOpen(nowMs)) {
3768
- suppressReason = "provider_circuit_open";
3769
- } else {
3770
- const st = this.extractionRetryState.get(selfNamespace)?.get(extractionFingerprint);
3771
- if (st && nowMs < st.nextEligibleAtMs) suppressReason = "extraction_backoff";
3772
- }
3773
- if (suppressReason) {
3774
- try {
3775
- await this.deps.maybeCapturePassiveCorrections(normalizedTurns, {
3776
- sessionKey,
3777
- principal,
3778
- namespace: selfNamespace,
3779
- bufferKey,
3780
- isLiveSession: clearBufferAfterExtraction
3781
- });
3782
- } catch (captureErr) {
3783
- log.warn("runExtraction: passive correction capture failed on suppressed attempt (non-fatal)", captureErr);
3784
- }
3785
- return { status: "skipped", reason: suppressReason, persistedCount: 0, durableOutputCount: 0 };
3786
- }
3787
- } catch (err) {
3788
- log.warn("runExtraction: extraction retry gate check failed; proceeding (fail-open)", err);
3789
- }
3790
- }
3791
- const existingEntities = await storage.listEntityNames();
3792
- const result = await raceRecallAbort(
3793
- this.deps.getExtraction().extract(normalizedTurns, existingEntities),
3794
- options.abortSignal,
3795
- "extraction aborted (during_extract)"
3796
- );
3797
- throwIfDeadlineExceeded("before_persist");
3798
- throwIfAborted2("before_persist");
3799
- if (!result) {
3800
- log.warn("runExtraction: extraction returned null/undefined");
3801
- if (options.failOnExtractionFailure) {
3802
- throw new Error("extraction failed: invalid_extraction_result");
3803
- }
3804
- await clearBuffer();
3805
- return {
3806
- status: "skipped",
3807
- reason: "invalid_extraction_result",
3808
- persistedCount: 0,
3809
- durableOutputCount: 0
3810
- };
3811
- }
3812
- const invalidExtractionResultFields = [
3813
- ["facts", result.facts],
3814
- ["entities", result.entities],
3815
- ["questions", result.questions],
3816
- ["profileUpdates", result.profileUpdates]
3817
- ].filter(([, value]) => !Array.isArray(value)).map(([field]) => field);
3818
- if (invalidExtractionResultFields.length > 0) {
3819
- log.warn("runExtraction: extraction returned invalid collection fields", {
3820
- invalidFields: invalidExtractionResultFields,
3821
- resultKeys: typeof result === "object" && result !== null ? Object.keys(result) : []
3822
- });
3823
- if (options.failOnExtractionFailure) {
3824
- throw new Error("extraction failed: invalid_extraction_result");
3825
- }
3826
- await clearBuffer();
3827
- return {
3828
- status: "skipped",
3829
- reason: "invalid_extraction_result",
3830
- persistedCount: 0,
3831
- durableOutputCount: 0
3832
- };
3833
- }
3834
- const extractionFailure = typeof result.extractionFailure === "string" && result.extractionFailure.trim().length > 0 ? result.extractionFailure : void 0;
3835
- let recordedRetryFailure = false;
3836
- if (extractionFingerprint && extractionRetryEnabled) {
3837
- if (extractionFailure) {
3838
- try {
3839
- meta ??= await storage.loadMeta();
3840
- await this.recordExtractionFailure(
3841
- storage,
3842
- selfNamespace,
3843
- extractionFingerprint,
3844
- result.extractionFailureClass ?? "provider_retryable",
3845
- meta,
3846
- Date.now()
3847
- );
3848
- recordedRetryFailure = true;
3849
- } catch (err) {
3850
- log.warn("runExtraction: failed to load meta for retry bookkeeping (non-fatal)", err);
3851
- }
3852
- } else {
3853
- this.resetProviderBreakerOnSuccess();
3854
- try {
3855
- meta ??= await storage.loadMeta();
3856
- this.hydrateRetryStateFromMeta(selfNamespace, meta);
3857
- if (this.clearExtractionRetryEntry(selfNamespace, extractionFingerprint, meta)) {
3858
- await storage.saveMeta(meta);
3859
- }
3860
- } catch (err) {
3861
- log.warn("runExtraction: failed to persist cleared retry state (non-fatal)", err);
3862
- }
3863
- }
3864
- }
3865
- if (options.failOnExtractionFailure && extractionFailure) {
3866
- throw new Error(`extraction failed: ${extractionFailure}`);
3867
- }
3868
- if (result.facts.length === 0 && result.entities.length === 0 && result.questions.length === 0 && result.profileUpdates.length === 0) {
3869
- log.debug("runExtraction: extraction produced no durable outputs; skipping persistence");
3870
- if (extractionFailure) {
3871
- log.warn(
3872
- "runExtraction: extraction reported failure with no durable outputs; not marking fingerprint processed",
3873
- { extractionFailure }
3874
- );
3875
- }
3876
- if (extractionFingerprint && shouldPersistProcessedFingerprint && !extractionFailure) {
3877
- meta ??= await storage.loadMeta();
3878
- await this.deps.recordProcessedExtractionFingerprint(storage, extractionFingerprint, meta);
3879
- meta.extractionCount += 1;
3880
- meta.lastExtractionAt = (/* @__PURE__ */ new Date()).toISOString();
3881
- await storage.saveMeta(meta);
3882
- }
3883
- await this.deps.maybeCapturePassiveCorrections(normalizedTurns, {
3884
- sessionKey,
3885
- principal,
3886
- namespace: selfNamespace,
3887
- bufferKey,
3888
- isLiveSession: clearBufferAfterExtraction
3889
- });
3890
- if (recordedRetryFailure) {
3891
- log.debug("runExtraction: retaining buffer for backoff retry after failure");
3892
- } else {
3893
- await clearBuffer();
3894
- }
3895
- return { status: "skipped", reason: "empty_extraction_result", persistedCount: 0, durableOutputCount: 0 };
3896
- }
3897
- let threadIdForExtraction = null;
3898
- if (resolvePresentationCapabilities(this.config).threading && turns.length > 0) {
3899
- const lastTurn = turns[turns.length - 1];
3900
- try {
3901
- threadIdForExtraction = await this.deps.getThreading().processTurn(lastTurn, []);
3902
- } catch (err) {
3903
- log.warn("[threading] processTurn failed before persistence (non-fatal)", err);
3904
- }
3905
- }
3906
- const { persistedIds } = await this.deps.persistExtraction(
3907
- result,
3908
- storage,
3909
- threadIdForExtraction,
3910
- { sessionKey, principal, validAt: sourceValidAt, sourceConnector: deriveSourceConnector(targetTurns) },
3911
- // Pass the KNOWN base namespace (NHIdx) so the catalog write touch records the
3912
- // real namespace rather than a guess decoded from the storage dir.
3913
- selfNamespace,
3914
- scopeProfileGatePlan,
3915
- // Verbatim source turns for the faithfulness gate (#1576) so it can
3916
- // locate a quote per fact when #1575 spans are absent.
3917
- normalizedTurns.map((t) => t.content).join("\n\n")
3918
- );
3919
- let postPersistMetadataFailed = false;
3920
- meta ??= await storage.loadMeta();
3921
- if (extractionFingerprint && shouldPersistProcessedFingerprint) {
3922
- try {
3923
- await this.deps.recordProcessedExtractionFingerprint(storage, extractionFingerprint, meta);
3924
- } catch (error) {
3925
- log.warn(
3926
- "runExtraction: failed to persist processed extraction fingerprint; continuing with buffer clear",
3927
- error
3928
- );
3929
- postPersistMetadataFailed = true;
3930
- }
3931
- }
3932
- meta.extractionCount += 1;
3933
- meta.lastExtractionAt = (/* @__PURE__ */ new Date()).toISOString();
3934
- meta.totalMemories += Array.isArray(result?.facts) ? result.facts.length : 0;
3935
- meta.totalEntities += Array.isArray(result?.entities) ? result.entities.length : 0;
3936
- try {
3937
- await storage.saveMeta(meta);
3938
- } catch (error) {
3939
- log.warn(
3940
- "runExtraction: failed to save extraction metadata after durable persistence; continuing with buffer clear",
3941
- error
3942
- );
3943
- postPersistMetadataFailed = true;
3944
- }
3945
- const durableOutputCount = result.facts.length + result.entities.length + result.questions.length + result.profileUpdates.length;
3946
- try {
3947
- if (clearBufferAfterExtraction && !this.config.extractionJudgeShadow) {
3948
- const deferredCount = this.deps.getLastPersistExtractionDeferredCount();
3949
- if (deferredCount > 0 && normalizedTurns.length > 0) {
3950
- await this.deps.getBuffer().retainDeferredTurns(bufferKey, normalizedTurns, 10);
3951
- } else {
3952
- await this.deps.getBuffer().retainDeferredTurns(bufferKey, [], 0);
3953
- }
3954
- }
3955
- } catch (err) {
3956
- log.debug(
3957
- `extraction-judge: defer retention failed (non-fatal): ${err instanceof Error ? err.message : String(err)}`
3958
- );
3959
- }
3960
- await clearBuffer({ ignoreAbort: true });
3961
- await this.deps.maybeCapturePassiveCorrections(normalizedTurns, {
3962
- sessionKey,
3963
- principal,
3964
- namespace: selfNamespace,
3965
- bufferKey,
3966
- isLiveSession: clearBufferAfterExtraction
3967
- });
3968
- if (resolvePresentationCapabilities(this.config).memoryBoxes && persistedIds.length > 0) {
3969
- const extractionTopics = deriveTopicsFromExtraction(result);
3970
- const firstUserTurn = turns.find((t) => t.role === "user");
3971
- const boxGoal = firstUserTurn?.content?.slice(0, 100)?.trim() || void 0;
3972
- await this.deps.boxBuilderFor(storage).onExtraction({
3973
- topics: extractionTopics,
3974
- memoryIds: persistedIds,
3975
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
3976
- goal: boxGoal
3977
- }).catch((err) => log.warn("[boxes] onExtraction failed (non-fatal)", err));
3978
- }
3979
- if (resolvePresentationCapabilities(this.config).threading && threadIdForExtraction && persistedIds.length > 0) {
3980
- await this.deps.appendPersistedThreadEpisodes(threadIdForExtraction, persistedIds);
3981
- }
3982
- if (resolvePresentationCapabilities(this.config).threading && threadIdForExtraction) {
3983
- const conversationContent = turns.map((t) => t.content).join(" ");
3984
- try {
3985
- await this.deps.getThreading().updateThreadTitle(threadIdForExtraction, conversationContent);
3986
- } catch (err) {
3987
- log.warn("[threading] updateThreadTitle failed after persistence (non-fatal)", err);
3988
- }
3989
- }
3990
- const nonZeroExtraction = durableOutputCount > 0;
3991
- try {
3992
- this.deps.maybeScheduleConsolidation(nonZeroExtraction);
3993
- } catch (err) {
3994
- log.warn("runExtraction: consolidation scheduling failed after persistence (non-fatal)", err);
3995
- }
3996
- try {
3997
- this.deps.requestQmdMaintenance();
3998
- } catch (err) {
3999
- log.warn("runExtraction: QMD maintenance scheduling failed after persistence (non-fatal)", err);
4000
- }
4001
- try {
4002
- await this.deps.runTierMigrationCycle(storage, "extraction");
4003
- } catch (err) {
4004
- log.warn("runExtraction: tier migration failed after persistence (non-fatal)", err);
2753
+ log.warn(
2754
+ `contradiction auto-resolve supersede failed for ${contradiction.supersededId}: ${err}`
2755
+ );
4005
2756
  }
4006
- return {
4007
- status: "completed",
4008
- persistedCount: persistedIds.length,
4009
- durableOutputCount,
4010
- postPersistMetadataFailed
4011
- };
4012
2757
  }
4013
- };
4014
- function deriveSourceConnector(turns) {
4015
- if (turns.length === 0) return void 0;
4016
- const connectors = /* @__PURE__ */ new Set();
4017
- let untaggedCount = 0;
4018
- for (const turn of turns) {
4019
- if (typeof turn.sourceConnector === "string" && turn.sourceConnector.length > 0) {
4020
- connectors.add(turn.sourceConnector);
4021
- } else {
4022
- untaggedCount += 1;
2758
+ // ---------------------------------------------------------------------------
2759
+ // Memory Linking (Phase 3A)
2760
+ // ---------------------------------------------------------------------------
2761
+ /**
2762
+ * Suggest links for a new memory based on similar existing memories.
2763
+ */
2764
+ async suggestLinksForMemory(content, category, namespaceScope) {
2765
+ if (!this.isSearchAvailable()) return [];
2766
+ const results = await this.searchAcrossNamespaces({
2767
+ query: content,
2768
+ namespaces: [namespaceScope],
2769
+ maxResults: 5,
2770
+ mode: "search"
2771
+ });
2772
+ if (results.length === 0) return [];
2773
+ const candidates = [];
2774
+ for (const result of results) {
2775
+ const memoryId = this.extractMemoryIdsFromResults([result])[0];
2776
+ if (!memoryId) continue;
2777
+ const resultNamespace = this.namespaceFromPath(result.path);
2778
+ if (resultNamespace !== namespaceScope) continue;
2779
+ const resultStorage = await this.storageForNamespace(resultNamespace);
2780
+ const memory = await resultStorage.getMemoryById(memoryId);
2781
+ if (memory && memory.frontmatter.status !== "superseded" && memory.frontmatter.status !== "forgotten") {
2782
+ candidates.push({
2783
+ id: memory.frontmatter.id,
2784
+ content: memory.content,
2785
+ category: memory.frontmatter.category
2786
+ });
2787
+ }
4023
2788
  }
2789
+ if (candidates.length === 0) return [];
2790
+ const extraction = this.getExtraction();
2791
+ const suggestions = await extraction.suggestLinks(
2792
+ { content, category },
2793
+ candidates
2794
+ );
2795
+ if (!suggestions || suggestions.links.length === 0) return [];
2796
+ return suggestions.links.map((link) => ({
2797
+ targetId: link.targetId,
2798
+ linkType: link.linkType,
2799
+ strength: link.strength,
2800
+ reason: link.reason || void 0
2801
+ }));
4024
2802
  }
4025
- if (untaggedCount > 0) return void 0;
4026
- return connectors.size === 1 ? [...connectors][0] : void 0;
4027
- }
2803
+ };
4028
2804
 
4029
2805
  // src/orchestration/consolidation-run.ts
4030
- import path5 from "path";
2806
+ import path4 from "path";
4031
2807
  import { mkdir as mkdir2, readFile, writeFile as writeFile2 } from "fs/promises";
4032
2808
  var ConsolidationRunCoordinator = class {
4033
2809
  constructor(deps) {
@@ -4258,7 +3034,7 @@ var ConsolidationRunCoordinator = class {
4258
3034
  }
4259
3035
  if (resolveConsolidationCapabilities(config).semanticConsolidation) {
4260
3036
  try {
4261
- const stateFilePath = path5.join(
3037
+ const stateFilePath = path4.join(
4262
3038
  config.memoryDir,
4263
3039
  "state",
4264
3040
  "semantic-consolidation-last-run.json"
@@ -4306,7 +3082,7 @@ var ConsolidationRunCoordinator = class {
4306
3082
  );
4307
3083
  }
4308
3084
  if (semResult.errors === 0 || semResult.memoriesArchived > 0) {
4309
- const stateDir = path5.join(config.memoryDir, "state");
3085
+ const stateDir = path4.join(config.memoryDir, "state");
4310
3086
  await mkdir2(stateDir, { recursive: true });
4311
3087
  await writeFile2(
4312
3088
  stateFilePath,
@@ -6229,14 +5005,14 @@ var ExtractionPersistCoordinator = class {
6229
5005
  };
6230
5006
 
6231
5007
  // src/orchestration/recall-internal.ts
6232
- import { createHash as createHash5 } from "crypto";
5008
+ import { createHash as createHash3 } from "crypto";
6233
5009
  import { readFile as readFile2, stat, unlink } from "fs/promises";
6234
- import path8 from "path";
5010
+ import path7 from "path";
6235
5011
 
6236
5012
  // src/orchestration/graph-recall-coordinator.ts
6237
- import { createHash as createHash4 } from "crypto";
5013
+ import { createHash as createHash2 } from "crypto";
6238
5014
  import { mkdir as mkdir3, writeFile as writeFile3 } from "fs/promises";
6239
- import path6 from "path";
5015
+ import path5 from "path";
6240
5016
  function mergeGraphExpandedResults(primary, expanded) {
6241
5017
  const mergedByNamespaceAndPath = /* @__PURE__ */ new Map();
6242
5018
  for (const item of [...primary, ...expanded]) {
@@ -6253,11 +5029,11 @@ function mergeGraphExpandedResults(primary, expanded) {
6253
5029
  return Array.from(mergedByNamespaceAndPath.values());
6254
5030
  }
6255
5031
  function graphPathRelativeToStorage(storageDir, candidatePath) {
6256
- const absolutePath = path6.isAbsolute(candidatePath) ? candidatePath : path6.resolve(storageDir, candidatePath);
6257
- const rel = path6.relative(storageDir, absolutePath);
5032
+ const absolutePath = path5.isAbsolute(candidatePath) ? candidatePath : path5.resolve(storageDir, candidatePath);
5033
+ const rel = path5.relative(storageDir, absolutePath);
6258
5034
  if (!rel || rel === ".") return null;
6259
5035
  if (rel.startsWith("..")) return null;
6260
- return rel.split(path6.sep).join("/");
5036
+ return rel.split(path5.sep).join("/");
6261
5037
  }
6262
5038
  function normalizeGraphActivationScore(score) {
6263
5039
  const bounded = Number.isFinite(score) && score > 0 ? score : 0;
@@ -6328,7 +5104,7 @@ var GraphRecallCoordinator = class {
6328
5104
  resolvedPath = resolvedCold.result.path;
6329
5105
  resolvedResult = resolvedCold.result;
6330
5106
  }
6331
- if (!path6.isAbsolute(resolvedPath)) {
5107
+ if (!path5.isAbsolute(resolvedPath)) {
6332
5108
  resolvedAmbiguousSeeds.set(result.path, null);
6333
5109
  return null;
6334
5110
  }
@@ -6353,7 +5129,7 @@ var GraphRecallCoordinator = class {
6353
5129
  }
6354
5130
  continue;
6355
5131
  }
6356
- if (path6.isAbsolute(result.path)) {
5132
+ if (path5.isAbsolute(result.path)) {
6357
5133
  const resolved = await resolveAmbiguousSeedOwner(result, null);
6358
5134
  if (resolved) {
6359
5135
  addResultForNamespace(resolved.namespace, resolved.result);
@@ -6396,7 +5172,7 @@ var GraphRecallCoordinator = class {
6396
5172
  0
6397
5173
  );
6398
5174
  seedPaths.push(
6399
- ...seedRelativePaths.map((rel) => path6.join(storage.dir, rel))
5175
+ ...seedRelativePaths.map((rel) => path5.join(storage.dir, rel))
6400
5176
  );
6401
5177
  const seedSet = new Set(seedRelativePaths);
6402
5178
  const expanded = await this.graphIndexFor(storage).spreadingActivation(
@@ -6412,7 +5188,7 @@ var GraphRecallCoordinator = class {
6412
5188
  for (const candidate of expanded.slice(0, perNamespaceExpandedCap)) {
6413
5189
  if (deadlineExpired()) break;
6414
5190
  if (seedSet.has(candidate.path)) continue;
6415
- const memoryPath = path6.resolve(storage.dir, candidate.path);
5191
+ const memoryPath = path5.resolve(storage.dir, candidate.path);
6416
5192
  const memory = await storage.readMemoryByPath(memoryPath);
6417
5193
  if (deadlineExpired()) break;
6418
5194
  if (!memory) continue;
@@ -6440,7 +5216,7 @@ var GraphRecallCoordinator = class {
6440
5216
  path: memory.path,
6441
5217
  score,
6442
5218
  namespace,
6443
- seed: path6.resolve(storage.dir, candidate.seed),
5219
+ seed: path5.resolve(storage.dir, candidate.seed),
6444
5220
  hopDepth: candidate.hopDepth,
6445
5221
  decayedWeight: candidate.decayedWeight,
6446
5222
  graphType: candidate.graphType,
@@ -6464,12 +5240,12 @@ var GraphRecallCoordinator = class {
6464
5240
  }
6465
5241
  async recordLastGraphRecallSnapshot(options) {
6466
5242
  try {
6467
- const snapshotPath = path6.join(
5243
+ const snapshotPath = path5.join(
6468
5244
  options.storage.dir,
6469
5245
  "state",
6470
5246
  "last_graph_recall.json"
6471
5247
  );
6472
- await mkdir3(path6.dirname(snapshotPath), { recursive: true });
5248
+ await mkdir3(path5.dirname(snapshotPath), { recursive: true });
6473
5249
  const now = (/* @__PURE__ */ new Date()).toISOString();
6474
5250
  const totalSeedCount = options.seedPaths.length;
6475
5251
  const totalExpandedCount = options.expandedPaths.length;
@@ -6481,7 +5257,7 @@ var GraphRecallCoordinator = class {
6481
5257
  const payload = {
6482
5258
  recordedAt: now,
6483
5259
  mode: options.recallMode,
6484
- queryHash: createHash4("sha256").update(options.prompt).digest("hex"),
5260
+ queryHash: createHash2("sha256").update(options.prompt).digest("hex"),
6485
5261
  queryLength: options.prompt.length,
6486
5262
  namespaces: options.recallNamespaces,
6487
5263
  seedCount: totalSeedCount,
@@ -6584,7 +5360,7 @@ ${blocks.join("\n\n")}`;
6584
5360
  }
6585
5361
 
6586
5362
  // src/orchestration/generic-recall-paths.ts
6587
- import path7 from "path";
5363
+ import path6 from "path";
6588
5364
  var CATEGORY_MEMORY_ROOTS = Object.fromEntries(
6589
5365
  ALL_CATEGORY_DIRS.map((directory) => [directory, true])
6590
5366
  );
@@ -6609,7 +5385,7 @@ function normalizeQmdUriPath(relativePath, source) {
6609
5385
  }
6610
5386
  }
6611
5387
  function stripQmdCollectionPrefix(relativePath, policy, source) {
6612
- const normalized = path7.posix.normalize(normalizeQmdUriPath(relativePath, source).replace(/\\/g, "/"));
5388
+ const normalized = path6.posix.normalize(normalizeQmdUriPath(relativePath, source).replace(/\\/g, "/"));
6613
5389
  const slashIndex = normalized.indexOf("/");
6614
5390
  if (slashIndex <= 0 || slashIndex >= normalized.length - 1) return normalized;
6615
5391
  const prefix = normalized.slice(0, slashIndex);
@@ -6618,8 +5394,8 @@ function stripQmdCollectionPrefix(relativePath, policy, source) {
6618
5394
  return matchesHotCollection || matchesColdCollection ? normalized.slice(slashIndex + 1) : normalized;
6619
5395
  }
6620
5396
  function isTopLevelArchivePath(filePath, policy = {}, source = "filesystem") {
6621
- const isAbsolutePath = path7.isAbsolute(filePath);
6622
- const relative = policy.memoryDir && isAbsolutePath ? path7.relative(policy.memoryDir, path7.resolve(filePath)) : filePath;
5397
+ const isAbsolutePath = path6.isAbsolute(filePath);
5398
+ const relative = policy.memoryDir && isAbsolutePath ? path6.relative(policy.memoryDir, path6.resolve(filePath)) : filePath;
6623
5399
  const normalized = !isAbsolutePath ? stripQmdCollectionPrefix(relative, policy, source) : relative;
6624
5400
  return /^(?:archive|namespaces[\\/][^\\/]+[\\/]archive)(?:[\\/]|$)/i.test(normalized);
6625
5401
  }
@@ -6705,8 +5481,8 @@ var RecallInternalCoordinator = class {
6705
5481
  timings,
6706
5482
  logger: log
6707
5483
  });
6708
- const promptHash = createHash5("sha256").update(prompt).digest("hex");
6709
- const traceId = createHash5("sha256").update(`${sessionKey ?? "default"}:${recallStart}:${promptHash}`).digest("hex").slice(0, 16);
5484
+ const promptHash = createHash3("sha256").update(prompt).digest("hex");
5485
+ const traceId = createHash3("sha256").update(`${sessionKey ?? "default"}:${recallStart}:${promptHash}`).digest("hex").slice(0, 16);
6710
5486
  const sectionBuckets = /* @__PURE__ */ new Map();
6711
5487
  const queryPolicy = buildRecallQueryPolicy(prompt, sessionKey, {
6712
5488
  cronRecallPolicyEnabled: resolveRecallAuxiliaryCapabilities(this.deps.config).cronRecallPolicy,
@@ -6715,7 +5491,7 @@ var RecallInternalCoordinator = class {
6715
5491
  cronConversationRecallMode: this.deps.config.cronConversationRecallMode
6716
5492
  });
6717
5493
  const retrievalQuery = queryPolicy.retrievalQuery || prompt;
6718
- const retrievalQueryHash = createHash5("sha256").update(retrievalQuery).digest("hex");
5494
+ const retrievalQueryHash = createHash3("sha256").update(retrievalQuery).digest("hex");
6719
5495
  const policyVersion = this.deps.currentPolicyVersion();
6720
5496
  let recallSource = "none";
6721
5497
  let recalledMemoryCount = 0;
@@ -6855,7 +5631,7 @@ var RecallInternalCoordinator = class {
6855
5631
  const graphExpandedResultPaths = /* @__PURE__ */ new Set();
6856
5632
  const graphSourceLabelsForPath = (resultPath) => {
6857
5633
  const labels = [];
6858
- const normalizedPath = resultPath.split(path8.sep).join("/");
5634
+ const normalizedPath = resultPath.split(path7.sep).join("/");
6859
5635
  const isEntityPath = normalizedPath.startsWith("entities/") || normalizedPath.includes("/entities/");
6860
5636
  if (graphBaselinePaths.has(resultPath)) labels.push("baseline");
6861
5637
  if (graphExpandedResultPaths.has(resultPath))
@@ -7016,7 +5792,7 @@ var RecallInternalCoordinator = class {
7016
5792
  profileStorageNamespaces.map((namespace) => this.deps.storageRouter.storageFor(namespace))
7017
5793
  );
7018
5794
  const emptyProfileStorage = new Proxy(
7019
- { dir: path8.join(this.deps.config.memoryDir, ".empty-scope-profile") },
5795
+ { dir: path7.join(this.deps.config.memoryDir, ".empty-scope-profile") },
7020
5796
  {
7021
5797
  get(target, prop) {
7022
5798
  if (prop in target) return target[prop];
@@ -8498,11 +7274,11 @@ ${formatted}`;
8498
7274
  if (!resolveRecallAuxiliaryCapabilities(this.deps.config).compactionReset) return null;
8499
7275
  const workspaceDir = compactionWorkspaceDir || this.deps.config.workspaceDir || defaultWorkspaceDir();
8500
7276
  const safeSessionKey = sanitizeSessionKeyForFilename(effectiveSessionKey);
8501
- const signalPath = path8.join(
7277
+ const signalPath = path7.join(
8502
7278
  workspaceDir,
8503
7279
  `.compaction-reset-signal-${safeSessionKey}`
8504
7280
  );
8505
- const bootPath = path8.join(workspaceDir, "BOOT.md");
7281
+ const bootPath = path7.join(workspaceDir, "BOOT.md");
8506
7282
  try {
8507
7283
  const signalStat = await stat(signalPath).catch(() => null);
8508
7284
  if (!signalStat) return null;
@@ -10655,8 +9431,8 @@ ${tmtNode.summary}`
10655
9431
  };
10656
9432
 
10657
9433
  // src/orchestration/recall-search-pipeline.ts
10658
- import { createHash as createHash6 } from "crypto";
10659
- import path9 from "path";
9434
+ import { createHash as createHash4 } from "crypto";
9435
+ import path8 from "path";
10660
9436
  var RecallSearchPipelineCoordinator = class {
10661
9437
  constructor(deps) {
10662
9438
  this.deps = deps;
@@ -10821,7 +9597,7 @@ var RecallSearchPipelineCoordinator = class {
10821
9597
  if (!options.onDebugSnapshot) return;
10822
9598
  await options.onDebugSnapshot({
10823
9599
  recordedAt: (/* @__PURE__ */ new Date()).toISOString(),
10824
- queryHash: createHash6("sha256").update(prompt).digest("hex"),
9600
+ queryHash: createHash4("sha256").update(prompt).digest("hex"),
10825
9601
  queryLength: prompt.length,
10826
9602
  collection: options.collection,
10827
9603
  namespaces: options.recallNamespaces,
@@ -10964,7 +9740,7 @@ var RecallSearchPipelineCoordinator = class {
10964
9740
  if (hits.length === 0) return [];
10965
9741
  const results = [];
10966
9742
  for (const hit of hits) {
10967
- const fullPath = path9.isAbsolute(hit.path) ? hit.path : path9.join(this.deps.config.memoryDir, hit.path);
9743
+ const fullPath = path8.isAbsolute(hit.path) ? hit.path : path8.join(this.deps.config.memoryDir, hit.path);
10968
9744
  const memory = await this.deps.storage.readMemoryByPath(fullPath);
10969
9745
  if (!memory) continue;
10970
9746
  results.push({
@@ -11127,7 +9903,7 @@ var RecallSearchPipelineCoordinator = class {
11127
9903
  const storage = await this.deps.storageRouter.storageFor(namespace);
11128
9904
  const storageDir = typeof storage.dir === "string" && storage.dir ? storage.dir : null;
11129
9905
  if (!storageDir) continue;
11130
- const recallRoot = path9.resolve(storageDir);
9906
+ const recallRoot = path8.resolve(storageDir);
11131
9907
  if (seenRecallRoots.has(recallRoot)) continue;
11132
9908
  seenRecallRoots.add(recallRoot);
11133
9909
  recallRoots.push(recallRoot);
@@ -11151,8 +9927,8 @@ var RecallSearchPipelineCoordinator = class {
11151
9927
  if (resolvedCold) scopedResults.push(resolvedCold.result);
11152
9928
  continue;
11153
9929
  }
11154
- if (path9.isAbsolute(result.path)) {
11155
- if (recallRoots.some((recallRoot) => isPathInsideStorageRoot(recallRoot, path9.resolve(result.path)))) {
9930
+ if (path8.isAbsolute(result.path)) {
9931
+ if (recallRoots.some((recallRoot) => isPathInsideStorageRoot(recallRoot, path8.resolve(result.path)))) {
11156
9932
  scopedResults.push(result);
11157
9933
  }
11158
9934
  continue;
@@ -11436,7 +10212,10 @@ var RecallSearchPipelineCoordinator = class {
11436
10212
  continue;
11437
10213
  }
11438
10214
  }
11439
- filtered.push(r);
10215
+ filtered.push({
10216
+ ...r,
10217
+ sourceConnector: memory ? memory.frontmatter.sourceConnector : void 0
10218
+ });
11440
10219
  }
11441
10220
  if (lifecycleFilteredCount > 0) {
11442
10221
  log.debug(
@@ -11679,7 +10458,7 @@ var RecallSearchPipelineCoordinator = class {
11679
10458
  };
11680
10459
 
11681
10460
  // src/orchestration/turn-ingestion.ts
11682
- import { createHash as createHash7, randomBytes } from "crypto";
10461
+ import { createHash as createHash5, randomBytes } from "crypto";
11683
10462
  var TurnIngestionCoordinator = class {
11684
10463
  constructor(deps) {
11685
10464
  this.deps = deps;
@@ -11742,6 +10521,7 @@ var TurnIngestionCoordinator = class {
11742
10521
  timestamp: turn.timestamp,
11743
10522
  sourceValidAt: turn.sourceValidAt,
11744
10523
  sessionKey: key,
10524
+ ...options.sessionOwnerPrincipal ? { sessionOwnerPrincipal: options.sessionOwnerPrincipal } : {},
11745
10525
  parts: turn.parts,
11746
10526
  rawContent: turn.rawContent,
11747
10527
  sourceFormat: turn.sourceFormat,
@@ -11863,7 +10643,7 @@ var TurnIngestionCoordinator = class {
11863
10643
  const shouldUseStableBatchKey = turns.some(
11864
10644
  (turn) => turn.persistProcessedFingerprint === true || typeof turn.turnFingerprint === "string" && turn.turnFingerprint.length > 0
11865
10645
  );
11866
- const stableBatchFingerprint = shouldUseStableBatchKey ? createHash7("sha256").update(
10646
+ const stableBatchFingerprint = shouldUseStableBatchKey ? createHash5("sha256").update(
11867
10647
  turns.map(
11868
10648
  (turn) => [
11869
10649
  turn.role,
@@ -12058,41 +10838,70 @@ var TurnIngestionCoordinator = class {
12058
10838
  timeout = void 0;
12059
10839
  }
12060
10840
  };
10841
+ let abortHandler;
10842
+ const clearAbortListener = () => {
10843
+ if (abortHandler && options.abortSignal) {
10844
+ options.abortSignal.removeEventListener("abort", abortHandler);
10845
+ abortHandler = void 0;
10846
+ }
10847
+ };
12061
10848
  const settleTask = (error, result) => {
12062
10849
  if (settled) return false;
12063
10850
  settled = true;
12064
10851
  clearQueueWaitTimer();
10852
+ clearAbortListener();
12065
10853
  options.onTaskSettled?.(error, result);
12066
10854
  return true;
12067
10855
  };
12068
- if (typeof extractionDeadlineMs === "number") {
12069
- const remainingMs = extractionDeadlineMs - Date.now();
12070
- if (remainingMs <= 0) {
12071
- settleTask(new Error("replay extraction deadline exceeded (queue_wait)"));
10856
+ if (options.abortSignal) {
10857
+ const signal = options.abortSignal;
10858
+ abortHandler = () => settleTask(signal.reason ?? abortError("extraction aborted (queue_wait)"));
10859
+ signal.addEventListener("abort", abortHandler, { once: true });
10860
+ if (signal.aborted) {
10861
+ settleTask(signal.reason ?? abortError("extraction aborted (queue_wait)"));
12072
10862
  return;
12073
10863
  }
12074
- timeout = setTimeout(() => {
12075
- settleTask(new Error("replay extraction deadline exceeded (queue_wait)"));
12076
- }, remainingMs);
10864
+ }
10865
+ if (typeof extractionDeadlineMs === "number") {
10866
+ const deadline = extractionDeadlineMs;
10867
+ const maxTimerDelayMs = 2147483647;
10868
+ const scheduleQueueWaitTimeout = () => {
10869
+ const remainingMs = deadline - Date.now();
10870
+ if (remainingMs <= 0) {
10871
+ settleTask(new ExtractionDeadlineError("queue_wait"));
10872
+ return;
10873
+ }
10874
+ timeout = setTimeout(() => {
10875
+ if (Date.now() >= deadline) {
10876
+ settleTask(new ExtractionDeadlineError("queue_wait"));
10877
+ } else {
10878
+ scheduleQueueWaitTimeout();
10879
+ }
10880
+ }, Math.min(remainingMs, maxTimerDelayMs));
10881
+ };
10882
+ scheduleQueueWaitTimeout();
12077
10883
  }
12078
10884
  this.deps.extractionQueueCoordinator.enqueue(async () => {
12079
10885
  if (settled) return;
12080
10886
  if (typeof extractionDeadlineMs === "number" && extractionDeadlineMs <= Date.now()) {
12081
- settleTask(new Error("replay extraction deadline exceeded (queue_wait)"));
10887
+ settleTask(new ExtractionDeadlineError("queue_wait"));
12082
10888
  return;
12083
10889
  }
12084
10890
  clearQueueWaitTimer();
12085
10891
  try {
12086
10892
  const result = await this.deps.runExtraction(turnsToExtract, {
12087
10893
  clearBufferAfterExtraction: options.clearBufferAfterExtraction ?? true,
10894
+ clearMatchingTurns: options.clearMatchingTurns === true,
12088
10895
  skipCharThreshold: options.skipCharThreshold ?? false,
12089
10896
  skipUserTurnThreshold: options.skipUserTurnThreshold ?? false,
12090
10897
  deadlineMs: extractionDeadlineMs,
12091
10898
  bufferKey,
10899
+ onDurableCommit: options.onDurableCommit,
12092
10900
  abortSignal: options.abortSignal,
12093
10901
  failOnExtractionFailure: options.failOnExtractionFailure === true,
12094
10902
  writeNamespaceOverride: options.writeNamespaceOverride,
12095
10903
  principalOverride: options.principalOverride,
10904
+ scopeProfileWritePlan: options.scopeProfileWritePlan,
12096
10905
  forceExtractionAttempt: options.forceExtractionAttempt === true
12097
10906
  });
12098
10907
  settleTask(void 0, result);
@@ -12138,11 +10947,12 @@ var TurnIngestionCoordinator = class {
12138
10947
  bufferKey: opts.bufferKey,
12139
10948
  sessionKey: opts.sessionKey,
12140
10949
  principal: opts.principal,
12141
- namespace: opts.namespace
10950
+ namespace: opts.namespace,
10951
+ abortSignal: opts.abortSignal
12142
10952
  },
12143
10953
  captureConfig,
12144
10954
  {
12145
- planCorrection: (req) => service.plan(req),
10955
+ planCorrection: (req, planOpts) => service.plan(req, planOpts),
12146
10956
  applyCorrection: (planId, applyOpts) => service.apply(planId, applyOpts),
12147
10957
  storageDir: async (ns) => (await this.deps.getStorage(ns)).dir,
12148
10958
  // Resolve `[m:xxxx]` handles to concrete memory ids via the single
@@ -12175,7 +10985,7 @@ var TurnIngestionCoordinator = class {
12175
10985
 
12176
10986
  // src/orchestration/recall-introspection.ts
12177
10987
  import { mkdir as mkdir5, readFile as readFile4, writeFile as writeFile5 } from "fs/promises";
12178
- import path11 from "path";
10988
+ import path10 from "path";
12179
10989
 
12180
10990
  // src/taxonomy/default-taxonomy.ts
12181
10991
  var DEFAULT_TAXONOMY = {
@@ -12298,7 +11108,7 @@ function generateResolverDocument(taxonomy) {
12298
11108
 
12299
11109
  // src/taxonomy/taxonomy-loader.ts
12300
11110
  import { readFile as readFile3, mkdir as mkdir4, writeFile as writeFile4 } from "fs/promises";
12301
- import path10 from "path";
11111
+ import path9 from "path";
12302
11112
  var TAXONOMY_DIR = ".taxonomy";
12303
11113
  var TAXONOMY_FILE = "taxonomy.json";
12304
11114
  var MAX_SLUG_LENGTH = 32;
@@ -12396,7 +11206,7 @@ function validateTaxonomy(taxonomy) {
12396
11206
  }
12397
11207
  }
12398
11208
  async function loadTaxonomy(memoryDir) {
12399
- const taxonomyPath = path10.join(memoryDir, TAXONOMY_DIR, TAXONOMY_FILE);
11209
+ const taxonomyPath = path9.join(memoryDir, TAXONOMY_DIR, TAXONOMY_FILE);
12400
11210
  let raw;
12401
11211
  try {
12402
11212
  raw = await readFile3(taxonomyPath, "utf-8");
@@ -12446,16 +11256,16 @@ async function loadTaxonomy(memoryDir) {
12446
11256
  }
12447
11257
  async function saveTaxonomy(memoryDir, taxonomy) {
12448
11258
  validateTaxonomy(taxonomy);
12449
- const dir = path10.join(memoryDir, TAXONOMY_DIR);
11259
+ const dir = path9.join(memoryDir, TAXONOMY_DIR);
12450
11260
  await mkdir4(dir, { recursive: true });
12451
- const filePath = path10.join(dir, TAXONOMY_FILE);
11261
+ const filePath = path9.join(dir, TAXONOMY_FILE);
12452
11262
  await writeFile4(filePath, JSON.stringify(taxonomy, null, 2) + "\n", "utf-8");
12453
11263
  }
12454
11264
  function getTaxonomyDir(memoryDir) {
12455
- return path10.join(memoryDir, TAXONOMY_DIR);
11265
+ return path9.join(memoryDir, TAXONOMY_DIR);
12456
11266
  }
12457
11267
  function getTaxonomyFilePath(memoryDir) {
12458
- return path10.join(memoryDir, TAXONOMY_DIR, TAXONOMY_FILE);
11268
+ return path9.join(memoryDir, TAXONOMY_DIR, TAXONOMY_FILE);
12459
11269
  }
12460
11270
 
12461
11271
  // src/orchestration/recall-introspection.ts
@@ -12479,7 +11289,7 @@ var RecallIntrospectionCoordinator = class {
12479
11289
  }
12480
11290
  async getLastGraphRecallSnapshot(namespace) {
12481
11291
  const storage = await this.deps.getStorage(namespace);
12482
- const snapshotPath = path11.join(
11292
+ const snapshotPath = path10.join(
12483
11293
  storage.dir,
12484
11294
  "state",
12485
11295
  "last_graph_recall.json"
@@ -12518,7 +11328,7 @@ var RecallIntrospectionCoordinator = class {
12518
11328
  }
12519
11329
  async getLastIntentSnapshot(namespace) {
12520
11330
  const storage = await this.deps.getStorage(namespace);
12521
- const snapshotPath = path11.join(storage.dir, "state", "last_intent.json");
11331
+ const snapshotPath = path10.join(storage.dir, "state", "last_intent.json");
12522
11332
  try {
12523
11333
  const raw = await readFile4(snapshotPath, "utf-8");
12524
11334
  const parsed = JSON.parse(raw);
@@ -12551,7 +11361,7 @@ var RecallIntrospectionCoordinator = class {
12551
11361
  }
12552
11362
  async getLastQmdRecallSnapshot(namespace) {
12553
11363
  const storage = await this.deps.getStorage(namespace);
12554
- const snapshotPath = path11.join(
11364
+ const snapshotPath = path10.join(
12555
11365
  storage.dir,
12556
11366
  "state",
12557
11367
  "last_qmd_recall.json"
@@ -12841,12 +11651,12 @@ var RecallIntrospectionCoordinator = class {
12841
11651
  }
12842
11652
  async recordLastIntentSnapshot(options) {
12843
11653
  try {
12844
- const snapshotPath = path11.join(
11654
+ const snapshotPath = path10.join(
12845
11655
  options.storage.dir,
12846
11656
  "state",
12847
11657
  "last_intent.json"
12848
11658
  );
12849
- await mkdir5(path11.dirname(snapshotPath), { recursive: true });
11659
+ await mkdir5(path10.dirname(snapshotPath), { recursive: true });
12850
11660
  await writeFile5(
12851
11661
  snapshotPath,
12852
11662
  JSON.stringify(options.snapshot, null, 2),
@@ -12858,12 +11668,12 @@ var RecallIntrospectionCoordinator = class {
12858
11668
  }
12859
11669
  async recordLastQmdRecallSnapshot(options) {
12860
11670
  try {
12861
- const snapshotPath = path11.join(
11671
+ const snapshotPath = path10.join(
12862
11672
  options.storage.dir,
12863
11673
  "state",
12864
11674
  "last_qmd_recall.json"
12865
11675
  );
12866
- await mkdir5(path11.dirname(snapshotPath), { recursive: true });
11676
+ await mkdir5(path10.dirname(snapshotPath), { recursive: true });
12867
11677
  await writeFile5(
12868
11678
  snapshotPath,
12869
11679
  JSON.stringify(options.snapshot, null, 2),
@@ -12878,8 +11688,8 @@ var RecallIntrospectionCoordinator = class {
12878
11688
  const stateDir = await this.deps.resolveStateDirForNamespace(
12879
11689
  options.namespace
12880
11690
  );
12881
- const snapshotPath = path11.join(stateDir, "last_intent.json");
12882
- await mkdir5(path11.dirname(snapshotPath), { recursive: true });
11691
+ const snapshotPath = path10.join(stateDir, "last_intent.json");
11692
+ await mkdir5(path10.dirname(snapshotPath), { recursive: true });
12883
11693
  await writeFile5(
12884
11694
  snapshotPath,
12885
11695
  JSON.stringify(options.snapshot, null, 2),
@@ -12893,7 +11703,7 @@ var RecallIntrospectionCoordinator = class {
12893
11703
 
12894
11704
  // src/orchestration/orchestrator-init.ts
12895
11705
  import { readdir as readdir2, stat as stat2, unlink as unlink2 } from "fs/promises";
12896
- import path12 from "path";
11706
+ import path11 from "path";
12897
11707
  var OrchestratorInitCoordinator = class {
12898
11708
  constructor(deps) {
12899
11709
  this.deps = deps;
@@ -12989,7 +11799,7 @@ var OrchestratorInitCoordinator = class {
12989
11799
  const files = await readdir2(wsDir).catch(() => []);
12990
11800
  for (const f of files) {
12991
11801
  if (!f.startsWith(".compaction-reset-signal-")) continue;
12992
- const fp = path12.join(wsDir, f);
11802
+ const fp = path11.join(wsDir, f);
12993
11803
  const s = await stat2(fp).catch(() => null);
12994
11804
  if (s && Date.now() - s.mtimeMs >= COMPACTION_SIGNAL_MAX_AGE_MS) {
12995
11805
  await unlink2(fp).catch(() => {
@@ -13341,7 +12151,7 @@ var OrchestratorInitCoordinator = class {
13341
12151
  };
13342
12152
 
13343
12153
  // src/orchestration/persistence-index.ts
13344
- import path13 from "path";
12154
+ import path12 from "path";
13345
12155
  var PersistenceIndexCoordinator = class {
13346
12156
  constructor(deps) {
13347
12157
  this.deps = deps;
@@ -13527,7 +12337,7 @@ var PersistenceIndexCoordinator = class {
13527
12337
  const allMems = allMemsForGraph ?? [];
13528
12338
  for (const m of allMems) {
13529
12339
  if (m.frontmatter.entityRef === entityRef) {
13530
- const rel = path13.relative(storage.dir, m.path);
12340
+ const rel = path12.relative(storage.dir, m.path);
13531
12341
  if (rel !== memoryRelPath) entitySiblings.push(rel);
13532
12342
  }
13533
12343
  }
@@ -13676,7 +12486,7 @@ var PersistenceIndexCoordinator = class {
13676
12486
 
13677
12487
  // src/orchestration/workspace-ops.ts
13678
12488
  import { lstat, mkdir as mkdir6, readFile as readFile5, readdir as readdir3, realpath, writeFile as writeFile6 } from "fs/promises";
13679
- import path14 from "path";
12489
+ import path13 from "path";
13680
12490
 
13681
12491
  // src/maintenance/pattern-reinforcement.ts
13682
12492
  function patternReinforcementKey(content) {
@@ -15575,8 +14385,8 @@ var MeetingsService = class {
15575
14385
  // src/orchestration/workspace-ops.ts
15576
14386
  var MEETINGS_BUILD_DEBOUNCE_MS = 5e3;
15577
14387
  function matchesMemoryPath(candidatePath, requestedPath, memoryDir) {
15578
- const normalizedCandidate = path14.resolve(candidatePath);
15579
- return normalizedCandidate === path14.resolve(requestedPath) || normalizedCandidate === path14.resolve(memoryDir, requestedPath);
14388
+ const normalizedCandidate = path13.resolve(candidatePath);
14389
+ return normalizedCandidate === path13.resolve(requestedPath) || normalizedCandidate === path13.resolve(memoryDir, requestedPath);
15580
14390
  }
15581
14391
  function accessTrackingPathCandidates(storageDir, memoryPath) {
15582
14392
  const candidates = qmdResultPathCandidates(storageDir, memoryPath);
@@ -15584,12 +14394,12 @@ function accessTrackingPathCandidates(storageDir, memoryPath) {
15584
14394
  if (!parts) return candidates;
15585
14395
  candidates.push(
15586
14396
  ...qmdResultPathCandidates(storageDir, parts.relativePath),
15587
- ...qmdResultPathCandidates(path14.join(storageDir, "cold"), parts.relativePath)
14397
+ ...qmdResultPathCandidates(path13.join(storageDir, "cold"), parts.relativePath)
15588
14398
  );
15589
14399
  return [...new Set(candidates)];
15590
14400
  }
15591
14401
  function canonicalMemoryPath(memoryPath, memoryDir) {
15592
- return path14.resolve(path14.isAbsolute(memoryPath) ? memoryPath : path14.resolve(memoryDir, memoryPath));
14402
+ return path13.resolve(path13.isAbsolute(memoryPath) ? memoryPath : path13.resolve(memoryDir, memoryPath));
15593
14403
  }
15594
14404
  var WorkspaceOpsCoordinator = class {
15595
14405
  constructor(deps) {
@@ -15671,15 +14481,15 @@ var WorkspaceOpsCoordinator = class {
15671
14481
  this.deps.lastFileHygieneRunAtMs = now;
15672
14482
  if (hygiene.rotateEnabled) {
15673
14483
  for (const rel of hygiene.rotatePaths) {
15674
- const abs = path14.isAbsolute(rel) ? rel : path14.join(this.deps.config.workspaceDir, rel);
14484
+ const abs = path13.isAbsolute(rel) ? rel : path13.join(this.deps.config.workspaceDir, rel);
15675
14485
  try {
15676
14486
  const raw = await readFile5(abs, "utf-8");
15677
14487
  if (raw.length > hygiene.rotateMaxBytes) {
15678
- const archiveDir = path14.join(
14488
+ const archiveDir = path13.join(
15679
14489
  this.deps.config.workspaceDir,
15680
14490
  hygiene.archiveDir
15681
14491
  );
15682
- const base = path14.basename(abs);
14492
+ const base = path13.basename(abs);
15683
14493
  const prefix = base.toUpperCase().replace(/\.MD$/i, "").replace(/[^A-Z0-9]+/g, "-") || "FILE";
15684
14494
  const { newContent } = await rotateMarkdownFileToArchive({
15685
14495
  filePath: abs,
@@ -15704,8 +14514,8 @@ var WorkspaceOpsCoordinator = class {
15704
14514
  log.warn(w.message);
15705
14515
  }
15706
14516
  if (hygiene.warningsLogEnabled && warnings.length > 0) {
15707
- const fp = path14.join(this.deps.config.memoryDir, hygiene.warningsLogPath);
15708
- await mkdir6(path14.dirname(fp), { recursive: true });
14517
+ const fp = path13.join(this.deps.config.memoryDir, hygiene.warningsLogPath);
14518
+ await mkdir6(path13.dirname(fp), { recursive: true });
15709
14519
  const stamp = (/* @__PURE__ */ new Date()).toISOString();
15710
14520
  const block = `
15711
14521
 
@@ -15745,7 +14555,7 @@ var WorkspaceOpsCoordinator = class {
15745
14555
  for (const categoryDir of RECALL_FALLBACK_DIRS) {
15746
14556
  if (memoryRootReal === null) break;
15747
14557
  for (const date of datesToScan) {
15748
- const dateDir = path14.join(storage.dir, categoryDir, date);
14558
+ const dateDir = path13.join(storage.dir, categoryDir, date);
15749
14559
  try {
15750
14560
  const dirStat = await lstat(dateDir);
15751
14561
  if (dirStat.isSymbolicLink() || !dirStat.isDirectory()) continue;
@@ -15754,7 +14564,7 @@ var WorkspaceOpsCoordinator = class {
15754
14564
  for (const entry of entries) {
15755
14565
  if (entry.isSymbolicLink()) continue;
15756
14566
  if (!entry.name.endsWith(".md")) continue;
15757
- const fullPath = path14.join(dateDir, entry.name);
14567
+ const fullPath = path13.join(dateDir, entry.name);
15758
14568
  try {
15759
14569
  assertPathInsideRoot(memoryRootReal, await realpath(fullPath), fullPath);
15760
14570
  const raw = await readFile5(fullPath, "utf-8");
@@ -15776,7 +14586,7 @@ var WorkspaceOpsCoordinator = class {
15776
14586
  facts.push({
15777
14587
  path: fullPath,
15778
14588
  frontmatter: {
15779
- id: fm.id || path14.basename(entry.name, ".md"),
14589
+ id: fm.id || path13.basename(entry.name, ".md"),
15780
14590
  category: fm.category || "fact",
15781
14591
  created,
15782
14592
  updated: fm.updated || created,
@@ -15799,13 +14609,13 @@ var WorkspaceOpsCoordinator = class {
15799
14609
  return a.frontmatter.created < b.frontmatter.created ? -1 : 1;
15800
14610
  });
15801
14611
  const hourlySummaries = [];
15802
- const hourlyBaseDir = path14.join(storage.dir, "summaries", "hourly");
14612
+ const hourlyBaseDir = path13.join(storage.dir, "summaries", "hourly");
15803
14613
  try {
15804
14614
  const sessionKeys = await readdir3(hourlyBaseDir, { withFileTypes: true });
15805
14615
  for (const sk of sessionKeys) {
15806
14616
  if (!sk.isDirectory()) continue;
15807
14617
  for (const date of datesToScan) {
15808
- const summaryFile = path14.join(hourlyBaseDir, sk.name, `${date}.md`);
14618
+ const summaryFile = path13.join(hourlyBaseDir, sk.name, `${date}.md`);
15809
14619
  try {
15810
14620
  const raw = await readFile5(summaryFile, "utf-8");
15811
14621
  const filtered = filterHourlySummaryMarkdownForLocalDay(
@@ -16269,18 +15079,18 @@ ${reflectionsContent.trim()}
16269
15079
  // src/orchestration/namespace-read-fanout.ts
16270
15080
  import { existsSync, readFileSync } from "fs";
16271
15081
  import { stat as stat3 } from "fs/promises";
16272
- import path16 from "path";
15082
+ import path15 from "path";
16273
15083
 
16274
15084
  // src/orchestration/orchestrator-namespace-scope.ts
16275
- import path15 from "path";
15085
+ import path14 from "path";
16276
15086
  function computeSemanticDedupScope(targetStorage, config) {
16277
15087
  if (!resolveNamespaceCapabilities(config).namespaces) return {};
16278
- const memoryDir = path15.resolve(config.memoryDir);
16279
- const storageDir = path15.resolve(targetStorage.dir);
15088
+ const memoryDir = path14.resolve(config.memoryDir);
15089
+ const storageDir = path14.resolve(targetStorage.dir);
16280
15090
  if (storageDir === memoryDir) {
16281
15091
  return { pathExcludePrefixes: ["namespaces/"] };
16282
15092
  }
16283
- let rel = path15.relative(memoryDir, storageDir);
15093
+ let rel = path14.relative(memoryDir, storageDir);
16284
15094
  if (!rel || rel.startsWith("..")) {
16285
15095
  log.debug(
16286
15096
  `semantic dedup: target storage dir ${storageDir} is outside memoryDir ${memoryDir}; scoping lookup to absolute path prefix`
@@ -16333,7 +15143,7 @@ var NamespaceReadFanoutCoordinator = class {
16333
15143
  loadNamespaceStorageDirHintsFromCatalog() {
16334
15144
  if (this.deps.namespaceStorageDirHintsLoaded || !this.deps.namespaceCatalog.enabled) return;
16335
15145
  this.deps.namespaceStorageDirHintsLoaded = true;
16336
- const catalogPath = path16.join(this.deps.config.memoryDir, "state", "namespaces.jsonl");
15146
+ const catalogPath = path15.join(this.deps.config.memoryDir, "state", "namespaces.jsonl");
16337
15147
  if (!existsSync(catalogPath)) return;
16338
15148
  let body;
16339
15149
  try {
@@ -16370,7 +15180,7 @@ var NamespaceReadFanoutCoordinator = class {
16370
15180
  if (!this.deps.storageDirMatchesNamespaceHint(record.namespace, record.storageDir)) {
16371
15181
  continue;
16372
15182
  }
16373
- const resolvedStorageDir = path16.resolve(record.storageDir);
15183
+ const resolvedStorageDir = path15.resolve(record.storageDir);
16374
15184
  const current = preferredByStorageDir.get(resolvedStorageDir);
16375
15185
  preferredByStorageDir.set(
16376
15186
  resolvedStorageDir,
@@ -16551,12 +15361,12 @@ var NamespaceReadFanoutCoordinator = class {
16551
15361
  }
16552
15362
  async resolveStateDirForNamespace(namespace) {
16553
15363
  if (!resolveNamespaceCapabilities(this.deps.config).namespaces) {
16554
- return path16.join(this.deps.config.memoryDir, "state");
15364
+ return path15.join(this.deps.config.memoryDir, "state");
16555
15365
  }
16556
15366
  if (namespace !== this.deps.config.defaultNamespace) {
16557
- return path16.join(this.deps.config.memoryDir, "namespaces", namespace, "state");
15367
+ return path15.join(this.deps.config.memoryDir, "namespaces", namespace, "state");
16558
15368
  }
16559
- const candidate = path16.join(
15369
+ const candidate = path15.join(
16560
15370
  this.deps.config.memoryDir,
16561
15371
  "namespaces",
16562
15372
  this.deps.config.defaultNamespace
@@ -16564,11 +15374,11 @@ var NamespaceReadFanoutCoordinator = class {
16564
15374
  try {
16565
15375
  const candidateStat = await stat3(candidate);
16566
15376
  if (candidateStat.isDirectory()) {
16567
- return path16.join(candidate, "state");
15377
+ return path15.join(candidate, "state");
16568
15378
  }
16569
15379
  } catch {
16570
15380
  }
16571
- return path16.join(this.deps.config.memoryDir, "state");
15381
+ return path15.join(this.deps.config.memoryDir, "state");
16572
15382
  }
16573
15383
  namespaceFromPath(p) {
16574
15384
  if (!resolveNamespaceCapabilities(this.deps.config).namespaces) return this.deps.config.defaultNamespace;
@@ -16781,270 +15591,6 @@ var RecallEntryCoordinator = class {
16781
15591
  }
16782
15592
  };
16783
15593
 
16784
- // src/orchestration/session-context.ts
16785
- var SessionContextCoordinator = class {
16786
- constructor(deps) {
16787
- this.deps = deps;
16788
- }
16789
- deps;
16790
- /**
16791
- * Effective namespace a same-session LCM/structured-history READER must use
16792
- * to find what the access `observe` surface WROTE (#1495 thread 2).
16793
- *
16794
- * This MUST mirror the `observe` scope plan's write-namespace resolution, NOT
16795
- * `resolveSelfNamespace`: when no coding overlay applies, `observe` archives
16796
- * under `config.defaultNamespace` (an unqualified observed turn is NOT moved
16797
- * to the principal self namespace — identical to
16798
- * `resolveCodingScopedWriteNamespace`/`memory_store`, rule 39). Only when a
16799
- * coding overlay actually changes the namespace does the writer (and so the
16800
- * reader) use the overlaid `project-*` namespace. Returning the self base for
16801
- * the no-overlay case would prefix the read key with a namespace the writer
16802
- * never used, so the reader would miss its own evidence.
16803
- *
16804
- * Honours the access-surface `principalOverride` (#1505 thread 2, codex): when
16805
- * a recall supplies an authenticated principal NOT encoded in the raw
16806
- * `sessionKey`, `observe` archived LCM under THAT principal's base namespace.
16807
- * Deriving the base from `resolvePrincipal(sessionKey)` alone could fall back
16808
- * to `default`, so principal `alice` observing `sess-1` would write under
16809
- * `alice` but READ under `default`. Threading the override here keeps the read
16810
- * base identical to the write base.
16811
- *
16812
- * READ-AUTHORIZATION gate (#1505 round 3, codex P2 "Gate LCM recall keys by
16813
- * readable namespaces"): the overlay LCM read key is a `<principal>-project-*`
16814
- * sub-namespace of the principal SELF base. The normal recall namespace set
16815
- * below only substitutes the coding overlay when the principal SELF base is
16816
- * actually in the readable recall set (`recallNamespacesForPrincipal` — gated
16817
- * by `defaultRecallNamespaces.includes("self")` AND `canReadNamespace`). If a
16818
- * principal can WRITE but not READ its self namespace (or `defaultRecall-
16819
- * Namespaces` omits `self`), QMD/file recall never touches those overlay rows,
16820
- * so neither may the LCM read key. When the self base is NOT readable, fall
16821
- * back to the default store — exactly what an unqualified, unauthorized recall
16822
- * resolves to — rather than injecting overlay rows the rest of recall excludes
16823
- * (rule 42 read/write parity; rule 48 least-privilege).
16824
- */
16825
- lcmReadNamespaceForSession(sessionKey, principalOverride) {
16826
- const principal = typeof principalOverride === "string" && principalOverride.length > 0 ? principalOverride : this.deps.resolvePrincipal(sessionKey);
16827
- const base = defaultNamespaceForPrincipal(principal, this.deps.config);
16828
- const overlaid = this.deps.applyCodingNamespaceOverlay(sessionKey, base);
16829
- if (overlaid === base) return this.deps.config.defaultNamespace;
16830
- const selfReadableInRecall = recallNamespacesForPrincipal(
16831
- principal,
16832
- this.deps.config
16833
- ).includes(base);
16834
- return selfReadableInRecall ? overlaid : this.deps.config.defaultNamespace;
16835
- }
16836
- /**
16837
- * Attach a coding-agent context to a session (issue #569). Called by the
16838
- * Claude Code / Codex / Cursor connectors at session start after
16839
- * `resolveGitContext(cwd)`. The context is consulted by the recall path
16840
- * and the write path so that memories route to a project- (and optionally
16841
- * branch-) scoped namespace.
16842
- *
16843
- * Pass `null` to clear.
16844
- */
16845
- setCodingContextForSession(sessionKey, codingContext) {
16846
- if (typeof sessionKey !== "string" || sessionKey.length === 0) return;
16847
- this.deps.ensureSessionBindingMaps();
16848
- if (codingContext === null) {
16849
- this.deps._codingContextBySession.delete(sessionKey);
16850
- return;
16851
- }
16852
- this.deps._codingContextBySession.set(sessionKey, codingContext);
16853
- }
16854
- /**
16855
- * Read-only accessor for the coding context attached to a session. Returns
16856
- * `null` when none is set. Used by `remnic doctor` and by tests.
16857
- *
16858
- * Defensive `_codingContextBySession` lookup — legacy orchestrator-flush
16859
- * tests use `Object.create(Orchestrator.prototype)` which does not run
16860
- * class-field initializers, so the Map may be undefined on stubs.
16861
- */
16862
- getCodingContextForSession(sessionKey) {
16863
- if (typeof sessionKey !== "string" || sessionKey.length === 0) return null;
16864
- return this.deps._codingContextBySession?.get(sessionKey) ?? null;
16865
- }
16866
- /**
16867
- * Shared helper used by both the recall path and the write path (rule 42).
16868
- *
16869
- * Given a base namespace computed from the principal, returns the overlaid
16870
- * coding namespace when the session has a coding context AND
16871
- * `codingMode.projectScope` is true AND `namespacesEnabled` is true.
16872
- * Otherwise returns `baseNamespace` unchanged — CLAUDE.md #30 escape hatch.
16873
- *
16874
- * Principal isolation (CLAUDE.md rule 42): the overlay is COMBINED with
16875
- * the principal-derived `baseNamespace` rather than replacing it, so two
16876
- * principals working in the same repository do not share memories through
16877
- * a common `project-*` namespace.
16878
- *
16879
- * Namespaces-disabled gate: when `namespacesEnabled` is false, the
16880
- * storage router maps every namespace to the same `memoryDir`. Returning
16881
- * `project-*` in that mode would create apparent route separation with
16882
- * no actual storage isolation — a false-isolation trap. In that mode we
16883
- * return `baseNamespace` unchanged so coding mode degrades to the existing
16884
- * unscoped behavior.
16885
- *
16886
- * @internal
16887
- */
16888
- applyCodingNamespaceOverlay(sessionKey, baseNamespace) {
16889
- if (!resolveNamespaceCapabilities(this.deps.config).namespaces) return baseNamespace;
16890
- const codingContext = this.deps.getCodingContextForSession(sessionKey);
16891
- const overlay = resolveCodingNamespaceOverlay(codingContext, this.deps.config.codingMode, this.deps.config.defaultNamespace);
16892
- if (!overlay) return baseNamespace;
16893
- return combineNamespaces(baseNamespace, overlay.namespace);
16894
- }
16895
- /**
16896
- * Register a peer ID for a session so recall can inject the peer's
16897
- * profile into context (issue #679 PR 3/5). Pass `null` to clear.
16898
- *
16899
- * Connectors and the `before_agent_start` hook call this when the
16900
- * session's counter-party is known. The ID is validated against
16901
- * `PEER_ID_PATTERN` before storing.
16902
- *
16903
- * Fail-closed (Codex P1 review): an invalid peerId clears any
16904
- * previously registered mapping for the session rather than silently
16905
- * keeping stale data. This prevents a malformed metadata update from
16906
- * mixing one peer's profile context into another session.
16907
- *
16908
- * Defensive init (Cursor review + rule 16): `Object.create(
16909
- * Orchestrator.prototype)` stubs in legacy tests skip class-field
16910
- * initializers, so `_peerIdBySession` may be undefined. Mirror the
16911
- * same guard used by `setCodingContextForSession`.
16912
- */
16913
- setPeerIdForSession(sessionKey, peerId) {
16914
- if (typeof sessionKey !== "string" || sessionKey.length === 0) return;
16915
- this.deps.ensureSessionBindingMaps();
16916
- if (peerId === null) {
16917
- this.deps._peerIdBySession.delete(sessionKey);
16918
- return;
16919
- }
16920
- if (typeof peerId !== "string" || peerId.length === 0 || peerId.length > 64 || !/^[A-Za-z0-9]+(?:[._-][A-Za-z0-9]+)*$/.test(peerId)) {
16921
- log.warn(`setPeerIdForSession: invalid peerId \u2014 clearing session mapping`);
16922
- this.deps._peerIdBySession.delete(sessionKey);
16923
- return;
16924
- }
16925
- this.deps._peerIdBySession.set(sessionKey, peerId);
16926
- }
16927
- /**
16928
- * Return the peer ID registered for a session, or `null` when none
16929
- * is set. Used by `recallInternal` to inject the peer profile section.
16930
- * Defensive `_peerIdBySession` lookup — legacy orchestrator-flush tests
16931
- * use `Object.create(Orchestrator.prototype)` which skips class-field
16932
- * initializers, so the Map may be undefined on stubs.
16933
- */
16934
- getPeerIdForSession(sessionKey) {
16935
- if (typeof sessionKey !== "string" || sessionKey.length === 0) return null;
16936
- return this.deps._peerIdBySession?.get(sessionKey) ?? null;
16937
- }
16938
- async runDeepSleepGovernanceNow(options) {
16939
- const targetStorage = options?.storage ?? this.deps.storage;
16940
- const { runMemoryGovernance } = await import("./maintenance/memory-governance.js");
16941
- const { summarizeGovernanceResultForDreams } = await import("./dreams-ledger-567VKVOU.js");
16942
- const govResult = await runMemoryGovernance({
16943
- memoryDir: targetStorage.dir,
16944
- mode: options?.dryRun === true ? "shadow" : "apply"
16945
- });
16946
- if (options?.dryRun !== true) {
16947
- try {
16948
- await this.deps.entitySynthesisCoordinator.processQueue(
16949
- this.deps.storageDirNamespace(targetStorage.dir),
16950
- 5
16951
- );
16952
- } catch (error) {
16953
- log.debug(`deep-sleep governance: entity synthesis refresh failed after apply: ${error}`);
16954
- }
16955
- }
16956
- return summarizeGovernanceResultForDreams(govResult, options?.dryRun === true);
16957
- }
16958
- async generateDaySummary(memories) {
16959
- if (this.deps.initPromise) {
16960
- let initGateTimeoutHandle;
16961
- try {
16962
- await Promise.race([
16963
- this.deps.initPromise.catch(() => void 0),
16964
- new Promise((resolve) => {
16965
- initGateTimeoutHandle = setTimeout(
16966
- resolve,
16967
- this.deps.config.initGateTimeoutMs
16968
- );
16969
- })
16970
- ]);
16971
- } finally {
16972
- if (initGateTimeoutHandle) clearTimeout(initGateTimeoutHandle);
16973
- }
16974
- }
16975
- return this.deps.extraction.generateDaySummary(memories);
16976
- }
16977
- async flushSession(sessionKey, options) {
16978
- if (typeof this.deps.buffer.flushPendingSave === "function") {
16979
- await this.deps.buffer.flushPendingSave({ throwOnFailure: true });
16980
- }
16981
- const explicitBufferKey = typeof options.bufferKey === "string" && options.bufferKey.length > 0 ? options.bufferKey : null;
16982
- const discoveredBufferKeys = explicitBufferKey || typeof sessionKey !== "string" || sessionKey.length === 0 || typeof this.deps.buffer.findBufferKeysForSession !== "function" ? [] : await this.deps.buffer.findBufferKeysForSession(sessionKey);
16983
- const bufferKeys = explicitBufferKey ? [explicitBufferKey] : discoveredBufferKeys.length > 0 ? discoveredBufferKeys : typeof sessionKey === "string" && sessionKey.length > 0 ? [sessionKey] : ["default"];
16984
- for (const bufferKey of bufferKeys) {
16985
- const turns = this.deps.buffer.getTurns(bufferKey);
16986
- if (turns.length === 0) continue;
16987
- await new Promise((resolve, reject) => {
16988
- void this.deps.queueBufferedExtraction(turns, "trigger_mode", {
16989
- bufferKey,
16990
- clearBufferAfterExtraction: true,
16991
- skipDedupeCheck: true,
16992
- forceExtractionAttempt: true,
16993
- abortSignal: options.abortSignal,
16994
- onTaskSettled: (error) => error ? reject(error) : resolve()
16995
- }).catch(reject);
16996
- });
16997
- }
16998
- }
16999
- /** Lazily construct the CorrectionService for passive capture. Stateless
17000
- * across requests (per #1580 design); cached for the orchestrator's life. */
17001
- passiveCorrectionService() {
17002
- if (this.deps._passiveCorrectionService) return this.deps._passiveCorrectionService;
17003
- this.deps._passiveCorrectionService = createCorrectionService({
17004
- orchestrator: this.deps.orchestratorSelf,
17005
- // Session-scoped write ACL (review: "passive capture bypasses write
17006
- // ACL"). A correction detected in session S plans only against S readable
17007
- // namespaces and applies only to writable ones (rule 42) — passive
17008
- // capture never becomes a cross-tenant mutation vector. Mirrors the
17009
- // access-service createCorrectionService wiring rather than bypassing it.
17010
- resolveAuthorizedNamespace: async (req) => {
17011
- const principal = req.principal || resolvePrincipal(req.sessionKey, this.deps.config);
17012
- const ns = req.namespace ?? defaultNamespaceForPrincipal(principal, this.deps.config);
17013
- if (!canWriteNamespace(principal, ns, this.deps.config)) {
17014
- throw new Error(
17015
- `passive correction: namespace "${ns}" is not writable for principal ${principal ?? "(none)"}`
17016
- );
17017
- }
17018
- return ns;
17019
- },
17020
- resolveReadableNamespaces: (req) => {
17021
- const principal = req.principal || resolvePrincipal(req.sessionKey, this.deps.config);
17022
- return recallNamespacesForPrincipal(principal, this.deps.config);
17023
- },
17024
- canWriteNamespace: async (req) => {
17025
- const principal = req.principal || resolvePrincipal(req.sessionKey, this.deps.config);
17026
- return canWriteNamespace(principal, req.namespace, this.deps.config);
17027
- },
17028
- llmComplete: async ({ system, user }) => {
17029
- const llmResult = await this.deps.localLlm.chatCompletion(
17030
- [
17031
- { role: "system", content: system },
17032
- { role: "user", content: user }
17033
- ],
17034
- { operation: "correction-classify", priority: "background" }
17035
- );
17036
- if (!llmResult) {
17037
- throw new Error(
17038
- "passive correction classify+draft: local LLM unavailable (disabled or in cooldown)"
17039
- );
17040
- }
17041
- return llmResult.content;
17042
- }
17043
- });
17044
- return this.deps._passiveCorrectionService;
17045
- }
17046
- };
17047
-
17048
15594
  // src/orchestration/recall-background-writes.ts
17049
15595
  var pendingWritesByOwner = /* @__PURE__ */ new WeakMap();
17050
15596
  function trackRecallWrite(owner, promise, label) {
@@ -17611,7 +16157,7 @@ var Orchestrator = class {
17611
16157
  const defaultNs = normalizeNamespaceIdentity(this.config.defaultNamespace);
17612
16158
  if (ns !== defaultNs && !isSafeRouteNamespace(ns)) return;
17613
16159
  if (!this.storageDirMatchesNamespaceHint(ns, storageDir)) return;
17614
- const resolvedStorageDir = path17.resolve(storageDir);
16160
+ const resolvedStorageDir = path16.resolve(storageDir);
17615
16161
  let hints = this.namespaceStorageDirHints.get(resolvedStorageDir);
17616
16162
  if (!hints) {
17617
16163
  hints = /* @__PURE__ */ new Set();
@@ -17622,21 +16168,21 @@ var Orchestrator = class {
17622
16168
  storageDirMatchesNamespaceHint(namespace, storageDir) {
17623
16169
  const ns = normalizeNamespaceIdentity(namespace);
17624
16170
  if (!ns) return false;
17625
- const resolvedStorageDir = path17.resolve(storageDir);
17626
- const resolvedMemoryDir = path17.resolve(this.config.memoryDir);
16171
+ const resolvedStorageDir = path16.resolve(storageDir);
16172
+ const resolvedMemoryDir = path16.resolve(this.config.memoryDir);
17627
16173
  const defaultNs = normalizeNamespaceIdentity(this.config.defaultNamespace);
17628
16174
  if (resolvedStorageDir === resolvedMemoryDir) return ns === defaultNs;
17629
- const resolvedNamespacesDir = path17.join(resolvedMemoryDir, "namespaces");
16175
+ const resolvedNamespacesDir = path16.join(resolvedMemoryDir, "namespaces");
17630
16176
  if (!isPathInsideStorageRoot(resolvedNamespacesDir, resolvedStorageDir)) return false;
17631
- const rawRoot = path17.resolve(resolvedNamespacesDir, ns);
17632
- const tokenRoot = path17.resolve(resolvedNamespacesDir, namespaceIdentityToken(ns));
16177
+ const rawRoot = path16.resolve(resolvedNamespacesDir, ns);
16178
+ const tokenRoot = path16.resolve(resolvedNamespacesDir, namespaceIdentityToken(ns));
17633
16179
  return resolvedStorageDir === rawRoot || resolvedStorageDir === tokenRoot;
17634
16180
  }
17635
16181
  namespaceStorageDirHintOwnershipRank(record, resolvedStorageDir, configured) {
17636
- if (resolvedStorageDir === path17.resolve(this.config.memoryDir)) {
16182
+ if (resolvedStorageDir === path16.resolve(this.config.memoryDir)) {
17637
16183
  return record.namespace === normalizeNamespaceIdentity(this.config.defaultNamespace) ? 0 : 3;
17638
16184
  }
17639
- const leaf = path17.basename(resolvedStorageDir);
16185
+ const leaf = path16.basename(resolvedStorageDir);
17640
16186
  const tokenOwnsRoot = namespaceIdentityToken(record.namespace) === leaf;
17641
16187
  if (tokenOwnsRoot && configured.has(record.namespace)) return 0;
17642
16188
  if (record.namespace === leaf) return 1;
@@ -17772,7 +16318,7 @@ var Orchestrator = class {
17772
16318
  StorageManager.setScopedCacheInvalidationDefault(config.memoryDir, scopedCacheInvalidationEnabled);
17773
16319
  this.profiler = new ProfilingCollector({
17774
16320
  enabled: resolvePipelineProcessingCapabilities(this.config).profiling,
17775
- storageDir: config.profilingStorageDir || path17.join(config.memoryDir, "profiling"),
16321
+ storageDir: config.profilingStorageDir || path16.join(config.memoryDir, "profiling"),
17776
16322
  maxTraces: config.profilingMaxTraces
17777
16323
  });
17778
16324
  this.namespaceCatalog = new NamespaceCatalog(config);
@@ -17859,7 +16405,7 @@ var Orchestrator = class {
17859
16405
  this.compounding = resolveConsolidationCapabilities(config).compounding ? new CompoundingEngine(config, this.storage) : void 0;
17860
16406
  this.buffer = new SmartBuffer(config, this.storage);
17861
16407
  this.transcript = new TranscriptManager(config);
17862
- this.conversationIndexDir = path17.join(
16408
+ this.conversationIndexDir = path16.join(
17863
16409
  config.memoryDir,
17864
16410
  "conversation-index",
17865
16411
  "chunks"
@@ -18006,7 +16552,7 @@ var Orchestrator = class {
18006
16552
  saveContentHashIndexes: () => this.saveContentHashIndexes()
18007
16553
  });
18008
16554
  this.threading = new ThreadingManager(
18009
- path17.join(config.memoryDir, "threads"),
16555
+ path16.join(config.memoryDir, "threads"),
18010
16556
  config.threadingGapMinutes
18011
16557
  );
18012
16558
  const lifecycleCaps = resolveMemoryLifecycleCapabilities(config);
@@ -18086,7 +16632,7 @@ var Orchestrator = class {
18086
16632
  utilityPromoteThresholdDelta: this.utilityRuntimeValues?.promoteThresholdDelta ?? 0,
18087
16633
  utilityDemoteThresholdDelta: this.utilityRuntimeValues?.demoteThresholdDelta ?? 0
18088
16634
  };
18089
- return createHash8("sha256").update(JSON.stringify(payload)).digest("hex").slice(0, 12);
16635
+ return createHash6("sha256").update(JSON.stringify(payload)).digest("hex").slice(0, 12);
18090
16636
  }
18091
16637
  effectiveLifecycleThresholds() {
18092
16638
  const archiveDecayThreshold = this.config.lifecycleArchiveDecayThreshold;
@@ -20112,9 +18658,9 @@ function readStructuralSymbol(entry) {
20112
18658
  const rec = entry;
20113
18659
  const symbol = typeof rec.symbol === "string" ? rec.symbol.trim() : "";
20114
18660
  if (!symbol) return null;
20115
- const path32 = typeof rec.path === "string" && rec.path.length > 0 ? rec.path : void 0;
18661
+ const path31 = typeof rec.path === "string" && rec.path.length > 0 ? rec.path : void 0;
20116
18662
  const kind = typeof rec.kind === "string" && rec.kind.length > 0 ? rec.kind : void 0;
20117
- const item = path32 !== void 0 && kind !== void 0 ? { symbol, path: path32, kind } : path32 !== void 0 ? { symbol, path: path32 } : kind !== void 0 ? { symbol, kind } : { symbol };
18663
+ const item = path31 !== void 0 && kind !== void 0 ? { symbol, path: path31, kind } : path31 !== void 0 ? { symbol, path: path31 } : kind !== void 0 ? { symbol, kind } : { symbol };
20118
18664
  return item;
20119
18665
  }
20120
18666
  function classifySpawnError(err) {
@@ -20188,7 +18734,7 @@ var DEFAULT_GRACE_PERIOD_DAYS = 7;
20188
18734
 
20189
18735
  // src/binary-lifecycle/backend.ts
20190
18736
  import fsp from "fs/promises";
20191
- import path18 from "path";
18737
+ import path17 from "path";
20192
18738
  var FilesystemBackend = class {
20193
18739
  type = "filesystem";
20194
18740
  basePath;
@@ -20196,19 +18742,19 @@ var FilesystemBackend = class {
20196
18742
  if (!basePath || basePath.trim().length === 0) {
20197
18743
  throw new Error("FilesystemBackend requires a non-empty basePath");
20198
18744
  }
20199
- this.basePath = path18.resolve(basePath);
18745
+ this.basePath = path17.resolve(basePath);
20200
18746
  }
20201
18747
  resolveRemotePath(remotePath) {
20202
- const resolved = path18.isAbsolute(remotePath) ? path18.resolve(remotePath) : path18.resolve(this.basePath, remotePath);
20203
- const relative = path18.relative(this.basePath, resolved);
20204
- if (relative === ".." || relative.startsWith(`..${path18.sep}`) || path18.isAbsolute(relative)) {
18748
+ const resolved = path17.isAbsolute(remotePath) ? path17.resolve(remotePath) : path17.resolve(this.basePath, remotePath);
18749
+ const relative = path17.relative(this.basePath, resolved);
18750
+ if (relative === ".." || relative.startsWith(`..${path17.sep}`) || path17.isAbsolute(relative)) {
20205
18751
  throw new Error(`FilesystemBackend remotePath escapes basePath: ${JSON.stringify(remotePath)}`);
20206
18752
  }
20207
18753
  return resolved;
20208
18754
  }
20209
18755
  isInsideBase(candidate, realBase) {
20210
- const relative = path18.relative(realBase, candidate);
20211
- return relative === "" || relative !== ".." && !relative.startsWith(`..${path18.sep}`) && !path18.isAbsolute(relative);
18756
+ const relative = path17.relative(realBase, candidate);
18757
+ return relative === "" || relative !== ".." && !relative.startsWith(`..${path17.sep}`) && !path17.isAbsolute(relative);
20212
18758
  }
20213
18759
  async realBasePathIfExists() {
20214
18760
  try {
@@ -20237,13 +18783,13 @@ var FilesystemBackend = class {
20237
18783
  }
20238
18784
  async ensureSafeParentDirectory(dest) {
20239
18785
  const realBase = await this.ensureBaseDirectory();
20240
- const destDir = path18.dirname(dest);
20241
- const relativeDir = path18.relative(this.basePath, destDir);
20242
- const segments = relativeDir === "" ? [] : relativeDir.split(path18.sep);
18786
+ const destDir = path17.dirname(dest);
18787
+ const relativeDir = path17.relative(this.basePath, destDir);
18788
+ const segments = relativeDir === "" ? [] : relativeDir.split(path17.sep);
20243
18789
  let current = this.basePath;
20244
18790
  for (const segment of segments) {
20245
18791
  if (segment === "." || segment === "") continue;
20246
- current = path18.join(current, segment);
18792
+ current = path17.join(current, segment);
20247
18793
  try {
20248
18794
  const stat5 = await fsp.lstat(current);
20249
18795
  if (stat5.isSymbolicLink()) {
@@ -20271,13 +18817,13 @@ var FilesystemBackend = class {
20271
18817
  if (realBase === null) {
20272
18818
  return null;
20273
18819
  }
20274
- const destDir = path18.dirname(dest);
20275
- const relativeDir = path18.relative(this.basePath, destDir);
20276
- const segments = relativeDir === "" ? [] : relativeDir.split(path18.sep);
18820
+ const destDir = path17.dirname(dest);
18821
+ const relativeDir = path17.relative(this.basePath, destDir);
18822
+ const segments = relativeDir === "" ? [] : relativeDir.split(path17.sep);
20277
18823
  let current = this.basePath;
20278
18824
  for (const segment of segments) {
20279
18825
  if (segment === "." || segment === "") continue;
20280
- current = path18.join(current, segment);
18826
+ current = path17.join(current, segment);
20281
18827
  let stat5;
20282
18828
  try {
20283
18829
  stat5 = await fsp.lstat(current);
@@ -20325,7 +18871,7 @@ var FilesystemBackend = class {
20325
18871
  return dest;
20326
18872
  }
20327
18873
  async upload(localPath, remotePath) {
20328
- if (path18.isAbsolute(remotePath)) {
18874
+ if (path17.isAbsolute(remotePath)) {
20329
18875
  throw new Error(`FilesystemBackend upload remotePath must be relative: ${JSON.stringify(remotePath)}`);
20330
18876
  }
20331
18877
  const dest = this.resolveRemotePath(remotePath);
@@ -20398,7 +18944,7 @@ function createBackend(cfg) {
20398
18944
 
20399
18945
  // src/binary-lifecycle/scanner.ts
20400
18946
  import fsp2 from "fs/promises";
20401
- import path19 from "path";
18947
+ import path18 from "path";
20402
18948
  import crypto from "crypto";
20403
18949
  function matchesPatterns(filename, patterns) {
20404
18950
  const lower = filename.toLowerCase();
@@ -20423,8 +18969,8 @@ async function scanForBinaries(memoryDir, config, manifest) {
20423
18969
  return;
20424
18970
  }
20425
18971
  for (const entry of entries) {
20426
- const fullPath = path19.join(dir, entry.name);
20427
- const relativePath = path19.relative(memoryDir, fullPath).split(path19.sep).join("/");
18972
+ const fullPath = path18.join(dir, entry.name);
18973
+ const relativePath = path18.relative(memoryDir, fullPath).split(path18.sep).join("/");
20428
18974
  if (entry.isDirectory()) {
20429
18975
  if (entry.name === ".binary-lifecycle") continue;
20430
18976
  await walk(fullPath);
@@ -20464,15 +19010,15 @@ async function hashFile(filePath) {
20464
19010
 
20465
19011
  // src/binary-lifecycle/manifest.ts
20466
19012
  import fsp3 from "fs/promises";
20467
- import path20 from "path";
19013
+ import path19 from "path";
20468
19014
  import crypto2 from "crypto";
20469
19015
  var MANIFEST_DIR = ".binary-lifecycle";
20470
19016
  var MANIFEST_FILE = "manifest.json";
20471
19017
  function manifestDir(memoryDir) {
20472
- return path20.join(memoryDir, MANIFEST_DIR);
19018
+ return path19.join(memoryDir, MANIFEST_DIR);
20473
19019
  }
20474
19020
  function manifestPath(memoryDir) {
20475
- return path20.join(memoryDir, MANIFEST_DIR, MANIFEST_FILE);
19021
+ return path19.join(memoryDir, MANIFEST_DIR, MANIFEST_FILE);
20476
19022
  }
20477
19023
  async function readManifest(memoryDir) {
20478
19024
  const filePath = manifestPath(memoryDir);
@@ -20524,12 +19070,12 @@ function emptyManifest() {
20524
19070
 
20525
19071
  // src/binary-lifecycle/pipeline.ts
20526
19072
  import fsp4 from "fs/promises";
20527
- import path21 from "path";
19073
+ import path20 from "path";
20528
19074
  import crypto3 from "crypto";
20529
19075
  function isRecallCorpusMarkdown(mdPath, memoryDir) {
20530
- const rel = path21.relative(memoryDir, mdPath);
20531
- if (rel.startsWith("..") || path21.isAbsolute(rel)) return false;
20532
- const top = rel.split(path21.sep)[0];
19076
+ const rel = path20.relative(memoryDir, mdPath);
19077
+ if (rel.startsWith("..") || path20.isAbsolute(rel)) return false;
19078
+ const top = rel.split(path20.sep)[0];
20533
19079
  return RECALL_FALLBACK_DIRS.includes(top);
20534
19080
  }
20535
19081
  async function hashFile2(filePath) {
@@ -20553,13 +19099,13 @@ function escapeRegex(s) {
20553
19099
  return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
20554
19100
  }
20555
19101
  function resolveManifestAssetPath(memoryDir, originalPath) {
20556
- if (originalPath.length === 0 || originalPath.includes("\0") || originalPath.includes("\\") || path21.isAbsolute(originalPath) || path21.win32.isAbsolute(originalPath)) {
19102
+ if (originalPath.length === 0 || originalPath.includes("\0") || originalPath.includes("\\") || path20.isAbsolute(originalPath) || path20.win32.isAbsolute(originalPath)) {
20557
19103
  return null;
20558
19104
  }
20559
- const memoryRoot = path21.resolve(memoryDir);
20560
- const fullPath = path21.resolve(memoryRoot, originalPath);
20561
- const relative = path21.relative(memoryRoot, fullPath);
20562
- if (relative === "" || relative === ".." || relative.startsWith(`..${path21.sep}`) || path21.isAbsolute(relative)) {
19105
+ const memoryRoot = path20.resolve(memoryDir);
19106
+ const fullPath = path20.resolve(memoryRoot, originalPath);
19107
+ const relative = path20.relative(memoryRoot, fullPath);
19108
+ if (relative === "" || relative === ".." || relative.startsWith(`..${path20.sep}`) || path20.isAbsolute(relative)) {
20563
19109
  return null;
20564
19110
  }
20565
19111
  return fullPath;
@@ -20570,7 +19116,7 @@ function validateBinaryLifecycleConfig(config) {
20570
19116
  }
20571
19117
  }
20572
19118
  function remotePathForAsset(backend, relPath) {
20573
- const normalized = relPath.split(path21.sep).join("/");
19119
+ const normalized = relPath.split(path20.sep).join("/");
20574
19120
  if (backend.type === "filesystem") {
20575
19121
  return `.binary-lifecycle/mirrors/${normalized}`;
20576
19122
  }
@@ -20583,11 +19129,11 @@ async function stageMirror(memoryDir, newPaths, backend, assets, log2, dryRun) {
20583
19129
  let mirrored = 0;
20584
19130
  const errors = [];
20585
19131
  for (const relPath of newPaths) {
20586
- const fullPath = path21.join(memoryDir, relPath);
19132
+ const fullPath = path20.join(memoryDir, relPath);
20587
19133
  try {
20588
19134
  const stat5 = await fsp4.stat(fullPath);
20589
19135
  const contentHash = await hashFile2(fullPath);
20590
- const ext = path21.extname(relPath);
19136
+ const ext = path20.extname(relPath);
20591
19137
  const mimeType = guessMimeType(ext);
20592
19138
  const remotePath = remotePathForAsset(backend, relPath);
20593
19139
  let backendLocation = remotePath;
@@ -20790,10 +19336,10 @@ async function countRemainingLocalReferences(memoryDir, asset, assetAbsolute, md
20790
19336
  return { remaining, errors };
20791
19337
  }
20792
19338
  function markdownReferencePattern(asset, assetAbsolute, mdPath) {
20793
- const mdDir = path21.dirname(mdPath);
19339
+ const mdDir = path20.dirname(mdPath);
20794
19340
  const candidates = /* @__PURE__ */ new Set();
20795
19341
  const addCandidate = (candidate) => {
20796
- const normalized = candidate.split(path21.sep).join("/");
19342
+ const normalized = candidate.split(path20.sep).join("/");
20797
19343
  if (normalized.length === 0) return;
20798
19344
  candidates.add(normalized);
20799
19345
  const isParentTraversal = normalized === ".." || normalized.startsWith("../");
@@ -20801,10 +19347,10 @@ function markdownReferencePattern(asset, assetAbsolute, mdPath) {
20801
19347
  candidates.add(`./${normalized}`);
20802
19348
  }
20803
19349
  };
20804
- addCandidate(path21.relative(mdDir, assetAbsolute));
20805
- const originalPath = asset.originalPath.split(path21.sep).join("/");
20806
- const originalAsFileRelative = path21.resolve(mdDir, ...originalPath.split("/"));
20807
- if (path21.resolve(originalAsFileRelative) === path21.resolve(assetAbsolute)) {
19350
+ addCandidate(path20.relative(mdDir, assetAbsolute));
19351
+ const originalPath = asset.originalPath.split(path20.sep).join("/");
19352
+ const originalAsFileRelative = path20.resolve(mdDir, ...originalPath.split("/"));
19353
+ if (path20.resolve(originalAsFileRelative) === path20.resolve(assetAbsolute)) {
20808
19354
  addCandidate(originalPath);
20809
19355
  }
20810
19356
  addCandidate(`/${originalPath}`);
@@ -20900,7 +19446,7 @@ async function findMarkdownFiles(dir) {
20900
19446
  return;
20901
19447
  }
20902
19448
  for (const entry of entries) {
20903
- const full = path21.join(current, entry.name);
19449
+ const full = path20.join(current, entry.name);
20904
19450
  if (entry.isDirectory()) {
20905
19451
  if (entry.name === ".binary-lifecycle") continue;
20906
19452
  await walk(full);
@@ -20975,7 +19521,7 @@ async function runBinaryLifecyclePipeline(memoryDir, config, backend, log2, opts
20975
19521
 
20976
19522
  // src/projection/index.ts
20977
19523
  import fs from "fs";
20978
- import path22 from "path";
19524
+ import path21 from "path";
20979
19525
  var VALID_PROJECTION_CATEGORIES = new Set(ALL_CATEGORY_KEYS);
20980
19526
  async function generateContextTree(options) {
20981
19527
  const startTime = Date.now();
@@ -20990,8 +19536,8 @@ async function generateContextTree(options) {
20990
19536
  let nodesGenerated = 0;
20991
19537
  let nodesSkipped = 0;
20992
19538
  const categoryCounts = {};
20993
- const resolvedMemoryDir = path22.resolve(memoryDir);
20994
- const resolvedOutputDir = path22.resolve(outputDir);
19539
+ const resolvedMemoryDir = path21.resolve(memoryDir);
19540
+ const resolvedOutputDir = path21.resolve(outputDir);
20995
19541
  const requestedCategories = validateProjectionCategories(filterCategories);
20996
19542
  const realMemoryDir = assertSafeMemoryRoot(resolvedMemoryDir);
20997
19543
  assertNotSymlink(resolvedOutputDir, "context tree outputDir");
@@ -21029,7 +19575,7 @@ async function generateContextTree(options) {
21029
19575
  }
21030
19576
  }
21031
19577
  if (includeEntities) {
21032
- const entitiesDir = path22.join(memoryDir, "entities");
19578
+ const entitiesDir = path21.join(memoryDir, "entities");
21033
19579
  if (fs.existsSync(entitiesDir)) {
21034
19580
  assertSafeInputRoot(realMemoryDir, entitiesDir, "entities root");
21035
19581
  categoryCounts["entity"] = 0;
@@ -21041,7 +19587,7 @@ async function generateContextTree(options) {
21041
19587
  continue;
21042
19588
  }
21043
19589
  const content = fs.readFileSync(filePath, "utf8");
21044
- const fileName = path22.basename(filePath, ".md");
19590
+ const fileName = path21.basename(filePath, ".md");
21045
19591
  const node = projectEntityNode(fileName, content);
21046
19592
  const outputPath = resolveContainedOutputPath(realOutputDir, "entities", `${fileName}.md`);
21047
19593
  writeProjectedContent(realOutputDir, outputPath, node.content);
@@ -21053,7 +19599,7 @@ async function generateContextTree(options) {
21053
19599
  }
21054
19600
  const shouldIncludeQuestions = includeQuestions && (requestedCategories === void 0 || requestedCategories.includes("question"));
21055
19601
  if (shouldIncludeQuestions) {
21056
- const questionsDir = path22.join(memoryDir, "questions");
19602
+ const questionsDir = path21.join(memoryDir, "questions");
21057
19603
  if (fs.existsSync(questionsDir)) {
21058
19604
  assertSafeInputRoot(realMemoryDir, questionsDir, "questions root");
21059
19605
  categoryCounts["question"] = 0;
@@ -21094,8 +19640,8 @@ async function generateContextTree(options) {
21094
19640
  };
21095
19641
  }
21096
19642
  function isPathInside(root, candidate) {
21097
- const relative = path22.relative(root, candidate);
21098
- return relative === "" || !relative.startsWith("..") && !path22.isAbsolute(relative);
19643
+ const relative = path21.relative(root, candidate);
19644
+ return relative === "" || !relative.startsWith("..") && !path21.isAbsolute(relative);
21099
19645
  }
21100
19646
  function assertNotSymlink(targetPath, label) {
21101
19647
  try {
@@ -21132,12 +19678,12 @@ function assertSafeInputRoot(realMemoryDir, targetPath, label) {
21132
19678
  }
21133
19679
  function assertSafeOutputTarget(realOutputDir, outputPath) {
21134
19680
  let current = realOutputDir;
21135
- const relative = path22.relative(realOutputDir, outputPath);
21136
- if (relative.startsWith("..") || path22.isAbsolute(relative)) {
19681
+ const relative = path21.relative(realOutputDir, outputPath);
19682
+ if (relative.startsWith("..") || path21.isAbsolute(relative)) {
21137
19683
  throw new Error(`context tree output path escapes outputDir: ${outputPath}`);
21138
19684
  }
21139
- for (const segment of relative.split(path22.sep).filter(Boolean)) {
21140
- current = path22.join(current, segment);
19685
+ for (const segment of relative.split(path21.sep).filter(Boolean)) {
19686
+ current = path21.join(current, segment);
21141
19687
  try {
21142
19688
  const stat5 = fs.lstatSync(current);
21143
19689
  if (stat5.isSymbolicLink()) {
@@ -21167,17 +19713,17 @@ function validateProjectionCategories(categories) {
21167
19713
  return validated;
21168
19714
  }
21169
19715
  function resolveContainedOutputPath(outputRoot, ...segments) {
21170
- const resolved = path22.resolve(outputRoot, ...segments);
21171
- const relative = path22.relative(outputRoot, resolved);
21172
- if (relative === "" || !relative.startsWith("..") && !path22.isAbsolute(relative)) {
19716
+ const resolved = path21.resolve(outputRoot, ...segments);
19717
+ const relative = path21.relative(outputRoot, resolved);
19718
+ if (relative === "" || !relative.startsWith("..") && !path21.isAbsolute(relative)) {
21173
19719
  return resolved;
21174
19720
  }
21175
19721
  throw new Error(`context tree output path escapes outputDir: ${segments.join("/")}`);
21176
19722
  }
21177
19723
  function writeProjectedContent(realOutputDir, outputPath, generatedContent) {
21178
19724
  assertSafeOutputTarget(realOutputDir, outputPath);
21179
- fs.mkdirSync(path22.dirname(outputPath), { recursive: true });
21180
- const realParent = fs.realpathSync(path22.dirname(outputPath));
19725
+ fs.mkdirSync(path21.dirname(outputPath), { recursive: true });
19726
+ const realParent = fs.realpathSync(path21.dirname(outputPath));
21181
19727
  if (!isPathInside(realOutputDir, realParent)) {
21182
19728
  throw new Error(`context tree output path escapes outputDir: ${outputPath}`);
21183
19729
  }
@@ -21216,7 +19762,7 @@ function walkR(dir, realMemoryDir) {
21216
19762
  const results = [];
21217
19763
  function walk(directory) {
21218
19764
  for (const entry of fs.readdirSync(directory, { withFileTypes: true })) {
21219
- const fullPath = path22.join(directory, entry.name);
19765
+ const fullPath = path21.join(directory, entry.name);
21220
19766
  if (entry.isSymbolicLink()) {
21221
19767
  throw new Error(`context tree input path contains symlink: ${fullPath}`);
21222
19768
  }
@@ -21269,13 +19815,13 @@ function extractBody(content) {
21269
19815
  }
21270
19816
  function projectNode(filePath, category, fm, rawContent) {
21271
19817
  const body = extractBody(rawContent);
21272
- const fileName = path22.basename(filePath, ".md");
21273
- const dateDir = path22.basename(path22.dirname(filePath));
19818
+ const fileName = path21.basename(filePath, ".md");
19819
+ const dateDir = path21.basename(path21.dirname(filePath));
21274
19820
  let relPath;
21275
19821
  if (/^\d{4}-\d{2}-\d{2}$/.test(dateDir)) {
21276
- relPath = path22.join(category, dateDir, `${fileName}.md`);
19822
+ relPath = path21.join(category, dateDir, `${fileName}.md`);
21277
19823
  } else {
21278
- relPath = path22.join(category, `${fileName}.md`);
19824
+ relPath = path21.join(category, `${fileName}.md`);
21279
19825
  }
21280
19826
  const generatedAt = (/* @__PURE__ */ new Date()).toISOString();
21281
19827
  const md = `# ${fm.id}
@@ -21321,7 +19867,7 @@ function projectEntityNode(fileName, content) {
21321
19867
  ${content}
21322
19868
  `;
21323
19869
  return {
21324
- path: path22.join("entities", `${fileName}.md`),
19870
+ path: path21.join("entities", `${fileName}.md`),
21325
19871
  category: "entity",
21326
19872
  title: fileName,
21327
19873
  content: md,
@@ -21374,7 +19920,7 @@ function generateIndex(categoryCounts, outputDir) {
21374
19920
 
21375
19921
  // src/onboarding/index.ts
21376
19922
  import fs2 from "fs";
21377
- import path23 from "path";
19923
+ import path22 from "path";
21378
19924
  var LANGUAGE_RULES = [
21379
19925
  {
21380
19926
  language: "TypeScript",
@@ -21476,7 +20022,7 @@ function onboard(options) {
21476
20022
  maxDepth = 6,
21477
20023
  excludeDirs = []
21478
20024
  } = options;
21479
- const directory = path23.resolve(options.directory ?? process.cwd());
20025
+ const directory = path22.resolve(options.directory ?? process.cwd());
21480
20026
  let rootStat;
21481
20027
  try {
21482
20028
  rootStat = fs2.statSync(directory);
@@ -21518,7 +20064,7 @@ function walkDir(root, exclude, maxDepth) {
21518
20064
  }
21519
20065
  for (const entry of entries) {
21520
20066
  if (exclude.has(entry.name)) continue;
21521
- const fullPath = path23.join(dir, entry.name);
20067
+ const fullPath = path22.join(dir, entry.name);
21522
20068
  if (entry.isDirectory()) {
21523
20069
  walk(fullPath, depth + 1);
21524
20070
  } else if (entry.isFile()) {
@@ -21533,11 +20079,11 @@ function detectLanguages(files, root) {
21533
20079
  const results = [];
21534
20080
  const extCounts = /* @__PURE__ */ new Map();
21535
20081
  for (const f of files) {
21536
- const ext = path23.extname(f).toLowerCase();
20082
+ const ext = path22.extname(f).toLowerCase();
21537
20083
  if (ext) extCounts.set(ext, (extCounts.get(ext) ?? 0) + 1);
21538
20084
  }
21539
20085
  const rootFiles = new Set(
21540
- files.filter((f) => path23.dirname(f) === root).map((f) => path23.basename(f))
20086
+ files.filter((f) => path22.dirname(f) === root).map((f) => path22.basename(f))
21541
20087
  );
21542
20088
  for (const rule of LANGUAGE_RULES) {
21543
20089
  const evidence = [];
@@ -21581,7 +20127,7 @@ function detectLanguages(files, root) {
21581
20127
  }
21582
20128
  function detectShape(files, root) {
21583
20129
  const rootFiles = new Set(
21584
- files.filter((f) => path23.dirname(f) === root).map((f) => path23.basename(f))
20130
+ files.filter((f) => path22.dirname(f) === root).map((f) => path22.basename(f))
21585
20131
  );
21586
20132
  const rootDirs = /* @__PURE__ */ new Set();
21587
20133
  try {
@@ -21592,7 +20138,7 @@ function detectShape(files, root) {
21592
20138
  }
21593
20139
  const evidence = [];
21594
20140
  if (rootFiles.has("package.json")) {
21595
- const pkg = readJsonSafe(path23.join(root, "package.json"));
20141
+ const pkg = readJsonSafe(path22.join(root, "package.json"));
21596
20142
  if (pkg?.workspaces) {
21597
20143
  evidence.push("package.json has workspaces");
21598
20144
  return { shape: "monorepo", evidence };
@@ -21606,13 +20152,13 @@ function detectShape(files, root) {
21606
20152
  evidence.push("workspace manifest found");
21607
20153
  return { shape: "workspace", evidence };
21608
20154
  }
21609
- const cargoToml = readTomlWorkspace(path23.join(root, "Cargo.toml"));
20155
+ const cargoToml = readTomlWorkspace(path22.join(root, "Cargo.toml"));
21610
20156
  if (cargoToml) {
21611
20157
  evidence.push("Cargo.toml has workspace");
21612
20158
  return { shape: "workspace", evidence };
21613
20159
  }
21614
20160
  if (rootFiles.has("package.json")) {
21615
- const pkg = readJsonSafe(path23.join(root, "package.json"));
20161
+ const pkg = readJsonSafe(path22.join(root, "package.json"));
21616
20162
  if (pkg?.exports || pkg?.main) {
21617
20163
  if (pkg?.bin) {
21618
20164
  evidence.push("package.json has bin");
@@ -21646,8 +20192,8 @@ function discoverDocs(files, root) {
21646
20192
  { pattern: /^\.editorconfig$/i, kind: "config" }
21647
20193
  ];
21648
20194
  for (const filePath of files) {
21649
- const basename = path23.basename(filePath).toLowerCase();
21650
- const relPath = path23.relative(root, filePath);
20195
+ const basename = path22.basename(filePath).toLowerCase();
20196
+ const relPath = path22.relative(root, filePath);
21651
20197
  let kind;
21652
20198
  for (const { pattern, kind: k } of docPatterns) {
21653
20199
  if (pattern.test(basename)) {
@@ -21659,7 +20205,7 @@ function discoverDocs(files, root) {
21659
20205
  kind = "docs";
21660
20206
  }
21661
20207
  if (!kind && (basename.endsWith(".md") || basename.endsWith(".mdx"))) {
21662
- if (path23.dirname(relPath) === "." || isUnderDocsDir(relPath)) {
20208
+ if (path22.dirname(relPath) === "." || isUnderDocsDir(relPath)) {
21663
20209
  kind = "docs";
21664
20210
  }
21665
20211
  }
@@ -21680,7 +20226,7 @@ function discoverDocs(files, root) {
21680
20226
  return docs;
21681
20227
  }
21682
20228
  function isUnderDocsDir(relPath) {
21683
- const parts = relPath.split(path23.sep);
20229
+ const parts = relPath.split(path22.sep);
21684
20230
  return parts[0] === "docs" || parts[0] === "doc" || parts[0] === "documentation";
21685
20231
  }
21686
20232
  function buildPlan(languages, shape, docs, _root) {
@@ -21724,7 +20270,7 @@ function readTomlWorkspace(filePath) {
21724
20270
 
21725
20271
  // src/curation/index.ts
21726
20272
  import fs3 from "fs";
21727
- import path24 from "path";
20273
+ import path23 from "path";
21728
20274
  import crypto4 from "crypto";
21729
20275
  async function curate(options) {
21730
20276
  const startTime = Date.now();
@@ -21815,12 +20361,12 @@ function resolveTargets(targetPath) {
21815
20361
  const extensions = /* @__PURE__ */ new Set([".md", ".txt", ".mdx", ".rst"]);
21816
20362
  function walk(dir) {
21817
20363
  for (const entry of fs3.readdirSync(dir, { withFileTypes: true })) {
21818
- const fullPath = path24.join(dir, entry.name);
20364
+ const fullPath = path23.join(dir, entry.name);
21819
20365
  if (entry.isDirectory()) {
21820
20366
  if (entry.name !== "node_modules" && entry.name !== ".git") {
21821
20367
  walk(fullPath);
21822
20368
  }
21823
- } else if (extensions.has(path24.extname(entry.name).toLowerCase())) {
20369
+ } else if (extensions.has(path23.extname(entry.name).toLowerCase())) {
21824
20370
  results.push(fullPath);
21825
20371
  }
21826
20372
  }
@@ -21829,12 +20375,12 @@ function resolveTargets(targetPath) {
21829
20375
  return results;
21830
20376
  }
21831
20377
  function resolveProvenanceRoot(targetPath) {
21832
- const resolvedTarget = path24.resolve(targetPath);
20378
+ const resolvedTarget = path23.resolve(targetPath);
21833
20379
  const stat5 = fs3.statSync(resolvedTarget);
21834
- return stat5.isFile() ? path24.dirname(resolvedTarget) : resolvedTarget;
20380
+ return stat5.isFile() ? path23.dirname(resolvedTarget) : resolvedTarget;
21835
20381
  }
21836
20382
  function extractStatements(content, filePath, projectRoot, source, sourceFileHash, categoryOverride, confidence, entityRef, tags) {
21837
- const relativePath = path24.relative(projectRoot, path24.resolve(filePath)) || path24.basename(filePath);
20383
+ const relativePath = path23.relative(projectRoot, path23.resolve(filePath)) || path23.basename(filePath);
21838
20384
  const statements = [];
21839
20385
  const now = (/* @__PURE__ */ new Date()).toISOString();
21840
20386
  const paragraphs = content.split(/\n{2,}/).map((p) => p.trim()).filter((p) => p.length > 20 && p.length < 2e3);
@@ -21928,7 +20474,7 @@ function loadExistingMemories(memoryDir) {
21928
20474
  if (!fs3.existsSync(memoryDir)) return result;
21929
20475
  const dirs = ALL_CATEGORY_DIRS;
21930
20476
  for (const dir of dirs) {
21931
- const fullDir = path24.join(memoryDir, dir);
20477
+ const fullDir = path23.join(memoryDir, dir);
21932
20478
  if (!fs3.existsSync(fullDir)) continue;
21933
20479
  walkFiles(fullDir, (filePath) => {
21934
20480
  const content = readFileSafe(filePath);
@@ -21950,10 +20496,10 @@ function writeStatement(stmt, memoryDir) {
21950
20496
  const now = /* @__PURE__ */ new Date();
21951
20497
  const dateDir = now.toISOString().split("T")[0];
21952
20498
  const categoryDir = getCategoryDir(memoryDir, stmt.category);
21953
- const dir = path24.join(categoryDir, dateDir);
20499
+ const dir = path23.join(categoryDir, dateDir);
21954
20500
  fs3.mkdirSync(dir, { recursive: true });
21955
20501
  const fileName = `${stmt.category}-${Date.now()}-${stmt.id.slice(0, 8)}.md`;
21956
- const filePath = path24.join(dir, fileName);
20502
+ const filePath = path23.join(dir, fileName);
21957
20503
  const frontmatter = [
21958
20504
  "---",
21959
20505
  `id: ${stmt.id}`,
@@ -22021,7 +20567,7 @@ function extractBody2(content) {
22021
20567
  }
22022
20568
  function walkFiles(dir, callback) {
22023
20569
  for (const entry of fs3.readdirSync(dir, { withFileTypes: true })) {
22024
- const fullPath = path24.join(dir, entry.name);
20570
+ const fullPath = path23.join(dir, entry.name);
22025
20571
  if (entry.isDirectory()) {
22026
20572
  walkFiles(fullPath, callback);
22027
20573
  } else if (entry.name.endsWith(".md")) {
@@ -22032,7 +20578,7 @@ function walkFiles(dir, callback) {
22032
20578
 
22033
20579
  // src/dedup/index.ts
22034
20580
  import fs4 from "fs";
22035
- import path25 from "path";
20581
+ import path24 from "path";
22036
20582
  import crypto5 from "crypto";
22037
20583
  var DEFAULT_DEDUP_THRESHOLD = 0.85;
22038
20584
  var DEFAULT_MAX_LOAD = 1e4;
@@ -22174,7 +20720,7 @@ function loadMemories(memoryDir, categories, maxLoad = 1e4) {
22174
20720
  const memoryRootReal = fs4.realpathSync(memoryDir);
22175
20721
  for (const category of allCategories) {
22176
20722
  if (result.length >= maxLoad) break;
22177
- const dir = path25.join(memoryDir, category);
20723
+ const dir = path24.join(memoryDir, category);
22178
20724
  if (!fs4.existsSync(dir)) continue;
22179
20725
  const categoryStat = fs4.lstatSync(dir);
22180
20726
  if (categoryStat.isSymbolicLink()) {
@@ -22235,15 +20781,15 @@ function extractBody3(content) {
22235
20781
  return match ? match[1].trim() : content.trim();
22236
20782
  }
22237
20783
  function assertPathInsideRoot2(rootReal, targetReal, sourcePath) {
22238
- const rel = path25.relative(rootReal, targetReal);
22239
- if (rel === "" || !rel.startsWith("..") && !path25.isAbsolute(rel)) {
20784
+ const rel = path24.relative(rootReal, targetReal);
20785
+ if (rel === "" || !rel.startsWith("..") && !path24.isAbsolute(rel)) {
22240
20786
  return;
22241
20787
  }
22242
20788
  throw new Error(`Refusing to scan memory path outside root: ${sourcePath}`);
22243
20789
  }
22244
20790
  function walkMdFiles(dir, memoryRootReal, categoryRootReal, callback) {
22245
20791
  for (const entry of fs4.readdirSync(dir, { withFileTypes: true })) {
22246
- const fullPath = path25.join(dir, entry.name);
20792
+ const fullPath = path24.join(dir, entry.name);
22247
20793
  const entryStat = fs4.lstatSync(fullPath);
22248
20794
  if (entryStat.isSymbolicLink()) {
22249
20795
  throw new Error(`Refusing to scan symlinked memory path: ${fullPath}`);
@@ -22261,7 +20807,7 @@ function walkMdFiles(dir, memoryRootReal, categoryRootReal, callback) {
22261
20807
 
22262
20808
  // src/review/index.ts
22263
20809
  import fs5 from "fs";
22264
- import path26 from "path";
20810
+ import path25 from "path";
22265
20811
  var DEFAULT_CONFIDENCE_THRESHOLD = 0.7;
22266
20812
  function realMemoryRoot(memoryDir) {
22267
20813
  try {
@@ -22273,8 +20819,8 @@ function realMemoryRoot(memoryDir) {
22273
20819
  }
22274
20820
  }
22275
20821
  function isPathInside2(rootReal, candidateReal) {
22276
- const relative = path26.relative(rootReal, candidateReal);
22277
- return relative === "" || !!relative && !relative.startsWith("..") && !path26.isAbsolute(relative);
20822
+ const relative = path25.relative(rootReal, candidateReal);
20823
+ return relative === "" || !!relative && !relative.startsWith("..") && !path25.isAbsolute(relative);
22278
20824
  }
22279
20825
  function isSafeDirectory(rootReal, dir) {
22280
20826
  try {
@@ -22317,7 +20863,7 @@ function listReviewItems(options) {
22317
20863
  if (filterReason && item.reviewReason !== filterReason) return;
22318
20864
  items.push(item);
22319
20865
  };
22320
- const suggestionsDir = path26.join(memoryDir, "suggestions");
20866
+ const suggestionsDir = path25.join(memoryDir, "suggestions");
22321
20867
  if (!isLimitReached() && fs5.existsSync(suggestionsDir) && isSafeDirectory(rootReal, suggestionsDir)) {
22322
20868
  walkMd(rootReal, suggestionsDir, (filePath, content) => {
22323
20869
  if (isLimitReached()) return true;
@@ -22338,7 +20884,7 @@ function listReviewItems(options) {
22338
20884
  return isLimitReached();
22339
20885
  });
22340
20886
  }
22341
- const reviewDir = path26.join(memoryDir, "review");
20887
+ const reviewDir = path25.join(memoryDir, "review");
22342
20888
  if (!isLimitReached() && fs5.existsSync(reviewDir) && isSafeDirectory(rootReal, reviewDir)) {
22343
20889
  walkMd(rootReal, reviewDir, (filePath, content) => {
22344
20890
  if (isLimitReached()) return true;
@@ -22363,7 +20909,7 @@ function listReviewItems(options) {
22363
20909
  const categories = ALL_CATEGORY_DIRS;
22364
20910
  for (const category of categories) {
22365
20911
  if (isLimitReached()) break;
22366
- const dir = path26.join(memoryDir, category);
20912
+ const dir = path25.join(memoryDir, category);
22367
20913
  if (!fs5.existsSync(dir) || !isSafeDirectory(rootReal, dir)) continue;
22368
20914
  walkMd(rootReal, dir, (filePath, content) => {
22369
20915
  if (isLimitReached()) return true;
@@ -22443,8 +20989,8 @@ function approveItem(memoryDir, itemId, options) {
22443
20989
  const targetDir = getCategoryDir(memoryDir, category);
22444
20990
  const dateDir = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
22445
20991
  ensureSafeDirectory(rootReal, targetDir);
22446
- const outputPath = path26.join(targetDir, dateDir, path26.basename(found.filePath));
22447
- ensureSafeDirectory(rootReal, path26.dirname(outputPath));
20992
+ const outputPath = path25.join(targetDir, dateDir, path25.basename(found.filePath));
20993
+ ensureSafeDirectory(rootReal, path25.dirname(outputPath));
22448
20994
  const promotedPath = writeFileWithoutClobber(outputPath, updatedContent, itemId);
22449
20995
  fs5.unlinkSync(found.filePath);
22450
20996
  return {
@@ -22502,13 +21048,13 @@ function findReviewFileById(memoryDir, id, options = {}) {
22502
21048
  const rootReal = realMemoryRoot(memoryDir);
22503
21049
  if (!rootReal) return null;
22504
21050
  for (const loc of ["suggestions", "review"]) {
22505
- const dir = path26.join(memoryDir, loc);
21051
+ const dir = path25.join(memoryDir, loc);
22506
21052
  if (!fs5.existsSync(dir) || !isSafeDirectory(rootReal, dir)) continue;
22507
21053
  const found = findFileById(rootReal, dir, id);
22508
21054
  if (found) return { filePath: found, location: "queue" };
22509
21055
  }
22510
21056
  for (const category of ALL_CATEGORY_DIRS) {
22511
- const dir = path26.join(memoryDir, category);
21057
+ const dir = path25.join(memoryDir, category);
22512
21058
  if (!fs5.existsSync(dir) || !isSafeDirectory(rootReal, dir)) continue;
22513
21059
  const found = findFileById(rootReal, dir, id, (fm) => isLowConfidenceReviewCandidate(fm, options));
22514
21060
  if (found) return { filePath: found, location: "category" };
@@ -22584,10 +21130,10 @@ function readFileSafe3(filePath) {
22584
21130
  }
22585
21131
  }
22586
21132
  function writeFileWithoutClobber(basePath, content, discriminator) {
22587
- const parsed = path26.parse(basePath);
21133
+ const parsed = path25.parse(basePath);
22588
21134
  const safeDiscriminator = sanitizeFilePart(discriminator);
22589
21135
  for (let attempt = 0; attempt < 1e3; attempt++) {
22590
- const candidate = attempt === 0 ? basePath : path26.join(
21136
+ const candidate = attempt === 0 ? basePath : path25.join(
22591
21137
  parsed.dir,
22592
21138
  `${parsed.name}-${safeDiscriminator}${attempt === 1 ? "" : `-${attempt}`}${parsed.ext || ".md"}`
22593
21139
  );
@@ -22643,7 +21189,7 @@ function extractBody4(content) {
22643
21189
  function walkMd(rootReal, dir, callback) {
22644
21190
  if (!isSafeDirectory(rootReal, dir)) return false;
22645
21191
  for (const entry of fs5.readdirSync(dir, { withFileTypes: true })) {
22646
- const fullPath = path26.join(dir, entry.name);
21192
+ const fullPath = path25.join(dir, entry.name);
22647
21193
  if (entry.isSymbolicLink()) continue;
22648
21194
  if (entry.isDirectory()) {
22649
21195
  if (walkMd(rootReal, fullPath, callback)) return true;
@@ -22658,7 +21204,7 @@ function walkMdPaths(rootReal, dir) {
22658
21204
  const results = [];
22659
21205
  if (!isSafeDirectory(rootReal, dir)) return results;
22660
21206
  for (const entry of fs5.readdirSync(dir, { withFileTypes: true })) {
22661
- const fullPath = path26.join(dir, entry.name);
21207
+ const fullPath = path25.join(dir, entry.name);
22662
21208
  if (entry.isSymbolicLink()) continue;
22663
21209
  if (entry.isDirectory()) {
22664
21210
  results.push(...walkMdPaths(rootReal, fullPath));
@@ -22671,7 +21217,7 @@ function walkMdPaths(rootReal, dir) {
22671
21217
 
22672
21218
  // src/sync/index.ts
22673
21219
  import fs6 from "fs";
22674
- import path27 from "path";
21220
+ import path26 from "path";
22675
21221
  import crypto6 from "crypto";
22676
21222
  var DEFAULT_EXTENSIONS = /* @__PURE__ */ new Set([".md", ".txt", ".mdx", ".rst"]);
22677
21223
  var DEFAULT_EXCLUDE2 = /* @__PURE__ */ new Set([
@@ -22693,7 +21239,7 @@ function syncChanges(options) {
22693
21239
  } = options;
22694
21240
  const extSet = new Set(extensions);
22695
21241
  const excludeSet = /* @__PURE__ */ new Set([...DEFAULT_EXCLUDE2, ...excludeDirs]);
22696
- const stateFilePath = options.stateFile ?? path27.join(memoryDir, ".sync-state.json");
21242
+ const stateFilePath = options.stateFile ?? path26.join(memoryDir, ".sync-state.json");
22697
21243
  const prevState = loadState(stateFilePath);
22698
21244
  const currentFiles = scanFiles(sourceDir, extSet, excludeSet);
22699
21245
  const changes = computeDiff(currentFiles, prevState.fileHashes, sourceDir);
@@ -22709,7 +21255,7 @@ function syncChanges(options) {
22709
21255
  for (const [relPath, hash] of Object.entries(currentFiles)) {
22710
21256
  newState.fileHashes[relPath] = hash;
22711
21257
  }
22712
- fs6.mkdirSync(path27.dirname(stateFilePath), { recursive: true });
21258
+ fs6.mkdirSync(path26.dirname(stateFilePath), { recursive: true });
22713
21259
  fs6.writeFileSync(stateFilePath, JSON.stringify(newState, null, 2));
22714
21260
  }
22715
21261
  return {
@@ -22775,13 +21321,13 @@ function scanFiles(root, extensions, exclude) {
22775
21321
  }
22776
21322
  for (const entry of entries) {
22777
21323
  if (exclude.has(entry.name)) continue;
22778
- const fullPath = path27.join(dir, entry.name);
21324
+ const fullPath = path26.join(dir, entry.name);
22779
21325
  if (entry.isDirectory()) {
22780
21326
  walk(fullPath);
22781
21327
  } else if (entry.isFile()) {
22782
- const ext = path27.extname(entry.name).toLowerCase();
21328
+ const ext = path26.extname(entry.name).toLowerCase();
22783
21329
  if (!extensions.has(ext)) continue;
22784
- const relPath = path27.relative(root, fullPath);
21330
+ const relPath = path26.relative(root, fullPath);
22785
21331
  try {
22786
21332
  const content = fs6.readFileSync(fullPath, "utf8");
22787
21333
  result[relPath] = hashContent3(content);
@@ -22796,7 +21342,7 @@ function scanFiles(root, extensions, exclude) {
22796
21342
  function computeDiff(current, previous, sourceDir) {
22797
21343
  const changes = [];
22798
21344
  for (const [relPath, hash] of Object.entries(current)) {
22799
- const fullPath = path27.join(sourceDir, relPath);
21345
+ const fullPath = path26.join(sourceDir, relPath);
22800
21346
  if (!(relPath in previous)) {
22801
21347
  let size = 0;
22802
21348
  try {
@@ -22829,7 +21375,7 @@ function computeDiff(current, previous, sourceDir) {
22829
21375
  for (const relPath of Object.keys(previous)) {
22830
21376
  if (!(relPath in current)) {
22831
21377
  changes.push({
22832
- filePath: path27.join(sourceDir, relPath),
21378
+ filePath: path26.join(sourceDir, relPath),
22833
21379
  relativePath: relPath,
22834
21380
  type: "deleted",
22835
21381
  currentHash: "",
@@ -22859,20 +21405,20 @@ function hashContent3(content) {
22859
21405
  import { spawnSync } from "child_process";
22860
21406
  import crypto7 from "crypto";
22861
21407
  import fs7 from "fs";
22862
- import path28 from "path";
21408
+ import path27 from "path";
22863
21409
  var MANIFEST_VERSION = 1;
22864
21410
  var MANIFEST_LOCK_STALE_MS = 3e4;
22865
21411
  var MANIFEST_LOCK_TIMEOUT_MS = MANIFEST_LOCK_STALE_MS + 1e4;
22866
21412
  var MANIFEST_LOCK_SLEEP_MS = 20;
22867
21413
  function normalizeSpaceMemoryDir(memoryDir) {
22868
- return path28.resolve(memoryDir);
21414
+ return path27.resolve(memoryDir);
22869
21415
  }
22870
21416
  function getSpacesDir(baseDir) {
22871
21417
  const homeDir = baseDir ?? resolveHomeDir();
22872
- return path28.join(homeDir, ".config", "engram", "spaces");
21418
+ return path27.join(homeDir, ".config", "engram", "spaces");
22873
21419
  }
22874
21420
  function getManifestPath(baseDir) {
22875
- return path28.join(getSpacesDir(baseDir), "manifest.json");
21421
+ return path27.join(getSpacesDir(baseDir), "manifest.json");
22876
21422
  }
22877
21423
  function loadManifest(baseDir, memoryDirOverride) {
22878
21424
  if (fs7.existsSync(getManifestPath(baseDir))) {
@@ -22919,9 +21465,9 @@ function readManifestUnlocked(baseDir, memoryDirOverride, options = {}) {
22919
21465
  }
22920
21466
  function saveManifestUnlocked(manifest, baseDir) {
22921
21467
  const manifestPath2 = getManifestPath(baseDir);
22922
- const manifestDir2 = path28.dirname(manifestPath2);
21468
+ const manifestDir2 = path27.dirname(manifestPath2);
22923
21469
  fs7.mkdirSync(manifestDir2, { recursive: true });
22924
- const tempPath = path28.join(manifestDir2, `.manifest.${process.pid}.${Date.now()}.${crypto7.randomUUID()}.tmp`);
21470
+ const tempPath = path27.join(manifestDir2, `.manifest.${process.pid}.${Date.now()}.${crypto7.randomUUID()}.tmp`);
22925
21471
  try {
22926
21472
  fs7.writeFileSync(tempPath, `${JSON.stringify(manifest, null, 2)}
22927
21473
  `, { flag: "wx" });
@@ -22936,7 +21482,7 @@ function saveManifestUnlocked(manifest, baseDir) {
22936
21482
  }
22937
21483
  function withManifestLock(baseDir, operation) {
22938
21484
  const lockDir = `${getManifestPath(baseDir)}.lock`;
22939
- fs7.mkdirSync(path28.dirname(lockDir), { recursive: true });
21485
+ fs7.mkdirSync(path27.dirname(lockDir), { recursive: true });
22940
21486
  const lockOwner = acquireManifestLock(lockDir);
22941
21487
  try {
22942
21488
  return operation();
@@ -22962,7 +21508,7 @@ function acquireManifestLock(lockDir) {
22962
21508
  try {
22963
21509
  fs7.mkdirSync(lockDir, { recursive: false });
22964
21510
  try {
22965
- fs7.writeFileSync(path28.join(lockDir, "owner"), `${owner}
21511
+ fs7.writeFileSync(path27.join(lockDir, "owner"), `${owner}
22966
21512
  `, { flag: "wx" });
22967
21513
  } catch (error) {
22968
21514
  fs7.rmSync(lockDir, { recursive: true, force: true });
@@ -22992,7 +21538,7 @@ function acquireManifestLock(lockDir) {
22992
21538
  }
22993
21539
  function releaseManifestLock(lockDir, owner) {
22994
21540
  try {
22995
- const ownerPath = path28.join(lockDir, "owner");
21541
+ const ownerPath = path27.join(lockDir, "owner");
22996
21542
  if (fs7.readFileSync(ownerPath, "utf8").trim() === owner) {
22997
21543
  fs7.rmSync(lockDir, { recursive: true, force: true });
22998
21544
  }
@@ -23008,7 +21554,7 @@ function removeStaleManifestLock(lockDir) {
23008
21554
  try {
23009
21555
  fs7.mkdirSync(reclaimDir, { recursive: false });
23010
21556
  try {
23011
- fs7.writeFileSync(path28.join(reclaimDir, "owner"), `${reclaimOwner}
21557
+ fs7.writeFileSync(path27.join(reclaimDir, "owner"), `${reclaimOwner}
23012
21558
  `, { flag: "wx" });
23013
21559
  } catch (error) {
23014
21560
  fs7.rmSync(reclaimDir, { recursive: true, force: true });
@@ -23083,7 +21629,7 @@ function readManifestLockSnapshot(lockDir) {
23083
21629
  throw error;
23084
21630
  }
23085
21631
  try {
23086
- const owner = fs7.readFileSync(path28.join(lockDir, "owner"), "utf8").trim();
21632
+ const owner = fs7.readFileSync(path27.join(lockDir, "owner"), "utf8").trim();
23087
21633
  return { mtimeMs: stat5.mtimeMs, owner };
23088
21634
  } catch (error) {
23089
21635
  if (error.code === "ENOENT") {
@@ -23155,8 +21701,8 @@ function sleepSync(ms) {
23155
21701
  }
23156
21702
  function createPersonalSpace(baseDir, memoryDirOverride) {
23157
21703
  const homeDir = baseDir ?? resolveHomeDir();
23158
- const standalonePath = path28.join(homeDir, ".engram", "memory");
23159
- const openclawPath = path28.join(homeDir, ".openclaw", "workspace", "memory", "local");
21704
+ const standalonePath = path27.join(homeDir, ".engram", "memory");
21705
+ const openclawPath = path27.join(homeDir, ".openclaw", "workspace", "memory", "local");
23160
21706
  const memoryDir = memoryDirOverride ?? readEnvVar("REMNIC_MEMORY_DIR") ?? readEnvVar("ENGRAM_MEMORY_DIR") ?? (fs7.existsSync(standalonePath) ? standalonePath : fs7.existsSync(openclawPath) ? openclawPath : standalonePath);
23161
21707
  const normalizedMemoryDir = normalizeSpaceMemoryDir(memoryDir);
23162
21708
  const now = (/* @__PURE__ */ new Date()).toISOString();
@@ -23185,7 +21731,7 @@ function createSpace(options) {
23185
21731
  const id = options.name.toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/-+/g, "-");
23186
21732
  const now = (/* @__PURE__ */ new Date()).toISOString();
23187
21733
  const memoryDir = normalizeSpaceMemoryDir(
23188
- options.memoryDir ?? path28.join(getSpacesDir(options.baseDir), id, "memory")
21734
+ options.memoryDir ?? path27.join(getSpacesDir(options.baseDir), id, "memory")
23189
21735
  );
23190
21736
  const space = updateManifest(options.baseDir, (manifest) => {
23191
21737
  if (manifest.spaces.some((s) => s.id === id)) {
@@ -23406,14 +21952,14 @@ function mergeSpaces(sourceSpaceId, targetSpaceId, options) {
23406
21952
  };
23407
21953
  }
23408
21954
  function getAuditLog(baseDir) {
23409
- const auditPath = path28.join(getSpacesDir(baseDir), "audit.jsonl");
21955
+ const auditPath = path27.join(getSpacesDir(baseDir), "audit.jsonl");
23410
21956
  if (!fs7.existsSync(auditPath)) return [];
23411
21957
  const lines = fs7.readFileSync(auditPath, "utf8").trim().split("\n");
23412
21958
  return lines.filter((l) => l.trim()).map((l) => JSON.parse(l));
23413
21959
  }
23414
21960
  function appendAudit(entry, baseDir) {
23415
- const auditPath = path28.join(getSpacesDir(baseDir), "audit.jsonl");
23416
- fs7.mkdirSync(path28.dirname(auditPath), { recursive: true });
21961
+ const auditPath = path27.join(getSpacesDir(baseDir), "audit.jsonl");
21962
+ fs7.mkdirSync(path27.dirname(auditPath), { recursive: true });
23417
21963
  const full = {
23418
21964
  id: crypto7.randomUUID(),
23419
21965
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
@@ -23445,8 +21991,8 @@ function copyMemories(sourceDir, targetDir, options) {
23445
21991
  continue;
23446
21992
  }
23447
21993
  const content = fs7.readFileSync(sourcePath, "utf8");
23448
- const relativePath = path28.relative(sourceRoot, sourceRealPath);
23449
- const targetPath = path28.resolve(targetRoot, relativePath);
21994
+ const relativePath = path27.relative(sourceRoot, sourceRealPath);
21995
+ const targetPath = path27.resolve(targetRoot, relativePath);
23450
21996
  if (!isPathInsideRoot(targetPath, targetRoot)) {
23451
21997
  skipped++;
23452
21998
  continue;
@@ -23488,8 +22034,8 @@ function copyMemories(sourceDir, targetDir, options) {
23488
22034
  skipped++;
23489
22035
  continue;
23490
22036
  }
23491
- fs7.mkdirSync(path28.dirname(targetPath), { recursive: true });
23492
- const targetParentRealPath = safeRealpath(path28.dirname(targetPath));
22037
+ fs7.mkdirSync(path27.dirname(targetPath), { recursive: true });
22038
+ const targetParentRealPath = safeRealpath(path27.dirname(targetPath));
23493
22039
  if (!targetParentRealPath || !isPathInsideRoot(targetParentRealPath, targetRoot)) {
23494
22040
  skipped++;
23495
22041
  continue;
@@ -23507,7 +22053,7 @@ function walkMd2(dir) {
23507
22053
  const results = [];
23508
22054
  function walk(d) {
23509
22055
  for (const entry of fs7.readdirSync(d, { withFileTypes: true })) {
23510
- const fullPath = path28.join(d, entry.name);
22056
+ const fullPath = path27.join(d, entry.name);
23511
22057
  if (entry.isSymbolicLink()) {
23512
22058
  continue;
23513
22059
  }
@@ -23536,8 +22082,8 @@ function safeRealpath(filePath) {
23536
22082
  }
23537
22083
  }
23538
22084
  function isPathInsideRoot(candidatePath, rootPath) {
23539
- const relative = path28.relative(rootPath, candidatePath);
23540
- return relative === "" || !relative.startsWith("..") && !path28.isAbsolute(relative);
22085
+ const relative = path27.relative(rootPath, candidatePath);
22086
+ return relative === "" || !relative.startsWith("..") && !path27.isAbsolute(relative);
23541
22087
  }
23542
22088
  function parseSimpleFrontmatter(content) {
23543
22089
  const match = content.match(/^---\n([\s\S]*?)\n---/);
@@ -23657,22 +22203,22 @@ var REMNIC_RECALL_DECISION_RULES = `## When to Use Recall vs Direct Read
23657
22203
 
23658
22204
  // src/memory-extension/codex-publisher.ts
23659
22205
  import fs8 from "fs";
23660
- import os2 from "os";
23661
- import path29 from "path";
22206
+ import os from "os";
22207
+ import path28 from "path";
23662
22208
  var REMNIC_EXTENSION_DIR_NAME = "remnic";
23663
22209
  function resolveEnvHome(env) {
23664
22210
  if (env === void 0) return resolveHomeDir();
23665
- return env.HOME?.trim() || env.USERPROFILE?.trim() || os2.homedir();
22211
+ return env.HOME?.trim() || env.USERPROFILE?.trim() || os.homedir();
23666
22212
  }
23667
22213
  function expandTildeWithHome(input, homeDir) {
23668
22214
  if (input === "~") return homeDir;
23669
22215
  if (input.startsWith("~/") || input.startsWith("~\\")) {
23670
- return path29.join(homeDir, input.slice(2));
22216
+ return path28.join(homeDir, input.slice(2));
23671
22217
  }
23672
22218
  return input;
23673
22219
  }
23674
22220
  function normalizeHostRoot(input, homeDir) {
23675
- return path29.resolve(expandTildeWithHome(input.trim(), homeDir));
22221
+ return path28.resolve(expandTildeWithHome(input.trim(), homeDir));
23676
22222
  }
23677
22223
  var CodexMemoryExtensionPublisher = class {
23678
22224
  hostId = "codex";
@@ -23686,12 +22232,12 @@ var CodexMemoryExtensionPublisher = class {
23686
22232
  async resolveExtensionRoot(env) {
23687
22233
  const homeDir = resolveEnvHome(env);
23688
22234
  const codexHomeInput = env === void 0 ? readEnvVar("CODEX_HOME")?.trim() : env.CODEX_HOME?.trim();
23689
- const codexHome = codexHomeInput ? normalizeHostRoot(codexHomeInput, homeDir) : path29.resolve(homeDir, ".codex");
23690
- return path29.join(codexHome, "memories_extensions", REMNIC_EXTENSION_DIR_NAME);
22235
+ const codexHome = codexHomeInput ? normalizeHostRoot(codexHomeInput, homeDir) : path28.resolve(homeDir, ".codex");
22236
+ return path28.join(codexHome, "memories_extensions", REMNIC_EXTENSION_DIR_NAME);
23691
22237
  }
23692
22238
  async isHostAvailable() {
23693
22239
  try {
23694
- const home = readEnvVar("CODEX_HOME")?.trim() || path29.join(resolveHomeDir(), ".codex");
22240
+ const home = readEnvVar("CODEX_HOME")?.trim() || path28.join(resolveHomeDir(), ".codex");
23695
22241
  return fs8.existsSync(home);
23696
22242
  } catch {
23697
22243
  return false;
@@ -23742,7 +22288,7 @@ When running inside the Codex phase-2 consolidation sandbox:
23742
22288
  }
23743
22289
  async publish(ctx) {
23744
22290
  const extensionRoot = await this.resolveExtensionRoot();
23745
- const instructionsPath = path29.join(extensionRoot, "instructions.md");
22291
+ const instructionsPath = path28.join(extensionRoot, "instructions.md");
23746
22292
  const filesWritten = [];
23747
22293
  const skipped = [];
23748
22294
  ctx.log.info(`Publishing Codex memory extension to ${extensionRoot}`);
@@ -24116,9 +22662,9 @@ async function generateActivityMemories(date, digestBody, config, deps) {
24116
22662
  }
24117
22663
 
24118
22664
  // src/session-summaries/index.ts
24119
- import { createHash as createHash9 } from "crypto";
22665
+ import { createHash as createHash7 } from "crypto";
24120
22666
  import { lstat as lstat2, mkdir as mkdir7, readFile as readFile6, readdir as readdir4, rename, rm, stat as stat4, writeFile as writeFile7 } from "fs/promises";
24121
- import path30 from "path";
22667
+ import path29 from "path";
24122
22668
 
24123
22669
  // src/session-summaries/adapters.ts
24124
22670
  var VALID_ROLES = /* @__PURE__ */ new Set(["user", "assistant", "tool", "system", "other"]);
@@ -24618,12 +23164,12 @@ var DEFAULT_MAX_FILES = 5e3;
24618
23164
  var DEFAULT_MAX_SESSIONS = 500;
24619
23165
  var SUPPORTED_EXTENSIONS = /* @__PURE__ */ new Set([".json", ".jsonl"]);
24620
23166
  function shortHash(value, length = 16) {
24621
- return createHash9("sha256").update(value).digest("hex").slice(0, length);
23167
+ return createHash7("sha256").update(value).digest("hex").slice(0, length);
24622
23168
  }
24623
23169
  async function listTranscriptFiles(root, maxFiles) {
24624
23170
  const out = [];
24625
23171
  let truncated = false;
24626
- const entrySortKey = (entryName, isDirectory) => isDirectory ? `${entryName}${path30.sep}` : entryName;
23172
+ const entrySortKey = (entryName, isDirectory) => isDirectory ? `${entryName}${path29.sep}` : entryName;
24627
23173
  async function visit(dir) {
24628
23174
  if (truncated) return;
24629
23175
  const entries = (await readdir4(dir, { withFileTypes: true })).sort(
@@ -24633,13 +23179,13 @@ async function listTranscriptFiles(root, maxFiles) {
24633
23179
  if (truncated) return;
24634
23180
  if (entry.name.startsWith(".")) continue;
24635
23181
  if (entry.isSymbolicLink()) continue;
24636
- const fullPath = path30.join(dir, entry.name);
23182
+ const fullPath = path29.join(dir, entry.name);
24637
23183
  if (entry.isDirectory()) {
24638
23184
  await visit(fullPath);
24639
23185
  continue;
24640
23186
  }
24641
23187
  if (!entry.isFile()) continue;
24642
- const ext = path30.extname(entry.name).toLowerCase();
23188
+ const ext = path29.extname(entry.name).toLowerCase();
24643
23189
  if (!SUPPORTED_EXTENSIONS.has(ext)) continue;
24644
23190
  out.push(fullPath);
24645
23191
  if (out.length > maxFiles) {
@@ -24666,7 +23212,7 @@ function normalizeInputDir(inputDir) {
24666
23212
  if (typeof inputDir !== "string" || inputDir.trim().length === 0) {
24667
23213
  throw new Error("inputDir must be a non-empty string");
24668
23214
  }
24669
- return path30.resolve(expandTildePath(inputDir.trim()));
23215
+ return path29.resolve(expandTildePath(inputDir.trim()));
24670
23216
  }
24671
23217
  function initRoleCounts() {
24672
23218
  return {
@@ -24823,11 +23369,11 @@ async function collectLocalSessionSummaries(options) {
24823
23369
  continue;
24824
23370
  }
24825
23371
  seenFileHashes.add(fileHash);
24826
- const fileExtension = path30.extname(filePath).toLowerCase();
23372
+ const fileExtension = path29.extname(filePath).toLowerCase();
24827
23373
  const parsed = await adapter.parseFile(
24828
23374
  {
24829
23375
  content,
24830
- fileName: path30.basename(filePath),
23376
+ fileName: path29.basename(filePath),
24831
23377
  fileExtension,
24832
23378
  fileRef: fileHash
24833
23379
  },
@@ -24883,7 +23429,7 @@ async function collectLocalSessionSummaries(options) {
24883
23429
  }
24884
23430
  async function readRedactionConfig(pathLike) {
24885
23431
  if (!pathLike) return void 0;
24886
- const raw = await readFile6(path30.resolve(expandTildePath(pathLike)), "utf-8");
23432
+ const raw = await readFile6(path29.resolve(expandTildePath(pathLike)), "utf-8");
24887
23433
  const parsed = JSON.parse(raw);
24888
23434
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
24889
23435
  throw new Error("redaction config must be a JSON object");
@@ -24896,15 +23442,15 @@ function toJsonl(drafts) {
24896
23442
  }
24897
23443
  function defaultDraftOutputPath(memoryDir, generatedAt) {
24898
23444
  const stamp = generatedAt.replace(/[:.]/g, "-");
24899
- return path30.join(
24900
- path30.resolve(expandTildePath(memoryDir)),
23445
+ return path29.join(
23446
+ path29.resolve(expandTildePath(memoryDir)),
24901
23447
  "state",
24902
23448
  "session-summary-drafts",
24903
23449
  `session-summaries-${stamp}.jsonl`
24904
23450
  );
24905
23451
  }
24906
23452
  async function writeDrafts(filePath, drafts) {
24907
- await mkdir7(path30.dirname(filePath), { recursive: true });
23453
+ await mkdir7(path29.dirname(filePath), { recursive: true });
24908
23454
  const tempPath = `${filePath}.${process.pid}.${Date.now()}.tmp`;
24909
23455
  try {
24910
23456
  await writeFile7(tempPath, toJsonl(drafts), "utf-8");
@@ -24922,7 +23468,7 @@ async function runLocalSessionSummaryCliCommand(options) {
24922
23468
  });
24923
23469
  const wroteFiles = [];
24924
23470
  if (options.output) {
24925
- const outputPath = path30.resolve(expandTildePath(options.output));
23471
+ const outputPath = path29.resolve(expandTildePath(options.output));
24926
23472
  await writeDrafts(outputPath, report.drafts);
24927
23473
  wroteFiles.push(outputPath);
24928
23474
  }
@@ -24957,19 +23503,19 @@ async function runLocalSessionSummaryCliCommand(options) {
24957
23503
 
24958
23504
  // src/transfer/capsule-fork.ts
24959
23505
  import { lstat as lstat3, mkdir as mkdir8, readFile as readFile7, realpath as realpath2, writeFile as writeFile8 } from "fs/promises";
24960
- import path31 from "path";
23506
+ import path30 from "path";
24961
23507
  async function forkCapsule(opts) {
24962
23508
  validateForkId(opts.forkId);
24963
- const rootAbs = path31.resolve(opts.targetRoot);
23509
+ const rootAbs = path30.resolve(opts.targetRoot);
24964
23510
  await assertIsDirectoryNotSymlink(rootAbs, "forkCapsule", "targetRoot");
24965
- const forkDirAbs = path31.join(rootAbs, "forks", opts.forkId);
23511
+ const forkDirAbs = path30.join(rootAbs, "forks", opts.forkId);
24966
23512
  const forkEntryExists = await pathEntryExists(forkDirAbs);
24967
23513
  if (forkEntryExists) {
24968
23514
  throw new Error(
24969
23515
  `forkCapsule: fork path already exists \u2014 forkId "${opts.forkId}" is already in use at: ${forkDirAbs}`
24970
23516
  );
24971
23517
  }
24972
- const archiveAbs = path31.resolve(opts.sourceArchive);
23518
+ const archiveAbs = path30.resolve(opts.sourceArchive);
24973
23519
  const importResult = await importCapsule({
24974
23520
  archivePath: archiveAbs,
24975
23521
  root: rootAbs,
@@ -24991,10 +23537,10 @@ async function forkCapsule(opts) {
24991
23537
  importedRecords: importResult.imported.length,
24992
23538
  skippedRecords: importResult.skipped.length
24993
23539
  };
24994
- const lineagePath = path31.join(forkDirAbs, "lineage.json");
23540
+ const lineagePath = path30.join(forkDirAbs, "lineage.json");
24995
23541
  const rootReal = await realpath2(rootAbs);
24996
23542
  await assertRealpathInsideRoot(rootReal, lineagePath, `forks/${opts.forkId}/lineage.json`, "forkCapsule");
24997
- await mkdir8(path31.dirname(lineagePath), { recursive: true });
23543
+ await mkdir8(path30.dirname(lineagePath), { recursive: true });
24998
23544
  await writeFile8(lineagePath, JSON.stringify(lineage, null, 2) + "\n", "utf-8");
24999
23545
  return {
25000
23546
  archivePath: archiveAbs,
@@ -25008,11 +23554,11 @@ async function readForkLineage(targetRoot, forkId) {
25008
23554
  if (typeof forkId !== "string" || forkId.length === 0 || forkId.length > 64 || !CAPSULE_ID_PATTERN.test(forkId)) {
25009
23555
  return null;
25010
23556
  }
25011
- const rootAbs = path31.resolve(targetRoot);
23557
+ const rootAbs = path30.resolve(targetRoot);
25012
23558
  const rootReal = await realpath2(rootAbs).catch(() => rootAbs);
25013
- const lineagePath = path31.join(rootReal, "forks", forkId, "lineage.json");
25014
- const rel = path31.relative(rootReal, lineagePath);
25015
- if (rel.startsWith("..") || path31.isAbsolute(rel)) {
23559
+ const lineagePath = path30.join(rootReal, "forks", forkId, "lineage.json");
23560
+ const rel = path30.relative(rootReal, lineagePath);
23561
+ if (rel.startsWith("..") || path30.isAbsolute(rel)) {
25016
23562
  return null;
25017
23563
  }
25018
23564
  if (!await isLineagePathContained(rootReal, lineagePath)) {
@@ -25053,60 +23599,23 @@ async function pathEntryExists(absPath) {
25053
23599
  async function isLineagePathContained(rootReal, lineagePath) {
25054
23600
  let existing = lineagePath;
25055
23601
  const suffix = [];
25056
- while (existing !== path31.dirname(existing)) {
23602
+ while (existing !== path30.dirname(existing)) {
25057
23603
  const st = await lstat3(existing).catch(() => null);
25058
23604
  if (st !== null) break;
25059
- suffix.unshift(path31.basename(existing));
25060
- existing = path31.dirname(existing);
23605
+ suffix.unshift(path30.basename(existing));
23606
+ existing = path30.dirname(existing);
25061
23607
  }
25062
23608
  const existingReal = await realpath2(existing).catch(() => existing);
25063
- const targetReal = suffix.length > 0 ? path31.join(existingReal, ...suffix) : existingReal;
25064
- const rel = path31.relative(rootReal, targetReal);
23609
+ const targetReal = suffix.length > 0 ? path30.join(existingReal, ...suffix) : existingReal;
23610
+ const rel = path30.relative(rootReal, targetReal);
25065
23611
  if (rel === "") return true;
25066
23612
  if (rel === "..") return false;
25067
- if (rel.startsWith(`..${path31.sep}`)) return false;
25068
- if (path31.isAbsolute(rel)) return false;
23613
+ if (rel.startsWith(`..${path30.sep}`)) return false;
23614
+ if (path30.isAbsolute(rel)) return false;
25069
23615
  return true;
25070
23616
  }
25071
23617
 
25072
23618
  export {
25073
- BulkImportBatchPartialFailureError,
25074
- mapRecallSourceToXrayServedBy,
25075
- throwIfRecallAborted,
25076
- raceRecallAbort,
25077
- COMPACTION_SIGNAL_MAX_AGE_MS,
25078
- normalizeIanaTimeZone,
25079
- formatDateInTimeZone,
25080
- utcDateKeysForLocalDay,
25081
- parseFiniteDate,
25082
- filterHourlySummaryMarkdownForLocalDay,
25083
- qmdStartupCollectionCheckWithTimeout,
25084
- defaultWorkspaceDir,
25085
- sanitizeSessionKeyForFilename,
25086
- targetSourceValidAtSortMs,
25087
- splitTurnsBySourceValidAt,
25088
- isArtifactMemoryPath,
25089
- buildCompressionGuidelinesMarkdown2 as buildCompressionGuidelinesMarkdown,
25090
- applyQueryAwareCandidateFilter,
25091
- tokenizeRecallQuery,
25092
- shouldFilterLifecycleRecallCandidate,
25093
- lifecycleRecallScoreAdjustment,
25094
- computeArtifactRecallLimit,
25095
- resolveEffectiveRecallMode,
25096
- resolveRecallModeDecision,
25097
- resolveRecallModeDecisionAsync,
25098
- computeArtifactCandidateFetchLimit,
25099
- computeQmdHybridFetchLimit,
25100
- summarizeGraphShadowComparison,
25101
- parseGraphRecallRankedResults,
25102
- parseMemoryIntentSnapshot,
25103
- parseQmdRecallResults,
25104
- mergeArtifactRecallCandidates,
25105
- resolveRecentThreadMemoryPaths,
25106
- buildMemoryPathById,
25107
- appendMemoryToGraphContext,
25108
- resolvePersistedMemoryRelativePath,
25109
- deriveTopicsFromExtraction,
25110
23619
  buildProcedureRecallSection,
25111
23620
  RELAY_DEMO_MISSION_ID,
25112
23621
  RELAY_DEMO_NAMESPACE,
@@ -25222,4 +23731,4 @@ export {
25222
23731
  filterRecallCandidates,
25223
23732
  Orchestrator
25224
23733
  };
25225
- //# sourceMappingURL=chunk-YNQBRLC5.js.map
23734
+ //# sourceMappingURL=chunk-LUQ443JP.js.map