@remnic/core 9.30.1 → 9.31.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 (493) hide show
  1. package/dist/access-admin-ops-surface.d.ts +10 -10
  2. package/dist/access-admin-ops-surface.js +50 -44
  3. package/dist/access-authorization-probe.d.ts +10 -10
  4. package/dist/access-authorization-probe.js +51 -45
  5. package/dist/access-boundary.d.ts +13 -11
  6. package/dist/access-boundary.js +50 -44
  7. package/dist/access-cli.js +168 -123
  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 +166 -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 +66 -59
  19. package/dist/access-identity-continuity-surface.d.ts +8 -8
  20. package/dist/access-identity-continuity-surface.js +50 -44
  21. package/dist/access-lcm-surface.d.ts +10 -10
  22. package/dist/access-lcm-surface.js +50 -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 +58 -52
  26. package/dist/access-memory-search-fanout.d.ts +2 -2
  27. package/dist/{access-namespace-preflight-VfXssvoI.d.ts → access-namespace-preflight-D4vW97H1.d.ts} +1 -1
  28. package/dist/access-namespace-preflight.d.ts +3 -3
  29. package/dist/access-namespace-preflight.js +50 -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 +50 -44
  35. package/dist/access-operations-batch.js +53 -47
  36. package/dist/access-operations.d.ts +11 -11
  37. package/dist/access-operations.js +55 -49
  38. package/dist/access-recall-concurrency.d.ts +10 -10
  39. package/dist/access-recall-concurrency.js +50 -44
  40. package/dist/access-recall-response.d.ts +10 -10
  41. package/dist/access-recall-response.js +50 -44
  42. package/dist/access-recall-surface.d.ts +10 -10
  43. package/dist/access-recall-surface.js +50 -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-B6PZ_xUL.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 +50 -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 +1 -1
  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-CGFYmTT8.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 +19 -19
  85. package/dist/causal-retrieval.js +2 -2
  86. package/dist/causal-trajectory-graph.d.ts +1 -1
  87. package/dist/causal-trajectory.js +1 -1
  88. package/dist/{chunk-LEPOP46W.js → chunk-227UFSEQ.js} +4 -4
  89. package/dist/{chunk-GIBMDSJ2.js → chunk-27P5YVDU.js} +2 -2
  90. package/dist/{chunk-2SA56WMI.js → chunk-2LTDWSR6.js} +4 -4
  91. package/dist/{chunk-OWHERGF2.js → chunk-2NLLXCJG.js} +2 -2
  92. package/dist/{chunk-YTSNAUXN.js → chunk-3F2LKUMU.js} +22 -8
  93. package/dist/chunk-3F2LKUMU.js.map +1 -0
  94. package/dist/chunk-3QL24R5Y.js +9 -0
  95. package/dist/chunk-3QL24R5Y.js.map +1 -0
  96. package/dist/chunk-4RNZMRAV.js +60 -0
  97. package/dist/chunk-4RNZMRAV.js.map +1 -0
  98. package/dist/{chunk-6U7F52DE.js → chunk-4XHR3I67.js} +60 -60
  99. package/dist/chunk-5IVLTFOV.js +65 -0
  100. package/dist/chunk-5IVLTFOV.js.map +1 -0
  101. package/dist/{chunk-2EUVEDF5.js → chunk-5XA7PQ5I.js} +2 -2
  102. package/dist/{chunk-ALSGMEJR.js → chunk-65ZPVYTA.js} +7 -7
  103. package/dist/{chunk-5VQJBH2G.js → chunk-6TAUHL33.js} +2 -2
  104. package/dist/{chunk-HUHX2OCX.js → chunk-7DRETLP5.js} +1 -1
  105. package/dist/chunk-7DRETLP5.js.map +1 -0
  106. package/dist/{chunk-RGIWINDN.js → chunk-7G5MH4NT.js} +30 -30
  107. package/dist/{chunk-WVO4G37W.js → chunk-7TEZUUGM.js} +3 -3
  108. package/dist/{chunk-MJCGLM25.js → chunk-7VUAG236.js} +5 -5
  109. package/dist/{chunk-M3C2V3PV.js → chunk-AJEMDQNA.js} +12 -12
  110. package/dist/{chunk-RKNJBZ55.js → chunk-AU7Q3LSC.js} +7 -7
  111. package/dist/{chunk-ACXPX4AG.js → chunk-BR2K43MK.js} +2 -2
  112. package/dist/{chunk-IYZ5K7MU.js → chunk-BUE5E2HL.js} +4 -187
  113. package/dist/chunk-BUE5E2HL.js.map +1 -0
  114. package/dist/{chunk-CZRYLSSW.js → chunk-BUGVGH4N.js} +2 -2
  115. package/dist/{chunk-YTQNQ4KB.js → chunk-C4VQMFVM.js} +3 -3
  116. package/dist/{chunk-ZPSVBSOF.js → chunk-CIVDJD6P.js} +3 -3
  117. package/dist/{chunk-K5GB36ME.js → chunk-CZDOT5I2.js} +2 -2
  118. package/dist/{chunk-VI2JQPNQ.js → chunk-E4PWACUN.js} +2 -2
  119. package/dist/{chunk-D2ANTDGO.js → chunk-E6BMSH7U.js} +2 -2
  120. package/dist/{chunk-P5PXWTW7.js → chunk-EJCAV3QZ.js} +3 -3
  121. package/dist/{chunk-CKMO4RDY.js → chunk-EMDLM3LW.js} +4 -4
  122. package/dist/chunk-ER7W6H4T.js +112 -0
  123. package/dist/chunk-ER7W6H4T.js.map +1 -0
  124. package/dist/{chunk-6FUPCJUL.js → chunk-FI4F5X2V.js} +54 -54
  125. package/dist/chunk-FI4F5X2V.js.map +1 -0
  126. package/dist/{chunk-LGHKJABJ.js → chunk-GOUILH55.js} +40 -18
  127. package/dist/chunk-GOUILH55.js.map +1 -0
  128. package/dist/{chunk-G5R3D5UP.js → chunk-GTTAHHD3.js} +2 -2
  129. package/dist/{chunk-H5CPS5JP.js → chunk-H36LJIPD.js} +3 -3
  130. package/dist/{chunk-AITCS2RC.js → chunk-IJ7HK452.js} +4 -4
  131. package/dist/{chunk-D3LMYTBV.js → chunk-J7WZUL2K.js} +9 -9
  132. package/dist/{chunk-5W4ZLBEZ.js → chunk-JCFTIQBR.js} +2 -2
  133. package/dist/{chunk-XOZ4ALGB.js → chunk-KE353EWI.js} +3 -3
  134. package/dist/{chunk-W5EG6LE3.js → chunk-KIT6M7EB.js} +3 -3
  135. package/dist/{chunk-5W7CTZ2E.js → chunk-KQAFEZQX.js} +4 -4
  136. package/dist/{chunk-Z54EM5YZ.js → chunk-MAXVH44E.js} +7 -7
  137. package/dist/{chunk-WZFAPHIK.js → chunk-MU7ZHSZE.js} +2 -2
  138. package/dist/chunk-N5Z4EVOR.js +123 -0
  139. package/dist/chunk-N5Z4EVOR.js.map +1 -0
  140. package/dist/{chunk-66772WBP.js → chunk-NFXQJHJD.js} +5 -5
  141. package/dist/{chunk-AZ5BTEKX.js → chunk-NQUF7XKR.js} +2 -2
  142. package/dist/{chunk-W4FBGYGK.js → chunk-NRV4Y3PM.js} +1 -1
  143. package/dist/{chunk-NHWB6HG2.js → chunk-NYCGIQRA.js} +2 -2
  144. package/dist/{chunk-4WKA6I65.js → chunk-OGCNZPKX.js} +1119 -309
  145. package/dist/chunk-OGCNZPKX.js.map +1 -0
  146. package/dist/{chunk-QJAQNXWI.js → chunk-ONHRRJZM.js} +6 -6
  147. package/dist/{chunk-FDAMS4PK.js → chunk-PNPOWBGC.js} +2 -2
  148. package/dist/{chunk-IC6CBHCA.js → chunk-QGENAYVS.js} +2 -2
  149. package/dist/{chunk-GBJ4RDFR.js → chunk-QIHIHZYC.js} +66 -91
  150. package/dist/chunk-QIHIHZYC.js.map +1 -0
  151. package/dist/{chunk-YNQBRLC5.js → chunk-RUYJ7TWU.js} +517 -2011
  152. package/dist/chunk-RUYJ7TWU.js.map +1 -0
  153. package/dist/{chunk-4A6YGWQN.js → chunk-TL4TO3EA.js} +115 -120
  154. package/dist/chunk-TL4TO3EA.js.map +1 -0
  155. package/dist/{chunk-SPJXKAVF.js → chunk-U52AKICI.js} +14 -13
  156. package/dist/chunk-U52AKICI.js.map +1 -0
  157. package/dist/chunk-ULARSG5Z.js +203 -0
  158. package/dist/chunk-ULARSG5Z.js.map +1 -0
  159. package/dist/{chunk-62U4J2GN.js → chunk-UR77VKF7.js} +2 -2
  160. package/dist/{chunk-JCBWCYEJ.js → chunk-VANLTS5F.js} +2 -2
  161. package/dist/{chunk-4Z4XNEWZ.js → chunk-VCD4PSK2.js} +56 -12
  162. package/dist/chunk-VCD4PSK2.js.map +1 -0
  163. package/dist/{chunk-RMMVQQA6.js → chunk-WDISJRMG.js} +2 -2
  164. package/dist/{chunk-B6JDYXL7.js → chunk-WWUVONGW.js} +7 -1
  165. package/dist/chunk-WWUVONGW.js.map +1 -0
  166. package/dist/{chunk-UVYI6VIX.js → chunk-X7Y7WX73.js} +1 -1
  167. package/dist/{chunk-TH2LSRMG.js → chunk-XHDIB4T4.js} +2 -2
  168. package/dist/{chunk-CVILPI77.js → chunk-XOQSEF7X.js} +6 -6
  169. package/dist/{chunk-LBOD4U5B.js → chunk-YFOMN2II.js} +6 -6
  170. package/dist/{chunk-RPW2NOU6.js → chunk-YIAA2X3D.js} +41 -1
  171. package/dist/chunk-YIAA2X3D.js.map +1 -0
  172. package/dist/chunk-YPC7W6GA.js +1604 -0
  173. package/dist/chunk-YPC7W6GA.js.map +1 -0
  174. package/dist/{chunk-I5NLEENJ.js → chunk-Z4SWV4VW.js} +3 -3
  175. package/dist/{chunk-PHWUFPCO.js → chunk-ZCPP5OW6.js} +61 -53
  176. package/dist/chunk-ZCPP5OW6.js.map +1 -0
  177. package/dist/{cli-C4GbETPC.d.ts → cli-BptUDTtp.d.ts} +5 -5
  178. package/dist/cli.d.ts +12 -12
  179. package/dist/cli.js +91 -84
  180. package/dist/compounding/engine.d.ts +2 -2
  181. package/dist/compounding/engine.js +14 -14
  182. package/dist/compounding/preference-consolidator.d.ts +1 -1
  183. package/dist/compression-optimizer.d.ts +1 -1
  184. package/dist/config.d.ts +1 -1
  185. package/dist/config.js +1 -1
  186. package/dist/connectors/codex-materialize-runner.d.ts +1 -1
  187. package/dist/connectors/codex-materialize-runner.js +14 -14
  188. package/dist/connectors/codex-materialize.d.ts +1 -1
  189. package/dist/connectors/index.d.ts +1 -1
  190. package/dist/connectors/index.js +17 -17
  191. package/dist/consolidation-provenance-check.d.ts +2 -2
  192. package/dist/consolidation-provenance-check.js +5 -5
  193. package/dist/consolidation-undo.d.ts +2 -2
  194. package/dist/consolidation-undo.js +3 -3
  195. package/dist/contradiction/index.d.ts +2 -2
  196. package/dist/contradiction/index.js +4 -4
  197. package/dist/conversation-index/backend.d.ts +1 -1
  198. package/dist/conversation-index/backend.js +2 -2
  199. package/dist/conversation-index/chunker.d.ts +1 -1
  200. package/dist/conversation-index/faiss-adapter.d.ts +1 -1
  201. package/dist/conversation-index/indexer.d.ts +1 -1
  202. package/dist/conversation-index/search.d.ts +1 -1
  203. package/dist/corpus-watermark.d.ts +1 -1
  204. package/dist/corpus-watermark.js +26 -26
  205. package/dist/day-summary.d.ts +1 -1
  206. package/dist/delinearize.d.ts +1 -1
  207. package/dist/direct-answer-wiring.d.ts +1 -1
  208. package/dist/direct-answer.d.ts +1 -1
  209. package/dist/embedding-fallback.d.ts +1 -1
  210. package/dist/enrichment/index.d.ts +1 -1
  211. package/dist/entity-retrieval.d.ts +2 -2
  212. package/dist/entity-retrieval.js +14 -14
  213. package/dist/entity-schema.d.ts +1 -1
  214. package/dist/explicit-capture.d.ts +8 -8
  215. package/dist/extraction-error-classification.d.ts +1 -1
  216. package/dist/extraction-faithfulness.d.ts +1 -1
  217. package/dist/extraction-judge-telemetry.d.ts +1 -1
  218. package/dist/extraction-judge-training.d.ts +1 -1
  219. package/dist/extraction-judge.d.ts +1 -1
  220. package/dist/extraction-liveness.d.ts +1 -1
  221. package/dist/extraction-source-grounding-rules.d.ts +1 -1
  222. package/dist/extraction-source-grounding.d.ts +15 -2
  223. package/dist/extraction-source-grounding.js +10 -1
  224. package/dist/extraction.d.ts +2 -15
  225. package/dist/extraction.js +5 -4
  226. package/dist/fallback-llm.d.ts +1 -1
  227. package/dist/graph-dashboard-diff.d.ts +1 -1
  228. package/dist/graph-dashboard-key.d.ts +1 -1
  229. package/dist/graph-dashboard-parser.d.ts +1 -1
  230. package/dist/graph-edge-reinforcement.d.ts +1 -1
  231. package/dist/graph-snapshot.d.ts +1 -1
  232. package/dist/graph.d.ts +1 -1
  233. package/dist/importance.d.ts +1 -1
  234. package/dist/importers/index.d.ts +1 -1
  235. package/dist/in-flight-reads.d.ts +1 -1
  236. package/dist/index.d.ts +19 -19
  237. package/dist/index.js +215 -207
  238. package/dist/intent.d.ts +1 -1
  239. package/dist/lcm/engine.d.ts +1 -1
  240. package/dist/lcm/engine.js +3 -3
  241. package/dist/lcm/index.d.ts +1 -1
  242. package/dist/lcm/index.js +6 -6
  243. package/dist/lcm/tools.d.ts +1 -1
  244. package/dist/lifecycle.d.ts +1 -1
  245. package/dist/live-connectors-runner.d.ts +1 -1
  246. package/dist/local-llm-helpers.d.ts +7 -0
  247. package/dist/local-llm-helpers.js +16 -0
  248. package/dist/local-llm-helpers.js.map +1 -0
  249. package/dist/local-llm.d.ts +3 -6
  250. package/dist/local-llm.js +2 -1
  251. package/dist/local-model-endpoint.d.ts +1 -1
  252. package/dist/maintenance/memory-governance.d.ts +1 -1
  253. package/dist/maintenance/memory-governance.js +14 -14
  254. package/dist/maintenance/rebuild-memory-lifecycle-ledger.d.ts +2 -2
  255. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +14 -14
  256. package/dist/maintenance/rebuild-memory-projection.d.ts +2 -2
  257. package/dist/maintenance/rebuild-memory-projection.js +15 -15
  258. package/dist/{maintenance-CL30NWtc.d.ts → maintenance-b6f92bRz.d.ts} +3 -3
  259. package/dist/mcp-memory-inspector-app.d.ts +10 -10
  260. package/dist/memory-action-policy.d.ts +1 -1
  261. package/dist/memory-cache.d.ts +1 -1
  262. package/dist/memory-corpus-version.js +2 -2
  263. package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
  264. package/dist/memory-projection-store.d.ts +1 -1
  265. package/dist/memory-provenance.d.ts +1 -1
  266. package/dist/memory-worth-outcomes.d.ts +2 -2
  267. package/dist/models-json.d.ts +1 -1
  268. package/dist/namespaces/migrate.d.ts +3 -3
  269. package/dist/namespaces/migrate.js +24 -24
  270. package/dist/namespaces/principal.d.ts +1 -1
  271. package/dist/namespaces/search.d.ts +1 -1
  272. package/dist/namespaces/search.js +9 -9
  273. package/dist/namespaces/storage.d.ts +3 -3
  274. package/dist/namespaces/storage.js +14 -14
  275. package/dist/native-knowledge.d.ts +1 -1
  276. package/dist/offline-sync-impression-drain.d.ts +1 -1
  277. package/dist/offline-sync-impression-drain.js +6 -5
  278. package/dist/operator-doctor-corpus.d.ts +1 -1
  279. package/dist/operator-doctor-corpus.js +29 -29
  280. package/dist/operator-doctor-replica.d.ts +1 -1
  281. package/dist/operator-doctor-replica.js +3 -3
  282. package/dist/operator-toolkit.d.ts +3 -3
  283. package/dist/operator-toolkit.js +38 -37
  284. package/dist/orchestration/compression-guideline-coordinator.d.ts +2 -2
  285. package/dist/orchestration/maintenance.d.ts +4 -4
  286. package/dist/orchestration/maintenance.js +22 -21
  287. package/dist/{orchestrator-CKTCRwWV.d.ts → orchestrator-3uGxC1qO.d.ts} +72 -34
  288. package/dist/orchestrator.d.ts +8 -8
  289. package/dist/orchestrator.js +167 -159
  290. package/dist/page-versioning.js +3 -3
  291. package/dist/patterns-cli.d.ts +1 -1
  292. package/dist/{pipeline-B7wj4rRZ.d.ts → pipeline-DepuNr-m.d.ts} +1 -1
  293. package/dist/policy-runtime.d.ts +1 -1
  294. package/dist/proactive-contention.d.ts +1 -1
  295. package/dist/provenance.d.ts +1 -1
  296. package/dist/{qmd-q9tg4dHp.d.ts → qmd-Dalr3Jby.d.ts} +1 -1
  297. package/dist/qmd-preflight.d.ts +2 -2
  298. package/dist/qmd-recall-cache.d.ts +1 -1
  299. package/dist/qmd.d.ts +2 -2
  300. package/dist/qmd.js +4 -4
  301. package/dist/recall-concurrency-config.d.ts +1 -1
  302. package/dist/recall-disclosure-escalation.d.ts +1 -1
  303. package/dist/recall-explain-renderer.d.ts +1 -1
  304. package/dist/recall-explain-renderer.js +3 -3
  305. package/dist/recall-memory-map.d.ts +1 -1
  306. package/dist/recall-planner-llm.d.ts +1 -1
  307. package/dist/recall-state.d.ts +1 -1
  308. package/dist/recall-tag-filter.d.ts +1 -1
  309. package/dist/recall-timings.d.ts +1 -1
  310. package/dist/recall-xray-cli.d.ts +1 -1
  311. package/dist/recall-xray-cli.js +4 -4
  312. package/dist/recall-xray-renderer.d.ts +1 -1
  313. package/dist/recall-xray-renderer.js +3 -3
  314. package/dist/recall-xray.d.ts +1 -1
  315. package/dist/recall-xray.js +2 -2
  316. package/dist/replay/normalizers/chatgpt.d.ts +1 -1
  317. package/dist/replay/normalizers/claude.d.ts +1 -1
  318. package/dist/replay/normalizers/openclaw.d.ts +1 -1
  319. package/dist/replay/normalizers/shared.d.ts +1 -1
  320. package/dist/replay/runner.d.ts +1 -1
  321. package/dist/replay/types.d.ts +1 -1
  322. package/dist/replica-divergence.d.ts +1 -1
  323. package/dist/replica-divergence.js +2 -2
  324. package/dist/replica-peers-config.d.ts +1 -1
  325. package/dist/resolve-auth-token.d.ts +1 -1
  326. package/dist/resume-bundles.js +1 -1
  327. package/dist/retrieval-agents.d.ts +2 -2
  328. package/dist/retrieval-tiers.d.ts +1 -1
  329. package/dist/routing/engine.d.ts +1 -1
  330. package/dist/routing/store.d.ts +1 -1
  331. package/dist/salvage-envelope.d.ts +1 -1
  332. package/dist/{scope-profiles-CWDyglPM.d.ts → scope-profiles-BpiM5hTU.d.ts} +1 -1
  333. package/dist/search/embed-helper.d.ts +1 -1
  334. package/dist/search/factory.d.ts +1 -1
  335. package/dist/search/factory.js +8 -8
  336. package/dist/search/index.d.ts +1 -1
  337. package/dist/search/index.js +12 -12
  338. package/dist/search/lancedb-backend.d.ts +1 -1
  339. package/dist/search/meilisearch-backend.d.ts +1 -1
  340. package/dist/search/noop-backend.d.ts +1 -1
  341. package/dist/search/orama-backend.d.ts +1 -1
  342. package/dist/search/port.d.ts +1 -1
  343. package/dist/search/remote-backend.d.ts +1 -1
  344. package/dist/{semantic-consolidation-BUE3deLn.d.ts → semantic-consolidation-CMtVrf9f.d.ts} +1 -1
  345. package/dist/semantic-consolidation.d.ts +2 -2
  346. package/dist/semantic-consolidation.js +16 -16
  347. package/dist/semantic-rule-promotion.js +14 -14
  348. package/dist/semantic-rule-verifier.d.ts +1 -1
  349. package/dist/semantic-rule-verifier.js +14 -14
  350. package/dist/{service-CXgM0bQG.d.ts → service-DuAxwSgg.d.ts} +2 -2
  351. package/dist/session-observer-bands.d.ts +1 -1
  352. package/dist/session-observer-state.d.ts +1 -1
  353. package/dist/shared-context/manager.d.ts +1 -1
  354. package/dist/signal.d.ts +1 -1
  355. package/dist/{storage-DysJq-XH.d.ts → storage-CF0Ih8GP.d.ts} +1 -1
  356. package/dist/storage.d.ts +2 -2
  357. package/dist/storage.js +13 -13
  358. package/dist/summarizer.d.ts +1 -1
  359. package/dist/summarizer.js +3 -2
  360. package/dist/summary-snapshot.d.ts +1 -1
  361. package/dist/temporal-supersession.d.ts +2 -2
  362. package/dist/temporal-timeline-recall.d.ts +1 -1
  363. package/dist/temporal-validity.d.ts +1 -1
  364. package/dist/threading.d.ts +1 -1
  365. package/dist/tier-migration.d.ts +2 -2
  366. package/dist/tier-routing.d.ts +1 -1
  367. package/dist/tokens.js +2 -2
  368. package/dist/topics.d.ts +1 -1
  369. package/dist/transcript.d.ts +1 -1
  370. package/dist/transfer/backup.js +2 -2
  371. package/dist/transfer/capsule-export.js +2 -2
  372. package/dist/transfer/capsule-import.js +5 -5
  373. package/dist/trust-score-stage.d.ts +1 -1
  374. package/dist/trust-score.d.ts +1 -1
  375. package/dist/{types-aPPzhnjT.d.ts → types-BpaYvJ6v.d.ts} +22 -2
  376. package/dist/types.d.ts +1 -1
  377. package/dist/types.js +1 -1
  378. package/dist/utility-runtime.d.ts +1 -1
  379. package/dist/verified-recall.js +14 -14
  380. package/dist/write-envelope.d.ts +1 -1
  381. package/package.json +2 -2
  382. package/src/access-boundary.ts +3 -0
  383. package/src/access-cli.test.ts +93 -0
  384. package/src/access-cli.ts +56 -2
  385. package/src/access-extraction-force-flush.ts +177 -0
  386. package/src/access-http-extraction-force-flush.test.ts +132 -0
  387. package/src/access-http-lcm-compaction.ts +99 -22
  388. package/src/access-http-lifecycle-flush.ts +81 -0
  389. package/src/access-http.test.ts +227 -0
  390. package/src/access-http.ts +33 -40
  391. package/src/access-mcp-output-schemas.ts +6 -0
  392. package/src/access-mcp.test.ts +40 -0
  393. package/src/access-mcp.ts +32 -1
  394. package/src/access-observe-helpers.ts +180 -0
  395. package/src/access-observe-write-surface.ts +78 -19
  396. package/src/access-operations-batch.ts +2 -1
  397. package/src/access-schema-pi.test.ts +17 -0
  398. package/src/access-schema.ts +28 -11
  399. package/src/access-service-helpers.ts +46 -0
  400. package/src/access-service-observe-lcm-parity.test.ts +781 -31
  401. package/src/access-service-observe-scope.test.ts +88 -0
  402. package/src/access-service.ts +46 -128
  403. package/src/access-surface-catalog.test.ts +32 -0
  404. package/src/access-surface-catalog.ts +2 -0
  405. package/src/buffer-session.test.ts +148 -0
  406. package/src/buffer-turn-helpers.ts +152 -0
  407. package/src/buffer.ts +126 -201
  408. package/src/correction/correction-access-wiring.ts +79 -27
  409. package/src/correction/correction-executor.test.ts +542 -1
  410. package/src/correction/correction-executor.ts +309 -89
  411. package/src/correction/correction-planner.test.ts +35 -1
  412. package/src/correction/correction-planner.ts +50 -3
  413. package/src/correction/correction-service.ts +12 -7
  414. package/src/correction/correction-storage-integration.test.ts +172 -1
  415. package/src/correction/passive-capture.test.ts +35 -0
  416. package/src/correction/passive-capture.ts +17 -3
  417. package/src/extraction-source-grounding.ts +55 -1
  418. package/src/extraction-timeout.test.ts +51 -0
  419. package/src/extraction.ts +64 -90
  420. package/src/local-llm-headers-timeout.test.ts +48 -0
  421. package/src/local-llm-helpers.ts +58 -0
  422. package/src/local-llm.ts +62 -58
  423. package/src/orchestration/extraction-run-helpers.ts +309 -0
  424. package/src/orchestration/extraction-run.test.ts +350 -7
  425. package/src/orchestration/extraction-run.ts +327 -250
  426. package/src/orchestration/session-context.ts +193 -18
  427. package/src/orchestration/turn-ingestion.ts +61 -11
  428. package/src/orchestrator-flush.test.ts +511 -5
  429. package/src/orchestrator.ts +8 -6
  430. package/src/types.ts +2 -2
  431. package/dist/chunk-4A6YGWQN.js.map +0 -1
  432. package/dist/chunk-4WKA6I65.js.map +0 -1
  433. package/dist/chunk-4Z4XNEWZ.js.map +0 -1
  434. package/dist/chunk-6FUPCJUL.js.map +0 -1
  435. package/dist/chunk-B6JDYXL7.js.map +0 -1
  436. package/dist/chunk-GBJ4RDFR.js.map +0 -1
  437. package/dist/chunk-HUHX2OCX.js.map +0 -1
  438. package/dist/chunk-IYZ5K7MU.js.map +0 -1
  439. package/dist/chunk-LGHKJABJ.js.map +0 -1
  440. package/dist/chunk-PHWUFPCO.js.map +0 -1
  441. package/dist/chunk-RPW2NOU6.js.map +0 -1
  442. package/dist/chunk-SPJXKAVF.js.map +0 -1
  443. package/dist/chunk-YNQBRLC5.js.map +0 -1
  444. package/dist/chunk-YTSNAUXN.js.map +0 -1
  445. /package/dist/{capsule-crypto-GWVG7LGC.js.map → access-extraction-force-flush.js.map} +0 -0
  446. /package/dist/{capsule-merge-5KKJQBWQ.js.map → capsule-merge-2H2IUTBT.js.map} +0 -0
  447. /package/dist/{chunk-LEPOP46W.js.map → chunk-227UFSEQ.js.map} +0 -0
  448. /package/dist/{chunk-GIBMDSJ2.js.map → chunk-27P5YVDU.js.map} +0 -0
  449. /package/dist/{chunk-2SA56WMI.js.map → chunk-2LTDWSR6.js.map} +0 -0
  450. /package/dist/{chunk-OWHERGF2.js.map → chunk-2NLLXCJG.js.map} +0 -0
  451. /package/dist/{chunk-6U7F52DE.js.map → chunk-4XHR3I67.js.map} +0 -0
  452. /package/dist/{chunk-2EUVEDF5.js.map → chunk-5XA7PQ5I.js.map} +0 -0
  453. /package/dist/{chunk-ALSGMEJR.js.map → chunk-65ZPVYTA.js.map} +0 -0
  454. /package/dist/{chunk-5VQJBH2G.js.map → chunk-6TAUHL33.js.map} +0 -0
  455. /package/dist/{chunk-RGIWINDN.js.map → chunk-7G5MH4NT.js.map} +0 -0
  456. /package/dist/{chunk-WVO4G37W.js.map → chunk-7TEZUUGM.js.map} +0 -0
  457. /package/dist/{chunk-MJCGLM25.js.map → chunk-7VUAG236.js.map} +0 -0
  458. /package/dist/{chunk-M3C2V3PV.js.map → chunk-AJEMDQNA.js.map} +0 -0
  459. /package/dist/{chunk-RKNJBZ55.js.map → chunk-AU7Q3LSC.js.map} +0 -0
  460. /package/dist/{chunk-ACXPX4AG.js.map → chunk-BR2K43MK.js.map} +0 -0
  461. /package/dist/{chunk-CZRYLSSW.js.map → chunk-BUGVGH4N.js.map} +0 -0
  462. /package/dist/{chunk-YTQNQ4KB.js.map → chunk-C4VQMFVM.js.map} +0 -0
  463. /package/dist/{chunk-ZPSVBSOF.js.map → chunk-CIVDJD6P.js.map} +0 -0
  464. /package/dist/{chunk-K5GB36ME.js.map → chunk-CZDOT5I2.js.map} +0 -0
  465. /package/dist/{chunk-VI2JQPNQ.js.map → chunk-E4PWACUN.js.map} +0 -0
  466. /package/dist/{chunk-D2ANTDGO.js.map → chunk-E6BMSH7U.js.map} +0 -0
  467. /package/dist/{chunk-P5PXWTW7.js.map → chunk-EJCAV3QZ.js.map} +0 -0
  468. /package/dist/{chunk-CKMO4RDY.js.map → chunk-EMDLM3LW.js.map} +0 -0
  469. /package/dist/{chunk-G5R3D5UP.js.map → chunk-GTTAHHD3.js.map} +0 -0
  470. /package/dist/{chunk-H5CPS5JP.js.map → chunk-H36LJIPD.js.map} +0 -0
  471. /package/dist/{chunk-AITCS2RC.js.map → chunk-IJ7HK452.js.map} +0 -0
  472. /package/dist/{chunk-D3LMYTBV.js.map → chunk-J7WZUL2K.js.map} +0 -0
  473. /package/dist/{chunk-5W4ZLBEZ.js.map → chunk-JCFTIQBR.js.map} +0 -0
  474. /package/dist/{chunk-XOZ4ALGB.js.map → chunk-KE353EWI.js.map} +0 -0
  475. /package/dist/{chunk-W5EG6LE3.js.map → chunk-KIT6M7EB.js.map} +0 -0
  476. /package/dist/{chunk-5W7CTZ2E.js.map → chunk-KQAFEZQX.js.map} +0 -0
  477. /package/dist/{chunk-Z54EM5YZ.js.map → chunk-MAXVH44E.js.map} +0 -0
  478. /package/dist/{chunk-WZFAPHIK.js.map → chunk-MU7ZHSZE.js.map} +0 -0
  479. /package/dist/{chunk-66772WBP.js.map → chunk-NFXQJHJD.js.map} +0 -0
  480. /package/dist/{chunk-AZ5BTEKX.js.map → chunk-NQUF7XKR.js.map} +0 -0
  481. /package/dist/{chunk-W4FBGYGK.js.map → chunk-NRV4Y3PM.js.map} +0 -0
  482. /package/dist/{chunk-NHWB6HG2.js.map → chunk-NYCGIQRA.js.map} +0 -0
  483. /package/dist/{chunk-QJAQNXWI.js.map → chunk-ONHRRJZM.js.map} +0 -0
  484. /package/dist/{chunk-FDAMS4PK.js.map → chunk-PNPOWBGC.js.map} +0 -0
  485. /package/dist/{chunk-IC6CBHCA.js.map → chunk-QGENAYVS.js.map} +0 -0
  486. /package/dist/{chunk-62U4J2GN.js.map → chunk-UR77VKF7.js.map} +0 -0
  487. /package/dist/{chunk-JCBWCYEJ.js.map → chunk-VANLTS5F.js.map} +0 -0
  488. /package/dist/{chunk-RMMVQQA6.js.map → chunk-WDISJRMG.js.map} +0 -0
  489. /package/dist/{chunk-UVYI6VIX.js.map → chunk-X7Y7WX73.js.map} +0 -0
  490. /package/dist/{chunk-TH2LSRMG.js.map → chunk-XHDIB4T4.js.map} +0 -0
  491. /package/dist/{chunk-CVILPI77.js.map → chunk-XOQSEF7X.js.map} +0 -0
  492. /package/dist/{chunk-LBOD4U5B.js.map → chunk-YFOMN2II.js.map} +0 -0
  493. /package/dist/{chunk-I5NLEENJ.js.map → chunk-Z4SWV4VW.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-YFOMN2II.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-E4PWACUN.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-NFXQJHJD.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-4XHR3I67.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-5XA7PQ5I.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-XHDIB4T4.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-AJEMDQNA.js";
251
244
  import {
252
245
  NamespaceCatalog,
253
246
  planNamespaceMaintenance
254
- } from "./chunk-H5CPS5JP.js";
247
+ } from "./chunk-H36LJIPD.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-PNPOWBGC.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-FI4F5X2V.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-OGCNZPKX.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-BR2K43MK.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-QGENAYVS.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-BUGVGH4N.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-7G5MH4NT.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-7DRETLP5.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
@@ -2719,1315 +2748,62 @@ var ContradictionLinkingCoordinator = class {
2719
2748
  contradiction.supersededCreated,
2720
2749
  contradiction.supersededTags
2721
2750
  );
2722
- }
2723
- } 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");
2751
+ }
4003
2752
  } 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;
@@ -11679,7 +10455,7 @@ var RecallSearchPipelineCoordinator = class {
11679
10455
  };
11680
10456
 
11681
10457
  // src/orchestration/turn-ingestion.ts
11682
- import { createHash as createHash7, randomBytes } from "crypto";
10458
+ import { createHash as createHash5, randomBytes } from "crypto";
11683
10459
  var TurnIngestionCoordinator = class {
11684
10460
  constructor(deps) {
11685
10461
  this.deps = deps;
@@ -11742,6 +10518,7 @@ var TurnIngestionCoordinator = class {
11742
10518
  timestamp: turn.timestamp,
11743
10519
  sourceValidAt: turn.sourceValidAt,
11744
10520
  sessionKey: key,
10521
+ ...options.sessionOwnerPrincipal ? { sessionOwnerPrincipal: options.sessionOwnerPrincipal } : {},
11745
10522
  parts: turn.parts,
11746
10523
  rawContent: turn.rawContent,
11747
10524
  sourceFormat: turn.sourceFormat,
@@ -11863,7 +10640,7 @@ var TurnIngestionCoordinator = class {
11863
10640
  const shouldUseStableBatchKey = turns.some(
11864
10641
  (turn) => turn.persistProcessedFingerprint === true || typeof turn.turnFingerprint === "string" && turn.turnFingerprint.length > 0
11865
10642
  );
11866
- const stableBatchFingerprint = shouldUseStableBatchKey ? createHash7("sha256").update(
10643
+ const stableBatchFingerprint = shouldUseStableBatchKey ? createHash5("sha256").update(
11867
10644
  turns.map(
11868
10645
  (turn) => [
11869
10646
  turn.role,
@@ -12058,41 +10835,70 @@ var TurnIngestionCoordinator = class {
12058
10835
  timeout = void 0;
12059
10836
  }
12060
10837
  };
10838
+ let abortHandler;
10839
+ const clearAbortListener = () => {
10840
+ if (abortHandler && options.abortSignal) {
10841
+ options.abortSignal.removeEventListener("abort", abortHandler);
10842
+ abortHandler = void 0;
10843
+ }
10844
+ };
12061
10845
  const settleTask = (error, result) => {
12062
10846
  if (settled) return false;
12063
10847
  settled = true;
12064
10848
  clearQueueWaitTimer();
10849
+ clearAbortListener();
12065
10850
  options.onTaskSettled?.(error, result);
12066
10851
  return true;
12067
10852
  };
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)"));
10853
+ if (options.abortSignal) {
10854
+ const signal = options.abortSignal;
10855
+ abortHandler = () => settleTask(signal.reason ?? abortError("extraction aborted (queue_wait)"));
10856
+ signal.addEventListener("abort", abortHandler, { once: true });
10857
+ if (signal.aborted) {
10858
+ settleTask(signal.reason ?? abortError("extraction aborted (queue_wait)"));
12072
10859
  return;
12073
10860
  }
12074
- timeout = setTimeout(() => {
12075
- settleTask(new Error("replay extraction deadline exceeded (queue_wait)"));
12076
- }, remainingMs);
10861
+ }
10862
+ if (typeof extractionDeadlineMs === "number") {
10863
+ const deadline = extractionDeadlineMs;
10864
+ const maxTimerDelayMs = 2147483647;
10865
+ const scheduleQueueWaitTimeout = () => {
10866
+ const remainingMs = deadline - Date.now();
10867
+ if (remainingMs <= 0) {
10868
+ settleTask(new ExtractionDeadlineError("queue_wait"));
10869
+ return;
10870
+ }
10871
+ timeout = setTimeout(() => {
10872
+ if (Date.now() >= deadline) {
10873
+ settleTask(new ExtractionDeadlineError("queue_wait"));
10874
+ } else {
10875
+ scheduleQueueWaitTimeout();
10876
+ }
10877
+ }, Math.min(remainingMs, maxTimerDelayMs));
10878
+ };
10879
+ scheduleQueueWaitTimeout();
12077
10880
  }
12078
10881
  this.deps.extractionQueueCoordinator.enqueue(async () => {
12079
10882
  if (settled) return;
12080
10883
  if (typeof extractionDeadlineMs === "number" && extractionDeadlineMs <= Date.now()) {
12081
- settleTask(new Error("replay extraction deadline exceeded (queue_wait)"));
10884
+ settleTask(new ExtractionDeadlineError("queue_wait"));
12082
10885
  return;
12083
10886
  }
12084
10887
  clearQueueWaitTimer();
12085
10888
  try {
12086
10889
  const result = await this.deps.runExtraction(turnsToExtract, {
12087
10890
  clearBufferAfterExtraction: options.clearBufferAfterExtraction ?? true,
10891
+ clearMatchingTurns: options.clearMatchingTurns === true,
12088
10892
  skipCharThreshold: options.skipCharThreshold ?? false,
12089
10893
  skipUserTurnThreshold: options.skipUserTurnThreshold ?? false,
12090
10894
  deadlineMs: extractionDeadlineMs,
12091
10895
  bufferKey,
10896
+ onDurableCommit: options.onDurableCommit,
12092
10897
  abortSignal: options.abortSignal,
12093
10898
  failOnExtractionFailure: options.failOnExtractionFailure === true,
12094
10899
  writeNamespaceOverride: options.writeNamespaceOverride,
12095
10900
  principalOverride: options.principalOverride,
10901
+ scopeProfileWritePlan: options.scopeProfileWritePlan,
12096
10902
  forceExtractionAttempt: options.forceExtractionAttempt === true
12097
10903
  });
12098
10904
  settleTask(void 0, result);
@@ -12138,11 +10944,12 @@ var TurnIngestionCoordinator = class {
12138
10944
  bufferKey: opts.bufferKey,
12139
10945
  sessionKey: opts.sessionKey,
12140
10946
  principal: opts.principal,
12141
- namespace: opts.namespace
10947
+ namespace: opts.namespace,
10948
+ abortSignal: opts.abortSignal
12142
10949
  },
12143
10950
  captureConfig,
12144
10951
  {
12145
- planCorrection: (req) => service.plan(req),
10952
+ planCorrection: (req, planOpts) => service.plan(req, planOpts),
12146
10953
  applyCorrection: (planId, applyOpts) => service.apply(planId, applyOpts),
12147
10954
  storageDir: async (ns) => (await this.deps.getStorage(ns)).dir,
12148
10955
  // Resolve `[m:xxxx]` handles to concrete memory ids via the single
@@ -12175,7 +10982,7 @@ var TurnIngestionCoordinator = class {
12175
10982
 
12176
10983
  // src/orchestration/recall-introspection.ts
12177
10984
  import { mkdir as mkdir5, readFile as readFile4, writeFile as writeFile5 } from "fs/promises";
12178
- import path11 from "path";
10985
+ import path10 from "path";
12179
10986
 
12180
10987
  // src/taxonomy/default-taxonomy.ts
12181
10988
  var DEFAULT_TAXONOMY = {
@@ -12298,7 +11105,7 @@ function generateResolverDocument(taxonomy) {
12298
11105
 
12299
11106
  // src/taxonomy/taxonomy-loader.ts
12300
11107
  import { readFile as readFile3, mkdir as mkdir4, writeFile as writeFile4 } from "fs/promises";
12301
- import path10 from "path";
11108
+ import path9 from "path";
12302
11109
  var TAXONOMY_DIR = ".taxonomy";
12303
11110
  var TAXONOMY_FILE = "taxonomy.json";
12304
11111
  var MAX_SLUG_LENGTH = 32;
@@ -12396,7 +11203,7 @@ function validateTaxonomy(taxonomy) {
12396
11203
  }
12397
11204
  }
12398
11205
  async function loadTaxonomy(memoryDir) {
12399
- const taxonomyPath = path10.join(memoryDir, TAXONOMY_DIR, TAXONOMY_FILE);
11206
+ const taxonomyPath = path9.join(memoryDir, TAXONOMY_DIR, TAXONOMY_FILE);
12400
11207
  let raw;
12401
11208
  try {
12402
11209
  raw = await readFile3(taxonomyPath, "utf-8");
@@ -12446,16 +11253,16 @@ async function loadTaxonomy(memoryDir) {
12446
11253
  }
12447
11254
  async function saveTaxonomy(memoryDir, taxonomy) {
12448
11255
  validateTaxonomy(taxonomy);
12449
- const dir = path10.join(memoryDir, TAXONOMY_DIR);
11256
+ const dir = path9.join(memoryDir, TAXONOMY_DIR);
12450
11257
  await mkdir4(dir, { recursive: true });
12451
- const filePath = path10.join(dir, TAXONOMY_FILE);
11258
+ const filePath = path9.join(dir, TAXONOMY_FILE);
12452
11259
  await writeFile4(filePath, JSON.stringify(taxonomy, null, 2) + "\n", "utf-8");
12453
11260
  }
12454
11261
  function getTaxonomyDir(memoryDir) {
12455
- return path10.join(memoryDir, TAXONOMY_DIR);
11262
+ return path9.join(memoryDir, TAXONOMY_DIR);
12456
11263
  }
12457
11264
  function getTaxonomyFilePath(memoryDir) {
12458
- return path10.join(memoryDir, TAXONOMY_DIR, TAXONOMY_FILE);
11265
+ return path9.join(memoryDir, TAXONOMY_DIR, TAXONOMY_FILE);
12459
11266
  }
12460
11267
 
12461
11268
  // src/orchestration/recall-introspection.ts
@@ -12479,7 +11286,7 @@ var RecallIntrospectionCoordinator = class {
12479
11286
  }
12480
11287
  async getLastGraphRecallSnapshot(namespace) {
12481
11288
  const storage = await this.deps.getStorage(namespace);
12482
- const snapshotPath = path11.join(
11289
+ const snapshotPath = path10.join(
12483
11290
  storage.dir,
12484
11291
  "state",
12485
11292
  "last_graph_recall.json"
@@ -12518,7 +11325,7 @@ var RecallIntrospectionCoordinator = class {
12518
11325
  }
12519
11326
  async getLastIntentSnapshot(namespace) {
12520
11327
  const storage = await this.deps.getStorage(namespace);
12521
- const snapshotPath = path11.join(storage.dir, "state", "last_intent.json");
11328
+ const snapshotPath = path10.join(storage.dir, "state", "last_intent.json");
12522
11329
  try {
12523
11330
  const raw = await readFile4(snapshotPath, "utf-8");
12524
11331
  const parsed = JSON.parse(raw);
@@ -12551,7 +11358,7 @@ var RecallIntrospectionCoordinator = class {
12551
11358
  }
12552
11359
  async getLastQmdRecallSnapshot(namespace) {
12553
11360
  const storage = await this.deps.getStorage(namespace);
12554
- const snapshotPath = path11.join(
11361
+ const snapshotPath = path10.join(
12555
11362
  storage.dir,
12556
11363
  "state",
12557
11364
  "last_qmd_recall.json"
@@ -12841,12 +11648,12 @@ var RecallIntrospectionCoordinator = class {
12841
11648
  }
12842
11649
  async recordLastIntentSnapshot(options) {
12843
11650
  try {
12844
- const snapshotPath = path11.join(
11651
+ const snapshotPath = path10.join(
12845
11652
  options.storage.dir,
12846
11653
  "state",
12847
11654
  "last_intent.json"
12848
11655
  );
12849
- await mkdir5(path11.dirname(snapshotPath), { recursive: true });
11656
+ await mkdir5(path10.dirname(snapshotPath), { recursive: true });
12850
11657
  await writeFile5(
12851
11658
  snapshotPath,
12852
11659
  JSON.stringify(options.snapshot, null, 2),
@@ -12858,12 +11665,12 @@ var RecallIntrospectionCoordinator = class {
12858
11665
  }
12859
11666
  async recordLastQmdRecallSnapshot(options) {
12860
11667
  try {
12861
- const snapshotPath = path11.join(
11668
+ const snapshotPath = path10.join(
12862
11669
  options.storage.dir,
12863
11670
  "state",
12864
11671
  "last_qmd_recall.json"
12865
11672
  );
12866
- await mkdir5(path11.dirname(snapshotPath), { recursive: true });
11673
+ await mkdir5(path10.dirname(snapshotPath), { recursive: true });
12867
11674
  await writeFile5(
12868
11675
  snapshotPath,
12869
11676
  JSON.stringify(options.snapshot, null, 2),
@@ -12878,8 +11685,8 @@ var RecallIntrospectionCoordinator = class {
12878
11685
  const stateDir = await this.deps.resolveStateDirForNamespace(
12879
11686
  options.namespace
12880
11687
  );
12881
- const snapshotPath = path11.join(stateDir, "last_intent.json");
12882
- await mkdir5(path11.dirname(snapshotPath), { recursive: true });
11688
+ const snapshotPath = path10.join(stateDir, "last_intent.json");
11689
+ await mkdir5(path10.dirname(snapshotPath), { recursive: true });
12883
11690
  await writeFile5(
12884
11691
  snapshotPath,
12885
11692
  JSON.stringify(options.snapshot, null, 2),
@@ -12893,7 +11700,7 @@ var RecallIntrospectionCoordinator = class {
12893
11700
 
12894
11701
  // src/orchestration/orchestrator-init.ts
12895
11702
  import { readdir as readdir2, stat as stat2, unlink as unlink2 } from "fs/promises";
12896
- import path12 from "path";
11703
+ import path11 from "path";
12897
11704
  var OrchestratorInitCoordinator = class {
12898
11705
  constructor(deps) {
12899
11706
  this.deps = deps;
@@ -12989,7 +11796,7 @@ var OrchestratorInitCoordinator = class {
12989
11796
  const files = await readdir2(wsDir).catch(() => []);
12990
11797
  for (const f of files) {
12991
11798
  if (!f.startsWith(".compaction-reset-signal-")) continue;
12992
- const fp = path12.join(wsDir, f);
11799
+ const fp = path11.join(wsDir, f);
12993
11800
  const s = await stat2(fp).catch(() => null);
12994
11801
  if (s && Date.now() - s.mtimeMs >= COMPACTION_SIGNAL_MAX_AGE_MS) {
12995
11802
  await unlink2(fp).catch(() => {
@@ -13341,7 +12148,7 @@ var OrchestratorInitCoordinator = class {
13341
12148
  };
13342
12149
 
13343
12150
  // src/orchestration/persistence-index.ts
13344
- import path13 from "path";
12151
+ import path12 from "path";
13345
12152
  var PersistenceIndexCoordinator = class {
13346
12153
  constructor(deps) {
13347
12154
  this.deps = deps;
@@ -13527,7 +12334,7 @@ var PersistenceIndexCoordinator = class {
13527
12334
  const allMems = allMemsForGraph ?? [];
13528
12335
  for (const m of allMems) {
13529
12336
  if (m.frontmatter.entityRef === entityRef) {
13530
- const rel = path13.relative(storage.dir, m.path);
12337
+ const rel = path12.relative(storage.dir, m.path);
13531
12338
  if (rel !== memoryRelPath) entitySiblings.push(rel);
13532
12339
  }
13533
12340
  }
@@ -13676,7 +12483,7 @@ var PersistenceIndexCoordinator = class {
13676
12483
 
13677
12484
  // src/orchestration/workspace-ops.ts
13678
12485
  import { lstat, mkdir as mkdir6, readFile as readFile5, readdir as readdir3, realpath, writeFile as writeFile6 } from "fs/promises";
13679
- import path14 from "path";
12486
+ import path13 from "path";
13680
12487
 
13681
12488
  // src/maintenance/pattern-reinforcement.ts
13682
12489
  function patternReinforcementKey(content) {
@@ -15575,8 +14382,8 @@ var MeetingsService = class {
15575
14382
  // src/orchestration/workspace-ops.ts
15576
14383
  var MEETINGS_BUILD_DEBOUNCE_MS = 5e3;
15577
14384
  function matchesMemoryPath(candidatePath, requestedPath, memoryDir) {
15578
- const normalizedCandidate = path14.resolve(candidatePath);
15579
- return normalizedCandidate === path14.resolve(requestedPath) || normalizedCandidate === path14.resolve(memoryDir, requestedPath);
14385
+ const normalizedCandidate = path13.resolve(candidatePath);
14386
+ return normalizedCandidate === path13.resolve(requestedPath) || normalizedCandidate === path13.resolve(memoryDir, requestedPath);
15580
14387
  }
15581
14388
  function accessTrackingPathCandidates(storageDir, memoryPath) {
15582
14389
  const candidates = qmdResultPathCandidates(storageDir, memoryPath);
@@ -15584,12 +14391,12 @@ function accessTrackingPathCandidates(storageDir, memoryPath) {
15584
14391
  if (!parts) return candidates;
15585
14392
  candidates.push(
15586
14393
  ...qmdResultPathCandidates(storageDir, parts.relativePath),
15587
- ...qmdResultPathCandidates(path14.join(storageDir, "cold"), parts.relativePath)
14394
+ ...qmdResultPathCandidates(path13.join(storageDir, "cold"), parts.relativePath)
15588
14395
  );
15589
14396
  return [...new Set(candidates)];
15590
14397
  }
15591
14398
  function canonicalMemoryPath(memoryPath, memoryDir) {
15592
- return path14.resolve(path14.isAbsolute(memoryPath) ? memoryPath : path14.resolve(memoryDir, memoryPath));
14399
+ return path13.resolve(path13.isAbsolute(memoryPath) ? memoryPath : path13.resolve(memoryDir, memoryPath));
15593
14400
  }
15594
14401
  var WorkspaceOpsCoordinator = class {
15595
14402
  constructor(deps) {
@@ -15671,15 +14478,15 @@ var WorkspaceOpsCoordinator = class {
15671
14478
  this.deps.lastFileHygieneRunAtMs = now;
15672
14479
  if (hygiene.rotateEnabled) {
15673
14480
  for (const rel of hygiene.rotatePaths) {
15674
- const abs = path14.isAbsolute(rel) ? rel : path14.join(this.deps.config.workspaceDir, rel);
14481
+ const abs = path13.isAbsolute(rel) ? rel : path13.join(this.deps.config.workspaceDir, rel);
15675
14482
  try {
15676
14483
  const raw = await readFile5(abs, "utf-8");
15677
14484
  if (raw.length > hygiene.rotateMaxBytes) {
15678
- const archiveDir = path14.join(
14485
+ const archiveDir = path13.join(
15679
14486
  this.deps.config.workspaceDir,
15680
14487
  hygiene.archiveDir
15681
14488
  );
15682
- const base = path14.basename(abs);
14489
+ const base = path13.basename(abs);
15683
14490
  const prefix = base.toUpperCase().replace(/\.MD$/i, "").replace(/[^A-Z0-9]+/g, "-") || "FILE";
15684
14491
  const { newContent } = await rotateMarkdownFileToArchive({
15685
14492
  filePath: abs,
@@ -15704,8 +14511,8 @@ var WorkspaceOpsCoordinator = class {
15704
14511
  log.warn(w.message);
15705
14512
  }
15706
14513
  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 });
14514
+ const fp = path13.join(this.deps.config.memoryDir, hygiene.warningsLogPath);
14515
+ await mkdir6(path13.dirname(fp), { recursive: true });
15709
14516
  const stamp = (/* @__PURE__ */ new Date()).toISOString();
15710
14517
  const block = `
15711
14518
 
@@ -15745,7 +14552,7 @@ var WorkspaceOpsCoordinator = class {
15745
14552
  for (const categoryDir of RECALL_FALLBACK_DIRS) {
15746
14553
  if (memoryRootReal === null) break;
15747
14554
  for (const date of datesToScan) {
15748
- const dateDir = path14.join(storage.dir, categoryDir, date);
14555
+ const dateDir = path13.join(storage.dir, categoryDir, date);
15749
14556
  try {
15750
14557
  const dirStat = await lstat(dateDir);
15751
14558
  if (dirStat.isSymbolicLink() || !dirStat.isDirectory()) continue;
@@ -15754,7 +14561,7 @@ var WorkspaceOpsCoordinator = class {
15754
14561
  for (const entry of entries) {
15755
14562
  if (entry.isSymbolicLink()) continue;
15756
14563
  if (!entry.name.endsWith(".md")) continue;
15757
- const fullPath = path14.join(dateDir, entry.name);
14564
+ const fullPath = path13.join(dateDir, entry.name);
15758
14565
  try {
15759
14566
  assertPathInsideRoot(memoryRootReal, await realpath(fullPath), fullPath);
15760
14567
  const raw = await readFile5(fullPath, "utf-8");
@@ -15776,7 +14583,7 @@ var WorkspaceOpsCoordinator = class {
15776
14583
  facts.push({
15777
14584
  path: fullPath,
15778
14585
  frontmatter: {
15779
- id: fm.id || path14.basename(entry.name, ".md"),
14586
+ id: fm.id || path13.basename(entry.name, ".md"),
15780
14587
  category: fm.category || "fact",
15781
14588
  created,
15782
14589
  updated: fm.updated || created,
@@ -15799,13 +14606,13 @@ var WorkspaceOpsCoordinator = class {
15799
14606
  return a.frontmatter.created < b.frontmatter.created ? -1 : 1;
15800
14607
  });
15801
14608
  const hourlySummaries = [];
15802
- const hourlyBaseDir = path14.join(storage.dir, "summaries", "hourly");
14609
+ const hourlyBaseDir = path13.join(storage.dir, "summaries", "hourly");
15803
14610
  try {
15804
14611
  const sessionKeys = await readdir3(hourlyBaseDir, { withFileTypes: true });
15805
14612
  for (const sk of sessionKeys) {
15806
14613
  if (!sk.isDirectory()) continue;
15807
14614
  for (const date of datesToScan) {
15808
- const summaryFile = path14.join(hourlyBaseDir, sk.name, `${date}.md`);
14615
+ const summaryFile = path13.join(hourlyBaseDir, sk.name, `${date}.md`);
15809
14616
  try {
15810
14617
  const raw = await readFile5(summaryFile, "utf-8");
15811
14618
  const filtered = filterHourlySummaryMarkdownForLocalDay(
@@ -16269,18 +15076,18 @@ ${reflectionsContent.trim()}
16269
15076
  // src/orchestration/namespace-read-fanout.ts
16270
15077
  import { existsSync, readFileSync } from "fs";
16271
15078
  import { stat as stat3 } from "fs/promises";
16272
- import path16 from "path";
15079
+ import path15 from "path";
16273
15080
 
16274
15081
  // src/orchestration/orchestrator-namespace-scope.ts
16275
- import path15 from "path";
15082
+ import path14 from "path";
16276
15083
  function computeSemanticDedupScope(targetStorage, config) {
16277
15084
  if (!resolveNamespaceCapabilities(config).namespaces) return {};
16278
- const memoryDir = path15.resolve(config.memoryDir);
16279
- const storageDir = path15.resolve(targetStorage.dir);
15085
+ const memoryDir = path14.resolve(config.memoryDir);
15086
+ const storageDir = path14.resolve(targetStorage.dir);
16280
15087
  if (storageDir === memoryDir) {
16281
15088
  return { pathExcludePrefixes: ["namespaces/"] };
16282
15089
  }
16283
- let rel = path15.relative(memoryDir, storageDir);
15090
+ let rel = path14.relative(memoryDir, storageDir);
16284
15091
  if (!rel || rel.startsWith("..")) {
16285
15092
  log.debug(
16286
15093
  `semantic dedup: target storage dir ${storageDir} is outside memoryDir ${memoryDir}; scoping lookup to absolute path prefix`
@@ -16333,7 +15140,7 @@ var NamespaceReadFanoutCoordinator = class {
16333
15140
  loadNamespaceStorageDirHintsFromCatalog() {
16334
15141
  if (this.deps.namespaceStorageDirHintsLoaded || !this.deps.namespaceCatalog.enabled) return;
16335
15142
  this.deps.namespaceStorageDirHintsLoaded = true;
16336
- const catalogPath = path16.join(this.deps.config.memoryDir, "state", "namespaces.jsonl");
15143
+ const catalogPath = path15.join(this.deps.config.memoryDir, "state", "namespaces.jsonl");
16337
15144
  if (!existsSync(catalogPath)) return;
16338
15145
  let body;
16339
15146
  try {
@@ -16370,7 +15177,7 @@ var NamespaceReadFanoutCoordinator = class {
16370
15177
  if (!this.deps.storageDirMatchesNamespaceHint(record.namespace, record.storageDir)) {
16371
15178
  continue;
16372
15179
  }
16373
- const resolvedStorageDir = path16.resolve(record.storageDir);
15180
+ const resolvedStorageDir = path15.resolve(record.storageDir);
16374
15181
  const current = preferredByStorageDir.get(resolvedStorageDir);
16375
15182
  preferredByStorageDir.set(
16376
15183
  resolvedStorageDir,
@@ -16551,12 +15358,12 @@ var NamespaceReadFanoutCoordinator = class {
16551
15358
  }
16552
15359
  async resolveStateDirForNamespace(namespace) {
16553
15360
  if (!resolveNamespaceCapabilities(this.deps.config).namespaces) {
16554
- return path16.join(this.deps.config.memoryDir, "state");
15361
+ return path15.join(this.deps.config.memoryDir, "state");
16555
15362
  }
16556
15363
  if (namespace !== this.deps.config.defaultNamespace) {
16557
- return path16.join(this.deps.config.memoryDir, "namespaces", namespace, "state");
15364
+ return path15.join(this.deps.config.memoryDir, "namespaces", namespace, "state");
16558
15365
  }
16559
- const candidate = path16.join(
15366
+ const candidate = path15.join(
16560
15367
  this.deps.config.memoryDir,
16561
15368
  "namespaces",
16562
15369
  this.deps.config.defaultNamespace
@@ -16564,11 +15371,11 @@ var NamespaceReadFanoutCoordinator = class {
16564
15371
  try {
16565
15372
  const candidateStat = await stat3(candidate);
16566
15373
  if (candidateStat.isDirectory()) {
16567
- return path16.join(candidate, "state");
15374
+ return path15.join(candidate, "state");
16568
15375
  }
16569
15376
  } catch {
16570
15377
  }
16571
- return path16.join(this.deps.config.memoryDir, "state");
15378
+ return path15.join(this.deps.config.memoryDir, "state");
16572
15379
  }
16573
15380
  namespaceFromPath(p) {
16574
15381
  if (!resolveNamespaceCapabilities(this.deps.config).namespaces) return this.deps.config.defaultNamespace;
@@ -16781,270 +15588,6 @@ var RecallEntryCoordinator = class {
16781
15588
  }
16782
15589
  };
16783
15590
 
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
15591
  // src/orchestration/recall-background-writes.ts
17049
15592
  var pendingWritesByOwner = /* @__PURE__ */ new WeakMap();
17050
15593
  function trackRecallWrite(owner, promise, label) {
@@ -17611,7 +16154,7 @@ var Orchestrator = class {
17611
16154
  const defaultNs = normalizeNamespaceIdentity(this.config.defaultNamespace);
17612
16155
  if (ns !== defaultNs && !isSafeRouteNamespace(ns)) return;
17613
16156
  if (!this.storageDirMatchesNamespaceHint(ns, storageDir)) return;
17614
- const resolvedStorageDir = path17.resolve(storageDir);
16157
+ const resolvedStorageDir = path16.resolve(storageDir);
17615
16158
  let hints = this.namespaceStorageDirHints.get(resolvedStorageDir);
17616
16159
  if (!hints) {
17617
16160
  hints = /* @__PURE__ */ new Set();
@@ -17622,21 +16165,21 @@ var Orchestrator = class {
17622
16165
  storageDirMatchesNamespaceHint(namespace, storageDir) {
17623
16166
  const ns = normalizeNamespaceIdentity(namespace);
17624
16167
  if (!ns) return false;
17625
- const resolvedStorageDir = path17.resolve(storageDir);
17626
- const resolvedMemoryDir = path17.resolve(this.config.memoryDir);
16168
+ const resolvedStorageDir = path16.resolve(storageDir);
16169
+ const resolvedMemoryDir = path16.resolve(this.config.memoryDir);
17627
16170
  const defaultNs = normalizeNamespaceIdentity(this.config.defaultNamespace);
17628
16171
  if (resolvedStorageDir === resolvedMemoryDir) return ns === defaultNs;
17629
- const resolvedNamespacesDir = path17.join(resolvedMemoryDir, "namespaces");
16172
+ const resolvedNamespacesDir = path16.join(resolvedMemoryDir, "namespaces");
17630
16173
  if (!isPathInsideStorageRoot(resolvedNamespacesDir, resolvedStorageDir)) return false;
17631
- const rawRoot = path17.resolve(resolvedNamespacesDir, ns);
17632
- const tokenRoot = path17.resolve(resolvedNamespacesDir, namespaceIdentityToken(ns));
16174
+ const rawRoot = path16.resolve(resolvedNamespacesDir, ns);
16175
+ const tokenRoot = path16.resolve(resolvedNamespacesDir, namespaceIdentityToken(ns));
17633
16176
  return resolvedStorageDir === rawRoot || resolvedStorageDir === tokenRoot;
17634
16177
  }
17635
16178
  namespaceStorageDirHintOwnershipRank(record, resolvedStorageDir, configured) {
17636
- if (resolvedStorageDir === path17.resolve(this.config.memoryDir)) {
16179
+ if (resolvedStorageDir === path16.resolve(this.config.memoryDir)) {
17637
16180
  return record.namespace === normalizeNamespaceIdentity(this.config.defaultNamespace) ? 0 : 3;
17638
16181
  }
17639
- const leaf = path17.basename(resolvedStorageDir);
16182
+ const leaf = path16.basename(resolvedStorageDir);
17640
16183
  const tokenOwnsRoot = namespaceIdentityToken(record.namespace) === leaf;
17641
16184
  if (tokenOwnsRoot && configured.has(record.namespace)) return 0;
17642
16185
  if (record.namespace === leaf) return 1;
@@ -17772,7 +16315,7 @@ var Orchestrator = class {
17772
16315
  StorageManager.setScopedCacheInvalidationDefault(config.memoryDir, scopedCacheInvalidationEnabled);
17773
16316
  this.profiler = new ProfilingCollector({
17774
16317
  enabled: resolvePipelineProcessingCapabilities(this.config).profiling,
17775
- storageDir: config.profilingStorageDir || path17.join(config.memoryDir, "profiling"),
16318
+ storageDir: config.profilingStorageDir || path16.join(config.memoryDir, "profiling"),
17776
16319
  maxTraces: config.profilingMaxTraces
17777
16320
  });
17778
16321
  this.namespaceCatalog = new NamespaceCatalog(config);
@@ -17859,7 +16402,7 @@ var Orchestrator = class {
17859
16402
  this.compounding = resolveConsolidationCapabilities(config).compounding ? new CompoundingEngine(config, this.storage) : void 0;
17860
16403
  this.buffer = new SmartBuffer(config, this.storage);
17861
16404
  this.transcript = new TranscriptManager(config);
17862
- this.conversationIndexDir = path17.join(
16405
+ this.conversationIndexDir = path16.join(
17863
16406
  config.memoryDir,
17864
16407
  "conversation-index",
17865
16408
  "chunks"
@@ -18006,7 +16549,7 @@ var Orchestrator = class {
18006
16549
  saveContentHashIndexes: () => this.saveContentHashIndexes()
18007
16550
  });
18008
16551
  this.threading = new ThreadingManager(
18009
- path17.join(config.memoryDir, "threads"),
16552
+ path16.join(config.memoryDir, "threads"),
18010
16553
  config.threadingGapMinutes
18011
16554
  );
18012
16555
  const lifecycleCaps = resolveMemoryLifecycleCapabilities(config);
@@ -18086,7 +16629,7 @@ var Orchestrator = class {
18086
16629
  utilityPromoteThresholdDelta: this.utilityRuntimeValues?.promoteThresholdDelta ?? 0,
18087
16630
  utilityDemoteThresholdDelta: this.utilityRuntimeValues?.demoteThresholdDelta ?? 0
18088
16631
  };
18089
- return createHash8("sha256").update(JSON.stringify(payload)).digest("hex").slice(0, 12);
16632
+ return createHash6("sha256").update(JSON.stringify(payload)).digest("hex").slice(0, 12);
18090
16633
  }
18091
16634
  effectiveLifecycleThresholds() {
18092
16635
  const archiveDecayThreshold = this.config.lifecycleArchiveDecayThreshold;
@@ -20112,9 +18655,9 @@ function readStructuralSymbol(entry) {
20112
18655
  const rec = entry;
20113
18656
  const symbol = typeof rec.symbol === "string" ? rec.symbol.trim() : "";
20114
18657
  if (!symbol) return null;
20115
- const path32 = typeof rec.path === "string" && rec.path.length > 0 ? rec.path : void 0;
18658
+ const path31 = typeof rec.path === "string" && rec.path.length > 0 ? rec.path : void 0;
20116
18659
  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 };
18660
+ 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
18661
  return item;
20119
18662
  }
20120
18663
  function classifySpawnError(err) {
@@ -20188,7 +18731,7 @@ var DEFAULT_GRACE_PERIOD_DAYS = 7;
20188
18731
 
20189
18732
  // src/binary-lifecycle/backend.ts
20190
18733
  import fsp from "fs/promises";
20191
- import path18 from "path";
18734
+ import path17 from "path";
20192
18735
  var FilesystemBackend = class {
20193
18736
  type = "filesystem";
20194
18737
  basePath;
@@ -20196,19 +18739,19 @@ var FilesystemBackend = class {
20196
18739
  if (!basePath || basePath.trim().length === 0) {
20197
18740
  throw new Error("FilesystemBackend requires a non-empty basePath");
20198
18741
  }
20199
- this.basePath = path18.resolve(basePath);
18742
+ this.basePath = path17.resolve(basePath);
20200
18743
  }
20201
18744
  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)) {
18745
+ const resolved = path17.isAbsolute(remotePath) ? path17.resolve(remotePath) : path17.resolve(this.basePath, remotePath);
18746
+ const relative = path17.relative(this.basePath, resolved);
18747
+ if (relative === ".." || relative.startsWith(`..${path17.sep}`) || path17.isAbsolute(relative)) {
20205
18748
  throw new Error(`FilesystemBackend remotePath escapes basePath: ${JSON.stringify(remotePath)}`);
20206
18749
  }
20207
18750
  return resolved;
20208
18751
  }
20209
18752
  isInsideBase(candidate, realBase) {
20210
- const relative = path18.relative(realBase, candidate);
20211
- return relative === "" || relative !== ".." && !relative.startsWith(`..${path18.sep}`) && !path18.isAbsolute(relative);
18753
+ const relative = path17.relative(realBase, candidate);
18754
+ return relative === "" || relative !== ".." && !relative.startsWith(`..${path17.sep}`) && !path17.isAbsolute(relative);
20212
18755
  }
20213
18756
  async realBasePathIfExists() {
20214
18757
  try {
@@ -20237,13 +18780,13 @@ var FilesystemBackend = class {
20237
18780
  }
20238
18781
  async ensureSafeParentDirectory(dest) {
20239
18782
  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);
18783
+ const destDir = path17.dirname(dest);
18784
+ const relativeDir = path17.relative(this.basePath, destDir);
18785
+ const segments = relativeDir === "" ? [] : relativeDir.split(path17.sep);
20243
18786
  let current = this.basePath;
20244
18787
  for (const segment of segments) {
20245
18788
  if (segment === "." || segment === "") continue;
20246
- current = path18.join(current, segment);
18789
+ current = path17.join(current, segment);
20247
18790
  try {
20248
18791
  const stat5 = await fsp.lstat(current);
20249
18792
  if (stat5.isSymbolicLink()) {
@@ -20271,13 +18814,13 @@ var FilesystemBackend = class {
20271
18814
  if (realBase === null) {
20272
18815
  return null;
20273
18816
  }
20274
- const destDir = path18.dirname(dest);
20275
- const relativeDir = path18.relative(this.basePath, destDir);
20276
- const segments = relativeDir === "" ? [] : relativeDir.split(path18.sep);
18817
+ const destDir = path17.dirname(dest);
18818
+ const relativeDir = path17.relative(this.basePath, destDir);
18819
+ const segments = relativeDir === "" ? [] : relativeDir.split(path17.sep);
20277
18820
  let current = this.basePath;
20278
18821
  for (const segment of segments) {
20279
18822
  if (segment === "." || segment === "") continue;
20280
- current = path18.join(current, segment);
18823
+ current = path17.join(current, segment);
20281
18824
  let stat5;
20282
18825
  try {
20283
18826
  stat5 = await fsp.lstat(current);
@@ -20325,7 +18868,7 @@ var FilesystemBackend = class {
20325
18868
  return dest;
20326
18869
  }
20327
18870
  async upload(localPath, remotePath) {
20328
- if (path18.isAbsolute(remotePath)) {
18871
+ if (path17.isAbsolute(remotePath)) {
20329
18872
  throw new Error(`FilesystemBackend upload remotePath must be relative: ${JSON.stringify(remotePath)}`);
20330
18873
  }
20331
18874
  const dest = this.resolveRemotePath(remotePath);
@@ -20398,7 +18941,7 @@ function createBackend(cfg) {
20398
18941
 
20399
18942
  // src/binary-lifecycle/scanner.ts
20400
18943
  import fsp2 from "fs/promises";
20401
- import path19 from "path";
18944
+ import path18 from "path";
20402
18945
  import crypto from "crypto";
20403
18946
  function matchesPatterns(filename, patterns) {
20404
18947
  const lower = filename.toLowerCase();
@@ -20423,8 +18966,8 @@ async function scanForBinaries(memoryDir, config, manifest) {
20423
18966
  return;
20424
18967
  }
20425
18968
  for (const entry of entries) {
20426
- const fullPath = path19.join(dir, entry.name);
20427
- const relativePath = path19.relative(memoryDir, fullPath).split(path19.sep).join("/");
18969
+ const fullPath = path18.join(dir, entry.name);
18970
+ const relativePath = path18.relative(memoryDir, fullPath).split(path18.sep).join("/");
20428
18971
  if (entry.isDirectory()) {
20429
18972
  if (entry.name === ".binary-lifecycle") continue;
20430
18973
  await walk(fullPath);
@@ -20464,15 +19007,15 @@ async function hashFile(filePath) {
20464
19007
 
20465
19008
  // src/binary-lifecycle/manifest.ts
20466
19009
  import fsp3 from "fs/promises";
20467
- import path20 from "path";
19010
+ import path19 from "path";
20468
19011
  import crypto2 from "crypto";
20469
19012
  var MANIFEST_DIR = ".binary-lifecycle";
20470
19013
  var MANIFEST_FILE = "manifest.json";
20471
19014
  function manifestDir(memoryDir) {
20472
- return path20.join(memoryDir, MANIFEST_DIR);
19015
+ return path19.join(memoryDir, MANIFEST_DIR);
20473
19016
  }
20474
19017
  function manifestPath(memoryDir) {
20475
- return path20.join(memoryDir, MANIFEST_DIR, MANIFEST_FILE);
19018
+ return path19.join(memoryDir, MANIFEST_DIR, MANIFEST_FILE);
20476
19019
  }
20477
19020
  async function readManifest(memoryDir) {
20478
19021
  const filePath = manifestPath(memoryDir);
@@ -20524,12 +19067,12 @@ function emptyManifest() {
20524
19067
 
20525
19068
  // src/binary-lifecycle/pipeline.ts
20526
19069
  import fsp4 from "fs/promises";
20527
- import path21 from "path";
19070
+ import path20 from "path";
20528
19071
  import crypto3 from "crypto";
20529
19072
  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];
19073
+ const rel = path20.relative(memoryDir, mdPath);
19074
+ if (rel.startsWith("..") || path20.isAbsolute(rel)) return false;
19075
+ const top = rel.split(path20.sep)[0];
20533
19076
  return RECALL_FALLBACK_DIRS.includes(top);
20534
19077
  }
20535
19078
  async function hashFile2(filePath) {
@@ -20553,13 +19096,13 @@ function escapeRegex(s) {
20553
19096
  return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
20554
19097
  }
20555
19098
  function resolveManifestAssetPath(memoryDir, originalPath) {
20556
- if (originalPath.length === 0 || originalPath.includes("\0") || originalPath.includes("\\") || path21.isAbsolute(originalPath) || path21.win32.isAbsolute(originalPath)) {
19099
+ if (originalPath.length === 0 || originalPath.includes("\0") || originalPath.includes("\\") || path20.isAbsolute(originalPath) || path20.win32.isAbsolute(originalPath)) {
20557
19100
  return null;
20558
19101
  }
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)) {
19102
+ const memoryRoot = path20.resolve(memoryDir);
19103
+ const fullPath = path20.resolve(memoryRoot, originalPath);
19104
+ const relative = path20.relative(memoryRoot, fullPath);
19105
+ if (relative === "" || relative === ".." || relative.startsWith(`..${path20.sep}`) || path20.isAbsolute(relative)) {
20563
19106
  return null;
20564
19107
  }
20565
19108
  return fullPath;
@@ -20570,7 +19113,7 @@ function validateBinaryLifecycleConfig(config) {
20570
19113
  }
20571
19114
  }
20572
19115
  function remotePathForAsset(backend, relPath) {
20573
- const normalized = relPath.split(path21.sep).join("/");
19116
+ const normalized = relPath.split(path20.sep).join("/");
20574
19117
  if (backend.type === "filesystem") {
20575
19118
  return `.binary-lifecycle/mirrors/${normalized}`;
20576
19119
  }
@@ -20583,11 +19126,11 @@ async function stageMirror(memoryDir, newPaths, backend, assets, log2, dryRun) {
20583
19126
  let mirrored = 0;
20584
19127
  const errors = [];
20585
19128
  for (const relPath of newPaths) {
20586
- const fullPath = path21.join(memoryDir, relPath);
19129
+ const fullPath = path20.join(memoryDir, relPath);
20587
19130
  try {
20588
19131
  const stat5 = await fsp4.stat(fullPath);
20589
19132
  const contentHash = await hashFile2(fullPath);
20590
- const ext = path21.extname(relPath);
19133
+ const ext = path20.extname(relPath);
20591
19134
  const mimeType = guessMimeType(ext);
20592
19135
  const remotePath = remotePathForAsset(backend, relPath);
20593
19136
  let backendLocation = remotePath;
@@ -20790,10 +19333,10 @@ async function countRemainingLocalReferences(memoryDir, asset, assetAbsolute, md
20790
19333
  return { remaining, errors };
20791
19334
  }
20792
19335
  function markdownReferencePattern(asset, assetAbsolute, mdPath) {
20793
- const mdDir = path21.dirname(mdPath);
19336
+ const mdDir = path20.dirname(mdPath);
20794
19337
  const candidates = /* @__PURE__ */ new Set();
20795
19338
  const addCandidate = (candidate) => {
20796
- const normalized = candidate.split(path21.sep).join("/");
19339
+ const normalized = candidate.split(path20.sep).join("/");
20797
19340
  if (normalized.length === 0) return;
20798
19341
  candidates.add(normalized);
20799
19342
  const isParentTraversal = normalized === ".." || normalized.startsWith("../");
@@ -20801,10 +19344,10 @@ function markdownReferencePattern(asset, assetAbsolute, mdPath) {
20801
19344
  candidates.add(`./${normalized}`);
20802
19345
  }
20803
19346
  };
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)) {
19347
+ addCandidate(path20.relative(mdDir, assetAbsolute));
19348
+ const originalPath = asset.originalPath.split(path20.sep).join("/");
19349
+ const originalAsFileRelative = path20.resolve(mdDir, ...originalPath.split("/"));
19350
+ if (path20.resolve(originalAsFileRelative) === path20.resolve(assetAbsolute)) {
20808
19351
  addCandidate(originalPath);
20809
19352
  }
20810
19353
  addCandidate(`/${originalPath}`);
@@ -20900,7 +19443,7 @@ async function findMarkdownFiles(dir) {
20900
19443
  return;
20901
19444
  }
20902
19445
  for (const entry of entries) {
20903
- const full = path21.join(current, entry.name);
19446
+ const full = path20.join(current, entry.name);
20904
19447
  if (entry.isDirectory()) {
20905
19448
  if (entry.name === ".binary-lifecycle") continue;
20906
19449
  await walk(full);
@@ -20975,7 +19518,7 @@ async function runBinaryLifecyclePipeline(memoryDir, config, backend, log2, opts
20975
19518
 
20976
19519
  // src/projection/index.ts
20977
19520
  import fs from "fs";
20978
- import path22 from "path";
19521
+ import path21 from "path";
20979
19522
  var VALID_PROJECTION_CATEGORIES = new Set(ALL_CATEGORY_KEYS);
20980
19523
  async function generateContextTree(options) {
20981
19524
  const startTime = Date.now();
@@ -20990,8 +19533,8 @@ async function generateContextTree(options) {
20990
19533
  let nodesGenerated = 0;
20991
19534
  let nodesSkipped = 0;
20992
19535
  const categoryCounts = {};
20993
- const resolvedMemoryDir = path22.resolve(memoryDir);
20994
- const resolvedOutputDir = path22.resolve(outputDir);
19536
+ const resolvedMemoryDir = path21.resolve(memoryDir);
19537
+ const resolvedOutputDir = path21.resolve(outputDir);
20995
19538
  const requestedCategories = validateProjectionCategories(filterCategories);
20996
19539
  const realMemoryDir = assertSafeMemoryRoot(resolvedMemoryDir);
20997
19540
  assertNotSymlink(resolvedOutputDir, "context tree outputDir");
@@ -21029,7 +19572,7 @@ async function generateContextTree(options) {
21029
19572
  }
21030
19573
  }
21031
19574
  if (includeEntities) {
21032
- const entitiesDir = path22.join(memoryDir, "entities");
19575
+ const entitiesDir = path21.join(memoryDir, "entities");
21033
19576
  if (fs.existsSync(entitiesDir)) {
21034
19577
  assertSafeInputRoot(realMemoryDir, entitiesDir, "entities root");
21035
19578
  categoryCounts["entity"] = 0;
@@ -21041,7 +19584,7 @@ async function generateContextTree(options) {
21041
19584
  continue;
21042
19585
  }
21043
19586
  const content = fs.readFileSync(filePath, "utf8");
21044
- const fileName = path22.basename(filePath, ".md");
19587
+ const fileName = path21.basename(filePath, ".md");
21045
19588
  const node = projectEntityNode(fileName, content);
21046
19589
  const outputPath = resolveContainedOutputPath(realOutputDir, "entities", `${fileName}.md`);
21047
19590
  writeProjectedContent(realOutputDir, outputPath, node.content);
@@ -21053,7 +19596,7 @@ async function generateContextTree(options) {
21053
19596
  }
21054
19597
  const shouldIncludeQuestions = includeQuestions && (requestedCategories === void 0 || requestedCategories.includes("question"));
21055
19598
  if (shouldIncludeQuestions) {
21056
- const questionsDir = path22.join(memoryDir, "questions");
19599
+ const questionsDir = path21.join(memoryDir, "questions");
21057
19600
  if (fs.existsSync(questionsDir)) {
21058
19601
  assertSafeInputRoot(realMemoryDir, questionsDir, "questions root");
21059
19602
  categoryCounts["question"] = 0;
@@ -21094,8 +19637,8 @@ async function generateContextTree(options) {
21094
19637
  };
21095
19638
  }
21096
19639
  function isPathInside(root, candidate) {
21097
- const relative = path22.relative(root, candidate);
21098
- return relative === "" || !relative.startsWith("..") && !path22.isAbsolute(relative);
19640
+ const relative = path21.relative(root, candidate);
19641
+ return relative === "" || !relative.startsWith("..") && !path21.isAbsolute(relative);
21099
19642
  }
21100
19643
  function assertNotSymlink(targetPath, label) {
21101
19644
  try {
@@ -21132,12 +19675,12 @@ function assertSafeInputRoot(realMemoryDir, targetPath, label) {
21132
19675
  }
21133
19676
  function assertSafeOutputTarget(realOutputDir, outputPath) {
21134
19677
  let current = realOutputDir;
21135
- const relative = path22.relative(realOutputDir, outputPath);
21136
- if (relative.startsWith("..") || path22.isAbsolute(relative)) {
19678
+ const relative = path21.relative(realOutputDir, outputPath);
19679
+ if (relative.startsWith("..") || path21.isAbsolute(relative)) {
21137
19680
  throw new Error(`context tree output path escapes outputDir: ${outputPath}`);
21138
19681
  }
21139
- for (const segment of relative.split(path22.sep).filter(Boolean)) {
21140
- current = path22.join(current, segment);
19682
+ for (const segment of relative.split(path21.sep).filter(Boolean)) {
19683
+ current = path21.join(current, segment);
21141
19684
  try {
21142
19685
  const stat5 = fs.lstatSync(current);
21143
19686
  if (stat5.isSymbolicLink()) {
@@ -21167,17 +19710,17 @@ function validateProjectionCategories(categories) {
21167
19710
  return validated;
21168
19711
  }
21169
19712
  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)) {
19713
+ const resolved = path21.resolve(outputRoot, ...segments);
19714
+ const relative = path21.relative(outputRoot, resolved);
19715
+ if (relative === "" || !relative.startsWith("..") && !path21.isAbsolute(relative)) {
21173
19716
  return resolved;
21174
19717
  }
21175
19718
  throw new Error(`context tree output path escapes outputDir: ${segments.join("/")}`);
21176
19719
  }
21177
19720
  function writeProjectedContent(realOutputDir, outputPath, generatedContent) {
21178
19721
  assertSafeOutputTarget(realOutputDir, outputPath);
21179
- fs.mkdirSync(path22.dirname(outputPath), { recursive: true });
21180
- const realParent = fs.realpathSync(path22.dirname(outputPath));
19722
+ fs.mkdirSync(path21.dirname(outputPath), { recursive: true });
19723
+ const realParent = fs.realpathSync(path21.dirname(outputPath));
21181
19724
  if (!isPathInside(realOutputDir, realParent)) {
21182
19725
  throw new Error(`context tree output path escapes outputDir: ${outputPath}`);
21183
19726
  }
@@ -21216,7 +19759,7 @@ function walkR(dir, realMemoryDir) {
21216
19759
  const results = [];
21217
19760
  function walk(directory) {
21218
19761
  for (const entry of fs.readdirSync(directory, { withFileTypes: true })) {
21219
- const fullPath = path22.join(directory, entry.name);
19762
+ const fullPath = path21.join(directory, entry.name);
21220
19763
  if (entry.isSymbolicLink()) {
21221
19764
  throw new Error(`context tree input path contains symlink: ${fullPath}`);
21222
19765
  }
@@ -21269,13 +19812,13 @@ function extractBody(content) {
21269
19812
  }
21270
19813
  function projectNode(filePath, category, fm, rawContent) {
21271
19814
  const body = extractBody(rawContent);
21272
- const fileName = path22.basename(filePath, ".md");
21273
- const dateDir = path22.basename(path22.dirname(filePath));
19815
+ const fileName = path21.basename(filePath, ".md");
19816
+ const dateDir = path21.basename(path21.dirname(filePath));
21274
19817
  let relPath;
21275
19818
  if (/^\d{4}-\d{2}-\d{2}$/.test(dateDir)) {
21276
- relPath = path22.join(category, dateDir, `${fileName}.md`);
19819
+ relPath = path21.join(category, dateDir, `${fileName}.md`);
21277
19820
  } else {
21278
- relPath = path22.join(category, `${fileName}.md`);
19821
+ relPath = path21.join(category, `${fileName}.md`);
21279
19822
  }
21280
19823
  const generatedAt = (/* @__PURE__ */ new Date()).toISOString();
21281
19824
  const md = `# ${fm.id}
@@ -21321,7 +19864,7 @@ function projectEntityNode(fileName, content) {
21321
19864
  ${content}
21322
19865
  `;
21323
19866
  return {
21324
- path: path22.join("entities", `${fileName}.md`),
19867
+ path: path21.join("entities", `${fileName}.md`),
21325
19868
  category: "entity",
21326
19869
  title: fileName,
21327
19870
  content: md,
@@ -21374,7 +19917,7 @@ function generateIndex(categoryCounts, outputDir) {
21374
19917
 
21375
19918
  // src/onboarding/index.ts
21376
19919
  import fs2 from "fs";
21377
- import path23 from "path";
19920
+ import path22 from "path";
21378
19921
  var LANGUAGE_RULES = [
21379
19922
  {
21380
19923
  language: "TypeScript",
@@ -21476,7 +20019,7 @@ function onboard(options) {
21476
20019
  maxDepth = 6,
21477
20020
  excludeDirs = []
21478
20021
  } = options;
21479
- const directory = path23.resolve(options.directory ?? process.cwd());
20022
+ const directory = path22.resolve(options.directory ?? process.cwd());
21480
20023
  let rootStat;
21481
20024
  try {
21482
20025
  rootStat = fs2.statSync(directory);
@@ -21518,7 +20061,7 @@ function walkDir(root, exclude, maxDepth) {
21518
20061
  }
21519
20062
  for (const entry of entries) {
21520
20063
  if (exclude.has(entry.name)) continue;
21521
- const fullPath = path23.join(dir, entry.name);
20064
+ const fullPath = path22.join(dir, entry.name);
21522
20065
  if (entry.isDirectory()) {
21523
20066
  walk(fullPath, depth + 1);
21524
20067
  } else if (entry.isFile()) {
@@ -21533,11 +20076,11 @@ function detectLanguages(files, root) {
21533
20076
  const results = [];
21534
20077
  const extCounts = /* @__PURE__ */ new Map();
21535
20078
  for (const f of files) {
21536
- const ext = path23.extname(f).toLowerCase();
20079
+ const ext = path22.extname(f).toLowerCase();
21537
20080
  if (ext) extCounts.set(ext, (extCounts.get(ext) ?? 0) + 1);
21538
20081
  }
21539
20082
  const rootFiles = new Set(
21540
- files.filter((f) => path23.dirname(f) === root).map((f) => path23.basename(f))
20083
+ files.filter((f) => path22.dirname(f) === root).map((f) => path22.basename(f))
21541
20084
  );
21542
20085
  for (const rule of LANGUAGE_RULES) {
21543
20086
  const evidence = [];
@@ -21581,7 +20124,7 @@ function detectLanguages(files, root) {
21581
20124
  }
21582
20125
  function detectShape(files, root) {
21583
20126
  const rootFiles = new Set(
21584
- files.filter((f) => path23.dirname(f) === root).map((f) => path23.basename(f))
20127
+ files.filter((f) => path22.dirname(f) === root).map((f) => path22.basename(f))
21585
20128
  );
21586
20129
  const rootDirs = /* @__PURE__ */ new Set();
21587
20130
  try {
@@ -21592,7 +20135,7 @@ function detectShape(files, root) {
21592
20135
  }
21593
20136
  const evidence = [];
21594
20137
  if (rootFiles.has("package.json")) {
21595
- const pkg = readJsonSafe(path23.join(root, "package.json"));
20138
+ const pkg = readJsonSafe(path22.join(root, "package.json"));
21596
20139
  if (pkg?.workspaces) {
21597
20140
  evidence.push("package.json has workspaces");
21598
20141
  return { shape: "monorepo", evidence };
@@ -21606,13 +20149,13 @@ function detectShape(files, root) {
21606
20149
  evidence.push("workspace manifest found");
21607
20150
  return { shape: "workspace", evidence };
21608
20151
  }
21609
- const cargoToml = readTomlWorkspace(path23.join(root, "Cargo.toml"));
20152
+ const cargoToml = readTomlWorkspace(path22.join(root, "Cargo.toml"));
21610
20153
  if (cargoToml) {
21611
20154
  evidence.push("Cargo.toml has workspace");
21612
20155
  return { shape: "workspace", evidence };
21613
20156
  }
21614
20157
  if (rootFiles.has("package.json")) {
21615
- const pkg = readJsonSafe(path23.join(root, "package.json"));
20158
+ const pkg = readJsonSafe(path22.join(root, "package.json"));
21616
20159
  if (pkg?.exports || pkg?.main) {
21617
20160
  if (pkg?.bin) {
21618
20161
  evidence.push("package.json has bin");
@@ -21646,8 +20189,8 @@ function discoverDocs(files, root) {
21646
20189
  { pattern: /^\.editorconfig$/i, kind: "config" }
21647
20190
  ];
21648
20191
  for (const filePath of files) {
21649
- const basename = path23.basename(filePath).toLowerCase();
21650
- const relPath = path23.relative(root, filePath);
20192
+ const basename = path22.basename(filePath).toLowerCase();
20193
+ const relPath = path22.relative(root, filePath);
21651
20194
  let kind;
21652
20195
  for (const { pattern, kind: k } of docPatterns) {
21653
20196
  if (pattern.test(basename)) {
@@ -21659,7 +20202,7 @@ function discoverDocs(files, root) {
21659
20202
  kind = "docs";
21660
20203
  }
21661
20204
  if (!kind && (basename.endsWith(".md") || basename.endsWith(".mdx"))) {
21662
- if (path23.dirname(relPath) === "." || isUnderDocsDir(relPath)) {
20205
+ if (path22.dirname(relPath) === "." || isUnderDocsDir(relPath)) {
21663
20206
  kind = "docs";
21664
20207
  }
21665
20208
  }
@@ -21680,7 +20223,7 @@ function discoverDocs(files, root) {
21680
20223
  return docs;
21681
20224
  }
21682
20225
  function isUnderDocsDir(relPath) {
21683
- const parts = relPath.split(path23.sep);
20226
+ const parts = relPath.split(path22.sep);
21684
20227
  return parts[0] === "docs" || parts[0] === "doc" || parts[0] === "documentation";
21685
20228
  }
21686
20229
  function buildPlan(languages, shape, docs, _root) {
@@ -21724,7 +20267,7 @@ function readTomlWorkspace(filePath) {
21724
20267
 
21725
20268
  // src/curation/index.ts
21726
20269
  import fs3 from "fs";
21727
- import path24 from "path";
20270
+ import path23 from "path";
21728
20271
  import crypto4 from "crypto";
21729
20272
  async function curate(options) {
21730
20273
  const startTime = Date.now();
@@ -21815,12 +20358,12 @@ function resolveTargets(targetPath) {
21815
20358
  const extensions = /* @__PURE__ */ new Set([".md", ".txt", ".mdx", ".rst"]);
21816
20359
  function walk(dir) {
21817
20360
  for (const entry of fs3.readdirSync(dir, { withFileTypes: true })) {
21818
- const fullPath = path24.join(dir, entry.name);
20361
+ const fullPath = path23.join(dir, entry.name);
21819
20362
  if (entry.isDirectory()) {
21820
20363
  if (entry.name !== "node_modules" && entry.name !== ".git") {
21821
20364
  walk(fullPath);
21822
20365
  }
21823
- } else if (extensions.has(path24.extname(entry.name).toLowerCase())) {
20366
+ } else if (extensions.has(path23.extname(entry.name).toLowerCase())) {
21824
20367
  results.push(fullPath);
21825
20368
  }
21826
20369
  }
@@ -21829,12 +20372,12 @@ function resolveTargets(targetPath) {
21829
20372
  return results;
21830
20373
  }
21831
20374
  function resolveProvenanceRoot(targetPath) {
21832
- const resolvedTarget = path24.resolve(targetPath);
20375
+ const resolvedTarget = path23.resolve(targetPath);
21833
20376
  const stat5 = fs3.statSync(resolvedTarget);
21834
- return stat5.isFile() ? path24.dirname(resolvedTarget) : resolvedTarget;
20377
+ return stat5.isFile() ? path23.dirname(resolvedTarget) : resolvedTarget;
21835
20378
  }
21836
20379
  function extractStatements(content, filePath, projectRoot, source, sourceFileHash, categoryOverride, confidence, entityRef, tags) {
21837
- const relativePath = path24.relative(projectRoot, path24.resolve(filePath)) || path24.basename(filePath);
20380
+ const relativePath = path23.relative(projectRoot, path23.resolve(filePath)) || path23.basename(filePath);
21838
20381
  const statements = [];
21839
20382
  const now = (/* @__PURE__ */ new Date()).toISOString();
21840
20383
  const paragraphs = content.split(/\n{2,}/).map((p) => p.trim()).filter((p) => p.length > 20 && p.length < 2e3);
@@ -21928,7 +20471,7 @@ function loadExistingMemories(memoryDir) {
21928
20471
  if (!fs3.existsSync(memoryDir)) return result;
21929
20472
  const dirs = ALL_CATEGORY_DIRS;
21930
20473
  for (const dir of dirs) {
21931
- const fullDir = path24.join(memoryDir, dir);
20474
+ const fullDir = path23.join(memoryDir, dir);
21932
20475
  if (!fs3.existsSync(fullDir)) continue;
21933
20476
  walkFiles(fullDir, (filePath) => {
21934
20477
  const content = readFileSafe(filePath);
@@ -21950,10 +20493,10 @@ function writeStatement(stmt, memoryDir) {
21950
20493
  const now = /* @__PURE__ */ new Date();
21951
20494
  const dateDir = now.toISOString().split("T")[0];
21952
20495
  const categoryDir = getCategoryDir(memoryDir, stmt.category);
21953
- const dir = path24.join(categoryDir, dateDir);
20496
+ const dir = path23.join(categoryDir, dateDir);
21954
20497
  fs3.mkdirSync(dir, { recursive: true });
21955
20498
  const fileName = `${stmt.category}-${Date.now()}-${stmt.id.slice(0, 8)}.md`;
21956
- const filePath = path24.join(dir, fileName);
20499
+ const filePath = path23.join(dir, fileName);
21957
20500
  const frontmatter = [
21958
20501
  "---",
21959
20502
  `id: ${stmt.id}`,
@@ -22021,7 +20564,7 @@ function extractBody2(content) {
22021
20564
  }
22022
20565
  function walkFiles(dir, callback) {
22023
20566
  for (const entry of fs3.readdirSync(dir, { withFileTypes: true })) {
22024
- const fullPath = path24.join(dir, entry.name);
20567
+ const fullPath = path23.join(dir, entry.name);
22025
20568
  if (entry.isDirectory()) {
22026
20569
  walkFiles(fullPath, callback);
22027
20570
  } else if (entry.name.endsWith(".md")) {
@@ -22032,7 +20575,7 @@ function walkFiles(dir, callback) {
22032
20575
 
22033
20576
  // src/dedup/index.ts
22034
20577
  import fs4 from "fs";
22035
- import path25 from "path";
20578
+ import path24 from "path";
22036
20579
  import crypto5 from "crypto";
22037
20580
  var DEFAULT_DEDUP_THRESHOLD = 0.85;
22038
20581
  var DEFAULT_MAX_LOAD = 1e4;
@@ -22174,7 +20717,7 @@ function loadMemories(memoryDir, categories, maxLoad = 1e4) {
22174
20717
  const memoryRootReal = fs4.realpathSync(memoryDir);
22175
20718
  for (const category of allCategories) {
22176
20719
  if (result.length >= maxLoad) break;
22177
- const dir = path25.join(memoryDir, category);
20720
+ const dir = path24.join(memoryDir, category);
22178
20721
  if (!fs4.existsSync(dir)) continue;
22179
20722
  const categoryStat = fs4.lstatSync(dir);
22180
20723
  if (categoryStat.isSymbolicLink()) {
@@ -22235,15 +20778,15 @@ function extractBody3(content) {
22235
20778
  return match ? match[1].trim() : content.trim();
22236
20779
  }
22237
20780
  function assertPathInsideRoot2(rootReal, targetReal, sourcePath) {
22238
- const rel = path25.relative(rootReal, targetReal);
22239
- if (rel === "" || !rel.startsWith("..") && !path25.isAbsolute(rel)) {
20781
+ const rel = path24.relative(rootReal, targetReal);
20782
+ if (rel === "" || !rel.startsWith("..") && !path24.isAbsolute(rel)) {
22240
20783
  return;
22241
20784
  }
22242
20785
  throw new Error(`Refusing to scan memory path outside root: ${sourcePath}`);
22243
20786
  }
22244
20787
  function walkMdFiles(dir, memoryRootReal, categoryRootReal, callback) {
22245
20788
  for (const entry of fs4.readdirSync(dir, { withFileTypes: true })) {
22246
- const fullPath = path25.join(dir, entry.name);
20789
+ const fullPath = path24.join(dir, entry.name);
22247
20790
  const entryStat = fs4.lstatSync(fullPath);
22248
20791
  if (entryStat.isSymbolicLink()) {
22249
20792
  throw new Error(`Refusing to scan symlinked memory path: ${fullPath}`);
@@ -22261,7 +20804,7 @@ function walkMdFiles(dir, memoryRootReal, categoryRootReal, callback) {
22261
20804
 
22262
20805
  // src/review/index.ts
22263
20806
  import fs5 from "fs";
22264
- import path26 from "path";
20807
+ import path25 from "path";
22265
20808
  var DEFAULT_CONFIDENCE_THRESHOLD = 0.7;
22266
20809
  function realMemoryRoot(memoryDir) {
22267
20810
  try {
@@ -22273,8 +20816,8 @@ function realMemoryRoot(memoryDir) {
22273
20816
  }
22274
20817
  }
22275
20818
  function isPathInside2(rootReal, candidateReal) {
22276
- const relative = path26.relative(rootReal, candidateReal);
22277
- return relative === "" || !!relative && !relative.startsWith("..") && !path26.isAbsolute(relative);
20819
+ const relative = path25.relative(rootReal, candidateReal);
20820
+ return relative === "" || !!relative && !relative.startsWith("..") && !path25.isAbsolute(relative);
22278
20821
  }
22279
20822
  function isSafeDirectory(rootReal, dir) {
22280
20823
  try {
@@ -22317,7 +20860,7 @@ function listReviewItems(options) {
22317
20860
  if (filterReason && item.reviewReason !== filterReason) return;
22318
20861
  items.push(item);
22319
20862
  };
22320
- const suggestionsDir = path26.join(memoryDir, "suggestions");
20863
+ const suggestionsDir = path25.join(memoryDir, "suggestions");
22321
20864
  if (!isLimitReached() && fs5.existsSync(suggestionsDir) && isSafeDirectory(rootReal, suggestionsDir)) {
22322
20865
  walkMd(rootReal, suggestionsDir, (filePath, content) => {
22323
20866
  if (isLimitReached()) return true;
@@ -22338,7 +20881,7 @@ function listReviewItems(options) {
22338
20881
  return isLimitReached();
22339
20882
  });
22340
20883
  }
22341
- const reviewDir = path26.join(memoryDir, "review");
20884
+ const reviewDir = path25.join(memoryDir, "review");
22342
20885
  if (!isLimitReached() && fs5.existsSync(reviewDir) && isSafeDirectory(rootReal, reviewDir)) {
22343
20886
  walkMd(rootReal, reviewDir, (filePath, content) => {
22344
20887
  if (isLimitReached()) return true;
@@ -22363,7 +20906,7 @@ function listReviewItems(options) {
22363
20906
  const categories = ALL_CATEGORY_DIRS;
22364
20907
  for (const category of categories) {
22365
20908
  if (isLimitReached()) break;
22366
- const dir = path26.join(memoryDir, category);
20909
+ const dir = path25.join(memoryDir, category);
22367
20910
  if (!fs5.existsSync(dir) || !isSafeDirectory(rootReal, dir)) continue;
22368
20911
  walkMd(rootReal, dir, (filePath, content) => {
22369
20912
  if (isLimitReached()) return true;
@@ -22443,8 +20986,8 @@ function approveItem(memoryDir, itemId, options) {
22443
20986
  const targetDir = getCategoryDir(memoryDir, category);
22444
20987
  const dateDir = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
22445
20988
  ensureSafeDirectory(rootReal, targetDir);
22446
- const outputPath = path26.join(targetDir, dateDir, path26.basename(found.filePath));
22447
- ensureSafeDirectory(rootReal, path26.dirname(outputPath));
20989
+ const outputPath = path25.join(targetDir, dateDir, path25.basename(found.filePath));
20990
+ ensureSafeDirectory(rootReal, path25.dirname(outputPath));
22448
20991
  const promotedPath = writeFileWithoutClobber(outputPath, updatedContent, itemId);
22449
20992
  fs5.unlinkSync(found.filePath);
22450
20993
  return {
@@ -22502,13 +21045,13 @@ function findReviewFileById(memoryDir, id, options = {}) {
22502
21045
  const rootReal = realMemoryRoot(memoryDir);
22503
21046
  if (!rootReal) return null;
22504
21047
  for (const loc of ["suggestions", "review"]) {
22505
- const dir = path26.join(memoryDir, loc);
21048
+ const dir = path25.join(memoryDir, loc);
22506
21049
  if (!fs5.existsSync(dir) || !isSafeDirectory(rootReal, dir)) continue;
22507
21050
  const found = findFileById(rootReal, dir, id);
22508
21051
  if (found) return { filePath: found, location: "queue" };
22509
21052
  }
22510
21053
  for (const category of ALL_CATEGORY_DIRS) {
22511
- const dir = path26.join(memoryDir, category);
21054
+ const dir = path25.join(memoryDir, category);
22512
21055
  if (!fs5.existsSync(dir) || !isSafeDirectory(rootReal, dir)) continue;
22513
21056
  const found = findFileById(rootReal, dir, id, (fm) => isLowConfidenceReviewCandidate(fm, options));
22514
21057
  if (found) return { filePath: found, location: "category" };
@@ -22584,10 +21127,10 @@ function readFileSafe3(filePath) {
22584
21127
  }
22585
21128
  }
22586
21129
  function writeFileWithoutClobber(basePath, content, discriminator) {
22587
- const parsed = path26.parse(basePath);
21130
+ const parsed = path25.parse(basePath);
22588
21131
  const safeDiscriminator = sanitizeFilePart(discriminator);
22589
21132
  for (let attempt = 0; attempt < 1e3; attempt++) {
22590
- const candidate = attempt === 0 ? basePath : path26.join(
21133
+ const candidate = attempt === 0 ? basePath : path25.join(
22591
21134
  parsed.dir,
22592
21135
  `${parsed.name}-${safeDiscriminator}${attempt === 1 ? "" : `-${attempt}`}${parsed.ext || ".md"}`
22593
21136
  );
@@ -22643,7 +21186,7 @@ function extractBody4(content) {
22643
21186
  function walkMd(rootReal, dir, callback) {
22644
21187
  if (!isSafeDirectory(rootReal, dir)) return false;
22645
21188
  for (const entry of fs5.readdirSync(dir, { withFileTypes: true })) {
22646
- const fullPath = path26.join(dir, entry.name);
21189
+ const fullPath = path25.join(dir, entry.name);
22647
21190
  if (entry.isSymbolicLink()) continue;
22648
21191
  if (entry.isDirectory()) {
22649
21192
  if (walkMd(rootReal, fullPath, callback)) return true;
@@ -22658,7 +21201,7 @@ function walkMdPaths(rootReal, dir) {
22658
21201
  const results = [];
22659
21202
  if (!isSafeDirectory(rootReal, dir)) return results;
22660
21203
  for (const entry of fs5.readdirSync(dir, { withFileTypes: true })) {
22661
- const fullPath = path26.join(dir, entry.name);
21204
+ const fullPath = path25.join(dir, entry.name);
22662
21205
  if (entry.isSymbolicLink()) continue;
22663
21206
  if (entry.isDirectory()) {
22664
21207
  results.push(...walkMdPaths(rootReal, fullPath));
@@ -22671,7 +21214,7 @@ function walkMdPaths(rootReal, dir) {
22671
21214
 
22672
21215
  // src/sync/index.ts
22673
21216
  import fs6 from "fs";
22674
- import path27 from "path";
21217
+ import path26 from "path";
22675
21218
  import crypto6 from "crypto";
22676
21219
  var DEFAULT_EXTENSIONS = /* @__PURE__ */ new Set([".md", ".txt", ".mdx", ".rst"]);
22677
21220
  var DEFAULT_EXCLUDE2 = /* @__PURE__ */ new Set([
@@ -22693,7 +21236,7 @@ function syncChanges(options) {
22693
21236
  } = options;
22694
21237
  const extSet = new Set(extensions);
22695
21238
  const excludeSet = /* @__PURE__ */ new Set([...DEFAULT_EXCLUDE2, ...excludeDirs]);
22696
- const stateFilePath = options.stateFile ?? path27.join(memoryDir, ".sync-state.json");
21239
+ const stateFilePath = options.stateFile ?? path26.join(memoryDir, ".sync-state.json");
22697
21240
  const prevState = loadState(stateFilePath);
22698
21241
  const currentFiles = scanFiles(sourceDir, extSet, excludeSet);
22699
21242
  const changes = computeDiff(currentFiles, prevState.fileHashes, sourceDir);
@@ -22709,7 +21252,7 @@ function syncChanges(options) {
22709
21252
  for (const [relPath, hash] of Object.entries(currentFiles)) {
22710
21253
  newState.fileHashes[relPath] = hash;
22711
21254
  }
22712
- fs6.mkdirSync(path27.dirname(stateFilePath), { recursive: true });
21255
+ fs6.mkdirSync(path26.dirname(stateFilePath), { recursive: true });
22713
21256
  fs6.writeFileSync(stateFilePath, JSON.stringify(newState, null, 2));
22714
21257
  }
22715
21258
  return {
@@ -22775,13 +21318,13 @@ function scanFiles(root, extensions, exclude) {
22775
21318
  }
22776
21319
  for (const entry of entries) {
22777
21320
  if (exclude.has(entry.name)) continue;
22778
- const fullPath = path27.join(dir, entry.name);
21321
+ const fullPath = path26.join(dir, entry.name);
22779
21322
  if (entry.isDirectory()) {
22780
21323
  walk(fullPath);
22781
21324
  } else if (entry.isFile()) {
22782
- const ext = path27.extname(entry.name).toLowerCase();
21325
+ const ext = path26.extname(entry.name).toLowerCase();
22783
21326
  if (!extensions.has(ext)) continue;
22784
- const relPath = path27.relative(root, fullPath);
21327
+ const relPath = path26.relative(root, fullPath);
22785
21328
  try {
22786
21329
  const content = fs6.readFileSync(fullPath, "utf8");
22787
21330
  result[relPath] = hashContent3(content);
@@ -22796,7 +21339,7 @@ function scanFiles(root, extensions, exclude) {
22796
21339
  function computeDiff(current, previous, sourceDir) {
22797
21340
  const changes = [];
22798
21341
  for (const [relPath, hash] of Object.entries(current)) {
22799
- const fullPath = path27.join(sourceDir, relPath);
21342
+ const fullPath = path26.join(sourceDir, relPath);
22800
21343
  if (!(relPath in previous)) {
22801
21344
  let size = 0;
22802
21345
  try {
@@ -22829,7 +21372,7 @@ function computeDiff(current, previous, sourceDir) {
22829
21372
  for (const relPath of Object.keys(previous)) {
22830
21373
  if (!(relPath in current)) {
22831
21374
  changes.push({
22832
- filePath: path27.join(sourceDir, relPath),
21375
+ filePath: path26.join(sourceDir, relPath),
22833
21376
  relativePath: relPath,
22834
21377
  type: "deleted",
22835
21378
  currentHash: "",
@@ -22859,20 +21402,20 @@ function hashContent3(content) {
22859
21402
  import { spawnSync } from "child_process";
22860
21403
  import crypto7 from "crypto";
22861
21404
  import fs7 from "fs";
22862
- import path28 from "path";
21405
+ import path27 from "path";
22863
21406
  var MANIFEST_VERSION = 1;
22864
21407
  var MANIFEST_LOCK_STALE_MS = 3e4;
22865
21408
  var MANIFEST_LOCK_TIMEOUT_MS = MANIFEST_LOCK_STALE_MS + 1e4;
22866
21409
  var MANIFEST_LOCK_SLEEP_MS = 20;
22867
21410
  function normalizeSpaceMemoryDir(memoryDir) {
22868
- return path28.resolve(memoryDir);
21411
+ return path27.resolve(memoryDir);
22869
21412
  }
22870
21413
  function getSpacesDir(baseDir) {
22871
21414
  const homeDir = baseDir ?? resolveHomeDir();
22872
- return path28.join(homeDir, ".config", "engram", "spaces");
21415
+ return path27.join(homeDir, ".config", "engram", "spaces");
22873
21416
  }
22874
21417
  function getManifestPath(baseDir) {
22875
- return path28.join(getSpacesDir(baseDir), "manifest.json");
21418
+ return path27.join(getSpacesDir(baseDir), "manifest.json");
22876
21419
  }
22877
21420
  function loadManifest(baseDir, memoryDirOverride) {
22878
21421
  if (fs7.existsSync(getManifestPath(baseDir))) {
@@ -22919,9 +21462,9 @@ function readManifestUnlocked(baseDir, memoryDirOverride, options = {}) {
22919
21462
  }
22920
21463
  function saveManifestUnlocked(manifest, baseDir) {
22921
21464
  const manifestPath2 = getManifestPath(baseDir);
22922
- const manifestDir2 = path28.dirname(manifestPath2);
21465
+ const manifestDir2 = path27.dirname(manifestPath2);
22923
21466
  fs7.mkdirSync(manifestDir2, { recursive: true });
22924
- const tempPath = path28.join(manifestDir2, `.manifest.${process.pid}.${Date.now()}.${crypto7.randomUUID()}.tmp`);
21467
+ const tempPath = path27.join(manifestDir2, `.manifest.${process.pid}.${Date.now()}.${crypto7.randomUUID()}.tmp`);
22925
21468
  try {
22926
21469
  fs7.writeFileSync(tempPath, `${JSON.stringify(manifest, null, 2)}
22927
21470
  `, { flag: "wx" });
@@ -22936,7 +21479,7 @@ function saveManifestUnlocked(manifest, baseDir) {
22936
21479
  }
22937
21480
  function withManifestLock(baseDir, operation) {
22938
21481
  const lockDir = `${getManifestPath(baseDir)}.lock`;
22939
- fs7.mkdirSync(path28.dirname(lockDir), { recursive: true });
21482
+ fs7.mkdirSync(path27.dirname(lockDir), { recursive: true });
22940
21483
  const lockOwner = acquireManifestLock(lockDir);
22941
21484
  try {
22942
21485
  return operation();
@@ -22962,7 +21505,7 @@ function acquireManifestLock(lockDir) {
22962
21505
  try {
22963
21506
  fs7.mkdirSync(lockDir, { recursive: false });
22964
21507
  try {
22965
- fs7.writeFileSync(path28.join(lockDir, "owner"), `${owner}
21508
+ fs7.writeFileSync(path27.join(lockDir, "owner"), `${owner}
22966
21509
  `, { flag: "wx" });
22967
21510
  } catch (error) {
22968
21511
  fs7.rmSync(lockDir, { recursive: true, force: true });
@@ -22992,7 +21535,7 @@ function acquireManifestLock(lockDir) {
22992
21535
  }
22993
21536
  function releaseManifestLock(lockDir, owner) {
22994
21537
  try {
22995
- const ownerPath = path28.join(lockDir, "owner");
21538
+ const ownerPath = path27.join(lockDir, "owner");
22996
21539
  if (fs7.readFileSync(ownerPath, "utf8").trim() === owner) {
22997
21540
  fs7.rmSync(lockDir, { recursive: true, force: true });
22998
21541
  }
@@ -23008,7 +21551,7 @@ function removeStaleManifestLock(lockDir) {
23008
21551
  try {
23009
21552
  fs7.mkdirSync(reclaimDir, { recursive: false });
23010
21553
  try {
23011
- fs7.writeFileSync(path28.join(reclaimDir, "owner"), `${reclaimOwner}
21554
+ fs7.writeFileSync(path27.join(reclaimDir, "owner"), `${reclaimOwner}
23012
21555
  `, { flag: "wx" });
23013
21556
  } catch (error) {
23014
21557
  fs7.rmSync(reclaimDir, { recursive: true, force: true });
@@ -23083,7 +21626,7 @@ function readManifestLockSnapshot(lockDir) {
23083
21626
  throw error;
23084
21627
  }
23085
21628
  try {
23086
- const owner = fs7.readFileSync(path28.join(lockDir, "owner"), "utf8").trim();
21629
+ const owner = fs7.readFileSync(path27.join(lockDir, "owner"), "utf8").trim();
23087
21630
  return { mtimeMs: stat5.mtimeMs, owner };
23088
21631
  } catch (error) {
23089
21632
  if (error.code === "ENOENT") {
@@ -23155,8 +21698,8 @@ function sleepSync(ms) {
23155
21698
  }
23156
21699
  function createPersonalSpace(baseDir, memoryDirOverride) {
23157
21700
  const homeDir = baseDir ?? resolveHomeDir();
23158
- const standalonePath = path28.join(homeDir, ".engram", "memory");
23159
- const openclawPath = path28.join(homeDir, ".openclaw", "workspace", "memory", "local");
21701
+ const standalonePath = path27.join(homeDir, ".engram", "memory");
21702
+ const openclawPath = path27.join(homeDir, ".openclaw", "workspace", "memory", "local");
23160
21703
  const memoryDir = memoryDirOverride ?? readEnvVar("REMNIC_MEMORY_DIR") ?? readEnvVar("ENGRAM_MEMORY_DIR") ?? (fs7.existsSync(standalonePath) ? standalonePath : fs7.existsSync(openclawPath) ? openclawPath : standalonePath);
23161
21704
  const normalizedMemoryDir = normalizeSpaceMemoryDir(memoryDir);
23162
21705
  const now = (/* @__PURE__ */ new Date()).toISOString();
@@ -23185,7 +21728,7 @@ function createSpace(options) {
23185
21728
  const id = options.name.toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/-+/g, "-");
23186
21729
  const now = (/* @__PURE__ */ new Date()).toISOString();
23187
21730
  const memoryDir = normalizeSpaceMemoryDir(
23188
- options.memoryDir ?? path28.join(getSpacesDir(options.baseDir), id, "memory")
21731
+ options.memoryDir ?? path27.join(getSpacesDir(options.baseDir), id, "memory")
23189
21732
  );
23190
21733
  const space = updateManifest(options.baseDir, (manifest) => {
23191
21734
  if (manifest.spaces.some((s) => s.id === id)) {
@@ -23406,14 +21949,14 @@ function mergeSpaces(sourceSpaceId, targetSpaceId, options) {
23406
21949
  };
23407
21950
  }
23408
21951
  function getAuditLog(baseDir) {
23409
- const auditPath = path28.join(getSpacesDir(baseDir), "audit.jsonl");
21952
+ const auditPath = path27.join(getSpacesDir(baseDir), "audit.jsonl");
23410
21953
  if (!fs7.existsSync(auditPath)) return [];
23411
21954
  const lines = fs7.readFileSync(auditPath, "utf8").trim().split("\n");
23412
21955
  return lines.filter((l) => l.trim()).map((l) => JSON.parse(l));
23413
21956
  }
23414
21957
  function appendAudit(entry, baseDir) {
23415
- const auditPath = path28.join(getSpacesDir(baseDir), "audit.jsonl");
23416
- fs7.mkdirSync(path28.dirname(auditPath), { recursive: true });
21958
+ const auditPath = path27.join(getSpacesDir(baseDir), "audit.jsonl");
21959
+ fs7.mkdirSync(path27.dirname(auditPath), { recursive: true });
23417
21960
  const full = {
23418
21961
  id: crypto7.randomUUID(),
23419
21962
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
@@ -23445,8 +21988,8 @@ function copyMemories(sourceDir, targetDir, options) {
23445
21988
  continue;
23446
21989
  }
23447
21990
  const content = fs7.readFileSync(sourcePath, "utf8");
23448
- const relativePath = path28.relative(sourceRoot, sourceRealPath);
23449
- const targetPath = path28.resolve(targetRoot, relativePath);
21991
+ const relativePath = path27.relative(sourceRoot, sourceRealPath);
21992
+ const targetPath = path27.resolve(targetRoot, relativePath);
23450
21993
  if (!isPathInsideRoot(targetPath, targetRoot)) {
23451
21994
  skipped++;
23452
21995
  continue;
@@ -23488,8 +22031,8 @@ function copyMemories(sourceDir, targetDir, options) {
23488
22031
  skipped++;
23489
22032
  continue;
23490
22033
  }
23491
- fs7.mkdirSync(path28.dirname(targetPath), { recursive: true });
23492
- const targetParentRealPath = safeRealpath(path28.dirname(targetPath));
22034
+ fs7.mkdirSync(path27.dirname(targetPath), { recursive: true });
22035
+ const targetParentRealPath = safeRealpath(path27.dirname(targetPath));
23493
22036
  if (!targetParentRealPath || !isPathInsideRoot(targetParentRealPath, targetRoot)) {
23494
22037
  skipped++;
23495
22038
  continue;
@@ -23507,7 +22050,7 @@ function walkMd2(dir) {
23507
22050
  const results = [];
23508
22051
  function walk(d) {
23509
22052
  for (const entry of fs7.readdirSync(d, { withFileTypes: true })) {
23510
- const fullPath = path28.join(d, entry.name);
22053
+ const fullPath = path27.join(d, entry.name);
23511
22054
  if (entry.isSymbolicLink()) {
23512
22055
  continue;
23513
22056
  }
@@ -23536,8 +22079,8 @@ function safeRealpath(filePath) {
23536
22079
  }
23537
22080
  }
23538
22081
  function isPathInsideRoot(candidatePath, rootPath) {
23539
- const relative = path28.relative(rootPath, candidatePath);
23540
- return relative === "" || !relative.startsWith("..") && !path28.isAbsolute(relative);
22082
+ const relative = path27.relative(rootPath, candidatePath);
22083
+ return relative === "" || !relative.startsWith("..") && !path27.isAbsolute(relative);
23541
22084
  }
23542
22085
  function parseSimpleFrontmatter(content) {
23543
22086
  const match = content.match(/^---\n([\s\S]*?)\n---/);
@@ -23657,22 +22200,22 @@ var REMNIC_RECALL_DECISION_RULES = `## When to Use Recall vs Direct Read
23657
22200
 
23658
22201
  // src/memory-extension/codex-publisher.ts
23659
22202
  import fs8 from "fs";
23660
- import os2 from "os";
23661
- import path29 from "path";
22203
+ import os from "os";
22204
+ import path28 from "path";
23662
22205
  var REMNIC_EXTENSION_DIR_NAME = "remnic";
23663
22206
  function resolveEnvHome(env) {
23664
22207
  if (env === void 0) return resolveHomeDir();
23665
- return env.HOME?.trim() || env.USERPROFILE?.trim() || os2.homedir();
22208
+ return env.HOME?.trim() || env.USERPROFILE?.trim() || os.homedir();
23666
22209
  }
23667
22210
  function expandTildeWithHome(input, homeDir) {
23668
22211
  if (input === "~") return homeDir;
23669
22212
  if (input.startsWith("~/") || input.startsWith("~\\")) {
23670
- return path29.join(homeDir, input.slice(2));
22213
+ return path28.join(homeDir, input.slice(2));
23671
22214
  }
23672
22215
  return input;
23673
22216
  }
23674
22217
  function normalizeHostRoot(input, homeDir) {
23675
- return path29.resolve(expandTildeWithHome(input.trim(), homeDir));
22218
+ return path28.resolve(expandTildeWithHome(input.trim(), homeDir));
23676
22219
  }
23677
22220
  var CodexMemoryExtensionPublisher = class {
23678
22221
  hostId = "codex";
@@ -23686,12 +22229,12 @@ var CodexMemoryExtensionPublisher = class {
23686
22229
  async resolveExtensionRoot(env) {
23687
22230
  const homeDir = resolveEnvHome(env);
23688
22231
  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);
22232
+ const codexHome = codexHomeInput ? normalizeHostRoot(codexHomeInput, homeDir) : path28.resolve(homeDir, ".codex");
22233
+ return path28.join(codexHome, "memories_extensions", REMNIC_EXTENSION_DIR_NAME);
23691
22234
  }
23692
22235
  async isHostAvailable() {
23693
22236
  try {
23694
- const home = readEnvVar("CODEX_HOME")?.trim() || path29.join(resolveHomeDir(), ".codex");
22237
+ const home = readEnvVar("CODEX_HOME")?.trim() || path28.join(resolveHomeDir(), ".codex");
23695
22238
  return fs8.existsSync(home);
23696
22239
  } catch {
23697
22240
  return false;
@@ -23742,7 +22285,7 @@ When running inside the Codex phase-2 consolidation sandbox:
23742
22285
  }
23743
22286
  async publish(ctx) {
23744
22287
  const extensionRoot = await this.resolveExtensionRoot();
23745
- const instructionsPath = path29.join(extensionRoot, "instructions.md");
22288
+ const instructionsPath = path28.join(extensionRoot, "instructions.md");
23746
22289
  const filesWritten = [];
23747
22290
  const skipped = [];
23748
22291
  ctx.log.info(`Publishing Codex memory extension to ${extensionRoot}`);
@@ -24116,9 +22659,9 @@ async function generateActivityMemories(date, digestBody, config, deps) {
24116
22659
  }
24117
22660
 
24118
22661
  // src/session-summaries/index.ts
24119
- import { createHash as createHash9 } from "crypto";
22662
+ import { createHash as createHash7 } from "crypto";
24120
22663
  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";
22664
+ import path29 from "path";
24122
22665
 
24123
22666
  // src/session-summaries/adapters.ts
24124
22667
  var VALID_ROLES = /* @__PURE__ */ new Set(["user", "assistant", "tool", "system", "other"]);
@@ -24618,12 +23161,12 @@ var DEFAULT_MAX_FILES = 5e3;
24618
23161
  var DEFAULT_MAX_SESSIONS = 500;
24619
23162
  var SUPPORTED_EXTENSIONS = /* @__PURE__ */ new Set([".json", ".jsonl"]);
24620
23163
  function shortHash(value, length = 16) {
24621
- return createHash9("sha256").update(value).digest("hex").slice(0, length);
23164
+ return createHash7("sha256").update(value).digest("hex").slice(0, length);
24622
23165
  }
24623
23166
  async function listTranscriptFiles(root, maxFiles) {
24624
23167
  const out = [];
24625
23168
  let truncated = false;
24626
- const entrySortKey = (entryName, isDirectory) => isDirectory ? `${entryName}${path30.sep}` : entryName;
23169
+ const entrySortKey = (entryName, isDirectory) => isDirectory ? `${entryName}${path29.sep}` : entryName;
24627
23170
  async function visit(dir) {
24628
23171
  if (truncated) return;
24629
23172
  const entries = (await readdir4(dir, { withFileTypes: true })).sort(
@@ -24633,13 +23176,13 @@ async function listTranscriptFiles(root, maxFiles) {
24633
23176
  if (truncated) return;
24634
23177
  if (entry.name.startsWith(".")) continue;
24635
23178
  if (entry.isSymbolicLink()) continue;
24636
- const fullPath = path30.join(dir, entry.name);
23179
+ const fullPath = path29.join(dir, entry.name);
24637
23180
  if (entry.isDirectory()) {
24638
23181
  await visit(fullPath);
24639
23182
  continue;
24640
23183
  }
24641
23184
  if (!entry.isFile()) continue;
24642
- const ext = path30.extname(entry.name).toLowerCase();
23185
+ const ext = path29.extname(entry.name).toLowerCase();
24643
23186
  if (!SUPPORTED_EXTENSIONS.has(ext)) continue;
24644
23187
  out.push(fullPath);
24645
23188
  if (out.length > maxFiles) {
@@ -24666,7 +23209,7 @@ function normalizeInputDir(inputDir) {
24666
23209
  if (typeof inputDir !== "string" || inputDir.trim().length === 0) {
24667
23210
  throw new Error("inputDir must be a non-empty string");
24668
23211
  }
24669
- return path30.resolve(expandTildePath(inputDir.trim()));
23212
+ return path29.resolve(expandTildePath(inputDir.trim()));
24670
23213
  }
24671
23214
  function initRoleCounts() {
24672
23215
  return {
@@ -24823,11 +23366,11 @@ async function collectLocalSessionSummaries(options) {
24823
23366
  continue;
24824
23367
  }
24825
23368
  seenFileHashes.add(fileHash);
24826
- const fileExtension = path30.extname(filePath).toLowerCase();
23369
+ const fileExtension = path29.extname(filePath).toLowerCase();
24827
23370
  const parsed = await adapter.parseFile(
24828
23371
  {
24829
23372
  content,
24830
- fileName: path30.basename(filePath),
23373
+ fileName: path29.basename(filePath),
24831
23374
  fileExtension,
24832
23375
  fileRef: fileHash
24833
23376
  },
@@ -24883,7 +23426,7 @@ async function collectLocalSessionSummaries(options) {
24883
23426
  }
24884
23427
  async function readRedactionConfig(pathLike) {
24885
23428
  if (!pathLike) return void 0;
24886
- const raw = await readFile6(path30.resolve(expandTildePath(pathLike)), "utf-8");
23429
+ const raw = await readFile6(path29.resolve(expandTildePath(pathLike)), "utf-8");
24887
23430
  const parsed = JSON.parse(raw);
24888
23431
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
24889
23432
  throw new Error("redaction config must be a JSON object");
@@ -24896,15 +23439,15 @@ function toJsonl(drafts) {
24896
23439
  }
24897
23440
  function defaultDraftOutputPath(memoryDir, generatedAt) {
24898
23441
  const stamp = generatedAt.replace(/[:.]/g, "-");
24899
- return path30.join(
24900
- path30.resolve(expandTildePath(memoryDir)),
23442
+ return path29.join(
23443
+ path29.resolve(expandTildePath(memoryDir)),
24901
23444
  "state",
24902
23445
  "session-summary-drafts",
24903
23446
  `session-summaries-${stamp}.jsonl`
24904
23447
  );
24905
23448
  }
24906
23449
  async function writeDrafts(filePath, drafts) {
24907
- await mkdir7(path30.dirname(filePath), { recursive: true });
23450
+ await mkdir7(path29.dirname(filePath), { recursive: true });
24908
23451
  const tempPath = `${filePath}.${process.pid}.${Date.now()}.tmp`;
24909
23452
  try {
24910
23453
  await writeFile7(tempPath, toJsonl(drafts), "utf-8");
@@ -24922,7 +23465,7 @@ async function runLocalSessionSummaryCliCommand(options) {
24922
23465
  });
24923
23466
  const wroteFiles = [];
24924
23467
  if (options.output) {
24925
- const outputPath = path30.resolve(expandTildePath(options.output));
23468
+ const outputPath = path29.resolve(expandTildePath(options.output));
24926
23469
  await writeDrafts(outputPath, report.drafts);
24927
23470
  wroteFiles.push(outputPath);
24928
23471
  }
@@ -24957,19 +23500,19 @@ async function runLocalSessionSummaryCliCommand(options) {
24957
23500
 
24958
23501
  // src/transfer/capsule-fork.ts
24959
23502
  import { lstat as lstat3, mkdir as mkdir8, readFile as readFile7, realpath as realpath2, writeFile as writeFile8 } from "fs/promises";
24960
- import path31 from "path";
23503
+ import path30 from "path";
24961
23504
  async function forkCapsule(opts) {
24962
23505
  validateForkId(opts.forkId);
24963
- const rootAbs = path31.resolve(opts.targetRoot);
23506
+ const rootAbs = path30.resolve(opts.targetRoot);
24964
23507
  await assertIsDirectoryNotSymlink(rootAbs, "forkCapsule", "targetRoot");
24965
- const forkDirAbs = path31.join(rootAbs, "forks", opts.forkId);
23508
+ const forkDirAbs = path30.join(rootAbs, "forks", opts.forkId);
24966
23509
  const forkEntryExists = await pathEntryExists(forkDirAbs);
24967
23510
  if (forkEntryExists) {
24968
23511
  throw new Error(
24969
23512
  `forkCapsule: fork path already exists \u2014 forkId "${opts.forkId}" is already in use at: ${forkDirAbs}`
24970
23513
  );
24971
23514
  }
24972
- const archiveAbs = path31.resolve(opts.sourceArchive);
23515
+ const archiveAbs = path30.resolve(opts.sourceArchive);
24973
23516
  const importResult = await importCapsule({
24974
23517
  archivePath: archiveAbs,
24975
23518
  root: rootAbs,
@@ -24991,10 +23534,10 @@ async function forkCapsule(opts) {
24991
23534
  importedRecords: importResult.imported.length,
24992
23535
  skippedRecords: importResult.skipped.length
24993
23536
  };
24994
- const lineagePath = path31.join(forkDirAbs, "lineage.json");
23537
+ const lineagePath = path30.join(forkDirAbs, "lineage.json");
24995
23538
  const rootReal = await realpath2(rootAbs);
24996
23539
  await assertRealpathInsideRoot(rootReal, lineagePath, `forks/${opts.forkId}/lineage.json`, "forkCapsule");
24997
- await mkdir8(path31.dirname(lineagePath), { recursive: true });
23540
+ await mkdir8(path30.dirname(lineagePath), { recursive: true });
24998
23541
  await writeFile8(lineagePath, JSON.stringify(lineage, null, 2) + "\n", "utf-8");
24999
23542
  return {
25000
23543
  archivePath: archiveAbs,
@@ -25008,11 +23551,11 @@ async function readForkLineage(targetRoot, forkId) {
25008
23551
  if (typeof forkId !== "string" || forkId.length === 0 || forkId.length > 64 || !CAPSULE_ID_PATTERN.test(forkId)) {
25009
23552
  return null;
25010
23553
  }
25011
- const rootAbs = path31.resolve(targetRoot);
23554
+ const rootAbs = path30.resolve(targetRoot);
25012
23555
  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)) {
23556
+ const lineagePath = path30.join(rootReal, "forks", forkId, "lineage.json");
23557
+ const rel = path30.relative(rootReal, lineagePath);
23558
+ if (rel.startsWith("..") || path30.isAbsolute(rel)) {
25016
23559
  return null;
25017
23560
  }
25018
23561
  if (!await isLineagePathContained(rootReal, lineagePath)) {
@@ -25053,60 +23596,23 @@ async function pathEntryExists(absPath) {
25053
23596
  async function isLineagePathContained(rootReal, lineagePath) {
25054
23597
  let existing = lineagePath;
25055
23598
  const suffix = [];
25056
- while (existing !== path31.dirname(existing)) {
23599
+ while (existing !== path30.dirname(existing)) {
25057
23600
  const st = await lstat3(existing).catch(() => null);
25058
23601
  if (st !== null) break;
25059
- suffix.unshift(path31.basename(existing));
25060
- existing = path31.dirname(existing);
23602
+ suffix.unshift(path30.basename(existing));
23603
+ existing = path30.dirname(existing);
25061
23604
  }
25062
23605
  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);
23606
+ const targetReal = suffix.length > 0 ? path30.join(existingReal, ...suffix) : existingReal;
23607
+ const rel = path30.relative(rootReal, targetReal);
25065
23608
  if (rel === "") return true;
25066
23609
  if (rel === "..") return false;
25067
- if (rel.startsWith(`..${path31.sep}`)) return false;
25068
- if (path31.isAbsolute(rel)) return false;
23610
+ if (rel.startsWith(`..${path30.sep}`)) return false;
23611
+ if (path30.isAbsolute(rel)) return false;
25069
23612
  return true;
25070
23613
  }
25071
23614
 
25072
23615
  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
23616
  buildProcedureRecallSection,
25111
23617
  RELAY_DEMO_MISSION_ID,
25112
23618
  RELAY_DEMO_NAMESPACE,
@@ -25222,4 +23728,4 @@ export {
25222
23728
  filterRecallCandidates,
25223
23729
  Orchestrator
25224
23730
  };
25225
- //# sourceMappingURL=chunk-YNQBRLC5.js.map
23731
+ //# sourceMappingURL=chunk-RUYJ7TWU.js.map