@remnic/core 9.26.0 → 9.28.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 (440) hide show
  1. package/dist/access-admin-ops-surface.d.ts +13 -10
  2. package/dist/access-admin-ops-surface.js +43 -38
  3. package/dist/access-audit.js +2 -2
  4. package/dist/access-authorization-probe.d.ts +13 -10
  5. package/dist/access-authorization-probe.js +44 -39
  6. package/dist/access-boundary.d.ts +13 -10
  7. package/dist/access-boundary.js +43 -38
  8. package/dist/access-cli.js +100 -94
  9. package/dist/access-cli.js.map +1 -1
  10. package/dist/access-health-types.d.ts +10 -1
  11. package/dist/access-http-lcm-compaction.d.ts +13 -10
  12. package/dist/access-http.d.ts +13 -10
  13. package/dist/access-http.js +53 -48
  14. package/dist/access-identity-continuity-surface.d.ts +9 -8
  15. package/dist/access-identity-continuity-surface.js +43 -38
  16. package/dist/access-lcm-surface.d.ts +13 -10
  17. package/dist/access-lcm-surface.js +43 -38
  18. package/dist/access-mcp.d.ts +13 -10
  19. package/dist/access-mcp.js +48 -43
  20. package/dist/access-memory-search-fanout.d.ts +2 -2
  21. package/dist/{access-namespace-preflight-wRSZEO5V.d.ts → access-namespace-preflight-BiQ_-iUJ.d.ts} +1 -1
  22. package/dist/access-namespace-preflight.d.ts +3 -3
  23. package/dist/access-namespace-preflight.js +43 -38
  24. package/dist/access-observe-write-surface.d.ts +13 -10
  25. package/dist/access-observe-write-surface.js +43 -38
  26. package/dist/access-operations-batch.js +45 -40
  27. package/dist/access-operations.d.ts +16 -13
  28. package/dist/access-operations.js +47 -42
  29. package/dist/access-recall-concurrency.d.ts +13 -10
  30. package/dist/access-recall-concurrency.js +43 -38
  31. package/dist/access-recall-response.d.ts +13 -10
  32. package/dist/access-recall-response.js +43 -38
  33. package/dist/access-recall-surface.d.ts +13 -10
  34. package/dist/access-recall-surface.js +43 -38
  35. package/dist/access-schema.d.ts +80 -80
  36. package/dist/access-schema.js +4 -4
  37. package/dist/{access-service-DL8FJnTj.d.ts → access-service-CXkIgcGh.d.ts} +12 -8
  38. package/dist/access-service.d.ts +13 -10
  39. package/dist/access-service.js +43 -38
  40. package/dist/access-surface-catalog.d.ts +13 -10
  41. package/dist/access-wearables-meetings-surface.d.ts +4 -3
  42. package/dist/action-confidence.d.ts +1 -1
  43. package/dist/active-memory-bridge.d.ts +1 -1
  44. package/dist/active-recall.d.ts +1 -1
  45. package/dist/active-recall.js +4 -2
  46. package/dist/active-recall.js.map +1 -1
  47. package/dist/adapters/index.js +7 -7
  48. package/dist/adapters/registry.js +3 -3
  49. package/dist/behavior-learner.d.ts +1 -1
  50. package/dist/behavior-signals.d.ts +1 -1
  51. package/dist/bootstrap.d.ts +9 -8
  52. package/dist/briefing.d.ts +3 -2
  53. package/dist/briefing.js +12 -10
  54. package/dist/buffer-surprise-report.d.ts +1 -1
  55. package/dist/buffer.d.ts +3 -2
  56. package/dist/bulk-import/index.d.ts +3 -3
  57. package/dist/calibration.d.ts +1 -1
  58. package/dist/capabilities.d.ts +1 -1
  59. package/dist/{capsule-crypto-YO5QJ6L3.js → capsule-crypto-7FJQINUR.js} +2 -2
  60. package/dist/{catalog-BLLxZ5L5.d.ts → catalog-Bouj8Gfg.d.ts} +1 -1
  61. package/dist/causal-behavior.d.ts +1 -1
  62. package/dist/causal-consolidation.d.ts +1 -1
  63. package/dist/causal-consolidation.js +13 -11
  64. package/dist/causal-consolidation.js.map +1 -1
  65. package/dist/causal-trajectory-graph.d.ts +1 -1
  66. package/dist/{chunk-7RZJWZ46.js → chunk-227UFSEQ.js} +5 -5
  67. package/dist/{chunk-VGEH3STZ.js → chunk-2BEJ4XCF.js} +2 -2
  68. package/dist/{chunk-LIIQPDFN.js → chunk-2FYNLDKJ.js} +24 -3
  69. package/dist/chunk-2FYNLDKJ.js.map +1 -0
  70. package/dist/{chunk-BXLOS5AJ.js → chunk-2NLLXCJG.js} +2 -2
  71. package/dist/{chunk-6NNNURLK.js → chunk-2PHX3I5C.js} +8 -8
  72. package/dist/{chunk-YN4AUGNF.js → chunk-2TQ2UFKH.js} +65 -60
  73. package/dist/chunk-2TQ2UFKH.js.map +1 -0
  74. package/dist/{chunk-XAAIUXJO.js → chunk-3BSJBIZ3.js} +2 -2
  75. package/dist/{chunk-JCVQV6QX.js → chunk-3UOSVTFR.js} +11 -11
  76. package/dist/{chunk-AJ7QCSIS.js → chunk-7CPOZH6Y.js} +2 -2
  77. package/dist/{chunk-EXM2Q555.js → chunk-AHFZXUZM.js} +7 -5
  78. package/dist/chunk-AHFZXUZM.js.map +1 -0
  79. package/dist/{chunk-M2KGXXTL.js → chunk-ALTP3MFS.js} +2 -2
  80. package/dist/{chunk-77CNV7DY.js → chunk-BLAKS3CP.js} +4 -4
  81. package/dist/{chunk-FE5FKTCI.js → chunk-BR4UFMLO.js} +2 -2
  82. package/dist/chunk-CVILPI77.js +432 -0
  83. package/dist/chunk-CVILPI77.js.map +1 -0
  84. package/dist/{chunk-H2PBM562.js → chunk-DKQM5Q6Q.js} +2 -2
  85. package/dist/{chunk-CSXHRAJJ.js → chunk-EG64LXKL.js} +3 -3
  86. package/dist/{chunk-PTN6UAUA.js → chunk-ES36HTSC.js} +4 -4
  87. package/dist/{chunk-WMDRLTNA.js → chunk-EZWWCN7I.js} +2 -2
  88. package/dist/{chunk-XKGPIWGI.js → chunk-FBZTWUK5.js} +5 -5
  89. package/dist/{chunk-GJJBPI6I.js → chunk-FOCEI3TN.js} +6 -3
  90. package/dist/chunk-FOCEI3TN.js.map +1 -0
  91. package/dist/{chunk-Y6E37WRG.js → chunk-GJPCP5CA.js} +2 -2
  92. package/dist/{chunk-IHMXPG4P.js → chunk-GQSMYXKL.js} +6 -4
  93. package/dist/{chunk-IHMXPG4P.js.map → chunk-GQSMYXKL.js.map} +1 -1
  94. package/dist/{chunk-TGQ2NTWH.js → chunk-IJ6WHMFB.js} +16 -2
  95. package/dist/{chunk-TGQ2NTWH.js.map → chunk-IJ6WHMFB.js.map} +1 -1
  96. package/dist/{chunk-VDX2J7OX.js → chunk-IPLYGWQF.js} +6 -6
  97. package/dist/{chunk-XNUBF6RF.js → chunk-IYT632D5.js} +3 -3
  98. package/dist/{chunk-2QSZNTDO.js → chunk-JBPKEARU.js} +7 -7
  99. package/dist/{chunk-67DSDRUB.js → chunk-JIF3VRKQ.js} +8 -8
  100. package/dist/{chunk-V25OWXAC.js → chunk-JQ7T5VDC.js} +1 -1
  101. package/dist/chunk-JQ7T5VDC.js.map +1 -0
  102. package/dist/{chunk-MIFF37NN.js → chunk-KKBTBUVT.js} +2 -2
  103. package/dist/{chunk-ZHP4SUPB.js → chunk-LIHC3T43.js} +2 -2
  104. package/dist/{chunk-PX7VDW7R.js → chunk-MJPV4LBH.js} +79 -79
  105. package/dist/{chunk-PX7VDW7R.js.map → chunk-MJPV4LBH.js.map} +1 -1
  106. package/dist/{chunk-UGH6VPPO.js → chunk-MWTMTW2T.js} +2 -2
  107. package/dist/{chunk-F6LSNPPB.js → chunk-MXJ3VP6S.js} +6 -6
  108. package/dist/{chunk-KPWLZBXZ.js → chunk-NBNDVNJ2.js} +186 -25
  109. package/dist/chunk-NBNDVNJ2.js.map +1 -0
  110. package/dist/{chunk-M5EPMNS4.js → chunk-P2CLYN6H.js} +2 -2
  111. package/dist/{chunk-7XXCIO6X.js → chunk-PXQM2HOG.js} +13 -6
  112. package/dist/{chunk-7XXCIO6X.js.map → chunk-PXQM2HOG.js.map} +1 -1
  113. package/dist/{chunk-UZK7VVPD.js → chunk-Q5VJUNXA.js} +1858 -272
  114. package/dist/chunk-Q5VJUNXA.js.map +1 -0
  115. package/dist/{chunk-KGTD2KZJ.js → chunk-Q6YJW6KE.js} +2 -2
  116. package/dist/{chunk-X3SQYAPP.js → chunk-R372P2EH.js} +2 -2
  117. package/dist/{chunk-HBVOJNV4.js → chunk-RKXZ7P4V.js} +3 -3
  118. package/dist/chunk-RMMVQQA6.js +70 -0
  119. package/dist/chunk-RMMVQQA6.js.map +1 -0
  120. package/dist/{chunk-E6EAB4J6.js → chunk-S24E4MBQ.js} +14 -14
  121. package/dist/chunk-S24E4MBQ.js.map +1 -0
  122. package/dist/{chunk-RYHWZ52A.js → chunk-S2BBISHU.js} +4 -4
  123. package/dist/{chunk-LLISELSY.js → chunk-TBMRQZDY.js} +2 -2
  124. package/dist/{chunk-FMLKOL2Z.js → chunk-TC3VNKGX.js} +4 -4
  125. package/dist/{chunk-7K5Q6COX.js → chunk-TVVEYCNW.js} +4 -4
  126. package/dist/{chunk-2XP3PWL3.js → chunk-UR5SIN7H.js} +53 -35
  127. package/dist/chunk-UR5SIN7H.js.map +1 -0
  128. package/dist/{chunk-NKDVXEFU.js → chunk-VFNI3RPT.js} +2 -2
  129. package/dist/chunk-VNA7W7QF.js +134 -0
  130. package/dist/chunk-VNA7W7QF.js.map +1 -0
  131. package/dist/{chunk-PQPSZICJ.js → chunk-VYYNBJXH.js} +5 -5
  132. package/dist/chunk-WNIUPHWV.js +152 -0
  133. package/dist/chunk-WNIUPHWV.js.map +1 -0
  134. package/dist/chunk-WRJVB3C2.js +118 -0
  135. package/dist/chunk-WRJVB3C2.js.map +1 -0
  136. package/dist/{chunk-SN3ZESWQ.js → chunk-WVVK2RFM.js} +6 -6
  137. package/dist/{chunk-DQEMWVMT.js → chunk-X7Y7WX73.js} +1 -1
  138. package/dist/{chunk-4KKV7W62.js → chunk-YOBNCD3Z.js} +6 -6
  139. package/dist/chunk-YXZG5TVN.js +40 -0
  140. package/dist/chunk-YXZG5TVN.js.map +1 -0
  141. package/dist/{chunk-4DJQYKMN.js → chunk-ZIKENA2C.js} +2 -2
  142. package/dist/chunk-ZIKENA2C.js.map +1 -0
  143. package/dist/{chunk-SK3EYPKC.js → chunk-ZN4UZWMT.js} +2 -2
  144. package/dist/{cli-BoouX6LX.d.ts → cli-DJbkaZBU.d.ts} +5 -5
  145. package/dist/cli.d.ts +14 -12
  146. package/dist/cli.js +79 -74
  147. package/dist/compounding/engine.d.ts +3 -2
  148. package/dist/compounding/engine.js +12 -10
  149. package/dist/compounding/preference-consolidator.d.ts +1 -1
  150. package/dist/compression-optimizer.d.ts +1 -1
  151. package/dist/config.d.ts +1 -1
  152. package/dist/config.js +4 -2
  153. package/dist/connectors/codex-materialize-runner.d.ts +1 -1
  154. package/dist/connectors/codex-materialize-runner.js +12 -10
  155. package/dist/connectors/codex-materialize.d.ts +1 -1
  156. package/dist/connectors/index.d.ts +1 -1
  157. package/dist/connectors/index.js +12 -10
  158. package/dist/consolidation-provenance-check.d.ts +3 -2
  159. package/dist/consolidation-undo.d.ts +3 -2
  160. package/dist/contradiction/index.d.ts +3 -2
  161. package/dist/conversation-index/backend.d.ts +1 -1
  162. package/dist/conversation-index/backend.js +2 -2
  163. package/dist/conversation-index/chunker.d.ts +1 -1
  164. package/dist/conversation-index/faiss-adapter.d.ts +1 -1
  165. package/dist/conversation-index/indexer.d.ts +1 -1
  166. package/dist/conversation-index/search.d.ts +1 -1
  167. package/dist/corpus-watermark.d.ts +15 -2
  168. package/dist/corpus-watermark.js +25 -21
  169. package/dist/day-summary.d.ts +1 -1
  170. package/dist/delinearize.d.ts +1 -1
  171. package/dist/direct-answer-wiring.d.ts +1 -1
  172. package/dist/direct-answer.d.ts +1 -1
  173. package/dist/embedding-fallback.d.ts +1 -1
  174. package/dist/enrichment/index.d.ts +1 -1
  175. package/dist/entity-id-normalization.d.ts +4 -0
  176. package/dist/entity-id-normalization.js +10 -0
  177. package/dist/entity-id-normalization.js.map +1 -0
  178. package/dist/entity-retrieval-boundaries.d.ts +3 -0
  179. package/dist/entity-retrieval-boundaries.js +8 -0
  180. package/dist/entity-retrieval-boundaries.js.map +1 -0
  181. package/dist/entity-retrieval.d.ts +3 -2
  182. package/dist/entity-retrieval.js +13 -10
  183. package/dist/entity-schema.d.ts +1 -1
  184. package/dist/entity-schema.js +1 -1
  185. package/dist/explicit-capture.d.ts +9 -8
  186. package/dist/extraction-error-classification.d.ts +1 -1
  187. package/dist/extraction-faithfulness.d.ts +1 -1
  188. package/dist/extraction-judge-telemetry.d.ts +1 -1
  189. package/dist/extraction-judge-training.d.ts +1 -1
  190. package/dist/extraction-judge.d.ts +1 -1
  191. package/dist/extraction-liveness.d.ts +1 -1
  192. package/dist/extraction.d.ts +1 -1
  193. package/dist/fallback-llm.d.ts +1 -1
  194. package/dist/{first-start-migration-LEXL3XYL.js → first-start-migration-BKNGOFED.js} +4 -4
  195. package/dist/graph-dashboard-diff.d.ts +1 -1
  196. package/dist/graph-dashboard-key.d.ts +1 -1
  197. package/dist/graph-dashboard-parser.d.ts +1 -1
  198. package/dist/graph-edge-reinforcement.d.ts +1 -1
  199. package/dist/graph-snapshot.d.ts +1 -1
  200. package/dist/graph.d.ts +1 -1
  201. package/dist/importance.d.ts +1 -1
  202. package/dist/importers/index.d.ts +1 -1
  203. package/dist/in-flight-reads.d.ts +1 -1
  204. package/dist/index.d.ts +409 -407
  205. package/dist/index.js +147 -141
  206. package/dist/intent.d.ts +1 -1
  207. package/dist/lcm/engine.d.ts +1 -1
  208. package/dist/lcm/engine.js +3 -3
  209. package/dist/lcm/index.d.ts +1 -1
  210. package/dist/lcm/index.js +9 -9
  211. package/dist/lcm/tools.d.ts +1 -1
  212. package/dist/lifecycle.d.ts +1 -1
  213. package/dist/live-connectors-runner.d.ts +1 -1
  214. package/dist/local-llm.d.ts +1 -1
  215. package/dist/local-model-endpoint.d.ts +1 -1
  216. package/dist/maintenance/memory-governance.d.ts +1 -1
  217. package/dist/maintenance/memory-governance.js +12 -10
  218. package/dist/maintenance/rebuild-memory-lifecycle-ledger.d.ts +3 -2
  219. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +12 -10
  220. package/dist/maintenance/rebuild-memory-projection.d.ts +3 -2
  221. package/dist/maintenance/rebuild-memory-projection.js +13 -11
  222. package/dist/{maintenance-DD22oIx9.d.ts → maintenance-DveW6azo.d.ts} +3 -3
  223. package/dist/mcp-memory-inspector-app.d.ts +13 -10
  224. package/dist/memory-action-policy.d.ts +1 -1
  225. package/dist/memory-cache.d.ts +1 -1
  226. package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
  227. package/dist/memory-projection-mutations.d.ts +4 -0
  228. package/dist/memory-projection-mutations.js +15 -0
  229. package/dist/memory-projection-mutations.js.map +1 -0
  230. package/dist/memory-projection-store.d.ts +1 -1
  231. package/dist/memory-provenance.d.ts +1 -1
  232. package/dist/memory-worth-outcomes.d.ts +3 -2
  233. package/dist/models-json.d.ts +1 -1
  234. package/dist/namespaces/migrate.d.ts +4 -3
  235. package/dist/namespaces/migrate.js +22 -20
  236. package/dist/namespaces/principal.d.ts +1 -1
  237. package/dist/namespaces/search.d.ts +1 -1
  238. package/dist/namespaces/search.js +9 -9
  239. package/dist/namespaces/storage.d.ts +4 -3
  240. package/dist/namespaces/storage.js +12 -10
  241. package/dist/native-knowledge.d.ts +1 -1
  242. package/dist/offline-sync-impression-drain.d.ts +1 -1
  243. package/dist/offline-sync-impression-drain.js +3 -3
  244. package/dist/operator-doctor-corpus.d.ts +22 -3
  245. package/dist/operator-doctor-corpus.js +32 -22
  246. package/dist/operator-doctor-replica.d.ts +52 -0
  247. package/dist/operator-doctor-replica.js +15 -0
  248. package/dist/operator-doctor-replica.js.map +1 -0
  249. package/dist/operator-toolkit.d.ts +7 -3
  250. package/dist/operator-toolkit.js +33 -27
  251. package/dist/orchestration/compression-guideline-coordinator.d.ts +3 -2
  252. package/dist/orchestration/maintenance.d.ts +5 -4
  253. package/dist/orchestration/maintenance.js +17 -15
  254. package/dist/{orchestrator-CFJ_TG6D.d.ts → orchestrator-Cvlgpe6I.d.ts} +7 -7
  255. package/dist/orchestrator.d.ts +9 -8
  256. package/dist/orchestrator.js +99 -93
  257. package/dist/patterns-cli.d.ts +1 -1
  258. package/dist/{pipeline-Bq5zU6Bp.d.ts → pipeline-BveYVaz7.d.ts} +1 -1
  259. package/dist/policy-runtime.d.ts +1 -1
  260. package/dist/proactive-contention.d.ts +1 -1
  261. package/dist/provenance.d.ts +1 -1
  262. package/dist/{qmd-3ILJkC70.d.ts → qmd-CLWDsbYR.d.ts} +1 -1
  263. package/dist/qmd-preflight.d.ts +2 -2
  264. package/dist/qmd-recall-cache.d.ts +1 -1
  265. package/dist/qmd.d.ts +2 -2
  266. package/dist/recall-concurrency-config.d.ts +1 -1
  267. package/dist/recall-disclosure-escalation.d.ts +1 -1
  268. package/dist/recall-explain-renderer.d.ts +1 -1
  269. package/dist/recall-explain-renderer.js +3 -3
  270. package/dist/recall-memory-map.d.ts +1 -1
  271. package/dist/recall-planner-llm.d.ts +1 -1
  272. package/dist/recall-state.d.ts +1 -1
  273. package/dist/recall-state.js +2 -2
  274. package/dist/recall-tag-filter.d.ts +1 -1
  275. package/dist/recall-timings.d.ts +1 -1
  276. package/dist/recall-xray-cli.d.ts +1 -1
  277. package/dist/recall-xray-cli.js +4 -4
  278. package/dist/recall-xray-renderer.d.ts +1 -1
  279. package/dist/recall-xray-renderer.js +3 -3
  280. package/dist/recall-xray.d.ts +1 -1
  281. package/dist/recall-xray.js +2 -2
  282. package/dist/replay/normalizers/chatgpt.d.ts +1 -1
  283. package/dist/replay/normalizers/claude.d.ts +1 -1
  284. package/dist/replay/normalizers/openclaw.d.ts +1 -1
  285. package/dist/replay/normalizers/shared.d.ts +1 -1
  286. package/dist/replay/runner.d.ts +1 -1
  287. package/dist/replay/types.d.ts +1 -1
  288. package/dist/replica-divergence.d.ts +279 -0
  289. package/dist/replica-divergence.js +28 -0
  290. package/dist/replica-divergence.js.map +1 -0
  291. package/dist/replica-peers-config.d.ts +5 -0
  292. package/dist/replica-peers-config.js +13 -0
  293. package/dist/replica-peers-config.js.map +1 -0
  294. package/dist/resolve-auth-token.d.ts +21 -2
  295. package/dist/resolve-auth-token.js +5 -1
  296. package/dist/resume-bundles.js +5 -3
  297. package/dist/retrieval-agents.d.ts +2 -2
  298. package/dist/retrieval-tiers.d.ts +1 -1
  299. package/dist/routing/engine.d.ts +1 -1
  300. package/dist/routing/store.d.ts +1 -1
  301. package/dist/salvage-envelope.d.ts +1 -1
  302. package/dist/schemas.d.ts +76 -76
  303. package/dist/{scope-profiles-D0-ff4xT.d.ts → scope-profiles-BVf3DZ7z.d.ts} +1 -1
  304. package/dist/search/embed-helper.d.ts +1 -1
  305. package/dist/search/factory.d.ts +1 -1
  306. package/dist/search/factory.js +8 -8
  307. package/dist/search/index.d.ts +1 -1
  308. package/dist/search/index.js +13 -13
  309. package/dist/search/lancedb-backend.d.ts +1 -1
  310. package/dist/search/lancedb-backend.js +2 -2
  311. package/dist/search/meilisearch-backend.d.ts +1 -1
  312. package/dist/search/meilisearch-backend.js +2 -2
  313. package/dist/search/noop-backend.d.ts +1 -1
  314. package/dist/search/orama-backend.d.ts +1 -1
  315. package/dist/search/orama-backend.js +2 -2
  316. package/dist/search/port.d.ts +1 -1
  317. package/dist/search/remote-backend.d.ts +1 -1
  318. package/dist/{semantic-consolidation-4Tfh7c1g.d.ts → semantic-consolidation-DXLV47y2.d.ts} +1 -1
  319. package/dist/semantic-consolidation.d.ts +2 -2
  320. package/dist/semantic-consolidation.js +13 -11
  321. package/dist/semantic-rule-promotion.js +12 -10
  322. package/dist/semantic-rule-verifier.d.ts +1 -1
  323. package/dist/semantic-rule-verifier.js +12 -10
  324. package/dist/{service-Z8uzoAST.d.ts → service-DbgPTeMJ.d.ts} +2 -2
  325. package/dist/session-observer-bands.d.ts +1 -1
  326. package/dist/session-observer-state.d.ts +1 -1
  327. package/dist/shared-context/manager.d.ts +9 -9
  328. package/dist/signal.d.ts +1 -1
  329. package/dist/{storage-BZVMn8yJ.d.ts → storage-DOzTm8wG.d.ts} +13 -22
  330. package/dist/storage.d.ts +3 -2
  331. package/dist/storage.js +13 -10
  332. package/dist/summarizer.d.ts +1 -1
  333. package/dist/summary-snapshot.d.ts +1 -1
  334. package/dist/temporal-supersession.d.ts +3 -2
  335. package/dist/temporal-timeline-recall.d.ts +1 -1
  336. package/dist/temporal-validity.d.ts +1 -1
  337. package/dist/threading.d.ts +1 -1
  338. package/dist/tier-migration.d.ts +3 -2
  339. package/dist/tier-routing.d.ts +1 -1
  340. package/dist/topics.d.ts +1 -1
  341. package/dist/transcript.d.ts +1 -1
  342. package/dist/transfer/autodetect.js +1 -1
  343. package/dist/transfer/backup.js +2 -2
  344. package/dist/transfer/capsule-export.js +3 -3
  345. package/dist/transfer/capsule-import.js +2 -2
  346. package/dist/transfer/types.d.ts +66 -66
  347. package/dist/trust-score-stage.d.ts +1 -1
  348. package/dist/trust-score.d.ts +1 -1
  349. package/dist/{types-DHBxIF0s.d.ts → types-BA7W-_xy.d.ts} +53 -4
  350. package/dist/types.d.ts +1 -1
  351. package/dist/types.js +1 -1
  352. package/dist/utility-runtime.d.ts +1 -1
  353. package/dist/verified-recall.js +12 -10
  354. package/dist/write-envelope.d.ts +1 -1
  355. package/package.json +2 -2
  356. package/src/access-health-types.ts +8 -0
  357. package/src/access-http.test.ts +4 -0
  358. package/src/access-service-health.test.ts +23 -0
  359. package/src/access-service.ts +27 -4
  360. package/src/cli.ts +9 -7
  361. package/src/config.ts +2 -1
  362. package/src/corpus-watermark.test.ts +21 -0
  363. package/src/corpus-watermark.ts +25 -3
  364. package/src/entity-id-normalization.ts +55 -0
  365. package/src/entity-retrieval-boundaries.ts +134 -0
  366. package/src/entity-retrieval.ts +253 -27
  367. package/src/entity-schema.ts +2 -1
  368. package/src/memory-projection-mutations.ts +132 -0
  369. package/src/namespaces/storage.ts +5 -3
  370. package/src/operator-doctor-corpus.ts +41 -0
  371. package/src/operator-doctor-replica.test.ts +261 -0
  372. package/src/operator-doctor-replica.ts +129 -0
  373. package/src/operator-toolkit.ts +5 -4
  374. package/src/orchestration/orchestrator-init.ts +2 -2
  375. package/src/replica-divergence.test.ts +1475 -0
  376. package/src/replica-divergence.ts +910 -0
  377. package/src/replica-peers-config.ts +250 -0
  378. package/src/resolve-auth-token.ts +38 -0
  379. package/src/storage/entity-canonical-id-migration-adapter.ts +72 -0
  380. package/src/storage/entity-canonical-id-migration-runner.ts +68 -0
  381. package/src/storage/entity-canonical-id-migration.ts +904 -0
  382. package/src/storage/entity-store.ts +44 -0
  383. package/src/storage/memory-frontmatter-metadata.ts +17 -0
  384. package/src/storage/memory-migration-serialization.ts +37 -0
  385. package/src/storage/memory-read-store.ts +3 -2
  386. package/src/storage/profile-header.ts +898 -0
  387. package/src/storage-profile-timestamp.test.ts +3358 -0
  388. package/src/storage.ts +73 -77
  389. package/src/testing/subjects/profile-header-write.test.ts +71 -0
  390. package/src/types.ts +3 -3
  391. package/dist/chunk-2XP3PWL3.js.map +0 -1
  392. package/dist/chunk-4DJQYKMN.js.map +0 -1
  393. package/dist/chunk-E6EAB4J6.js.map +0 -1
  394. package/dist/chunk-EXM2Q555.js.map +0 -1
  395. package/dist/chunk-GJJBPI6I.js.map +0 -1
  396. package/dist/chunk-KPWLZBXZ.js.map +0 -1
  397. package/dist/chunk-LIIQPDFN.js.map +0 -1
  398. package/dist/chunk-UZK7VVPD.js.map +0 -1
  399. package/dist/chunk-V25OWXAC.js.map +0 -1
  400. package/dist/chunk-YN4AUGNF.js.map +0 -1
  401. /package/dist/{capsule-crypto-YO5QJ6L3.js.map → capsule-crypto-7FJQINUR.js.map} +0 -0
  402. /package/dist/{chunk-7RZJWZ46.js.map → chunk-227UFSEQ.js.map} +0 -0
  403. /package/dist/{chunk-VGEH3STZ.js.map → chunk-2BEJ4XCF.js.map} +0 -0
  404. /package/dist/{chunk-BXLOS5AJ.js.map → chunk-2NLLXCJG.js.map} +0 -0
  405. /package/dist/{chunk-6NNNURLK.js.map → chunk-2PHX3I5C.js.map} +0 -0
  406. /package/dist/{chunk-XAAIUXJO.js.map → chunk-3BSJBIZ3.js.map} +0 -0
  407. /package/dist/{chunk-JCVQV6QX.js.map → chunk-3UOSVTFR.js.map} +0 -0
  408. /package/dist/{chunk-AJ7QCSIS.js.map → chunk-7CPOZH6Y.js.map} +0 -0
  409. /package/dist/{chunk-M2KGXXTL.js.map → chunk-ALTP3MFS.js.map} +0 -0
  410. /package/dist/{chunk-77CNV7DY.js.map → chunk-BLAKS3CP.js.map} +0 -0
  411. /package/dist/{chunk-FE5FKTCI.js.map → chunk-BR4UFMLO.js.map} +0 -0
  412. /package/dist/{chunk-H2PBM562.js.map → chunk-DKQM5Q6Q.js.map} +0 -0
  413. /package/dist/{chunk-CSXHRAJJ.js.map → chunk-EG64LXKL.js.map} +0 -0
  414. /package/dist/{chunk-PTN6UAUA.js.map → chunk-ES36HTSC.js.map} +0 -0
  415. /package/dist/{chunk-WMDRLTNA.js.map → chunk-EZWWCN7I.js.map} +0 -0
  416. /package/dist/{chunk-XKGPIWGI.js.map → chunk-FBZTWUK5.js.map} +0 -0
  417. /package/dist/{chunk-Y6E37WRG.js.map → chunk-GJPCP5CA.js.map} +0 -0
  418. /package/dist/{chunk-VDX2J7OX.js.map → chunk-IPLYGWQF.js.map} +0 -0
  419. /package/dist/{chunk-XNUBF6RF.js.map → chunk-IYT632D5.js.map} +0 -0
  420. /package/dist/{chunk-2QSZNTDO.js.map → chunk-JBPKEARU.js.map} +0 -0
  421. /package/dist/{chunk-67DSDRUB.js.map → chunk-JIF3VRKQ.js.map} +0 -0
  422. /package/dist/{chunk-MIFF37NN.js.map → chunk-KKBTBUVT.js.map} +0 -0
  423. /package/dist/{chunk-ZHP4SUPB.js.map → chunk-LIHC3T43.js.map} +0 -0
  424. /package/dist/{chunk-UGH6VPPO.js.map → chunk-MWTMTW2T.js.map} +0 -0
  425. /package/dist/{chunk-F6LSNPPB.js.map → chunk-MXJ3VP6S.js.map} +0 -0
  426. /package/dist/{chunk-M5EPMNS4.js.map → chunk-P2CLYN6H.js.map} +0 -0
  427. /package/dist/{chunk-KGTD2KZJ.js.map → chunk-Q6YJW6KE.js.map} +0 -0
  428. /package/dist/{chunk-X3SQYAPP.js.map → chunk-R372P2EH.js.map} +0 -0
  429. /package/dist/{chunk-HBVOJNV4.js.map → chunk-RKXZ7P4V.js.map} +0 -0
  430. /package/dist/{chunk-RYHWZ52A.js.map → chunk-S2BBISHU.js.map} +0 -0
  431. /package/dist/{chunk-LLISELSY.js.map → chunk-TBMRQZDY.js.map} +0 -0
  432. /package/dist/{chunk-FMLKOL2Z.js.map → chunk-TC3VNKGX.js.map} +0 -0
  433. /package/dist/{chunk-7K5Q6COX.js.map → chunk-TVVEYCNW.js.map} +0 -0
  434. /package/dist/{chunk-NKDVXEFU.js.map → chunk-VFNI3RPT.js.map} +0 -0
  435. /package/dist/{chunk-PQPSZICJ.js.map → chunk-VYYNBJXH.js.map} +0 -0
  436. /package/dist/{chunk-SN3ZESWQ.js.map → chunk-WVVK2RFM.js.map} +0 -0
  437. /package/dist/{chunk-DQEMWVMT.js.map → chunk-X7Y7WX73.js.map} +0 -0
  438. /package/dist/{chunk-4KKV7W62.js.map → chunk-YOBNCD3Z.js.map} +0 -0
  439. /package/dist/{chunk-SK3EYPKC.js.map → chunk-ZN4UZWMT.js.map} +0 -0
  440. /package/dist/{first-start-migration-LEXL3XYL.js.map → first-start-migration-BKNGOFED.js.map} +0 -0
@@ -1,3 +1,8 @@
1
+ import {
2
+ TombstoneStore,
3
+ buildRetiredFactTombstoneInputs,
4
+ collectRetiredMemoriesForRebuild
5
+ } from "./chunk-2QMKMVHH.js";
1
6
  import {
2
7
  WEARABLES_DIR_NAME,
3
8
  escapeSegmentText,
@@ -10,26 +15,23 @@ import {
10
15
  unescapeSpeakerLabel
11
16
  } from "./chunk-UHVXE24Y.js";
12
17
  import {
13
- TombstoneStore,
14
- buildRetiredFactTombstoneInputs,
15
- collectRetiredMemoriesForRebuild
16
- } from "./chunk-2QMKMVHH.js";
17
- import {
18
+ computeSupersessionKey,
19
+ normalizeSupersessionKey,
18
20
  supersessionKeysForFact
19
21
  } from "./chunk-DNHVPZOD.js";
20
- import {
21
- assertMemoryFrontmatterId,
22
- warnProjectionFallback
23
- } from "./chunk-HKF5VASQ.js";
24
22
  import {
25
23
  DEFAULT_CITATION_FORMAT,
26
24
  hasCitation,
27
25
  stripCitationForTemplate
28
26
  } from "./chunk-J6A3CX5N.js";
27
+ import {
28
+ assertMemoryFrontmatterId,
29
+ warnProjectionFallback
30
+ } from "./chunk-HKF5VASQ.js";
29
31
  import {
30
32
  SPECULATIVE_TTL_DAYS,
31
33
  confidenceTier
32
- } from "./chunk-V25OWXAC.js";
34
+ } from "./chunk-JQ7T5VDC.js";
33
35
  import {
34
36
  appendLifecycleEventsSerialized,
35
37
  drainPendingLifecycleLedgerForSync,
@@ -40,14 +42,10 @@ import {
40
42
  readMaybeEncryptedLines,
41
43
  readMemoryActionEventRowsFromLines,
42
44
  serializeLifecycleAppendPayload
43
- } from "./chunk-XKGPIWGI.js";
45
+ } from "./chunk-FBZTWUK5.js";
44
46
  import {
45
47
  namespaceIdentityFromToken
46
48
  } from "./chunk-EGGE52UU.js";
47
- import {
48
- assertPathInsideRoot,
49
- pathIsInside
50
- } from "./chunk-GCASGYIO.js";
51
49
  import {
52
50
  withHeldFileLock
53
51
  } from "./chunk-WL5EBRDH.js";
@@ -60,6 +58,14 @@ import {
60
58
  normalizeProjectionPreview,
61
59
  normalizeProjectionTags
62
60
  } from "./chunk-SCU65EZI.js";
61
+ import {
62
+ rewriteProjectedEntityReferences,
63
+ rewriteProjectedMemoryEntityReference
64
+ } from "./chunk-WRJVB3C2.js";
65
+ import {
66
+ assertPathInsideRoot,
67
+ pathIsInside
68
+ } from "./chunk-GCASGYIO.js";
63
69
  import {
64
70
  markProjectedMemoryPathInvalid,
65
71
  openProjectionReadonly,
@@ -81,6 +87,10 @@ import {
81
87
  serializeContinuityIncident,
82
88
  upsertContinuityLoopInMarkdown
83
89
  } from "./chunk-LDXUBPMO.js";
90
+ import {
91
+ parseFaithfulnessField,
92
+ serializeFaithfulnessFields
93
+ } from "./chunk-JYIJNNN3.js";
84
94
  import {
85
95
  composeMemoryEnvelope,
86
96
  isSealedMemoryEnvelope,
@@ -91,9 +101,8 @@ import {
91
101
  stripAttributesSuffix
92
102
  } from "./chunk-R3DJVOSM.js";
93
103
  import {
94
- parseFaithfulnessField,
95
- serializeFaithfulnessFields
96
- } from "./chunk-JYIJNNN3.js";
104
+ normalizeEntityName
105
+ } from "./chunk-YXZG5TVN.js";
97
106
  import {
98
107
  createVersion
99
108
  } from "./chunk-5VQJBH2G.js";
@@ -131,14 +140,14 @@ import {
131
140
  reconcileProvenanceRead,
132
141
  serializeProvenanceFields
133
142
  } from "./chunk-5I4M26Q7.js";
134
- import {
135
- sanitizeMemoryContent
136
- } from "./chunk-5GKPFL3S.js";
137
143
  import {
138
144
  matchEntitySchemaSection,
139
145
  normalizeEntityStructuredSection,
140
146
  sortStructuredSectionsBySchema
141
- } from "./chunk-4DJQYKMN.js";
147
+ } from "./chunk-ZIKENA2C.js";
148
+ import {
149
+ sanitizeMemoryContent
150
+ } from "./chunk-5GKPFL3S.js";
142
151
  import {
143
152
  parseFlexibleIsoTimestamp
144
153
  } from "./chunk-P7FMDTKL.js";
@@ -195,24 +204,40 @@ function assertInjectedStorageRooted(label, memoryDir, injected) {
195
204
 
196
205
  // src/storage.ts
197
206
  import {
198
- lstat as lstat2,
199
- readdir as readdir4,
200
- readFile,
201
- realpath as realpath2,
207
+ lstat as lstat3,
208
+ readdir as readdir5,
209
+ readFile as readFile2,
210
+ realpath as realpath3,
202
211
  stat as stat3,
203
- writeFile,
212
+ writeFile as writeFile2,
204
213
  mkdir as mkdir2,
205
- unlink as unlink2,
214
+ unlink as unlink3,
206
215
  appendFile,
207
216
  open
208
217
  } from "fs/promises";
209
- import { appendFileSync, createReadStream, mkdirSync, readFileSync, statSync } from "fs";
218
+ import { appendFileSync, createReadStream, mkdirSync, readFileSync as readFileSync2, statSync } from "fs";
210
219
  import { createHash as createHash5 } from "crypto";
211
- import path9 from "path";
220
+ import path10 from "path";
212
221
 
213
222
  // src/storage/memory-read-store.ts
214
223
  import { lstat, readdir, realpath, stat } from "fs/promises";
215
224
  import path2 from "path";
225
+
226
+ // src/storage/memory-frontmatter-metadata.ts
227
+ var rawFrontmatterByMemory = /* @__PURE__ */ new WeakMap();
228
+ function extractRawFrontmatter(raw) {
229
+ return raw.match(/^---\n([\s\S]*?)\n---\n?/)?.[1] ?? null;
230
+ }
231
+ function rememberRawFrontmatter(owner, raw) {
232
+ const frontmatter = extractRawFrontmatter(raw);
233
+ if (frontmatter !== null) rawFrontmatterByMemory.set(owner, frontmatter);
234
+ return owner;
235
+ }
236
+ function readRawFrontmatter(owner) {
237
+ return rawFrontmatterByMemory.get(owner);
238
+ }
239
+
240
+ // src/storage/memory-read-store.ts
216
241
  function isPropagatableReadError(err) {
217
242
  const code = err.code;
218
243
  return typeof code === "string" && code !== "ENOENT";
@@ -491,7 +516,7 @@ var MemoryReadStore = class {
491
516
  const raw = await readMaybeEncryptedFile(filePath, this.deps._secureStoreKey, this.deps.baseDir);
492
517
  const parsed = parseFrontmatter(raw);
493
518
  if (parsed) {
494
- return {
519
+ return rememberRawFrontmatter({
495
520
  path: filePath,
496
521
  frontmatter: normalizeFrontmatterForPath(
497
522
  parsed.frontmatter,
@@ -499,7 +524,7 @@ var MemoryReadStore = class {
499
524
  parsed.content
500
525
  ),
501
526
  content: parsed.content
502
- };
527
+ }, raw);
503
528
  }
504
529
  const normalizedPath = filePath.split(path2.sep).join("/");
505
530
  if (normalizedPath.includes("/entities/") && filePath.endsWith(".md")) {
@@ -705,6 +730,673 @@ var MemoryReadStore = class {
705
730
  }
706
731
  };
707
732
 
733
+ // src/storage/profile-header.ts
734
+ var LAST_UPDATED_HEADER = /^\*Last updated:[^*]*\*$/;
735
+ var PROFILE_TITLE = /^ {0,3}#(?:[ \t]+|$)/;
736
+ var MARKDOWN_HEADING = /^ {0,3}#{1,6}(?:[ \t]+|$)/;
737
+ var MARKDOWN_LIST_ITEM = /^(?:[-+*]|\d{1,9}[.)])[ \t]+/;
738
+ var MARKDOWN_LIST_ITEM_CAN_INTERRUPT = /^(?:[-+*]|1[.)])[ \t]+/;
739
+ var MARKDOWN_THEMATIC_BREAK = /^(?:(?:\*[ \t]*){3,}|(?:-[ \t]*){3,}|(?:_[ \t]*){3,})$/;
740
+ var MARKDOWN_SETEXT_UNDERLINE = /^(?:=+|-+)$/;
741
+ var MARKDOWN_BLOCK_QUOTE = /^>/;
742
+ var MARKDOWN_LINK_REFERENCE = /^\[(?:\\.|[^\\\[\]])+\]:[ \t]*(?:<[^>\n]*>|([^\s]+))(?:[ \t]+(?:"[^"\n]*"|'[^'\n]*'|\([^)\n]*\)))?$/;
743
+ var MARKDOWN_LINK_REFERENCE_LABEL = /^\[(?:\\.|[^\\\[\]])+\]:[ \t]*$/;
744
+ var MARKDOWN_LINK_REFERENCE_CONTINUATION = /^ {1,3}(?:"[^"\n]*"|'[^'\n]*'|\([^)\n]*\))$/;
745
+ var MARKDOWN_LINK_REFERENCE_DESTINATION_CONTINUATION = /^ {1,3}(?:<[^>\n]*>|(?!["'(])[^\s]+(?:[ \t]+(?:"[^"\n]*"|'[^'\n]*'|\([^)\n]*\)))?)$/;
746
+ var UTF8_BOM = "\uFEFF";
747
+ function isLastUpdatedHeader(line) {
748
+ const withoutBom = line.startsWith(UTF8_BOM) ? line.slice(1) : line;
749
+ if (isIndentedCodeLine(withoutBom)) return false;
750
+ return LAST_UPDATED_HEADER.test(withoutBom.trim());
751
+ }
752
+ function isIndentedCodeLine(line) {
753
+ let indentation = 0;
754
+ while (line[indentation] === " ") indentation += 1;
755
+ return indentation >= 4 || line[indentation] === " ";
756
+ }
757
+ function getFenceMarker(line) {
758
+ let indentation = 0;
759
+ while (line[indentation] === " ") indentation += 1;
760
+ if (indentation > 3 || line[indentation] === " ") return null;
761
+ const trimmed = line.slice(indentation);
762
+ const character = trimmed[0];
763
+ if (character !== "`" && character !== "~") return null;
764
+ let length = 0;
765
+ while (trimmed[length] === character) length += 1;
766
+ if (length < 3) return null;
767
+ const trailing = trimmed.slice(length);
768
+ if (character === "`" && trailing.includes("`")) return null;
769
+ return { indentation, character, length, trailing };
770
+ }
771
+ function isClosingFence(fence, openFence) {
772
+ return fence.character === openFence.character && fence.length >= openFence.length && fence.trailing.trim() === "";
773
+ }
774
+ var RAW_HTML_BLOCK_TAGS = ["pre", "textarea", "script", "style"];
775
+ var HTML_BLOCK_TAGS = [
776
+ "address",
777
+ "article",
778
+ "aside",
779
+ "base",
780
+ "basefont",
781
+ "blockquote",
782
+ "body",
783
+ "caption",
784
+ "center",
785
+ "col",
786
+ "colgroup",
787
+ "dd",
788
+ "details",
789
+ "dialog",
790
+ "dir",
791
+ "div",
792
+ "dl",
793
+ "dt",
794
+ "fieldset",
795
+ "figcaption",
796
+ "figure",
797
+ "footer",
798
+ "form",
799
+ "frame",
800
+ "frameset",
801
+ "h1",
802
+ "h2",
803
+ "h3",
804
+ "h4",
805
+ "h5",
806
+ "h6",
807
+ "head",
808
+ "header",
809
+ "hgroup",
810
+ "hr",
811
+ "html",
812
+ "iframe",
813
+ "legend",
814
+ "li",
815
+ "link",
816
+ "main",
817
+ "menu",
818
+ "menuitem",
819
+ "nav",
820
+ "noframes",
821
+ "ol",
822
+ "optgroup",
823
+ "option",
824
+ "p",
825
+ "param",
826
+ "search",
827
+ "section",
828
+ "summary",
829
+ "table",
830
+ "tbody",
831
+ "td",
832
+ "tfoot",
833
+ "th",
834
+ "thead",
835
+ "title",
836
+ "tr",
837
+ "track",
838
+ "ul"
839
+ ];
840
+ function findHtmlBlockTag(line, tags) {
841
+ const isClosing = line.startsWith("</");
842
+ const nameStart = isClosing ? 2 : 1;
843
+ for (const tag of tags) {
844
+ const nextCharacter = line[nameStart + tag.length];
845
+ const isSelfClosingSlash = !isClosing && nextCharacter === "/" && line[nameStart + tag.length + 1] === ">";
846
+ if (line.startsWith(`${isClosing ? "</" : "<"}${tag}`) && (nextCharacter === void 0 || nextCharacter === ">" || isSelfClosingSlash || nextCharacter === " " || nextCharacter === " ")) {
847
+ return tag;
848
+ }
849
+ }
850
+ return null;
851
+ }
852
+ function isAsciiLetter(character) {
853
+ return character >= "a" && character <= "z" || character >= "A" && character <= "Z";
854
+ }
855
+ function isHtmlTagNameCharacter(character) {
856
+ return isAsciiLetter(character) || character >= "0" && character <= "9" || character === "-";
857
+ }
858
+ var HTML_ATTRIBUTES = /^(?:[A-Za-z_:][A-Za-z0-9_.:-]*(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s"'=<>`]+))?)(?:\s+[A-Za-z_:][A-Za-z0-9_.:-]*(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s"'=<>`]+))?)*$/;
859
+ function hasValidHtmlTagAttributes(attributeText, isClosing) {
860
+ const trimmed = attributeText.trim();
861
+ if (isClosing || trimmed === "") return trimmed === "";
862
+ const withoutSelfClosingSlash = trimmed.endsWith("/") ? trimmed.slice(0, -1).trimEnd() : trimmed;
863
+ return withoutSelfClosingSlash === "" || HTML_ATTRIBUTES.test(withoutSelfClosingSlash);
864
+ }
865
+ function findCompleteHtmlTag(line) {
866
+ let index = 1;
867
+ const isClosing = line[index] === "/";
868
+ if (isClosing) index += 1;
869
+ const nameStart = index;
870
+ if (!isAsciiLetter(line[index] ?? "")) return null;
871
+ while (isHtmlTagNameCharacter(line[index] ?? "")) index += 1;
872
+ const nextCharacter = line[index] ?? "";
873
+ if (nextCharacter !== ">" && nextCharacter !== "/" && nextCharacter !== " " && nextCharacter !== " ") {
874
+ return null;
875
+ }
876
+ const name = line.slice(nameStart, index).toLowerCase();
877
+ let quote = null;
878
+ for (; index < line.length; index += 1) {
879
+ const character = line[index];
880
+ if (quote) {
881
+ if (character === quote) quote = null;
882
+ continue;
883
+ }
884
+ if (character === '"' || character === "'") {
885
+ quote = character;
886
+ continue;
887
+ }
888
+ if (character === ">" && line.slice(index + 1).trim() === "") {
889
+ const tagBody = line.slice(nameStart, index).trimEnd();
890
+ if (!hasValidHtmlTagAttributes(tagBody.slice(name.length), isClosing)) return null;
891
+ return {
892
+ name,
893
+ isClosing,
894
+ isSelfClosing: !isClosing && tagBody.endsWith("/")
895
+ };
896
+ }
897
+ }
898
+ return null;
899
+ }
900
+ function findHtmlTagPrefix(line) {
901
+ let quote = null;
902
+ for (let index = 1; index < line.length; index += 1) {
903
+ const character = line[index];
904
+ if (quote) {
905
+ if (character === quote) quote = null;
906
+ continue;
907
+ }
908
+ if (character === '"' || character === "'") {
909
+ quote = character;
910
+ continue;
911
+ }
912
+ if (character !== ">") continue;
913
+ return findCompleteHtmlTag(line.slice(0, index + 1));
914
+ }
915
+ return null;
916
+ }
917
+ function findHtmlTags(line) {
918
+ const tags = [];
919
+ let index = 0;
920
+ while (index < line.length) {
921
+ if (line[index] !== "<") {
922
+ index += 1;
923
+ continue;
924
+ }
925
+ let cursor = index + 1;
926
+ const isClosing = line[cursor] === "/";
927
+ if (isClosing) cursor += 1;
928
+ const nameStart = cursor;
929
+ if (!isAsciiLetter(line[cursor] ?? "")) {
930
+ index += 1;
931
+ continue;
932
+ }
933
+ while (isHtmlTagNameCharacter(line[cursor] ?? "")) cursor += 1;
934
+ const name = line.slice(nameStart, cursor).toLowerCase();
935
+ let quote = null;
936
+ for (; cursor < line.length; cursor += 1) {
937
+ const character = line[cursor] ?? "";
938
+ if (quote) {
939
+ if (character === quote) quote = null;
940
+ continue;
941
+ }
942
+ if (character === '"' || character === "'") {
943
+ quote = character;
944
+ continue;
945
+ }
946
+ if (character !== ">") continue;
947
+ const tagBody = line.slice(nameStart, cursor).trimEnd();
948
+ tags.push({
949
+ name,
950
+ isClosing,
951
+ isSelfClosing: !isClosing && tagBody.endsWith("/")
952
+ });
953
+ index = cursor + 1;
954
+ break;
955
+ }
956
+ if (cursor >= line.length) break;
957
+ }
958
+ return tags;
959
+ }
960
+ function updateHtmlBlockDepth(htmlBlock, line, skipFirstOpening) {
961
+ if (!htmlBlock.tagName) return htmlBlock;
962
+ let depth = htmlBlock.depth;
963
+ let skippedFirstOpening = !skipFirstOpening;
964
+ for (const tag of findHtmlTags(line)) {
965
+ if (tag.name !== htmlBlock.tagName) continue;
966
+ if (tag.isClosing) {
967
+ depth -= 1;
968
+ } else if (!tag.isSelfClosing) {
969
+ if (!skippedFirstOpening) {
970
+ skippedFirstOpening = true;
971
+ continue;
972
+ }
973
+ depth += 1;
974
+ }
975
+ }
976
+ if (depth > 0) return { ...htmlBlock, depth };
977
+ return htmlBlock.endsAtBlankLine ? { ...htmlBlock, endMarker: null, endsAtBlankLine: true, tagName: null, depth: 0 } : null;
978
+ }
979
+ function hasSpacedSelfClosingSlash(line) {
980
+ return /\s\/\s*>/.test(line);
981
+ }
982
+ function findHtmlBlockStart(normalizedLine, trimmedLine, allowGenericHtmlBlock) {
983
+ const rawTag = findHtmlBlockTag(normalizedLine, RAW_HTML_BLOCK_TAGS);
984
+ if (rawTag) {
985
+ const completeTag = findCompleteHtmlTag(trimmedLine) ?? findHtmlTagPrefix(trimmedLine);
986
+ if (!completeTag && normalizedLine.startsWith("</")) return null;
987
+ if (completeTag?.isSelfClosing && !hasSpacedSelfClosingSlash(trimmedLine)) return null;
988
+ const endMarker = `</${rawTag}>`;
989
+ if (hasHtmlBlockEndMarker(normalizedLine, endMarker)) {
990
+ if (!completeTag || completeTag.isClosing) return null;
991
+ return { endMarker, endsAtBlankLine: false, tagName: null, depth: 0 };
992
+ }
993
+ return { endMarker, endsAtBlankLine: false, tagName: null, depth: 0 };
994
+ }
995
+ if (normalizedLine.startsWith("<!--")) {
996
+ return { endMarker: "-->", endsAtBlankLine: false, tagName: null, depth: 0 };
997
+ }
998
+ if (normalizedLine.startsWith("<?")) {
999
+ return { endMarker: "?>", endsAtBlankLine: false, tagName: null, depth: 0 };
1000
+ }
1001
+ if (trimmedLine.startsWith("<![CDATA[")) {
1002
+ return { endMarker: "]]>", endsAtBlankLine: false, tagName: null, depth: 0 };
1003
+ }
1004
+ const declarationFirst = trimmedLine[2];
1005
+ if (trimmedLine.startsWith("<!") && declarationFirst && declarationFirst >= "A" && declarationFirst <= "Z") {
1006
+ return { endMarker: ">", endsAtBlankLine: false, tagName: null, depth: 0 };
1007
+ }
1008
+ const blockTag = findHtmlBlockTag(normalizedLine, HTML_BLOCK_TAGS);
1009
+ if (blockTag) {
1010
+ const completeTag = findCompleteHtmlTag(trimmedLine) ?? findHtmlTagPrefix(trimmedLine);
1011
+ if (!completeTag) {
1012
+ return { endMarker: null, endsAtBlankLine: true, tagName: null, depth: 0 };
1013
+ }
1014
+ if (completeTag.isSelfClosing) {
1015
+ return { endMarker: null, endsAtBlankLine: true, tagName: null, depth: 0 };
1016
+ }
1017
+ return { endMarker: `</${blockTag}>`, endsAtBlankLine: true, tagName: blockTag, depth: 1 };
1018
+ }
1019
+ if (!allowGenericHtmlBlock) return null;
1020
+ const genericTag = findCompleteHtmlTag(trimmedLine);
1021
+ if (!genericTag) return null;
1022
+ if (genericTag.isClosing || genericTag.isSelfClosing) {
1023
+ return { endMarker: null, endsAtBlankLine: true, tagName: null, depth: 0 };
1024
+ }
1025
+ return { endMarker: `</${genericTag.name}>`, endsAtBlankLine: true, tagName: genericTag.name, depth: 1 };
1026
+ }
1027
+ function parseProfileLines(content) {
1028
+ const segments = content.split(/(\r\n|\n|\r)/);
1029
+ const lines = [];
1030
+ for (let index = 0; index < segments.length; index += 2) {
1031
+ lines.push({
1032
+ content: segments[index] ?? "",
1033
+ ending: segments[index + 1] ?? ""
1034
+ });
1035
+ }
1036
+ return lines;
1037
+ }
1038
+ function renderProfileLines(lines) {
1039
+ let rendered = "";
1040
+ for (const line of lines) {
1041
+ rendered += line.content + line.ending;
1042
+ }
1043
+ return rendered;
1044
+ }
1045
+ function findFrontmatterEnd(lines) {
1046
+ const firstLine = lines[0]?.content.startsWith(UTF8_BOM) ? lines[0].content.slice(1) : lines[0]?.content;
1047
+ if (firstLine !== "---") return -1;
1048
+ for (let index = 1; index < lines.length; index += 1) {
1049
+ const line = lines[index]?.content.trimEnd();
1050
+ if (line === "---" || line === "...") return index;
1051
+ }
1052
+ return -1;
1053
+ }
1054
+ function hasHtmlBlockEndMarker(line, endMarker) {
1055
+ return line.includes(endMarker);
1056
+ }
1057
+ function shouldCloseHtmlBlock(line, endMarker) {
1058
+ const normalizedLine = line.trimStart().toLowerCase();
1059
+ return normalizedLine.includes(endMarker.toLowerCase());
1060
+ }
1061
+ function canStartGenericHtmlBlock(lines, index, previousHtmlTerminator) {
1062
+ const previousLine = lines[index - 1]?.content.trim() ?? "";
1063
+ if (previousLine === "") return true;
1064
+ return isCompletedIndentedCodeBlock(lines, index) || isMetadataBoundary(previousLine, previousHtmlTerminator) && !isLastUpdatedHeader(previousLine) && !MARKDOWN_LIST_ITEM.test(previousLine) && !MARKDOWN_BLOCK_QUOTE.test(previousLine);
1065
+ }
1066
+ function isHtmlBlockBoundary(lines, index, htmlTerminatorIndexes) {
1067
+ if (htmlTerminatorIndexes.has(index)) return true;
1068
+ const line = lines[index]?.content ?? "";
1069
+ const parserLine = index === 0 && line.startsWith(UTF8_BOM) ? line.slice(1) : line;
1070
+ if (isIndentedCodeLine(parserLine) || getFenceMarker(parserLine)) return false;
1071
+ const trimmedLine = parserLine.trimStart();
1072
+ return findHtmlBlockStart(
1073
+ trimmedLine.toLowerCase(),
1074
+ trimmedLine,
1075
+ canStartGenericHtmlBlock(lines, index, htmlTerminatorIndexes.has(index - 1))
1076
+ ) !== null;
1077
+ }
1078
+ function visitProfileMetadataLines(lines, visit, onHtmlBlockTerminator, onFenceBlockTerminator) {
1079
+ const frontmatterEnd = findFrontmatterEnd(lines);
1080
+ const htmlTerminatorIndexes = /* @__PURE__ */ new Set();
1081
+ const markHtmlTerminator = (index) => {
1082
+ htmlTerminatorIndexes.add(index);
1083
+ onHtmlBlockTerminator?.(index);
1084
+ };
1085
+ let openFence = null;
1086
+ let openHtmlBlock = null;
1087
+ for (let index = 0; index < lines.length; index += 1) {
1088
+ const line = lines[index]?.content ?? "";
1089
+ const parserLine = index === 0 && line.startsWith(UTF8_BOM) ? line.slice(1) : line;
1090
+ if (index <= frontmatterEnd) continue;
1091
+ const fence = getFenceMarker(parserLine);
1092
+ if (openFence) {
1093
+ const indentation = parserLine.length - parserLine.trimStart().length;
1094
+ const leavesListContainer = openFence.listIndentation !== null && parserLine.trim() !== "" && indentation < openFence.listIndentation;
1095
+ if (!leavesListContainer) {
1096
+ if (fence && isClosingFence(fence, openFence)) openFence = null;
1097
+ continue;
1098
+ }
1099
+ openFence = null;
1100
+ if (index > 0) onFenceBlockTerminator?.(index - 1);
1101
+ }
1102
+ const trimmedLine = parserLine.trimStart();
1103
+ const normalizedLine = trimmedLine.toLowerCase();
1104
+ if (openHtmlBlock) {
1105
+ const indentation = parserLine.length - parserLine.trimStart().length;
1106
+ const leavesListContainer = openHtmlBlock.listIndentation !== null && parserLine.trim() !== "" && indentation < openHtmlBlock.listIndentation;
1107
+ if (!leavesListContainer) {
1108
+ if (openHtmlBlock.endsAtBlankLine && normalizedLine === "") {
1109
+ openHtmlBlock = null;
1110
+ continue;
1111
+ }
1112
+ if (openHtmlBlock.tagName) {
1113
+ const nextHtmlBlock = updateHtmlBlockDepth(openHtmlBlock, normalizedLine, false);
1114
+ if (!nextHtmlBlock) markHtmlTerminator(index);
1115
+ openHtmlBlock = nextHtmlBlock;
1116
+ continue;
1117
+ }
1118
+ if (openHtmlBlock.endMarker && shouldCloseHtmlBlock(normalizedLine, openHtmlBlock.endMarker)) {
1119
+ openHtmlBlock = null;
1120
+ markHtmlTerminator(index);
1121
+ }
1122
+ continue;
1123
+ }
1124
+ openHtmlBlock = null;
1125
+ if (index > 0) markHtmlTerminator(index - 1);
1126
+ }
1127
+ if (isIndentedCodeLine(parserLine)) continue;
1128
+ if (fence) {
1129
+ openFence = {
1130
+ ...fence,
1131
+ listIndentation: isNestedListContent(lines, index, fence.indentation) ? fence.indentation : null
1132
+ };
1133
+ continue;
1134
+ }
1135
+ const htmlBlock = findHtmlBlockStart(
1136
+ normalizedLine,
1137
+ trimmedLine,
1138
+ canStartGenericHtmlBlock(lines, index, htmlTerminatorIndexes.has(index - 1))
1139
+ );
1140
+ if (htmlBlock) {
1141
+ markHtmlTerminator(index);
1142
+ const indentation = parserLine.length - parserLine.trimStart().length;
1143
+ const htmlBlockWithContainer = {
1144
+ ...htmlBlock,
1145
+ listIndentation: isNestedListContent(lines, index, indentation) ? indentation : null
1146
+ };
1147
+ if (htmlBlock.tagName) {
1148
+ openHtmlBlock = updateHtmlBlockDepth(htmlBlockWithContainer, normalizedLine, true);
1149
+ if (!openHtmlBlock) markHtmlTerminator(index);
1150
+ } else if (htmlBlock.endMarker && shouldCloseHtmlBlock(normalizedLine, htmlBlock.endMarker)) {
1151
+ openHtmlBlock = null;
1152
+ markHtmlTerminator(index);
1153
+ } else {
1154
+ openHtmlBlock = htmlBlockWithContainer;
1155
+ }
1156
+ continue;
1157
+ }
1158
+ visit(line, index);
1159
+ }
1160
+ }
1161
+ function isCompletedIndentedCodeBlock(lines, index) {
1162
+ if (!isIndentedCodeLine(lines[index - 1]?.content ?? "")) return false;
1163
+ let sawBlank = false;
1164
+ for (let previousIndex = index - 2; previousIndex >= 0; previousIndex -= 1) {
1165
+ const previousLine = lines[previousIndex]?.content ?? "";
1166
+ if (previousLine.trim() === "") {
1167
+ sawBlank = true;
1168
+ continue;
1169
+ }
1170
+ if (isIndentedCodeLine(previousLine)) continue;
1171
+ return sawBlank;
1172
+ }
1173
+ return true;
1174
+ }
1175
+ function isListContinuation(lines, index, indentation) {
1176
+ for (let previousIndex = index - 1; previousIndex >= 0; previousIndex -= 1) {
1177
+ const previousLine = lines[previousIndex]?.content ?? "";
1178
+ if (previousLine.trim() === "") return false;
1179
+ const previousIndentation = previousLine.length - previousLine.trimStart().length;
1180
+ if (previousIndentation > indentation) continue;
1181
+ const previousBoundaryLine = previousLine.trimStart();
1182
+ if (MARKDOWN_LIST_ITEM.test(previousBoundaryLine)) return true;
1183
+ if (MARKDOWN_HEADING.test(previousBoundaryLine) || MARKDOWN_THEMATIC_BREAK.test(previousBoundaryLine) || MARKDOWN_BLOCK_QUOTE.test(previousBoundaryLine) || getFenceMarker(previousLine) !== null) {
1184
+ return false;
1185
+ }
1186
+ }
1187
+ return false;
1188
+ }
1189
+ function isNestedListContent(lines, index, indentation) {
1190
+ for (let previousIndex = index - 1; previousIndex >= 0; previousIndex -= 1) {
1191
+ const previousLine = lines[previousIndex]?.content ?? "";
1192
+ if (previousLine.trim() === "") continue;
1193
+ const previousIndentation = previousLine.length - previousLine.trimStart().length;
1194
+ if (previousIndentation >= indentation) continue;
1195
+ if (MARKDOWN_LIST_ITEM.test(previousLine.trimStart()) || isListContinuation(lines, previousIndex, indentation)) {
1196
+ return true;
1197
+ }
1198
+ break;
1199
+ }
1200
+ return false;
1201
+ }
1202
+ function isValidBareLinkDestination(destination) {
1203
+ let parentheses = 0;
1204
+ for (let index = 0; index < destination.length; index += 1) {
1205
+ const character = destination[index];
1206
+ if (character === "\\") {
1207
+ if (index + 1 >= destination.length) return false;
1208
+ index += 1;
1209
+ continue;
1210
+ }
1211
+ if (character === "<" || character === ">") return false;
1212
+ if (character === "(") {
1213
+ parentheses += 1;
1214
+ } else if (character === ")") {
1215
+ if (parentheses === 0) return false;
1216
+ parentheses -= 1;
1217
+ }
1218
+ }
1219
+ return parentheses === 0;
1220
+ }
1221
+ function isMarkdownLinkReferenceDefinition(line) {
1222
+ const match = MARKDOWN_LINK_REFERENCE.exec(line);
1223
+ return match !== null && (match[1] === void 0 || isValidBareLinkDestination(match[1]));
1224
+ }
1225
+ function isMarkdownLinkReferenceDefinitionEnd(lines, index) {
1226
+ const line = lines[index]?.content ?? "";
1227
+ const boundaryLine = /^ {0,3}(?=\S)/.test(line) ? line.trimStart() : line;
1228
+ if (isMarkdownLinkReferenceDefinition(boundaryLine)) return true;
1229
+ if (MARKDOWN_LINK_REFERENCE_CONTINUATION.test(line)) {
1230
+ const previousLine2 = lines[index - 1]?.content ?? "";
1231
+ const previousBoundaryLine2 = /^ {0,3}(?=\S)/.test(previousLine2) ? previousLine2.trimStart() : previousLine2;
1232
+ if (isMarkdownLinkReferenceDefinition(previousBoundaryLine2)) return true;
1233
+ const destinationLine = lines[index - 1]?.content ?? "";
1234
+ if (!MARKDOWN_LINK_REFERENCE_DESTINATION_CONTINUATION.test(destinationLine)) return false;
1235
+ const labelLine = lines[index - 2]?.content ?? "";
1236
+ const labelBoundaryLine = /^ {0,3}(?=\S)/.test(labelLine) ? labelLine.trimStart() : labelLine;
1237
+ return MARKDOWN_LINK_REFERENCE_LABEL.test(labelBoundaryLine);
1238
+ }
1239
+ if (!MARKDOWN_LINK_REFERENCE_DESTINATION_CONTINUATION.test(line)) return false;
1240
+ const previousLine = lines[index - 1]?.content ?? "";
1241
+ const previousBoundaryLine = /^ {0,3}(?=\S)/.test(previousLine) ? previousLine.trimStart() : previousLine;
1242
+ return MARKDOWN_LINK_REFERENCE_LABEL.test(previousBoundaryLine);
1243
+ }
1244
+ function isProfileTitleLine(lines, index, line) {
1245
+ const titleLine = index === 0 && line.startsWith(UTF8_BOM) ? line.slice(1) : line;
1246
+ if (!PROFILE_TITLE.test(titleLine)) return false;
1247
+ const indentation = titleLine.length - titleLine.trimStart().length;
1248
+ if (indentation === 0 || index === 0) return true;
1249
+ const previousLine = lines[index - 1]?.content.trim() ?? "";
1250
+ return previousLine === "" ? !isNestedListContent(lines, index, indentation) : previousLine === "---" || previousLine === "...";
1251
+ }
1252
+ function findProfileTitleIndex(lines) {
1253
+ let titleIndex = -1;
1254
+ visitProfileMetadataLines(lines, (line, index) => {
1255
+ if (titleIndex >= 0) return;
1256
+ if (isProfileTitleLine(lines, index, line)) titleIndex = index;
1257
+ });
1258
+ return titleIndex;
1259
+ }
1260
+ function isSetextHeadingText(line) {
1261
+ const withoutBom = line.startsWith(UTF8_BOM) ? line.slice(1) : line;
1262
+ const boundaryLine = withoutBom.trim();
1263
+ return boundaryLine !== "" && !MARKDOWN_HEADING.test(boundaryLine) && !MARKDOWN_LIST_ITEM.test(boundaryLine) && !MARKDOWN_BLOCK_QUOTE.test(boundaryLine) && !MARKDOWN_THEMATIC_BREAK.test(boundaryLine) && !isMarkdownLinkReferenceDefinition(boundaryLine) && getFenceMarker(withoutBom) === null;
1264
+ }
1265
+ function isMetadataBoundary(line, htmlTerminator = false, allowSetext = true, allowParagraphListInterrupt = false, setextPreviousLine = "") {
1266
+ const listPattern = allowParagraphListInterrupt ? MARKDOWN_LIST_ITEM_CAN_INTERRUPT : MARKDOWN_LIST_ITEM;
1267
+ const boundaryLine = /^ {0,3}(?=\S)/.test(line) ? line.trimStart() : line;
1268
+ const isSetextUnderline = !allowSetext && MARKDOWN_SETEXT_UNDERLINE.test(boundaryLine) && isSetextHeadingText(setextPreviousLine);
1269
+ return line.trim() === "" || MARKDOWN_HEADING.test(boundaryLine) || listPattern.test(boundaryLine) || allowSetext && MARKDOWN_SETEXT_UNDERLINE.test(boundaryLine) || MARKDOWN_THEMATIC_BREAK.test(boundaryLine) && !isSetextUnderline || MARKDOWN_BLOCK_QUOTE.test(boundaryLine) || isMarkdownLinkReferenceDefinition(boundaryLine) || isLastUpdatedHeader(line) || getFenceMarker(line) !== null || htmlTerminator;
1270
+ }
1271
+ function isStandaloneMetadataLine(lines, index, frontmatterEnd, htmlTerminatorIndexes, fenceTerminatorIndexes, standaloneHeaderIndexes) {
1272
+ const currentLine = lines[index]?.content ?? "";
1273
+ const currentWithoutBom = currentLine.startsWith(UTF8_BOM) ? currentLine.slice(1) : currentLine;
1274
+ const indentation = currentWithoutBom.length - currentWithoutBom.trimStart().length;
1275
+ const previousLine = lines[index - 1]?.content.trimEnd() ?? "";
1276
+ const nextLine = lines[index + 1]?.content.trimEnd() ?? "";
1277
+ const previousWithoutBom = previousLine.startsWith(UTF8_BOM) ? previousLine.slice(1) : previousLine;
1278
+ const nextWithoutBom = nextLine.startsWith(UTF8_BOM) ? nextLine.slice(1) : nextLine;
1279
+ const previousLinkReferenceBoundary = isMarkdownLinkReferenceDefinitionEnd(lines, index - 1);
1280
+ const previousMetadataBoundary = isCompletedIndentedCodeBlock(lines, index) || previousLinkReferenceBoundary || fenceTerminatorIndexes.has(index - 1) || isMetadataBoundary(
1281
+ previousWithoutBom,
1282
+ htmlTerminatorIndexes.has(index - 1)
1283
+ ) && (!isLastUpdatedHeader(previousWithoutBom) || standaloneHeaderIndexes.has(index - 1));
1284
+ const nextHtmlBlockBoundary = isHtmlBlockBoundary(
1285
+ lines,
1286
+ index + 1,
1287
+ htmlTerminatorIndexes
1288
+ );
1289
+ const nextMetadataBoundary = nextHtmlBlockBoundary || isMetadataBoundary(
1290
+ nextWithoutBom,
1291
+ htmlTerminatorIndexes.has(index + 1),
1292
+ false,
1293
+ true,
1294
+ currentWithoutBom
1295
+ );
1296
+ const previousContainerMarker = !MARKDOWN_THEMATIC_BREAK.test(previousWithoutBom) && (MARKDOWN_LIST_ITEM.test(previousWithoutBom) || MARKDOWN_BLOCK_QUOTE.test(previousWithoutBom));
1297
+ const nestedListContent = indentation > 0 && isNestedListContent(lines, index, indentation);
1298
+ const startsBlock = (index === 0 || index === frontmatterEnd + 1 || previousMetadataBoundary) && !previousContainerMarker && !nestedListContent;
1299
+ const endsBlock = index === lines.length - 1 || nextMetadataBoundary;
1300
+ const compactHeaderAfterTitle = isProfileTitleLine(lines, index - 1, previousWithoutBom);
1301
+ const compactHeaderAfterHeader = isLastUpdatedHeader(previousWithoutBom) && standaloneHeaderIndexes.has(index - 1);
1302
+ return startsBlock && (endsBlock || compactHeaderAfterTitle || compactHeaderAfterHeader);
1303
+ }
1304
+ function findProfileHeaderIndexes(lines) {
1305
+ const indexes = [];
1306
+ const frontmatterEnd = findFrontmatterEnd(lines);
1307
+ const htmlTerminatorIndexes = /* @__PURE__ */ new Set();
1308
+ const fenceTerminatorIndexes = /* @__PURE__ */ new Set();
1309
+ const standaloneHeaderIndexes = /* @__PURE__ */ new Set();
1310
+ visitProfileMetadataLines(
1311
+ lines,
1312
+ (line, index) => {
1313
+ if (isLastUpdatedHeader(line) && isStandaloneMetadataLine(
1314
+ lines,
1315
+ index,
1316
+ frontmatterEnd,
1317
+ htmlTerminatorIndexes,
1318
+ fenceTerminatorIndexes,
1319
+ standaloneHeaderIndexes
1320
+ )) {
1321
+ indexes.push(index);
1322
+ standaloneHeaderIndexes.add(index);
1323
+ }
1324
+ },
1325
+ (index) => htmlTerminatorIndexes.add(index),
1326
+ (index) => fenceTerminatorIndexes.add(index)
1327
+ );
1328
+ return indexes;
1329
+ }
1330
+ function insertHeaderAfter(lines, index, header) {
1331
+ const insertAt = index + 1;
1332
+ const ending = lines[index]?.ending || lines[insertAt]?.ending || "\n";
1333
+ if (lines[insertAt]?.content.trim() === "") {
1334
+ lines.splice(
1335
+ insertAt + 1,
1336
+ 0,
1337
+ { content: header, ending },
1338
+ { content: "", ending }
1339
+ );
1340
+ } else {
1341
+ lines.splice(
1342
+ insertAt,
1343
+ 0,
1344
+ { content: "", ending },
1345
+ { content: header, ending },
1346
+ { content: "", ending }
1347
+ );
1348
+ }
1349
+ }
1350
+ function prependHeader(lines, header) {
1351
+ const frontmatterEnd = findFrontmatterEnd(lines);
1352
+ if (frontmatterEnd >= 0) {
1353
+ insertHeaderAfter(lines, frontmatterEnd, header);
1354
+ return renderProfileLines(lines);
1355
+ }
1356
+ const ending = lines[0]?.ending || "\n";
1357
+ if (lines[0]?.content.startsWith(UTF8_BOM)) {
1358
+ lines[0].content = lines[0].content.slice(1);
1359
+ lines.unshift(
1360
+ { content: `${UTF8_BOM}${header}`, ending },
1361
+ { content: "", ending }
1362
+ );
1363
+ return renderProfileLines(lines);
1364
+ }
1365
+ lines.unshift(
1366
+ { content: header, ending },
1367
+ { content: "", ending }
1368
+ );
1369
+ return renderProfileLines(lines);
1370
+ }
1371
+ function renderProfileWithLastUpdated(content, updatedAt) {
1372
+ const lines = parseProfileLines(content);
1373
+ const header = `*Last updated: ${updatedAt}*`;
1374
+ const titleIndex = findProfileTitleIndex(lines);
1375
+ const headerIndexes = findProfileHeaderIndexes(lines);
1376
+ if (headerIndexes.length > 0) {
1377
+ const firstHeaderIndex = headerIndexes[0];
1378
+ if (firstHeaderIndex === void 0) return renderProfileLines(lines);
1379
+ const canonicalIndex = titleIndex >= 0 ? headerIndexes.find((index) => index > titleIndex) ?? firstHeaderIndex : firstHeaderIndex;
1380
+ const preserveBomAtFileStart = headerIndexes.some(
1381
+ (index) => lines[index].content.startsWith(UTF8_BOM)
1382
+ );
1383
+ const bomPrefix = canonicalIndex === 0 && lines[canonicalIndex].content.startsWith(UTF8_BOM) ? UTF8_BOM : "";
1384
+ lines[canonicalIndex].content = `${bomPrefix}${header}`;
1385
+ for (let index = headerIndexes.length - 1; index >= 0; index -= 1) {
1386
+ const headerIndex = headerIndexes[index];
1387
+ if (headerIndex === void 0 || headerIndex === canonicalIndex) continue;
1388
+ lines.splice(headerIndex, 1);
1389
+ }
1390
+ if (preserveBomAtFileStart && !lines[0].content.startsWith(UTF8_BOM)) {
1391
+ lines[0].content = `${UTF8_BOM}${lines[0].content}`;
1392
+ }
1393
+ return renderProfileLines(lines);
1394
+ }
1395
+ if (titleIndex < 0) return prependHeader(lines, header);
1396
+ insertHeaderAfter(lines, titleIndex, header);
1397
+ return renderProfileLines(lines);
1398
+ }
1399
+
708
1400
  // src/orchestration/self-deps.ts
709
1401
  function selfDeps(self) {
710
1402
  const source = self;
@@ -725,8 +1417,748 @@ function selfDeps(self) {
725
1417
  }
726
1418
 
727
1419
  // src/storage/entity-store.ts
728
- import { readdir as readdir2, unlink } from "fs/promises";
1420
+ import { readdir as readdir3, unlink as unlink2 } from "fs/promises";
1421
+ import path4 from "path";
1422
+
1423
+ // src/storage/entity-canonical-id-migration.ts
1424
+ import { randomUUID } from "crypto";
1425
+ import {
1426
+ access,
1427
+ lstat as lstat2,
1428
+ readFile,
1429
+ readdir as readdir2,
1430
+ realpath as realpath2,
1431
+ rename,
1432
+ stat as statFile,
1433
+ unlink,
1434
+ writeFile
1435
+ } from "fs/promises";
729
1436
  import path3 from "path";
1437
+ import { readFileSync } from "fs";
1438
+ import { z } from "zod";
1439
+ var ENTITY_CANONICAL_ID_MIGRATION_VERSION = 1;
1440
+ var ENTITY_CANONICAL_ID_MIGRATION_FILE = "entity-canonical-id-migration-v1.json";
1441
+ var ENTITY_CANONICAL_ID_MIGRATION_LOCK_STALE_MS = 6e4;
1442
+ var ENTITY_CANONICAL_ID_MIGRATION_LOCK_MAX_WAIT_MS = 3e5;
1443
+ var TOMBSTONE_LOCK_STALE_MS = 3e4;
1444
+ var TOMBSTONE_LOCK_MAX_WAIT_MS = 5e3;
1445
+ var ENTITY_CANONICAL_ID_MUTATION_LOCK_STALE_MS = 6e4;
1446
+ var ENTITY_CANONICAL_ID_MUTATION_LOCK_MAX_WAIT_MS = 3e5;
1447
+ var MEMORY_REWRITE_MAX_PASSES = 3;
1448
+ var ENTITY_MAPPING_RESCAN_MAX_PASSES = 3;
1449
+ function loadHistoricalEntityCanonicalIds(stateDir) {
1450
+ const statePath2 = path3.join(stateDir, ENTITY_CANONICAL_ID_MIGRATION_FILE);
1451
+ try {
1452
+ const parsed = JSON.parse(readFileSync(statePath2, "utf-8"));
1453
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return {};
1454
+ const mappings = parsed.mappings;
1455
+ if (!mappings || typeof mappings !== "object" || Array.isArray(mappings)) return {};
1456
+ const cleaned = {};
1457
+ for (const [legacyId, canonicalId] of Object.entries(mappings)) {
1458
+ if (legacyId.length > 0 && typeof canonicalId === "string" && canonicalId.length > 0) {
1459
+ cleaned[legacyId] = canonicalId;
1460
+ }
1461
+ }
1462
+ return cleaned;
1463
+ } catch {
1464
+ return {};
1465
+ }
1466
+ }
1467
+ function resolveHistoricalEntityCanonicalId(normalized, mappings) {
1468
+ let current = normalized;
1469
+ const seen = /* @__PURE__ */ new Set();
1470
+ while (!seen.has(current)) {
1471
+ seen.add(current);
1472
+ const next = mappings[current];
1473
+ if (!next || next === current) break;
1474
+ current = next;
1475
+ }
1476
+ return current;
1477
+ }
1478
+ var EntityCanonicalIdMigrationStateSchema = z.object({
1479
+ version: z.literal(ENTITY_CANONICAL_ID_MIGRATION_VERSION),
1480
+ complete: z.boolean(),
1481
+ mappings: z.record(z.string().min(1))
1482
+ });
1483
+ async function fingerprintPath(filePath) {
1484
+ let fileStat;
1485
+ try {
1486
+ fileStat = await lstat2(filePath);
1487
+ } catch (error) {
1488
+ if (!isErrnoCode(error, "ENOENT")) throw error;
1489
+ }
1490
+ return fileStat ? `${fileStat.dev}:${fileStat.ino}:${fileStat.mtimeMs}:${fileStat.ctimeMs}:${fileStat.size}` : "missing";
1491
+ }
1492
+ async function getFingerprint(baseDir, entitiesDir, getCorpusScanVersion) {
1493
+ const [entityFingerprint, aliasFingerprint] = await Promise.all([
1494
+ fingerprintPath(entitiesDir),
1495
+ fingerprintPath(path3.join(baseDir, "config", "aliases.json"))
1496
+ ]);
1497
+ return `${entityFingerprint}:${aliasFingerprint}:${getCorpusScanVersion()}`;
1498
+ }
1499
+ async function validateRoots(baseDir, entitiesDir, stateDir, archiveDir) {
1500
+ let baseStat;
1501
+ try {
1502
+ baseStat = await lstat2(baseDir);
1503
+ } catch (error) {
1504
+ if (isErrnoCode(error, "ENOENT")) return;
1505
+ throw error;
1506
+ }
1507
+ if (baseStat.isSymbolicLink() || !baseStat.isDirectory()) {
1508
+ throw new Error(`Refusing entity canonical-id migration through unsafe memory root: ${baseDir}.`);
1509
+ }
1510
+ const memoryRoot = await realpath2(baseDir);
1511
+ const roots = [
1512
+ entitiesDir,
1513
+ stateDir,
1514
+ ...RECALL_FALLBACK_DIRS.map((directory) => path3.join(baseDir, directory)),
1515
+ path3.join(baseDir, "cold"),
1516
+ archiveDir
1517
+ ];
1518
+ for (const root of roots) {
1519
+ let rootStat;
1520
+ try {
1521
+ rootStat = await lstat2(root);
1522
+ } catch (error) {
1523
+ if (isErrnoCode(error, "ENOENT")) continue;
1524
+ throw error;
1525
+ }
1526
+ if (rootStat.isSymbolicLink() || !rootStat.isDirectory()) {
1527
+ throw new Error(`Refusing entity canonical-id migration through unsafe memory root: ${root}.`);
1528
+ }
1529
+ assertPathInsideRoot(memoryRoot, await realpath2(root), root);
1530
+ }
1531
+ }
1532
+ function statePath(deps) {
1533
+ return path3.join(deps.stateDir, ENTITY_CANONICAL_ID_MIGRATION_FILE);
1534
+ }
1535
+ async function assertSafeMigrationStateFile(deps) {
1536
+ const migrationStatePath = statePath(deps);
1537
+ let fileStat;
1538
+ try {
1539
+ fileStat = await lstat2(migrationStatePath);
1540
+ } catch (error) {
1541
+ if (isErrnoCode(error, "ENOENT")) return;
1542
+ throw error;
1543
+ }
1544
+ if (fileStat.isSymbolicLink() || !fileStat.isFile()) {
1545
+ throw new Error(
1546
+ `Refusing entity canonical-id migration through unsafe migration state file: ${migrationStatePath}.`
1547
+ );
1548
+ }
1549
+ const [stateRoot, stateFile] = await Promise.all([
1550
+ realpath2(deps.stateDir),
1551
+ realpath2(migrationStatePath)
1552
+ ]);
1553
+ assertPathInsideRoot(stateRoot, stateFile, migrationStatePath);
1554
+ }
1555
+ async function assertSafeTombstoneFile(deps, tombstonePath) {
1556
+ let fileStat;
1557
+ try {
1558
+ fileStat = await lstat2(tombstonePath);
1559
+ } catch (error) {
1560
+ if (isErrnoCode(error, "ENOENT")) return false;
1561
+ throw error;
1562
+ }
1563
+ if (fileStat.isSymbolicLink() || !fileStat.isFile()) {
1564
+ throw new Error(
1565
+ `Refusing entity canonical-id migration through unsafe tombstone ledger: ${tombstonePath}.`
1566
+ );
1567
+ }
1568
+ const [stateRoot, tombstoneFile] = await Promise.all([
1569
+ realpath2(deps.stateDir),
1570
+ realpath2(tombstonePath)
1571
+ ]);
1572
+ assertPathInsideRoot(stateRoot, tombstoneFile, tombstonePath);
1573
+ return true;
1574
+ }
1575
+ function lockPath(deps) {
1576
+ return path3.join(deps.stateDir, "entity-canonical-id-migration.lock");
1577
+ }
1578
+ async function withEntityCanonicalMutationLock(stateDir, task) {
1579
+ return withHeldFileLock(
1580
+ path3.join(stateDir, "entity-canonical-id-mutation.lock"),
1581
+ {
1582
+ staleMs: ENTITY_CANONICAL_ID_MUTATION_LOCK_STALE_MS,
1583
+ maxWaitMs: ENTITY_CANONICAL_ID_MUTATION_LOCK_MAX_WAIT_MS
1584
+ },
1585
+ async (acquired, lock) => {
1586
+ if (!acquired) throw new Error("Timed out waiting for entity mutation lock.");
1587
+ return task(() => lock.refresh());
1588
+ }
1589
+ );
1590
+ }
1591
+ async function readState(deps) {
1592
+ await assertSafeMigrationStateFile(deps);
1593
+ let raw;
1594
+ try {
1595
+ raw = await readFile(statePath(deps), "utf-8");
1596
+ } catch (error) {
1597
+ if (isErrnoCode(error, "ENOENT")) return null;
1598
+ throw error;
1599
+ }
1600
+ let parsed;
1601
+ try {
1602
+ parsed = JSON.parse(raw);
1603
+ } catch {
1604
+ throw new Error("Invalid entity canonical-id migration state.");
1605
+ }
1606
+ const result = EntityCanonicalIdMigrationStateSchema.safeParse(parsed);
1607
+ if (!result.success) throw new Error("Invalid entity canonical-id migration state.");
1608
+ return result.data;
1609
+ }
1610
+ async function writeState(deps, state) {
1611
+ const destination = statePath(deps);
1612
+ const temporary = `${destination}.${process.pid}.${randomUUID()}.tmp`;
1613
+ try {
1614
+ await writeFile(temporary, `${JSON.stringify(state, null, 2)}
1615
+ `, "utf-8");
1616
+ await rename(temporary, destination);
1617
+ } finally {
1618
+ await unlink(temporary).catch(() => void 0);
1619
+ }
1620
+ }
1621
+ async function fileExists(filePath) {
1622
+ try {
1623
+ await access(filePath);
1624
+ return true;
1625
+ } catch (error) {
1626
+ if (isErrnoCode(error, "ENOENT")) return false;
1627
+ throw error;
1628
+ }
1629
+ }
1630
+ async function sameFileIdentity(leftPath, rightPath) {
1631
+ try {
1632
+ const [left, right] = await Promise.all([statFile(leftPath), statFile(rightPath)]);
1633
+ return left.dev === right.dev && left.ino === right.ino;
1634
+ } catch (error) {
1635
+ if (isErrnoCode(error, "ENOENT")) return false;
1636
+ throw error;
1637
+ }
1638
+ }
1639
+ function assertSafeEntityId(entityId) {
1640
+ if (/[\/\\\0]/.test(entityId)) {
1641
+ throw new Error(`Refusing entity canonical-id migration through unsafe entity id: ${entityId}.`);
1642
+ }
1643
+ }
1644
+ async function assertNotSymlink(filePath, label) {
1645
+ let stat4;
1646
+ try {
1647
+ stat4 = await lstat2(filePath);
1648
+ } catch (error) {
1649
+ if (isErrnoCode(error, "ENOENT")) return;
1650
+ throw error;
1651
+ }
1652
+ if (stat4.isSymbolicLink()) {
1653
+ throw new Error(`Refusing entity canonical-id migration through symlink: ${label}.`);
1654
+ }
1655
+ }
1656
+ async function assertNotMemorySymlink(filePath) {
1657
+ let stat4;
1658
+ try {
1659
+ stat4 = await lstat2(filePath);
1660
+ } catch (error) {
1661
+ if (isErrnoCode(error, "ENOENT")) return;
1662
+ throw error;
1663
+ }
1664
+ if (stat4.isSymbolicLink()) {
1665
+ throw new Error(`Refusing entity canonical-id migration through symlinked memory: ${filePath}.`);
1666
+ }
1667
+ }
1668
+ async function assertEntityContentUnchanged(deps, filePath, expectedContent, legacyId) {
1669
+ const latestContent = await deps.readStorageSecureFile(filePath);
1670
+ if (latestContent !== expectedContent) {
1671
+ throw new Error(`Legacy entity id ${legacyId} changed while migration was running; retry migration.`);
1672
+ }
1673
+ }
1674
+ async function readSafeEntityEntries(entitiesDir) {
1675
+ const rootStat = await lstat2(entitiesDir);
1676
+ if (rootStat.isSymbolicLink() || !rootStat.isDirectory()) {
1677
+ throw new Error("Refusing entity canonical-id migration through a symlinked or non-directory entities root.");
1678
+ }
1679
+ const entries = await readdir2(entitiesDir);
1680
+ for (const entry of entries) {
1681
+ await assertNotSymlink(path3.join(entitiesDir, entry), entry);
1682
+ }
1683
+ return entries;
1684
+ }
1685
+ async function discoverMappings(deps, knownMappings = {}) {
1686
+ const mappings = {};
1687
+ const canonicalOwners = /* @__PURE__ */ new Map();
1688
+ const entityEntries = await readSafeEntityEntries(deps.entitiesDir);
1689
+ for (const entry of entityEntries) {
1690
+ if (!entry.endsWith(".md")) continue;
1691
+ const legacyId = entry.slice(0, -".md".length);
1692
+ assertSafeEntityId(legacyId);
1693
+ const legacyPath = deps.resolveEntityFilePath(legacyId);
1694
+ if (legacyPath === null) continue;
1695
+ const entityContent = await deps.readStorageSecureFile(legacyPath);
1696
+ if (!/^#[ \t]+[^\r\n \t]/m.test(entityContent) || !/^\*\*Type:\*\*[ \t]*[^\r\n \t]/m.test(entityContent)) {
1697
+ throw new Error(`Cannot migrate malformed entity file ${entry}: missing name heading or type.`);
1698
+ }
1699
+ const entity = deps.parseEntityFile(entityContent);
1700
+ if (!entity.name.trim() || !entity.type.trim()) {
1701
+ throw new Error(`Cannot migrate malformed entity file ${entry}: missing name or type.`);
1702
+ }
1703
+ const canonicalId = deps.normalizeEntityName(entity.name, entity.type);
1704
+ assertSafeEntityId(canonicalId);
1705
+ if (legacyId === canonicalId) continue;
1706
+ const canonicalPath = deps.resolveEntityFilePath(canonicalId);
1707
+ if (canonicalPath === null) continue;
1708
+ const canonicalExists = await fileExists(canonicalPath);
1709
+ if (canonicalExists && await sameFileIdentity(legacyPath, canonicalPath) && knownMappings[legacyId] === canonicalId) continue;
1710
+ if (canonicalExists) {
1711
+ const canonicalContent2 = await deps.readStorageSecureFile(canonicalPath);
1712
+ if (entityContent !== canonicalContent2) {
1713
+ throw new Error(`Cannot migrate legacy entity id ${legacyId}: ${canonicalId} already exists.`);
1714
+ }
1715
+ }
1716
+ const previousOwner = canonicalOwners.get(canonicalId);
1717
+ if (previousOwner !== void 0 && previousOwner !== legacyId) {
1718
+ throw new Error(
1719
+ `Cannot migrate legacy entity ids ${previousOwner} and ${legacyId}: both normalize to ${canonicalId}.`
1720
+ );
1721
+ }
1722
+ canonicalOwners.set(canonicalId, legacyId);
1723
+ mappings[legacyId] = canonicalId;
1724
+ }
1725
+ return mappings;
1726
+ }
1727
+ async function rewriteReferences(deps, mappings, refreshLock) {
1728
+ let rewroteColdMemory = false;
1729
+ for (let pass = 0; pass < MEMORY_REWRITE_MAX_PASSES; pass += 1) {
1730
+ deps.invalidateAllMemoriesCache();
1731
+ deps.invalidateColdMemoriesCache();
1732
+ const [hotMemories, coldMemories, archivedMemories] = await Promise.all([
1733
+ deps.readAllMemories(),
1734
+ deps.readAllColdMemories(),
1735
+ deps.readArchivedMemories()
1736
+ ]);
1737
+ const seenPaths = /* @__PURE__ */ new Set();
1738
+ let rewroteAny = false;
1739
+ for (const memory of [...hotMemories, ...coldMemories, ...archivedMemories]) {
1740
+ const memoryPath = path3.resolve(memory.path);
1741
+ if (seenPaths.has(memoryPath)) continue;
1742
+ seenPaths.add(memoryPath);
1743
+ const previousEntityRef = memory.frontmatter.entityRef;
1744
+ const canonicalId = previousEntityRef ? mappings[previousEntityRef] : void 0;
1745
+ if (!previousEntityRef || !canonicalId) continue;
1746
+ await assertNotMemorySymlink(memory.path);
1747
+ const observedMemoryFingerprint = await fingerprintPath(memory.path);
1748
+ if (observedMemoryFingerprint === "missing") continue;
1749
+ if (!await refreshLock()) throw new Error("Lost entity canonical-id migration lock.");
1750
+ const latestMemory = await deps.readMemoryByPath(memory.path);
1751
+ if (!latestMemory) continue;
1752
+ const latestMemoryFingerprint = await fingerprintPath(latestMemory.path);
1753
+ if (latestMemoryFingerprint !== observedMemoryFingerprint) continue;
1754
+ const latestPreviousEntityRef = latestMemory.frontmatter.entityRef;
1755
+ const latestCanonicalId = latestPreviousEntityRef ? mappings[latestPreviousEntityRef] : void 0;
1756
+ if (!latestPreviousEntityRef || !latestCanonicalId) continue;
1757
+ const memoryEncrypted = await deps.isEncryptedStorageFile(latestMemory.path);
1758
+ if (await fingerprintPath(latestMemory.path) !== latestMemoryFingerprint) continue;
1759
+ await deps.snapshotBeforeWrite(latestMemory.path, "write");
1760
+ if (await fingerprintPath(latestMemory.path) !== latestMemoryFingerprint) continue;
1761
+ await deps.writeStorageSecureFile(
1762
+ latestMemory.path,
1763
+ deps.serializeMemoryWithEntityRef(latestMemory, latestCanonicalId),
1764
+ memoryEncrypted
1765
+ );
1766
+ await deps.rewriteProjectedMemoryEntityReference(
1767
+ latestMemory.frontmatter.id,
1768
+ latestPreviousEntityRef,
1769
+ latestCanonicalId
1770
+ );
1771
+ rewroteAny = true;
1772
+ rewroteColdMemory ||= latestMemory.path.includes(`${path3.sep}cold${path3.sep}`);
1773
+ }
1774
+ if (!rewroteAny) return { rewroteColdMemory };
1775
+ }
1776
+ throw new Error("Memory references changed while entity canonical-id migration was running; retry migration.");
1777
+ }
1778
+ function rewriteTombstoneLine(line, mappings, normalizedMappings) {
1779
+ let parsed;
1780
+ try {
1781
+ parsed = JSON.parse(line);
1782
+ } catch {
1783
+ return line;
1784
+ }
1785
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return line;
1786
+ const tombstone = parsed;
1787
+ let changed = false;
1788
+ if (typeof tombstone.entityRef === "string") {
1789
+ const canonicalId = mappings[tombstone.entityRef];
1790
+ if (canonicalId) {
1791
+ tombstone.entityRef = canonicalId;
1792
+ changed = true;
1793
+ }
1794
+ }
1795
+ if (typeof tombstone.supersessionKey === "string") {
1796
+ const separator = tombstone.supersessionKey.indexOf("::");
1797
+ if (separator < 0) return changed ? JSON.stringify(tombstone) : line;
1798
+ const normalizedLegacyId = normalizeSupersessionKey(tombstone.supersessionKey.slice(0, separator));
1799
+ const canonicalId = normalizedMappings.get(normalizedLegacyId);
1800
+ if (canonicalId) {
1801
+ const canonicalKey = computeSupersessionKey(canonicalId, tombstone.supersessionKey.slice(separator + 2));
1802
+ if (canonicalKey) {
1803
+ tombstone.supersessionKey = canonicalKey;
1804
+ changed = true;
1805
+ }
1806
+ }
1807
+ }
1808
+ return changed ? JSON.stringify(tombstone) : line;
1809
+ }
1810
+ async function rewriteTombstoneReferences(deps, mappings, refreshLock) {
1811
+ const tombstonePath = path3.join(deps.stateDir, "tombstones.jsonl");
1812
+ const normalizedMappings = /* @__PURE__ */ new Map();
1813
+ for (const [legacyId, canonicalId] of Object.entries(mappings)) {
1814
+ const normalizedLegacyId = normalizeSupersessionKey(legacyId);
1815
+ if (normalizedLegacyId && !normalizedMappings.has(normalizedLegacyId)) {
1816
+ normalizedMappings.set(normalizedLegacyId, canonicalId);
1817
+ }
1818
+ }
1819
+ await withHeldFileLock(
1820
+ path3.join(deps.stateDir, "tombstones.lock"),
1821
+ {
1822
+ staleMs: TOMBSTONE_LOCK_STALE_MS,
1823
+ maxWaitMs: TOMBSTONE_LOCK_MAX_WAIT_MS
1824
+ },
1825
+ async (acquired, tombstoneLock) => {
1826
+ if (!acquired) throw new Error("Timed out waiting for active tombstone migration.");
1827
+ if (!await assertSafeTombstoneFile(deps, tombstonePath)) return;
1828
+ const tombstoneEncrypted = await deps.isEncryptedStorageFile(tombstonePath);
1829
+ const original = await deps.readStorageSecureFile(tombstonePath);
1830
+ let changed = false;
1831
+ const rewritten = original.split("\n").map((line) => {
1832
+ const next = rewriteTombstoneLine(line, mappings, normalizedMappings);
1833
+ changed ||= next !== line;
1834
+ return next;
1835
+ }).join("\n");
1836
+ if (!changed) return;
1837
+ if (!await refreshLock()) throw new Error("Lost entity canonical-id migration lock.");
1838
+ if (!await tombstoneLock.refresh()) throw new Error("Lost tombstone migration lock.");
1839
+ await deps.snapshotBeforeWrite(tombstonePath, "write");
1840
+ await deps.writeStorageSecureFile(tombstonePath, rewritten, tombstoneEncrypted);
1841
+ }
1842
+ );
1843
+ }
1844
+ async function rewriteRelationshipTargets(deps, mappings, refreshLock) {
1845
+ let rewritten = false;
1846
+ const entries = await readSafeEntityEntries(deps.entitiesDir);
1847
+ for (const entry of entries) {
1848
+ if (!entry.endsWith(".md")) continue;
1849
+ const entityPath = deps.resolveEntityFilePath(entry.slice(0, -".md".length));
1850
+ if (entityPath === null) continue;
1851
+ const observedEntityFingerprint = await fingerprintPath(entityPath);
1852
+ if (observedEntityFingerprint === "missing") continue;
1853
+ const entity = deps.parseEntityFile(await deps.readStorageSecureFile(entityPath));
1854
+ const relationships = entity.relationships.map((relationship) => {
1855
+ const target = mappings[relationship.target];
1856
+ return target ? { ...relationship, target } : relationship;
1857
+ });
1858
+ if (relationships.every((relationship, index) => relationship === entity.relationships[index])) continue;
1859
+ const rewroteEntity = await withEntityCanonicalMutationLock(
1860
+ deps.stateDir,
1861
+ async (refreshEntityLock) => {
1862
+ if (!await refreshLock()) throw new Error("Lost entity canonical-id migration lock.");
1863
+ const latestEntity = deps.parseEntityFile(await deps.readStorageSecureFile(entityPath));
1864
+ if (await fingerprintPath(entityPath) !== observedEntityFingerprint) return false;
1865
+ const latestRelationships = latestEntity.relationships.map((relationship) => {
1866
+ const target = mappings[relationship.target];
1867
+ return target ? { ...relationship, target } : relationship;
1868
+ });
1869
+ if (latestRelationships.every((relationship, index) => relationship === latestEntity.relationships[index])) {
1870
+ return false;
1871
+ }
1872
+ const entityEncrypted = await deps.isEncryptedStorageFile(entityPath);
1873
+ if (!await refreshEntityLock()) throw new Error("Lost entity mutation lock.");
1874
+ if (await fingerprintPath(entityPath) !== observedEntityFingerprint) return false;
1875
+ await deps.snapshotBeforeWrite(entityPath, "write");
1876
+ if (await fingerprintPath(entityPath) !== observedEntityFingerprint) return false;
1877
+ await deps.writeStorageSecureFile(
1878
+ entityPath,
1879
+ deps.serializeEntityFile({ ...latestEntity, relationships: latestRelationships }),
1880
+ entityEncrypted
1881
+ );
1882
+ return true;
1883
+ }
1884
+ );
1885
+ rewritten ||= rewroteEntity;
1886
+ }
1887
+ return rewritten;
1888
+ }
1889
+ async function rewriteKnownReferences(deps, mappings, refreshLock) {
1890
+ await rewriteRelationshipTargets(deps, mappings, refreshLock);
1891
+ let rewroteColdMemory = (await rewriteReferences(deps, mappings, refreshLock)).rewroteColdMemory;
1892
+ await rewriteTombstoneReferences(deps, mappings, refreshLock);
1893
+ await deps.rewriteProjectedEntityReferences(mappings);
1894
+ const finalMemoryPass = await rewriteReferences(deps, mappings, refreshLock);
1895
+ rewroteColdMemory ||= finalMemoryPass.rewroteColdMemory;
1896
+ return rewroteColdMemory;
1897
+ }
1898
+ function wouldCreateMappingCycle(mappings, legacyId, canonicalId) {
1899
+ let current = canonicalId;
1900
+ const seen = /* @__PURE__ */ new Set();
1901
+ while (true) {
1902
+ if (current === legacyId) return true;
1903
+ if (seen.has(current)) return false;
1904
+ seen.add(current);
1905
+ const next = mappings[current];
1906
+ if (!next || next === current) return false;
1907
+ current = next;
1908
+ }
1909
+ }
1910
+ function rejectMappingCycles(existing, discovered) {
1911
+ const accepted = {};
1912
+ const merged = { ...existing };
1913
+ for (const [legacyId, canonicalId] of Object.entries(discovered)) {
1914
+ if (merged[legacyId] === void 0 && wouldCreateMappingCycle(merged, legacyId, canonicalId)) continue;
1915
+ accepted[legacyId] = canonicalId;
1916
+ merged[legacyId] = canonicalId;
1917
+ }
1918
+ return accepted;
1919
+ }
1920
+ function mergeDiscoveredMappings(existing, discovered) {
1921
+ const merged = { ...existing };
1922
+ const canonicalOwners = /* @__PURE__ */ new Map();
1923
+ for (const [legacyId, canonicalId] of Object.entries(discovered)) {
1924
+ const previousMapping = merged[legacyId];
1925
+ if (previousMapping !== void 0 && previousMapping !== canonicalId) {
1926
+ throw new Error(`Legacy entity id ${legacyId} changed canonical target during migration.`);
1927
+ }
1928
+ if (previousMapping === void 0 && wouldCreateMappingCycle(merged, legacyId, canonicalId)) continue;
1929
+ const previousOwner = canonicalOwners.get(canonicalId);
1930
+ if (previousOwner !== void 0 && previousOwner !== legacyId) {
1931
+ throw new Error(
1932
+ `Cannot migrate legacy entity ids ${previousOwner} and ${legacyId}: both normalize to ${canonicalId}.`
1933
+ );
1934
+ }
1935
+ merged[legacyId] = canonicalId;
1936
+ canonicalOwners.set(canonicalId, legacyId);
1937
+ }
1938
+ return merged;
1939
+ }
1940
+ function collapseMappings(mappings) {
1941
+ const collapsed = {};
1942
+ for (const legacyId of Object.keys(mappings)) {
1943
+ let current = legacyId;
1944
+ const seen = /* @__PURE__ */ new Set();
1945
+ while (true) {
1946
+ const next = mappings[current];
1947
+ if (!next || next === current) break;
1948
+ if (seen.has(current)) {
1949
+ throw new Error(`Entity canonical-id migration mapping cycle includes ${legacyId}.`);
1950
+ }
1951
+ seen.add(current);
1952
+ current = next;
1953
+ }
1954
+ if (current !== legacyId) collapsed[legacyId] = current;
1955
+ }
1956
+ return collapsed;
1957
+ }
1958
+ async function migrateEntityFilePair(deps, legacyId, canonicalId, refreshMigrationLock) {
1959
+ return withEntityCanonicalMutationLock(deps.stateDir, async (refreshEntityLock) => {
1960
+ assertSafeEntityId(legacyId);
1961
+ assertSafeEntityId(canonicalId);
1962
+ const legacyPath = deps.resolveEntityFilePath(legacyId);
1963
+ const canonicalPath = deps.resolveEntityFilePath(canonicalId);
1964
+ if (legacyPath === null || canonicalPath === null) {
1965
+ throw new Error("Invalid entity canonical-id migration path.");
1966
+ }
1967
+ await assertNotSymlink(legacyPath, legacyId);
1968
+ await assertNotSymlink(canonicalPath, canonicalId);
1969
+ const legacyExists = await fileExists(legacyPath);
1970
+ const canonicalExists = await fileExists(canonicalPath);
1971
+ if (!legacyExists && !canonicalExists) return { deferred: true, progressed: false };
1972
+ if (legacyExists && canonicalExists) {
1973
+ if (await sameFileIdentity(legacyPath, canonicalPath)) return { deferred: false, progressed: false };
1974
+ const [legacyContent, canonicalContent2, legacyEncrypted, canonicalEncrypted] = await Promise.all([
1975
+ deps.readStorageSecureFile(legacyPath),
1976
+ deps.readStorageSecureFile(canonicalPath),
1977
+ deps.isEncryptedStorageFile(legacyPath),
1978
+ deps.isEncryptedStorageFile(canonicalPath)
1979
+ ]);
1980
+ if (legacyContent !== canonicalContent2) {
1981
+ throw new Error(`Cannot migrate legacy entity id ${legacyId}: ${canonicalId} already exists.`);
1982
+ }
1983
+ if (legacyEncrypted && !canonicalEncrypted) {
1984
+ if (!await refreshMigrationLock() || !await refreshEntityLock()) {
1985
+ throw new Error("Lost entity canonical-id migration lock.");
1986
+ }
1987
+ await deps.snapshotBeforeWrite(canonicalPath, "write");
1988
+ await deps.writeStorageSecureFile(canonicalPath, legacyContent, true);
1989
+ if (await deps.readStorageSecureFile(canonicalPath) !== legacyContent) {
1990
+ throw new Error(`Cannot verify migrated entity id ${canonicalId}.`);
1991
+ }
1992
+ }
1993
+ if (!await refreshMigrationLock() || !await refreshEntityLock()) {
1994
+ throw new Error("Lost entity canonical-id migration lock.");
1995
+ }
1996
+ await deps.snapshotBeforeWrite(legacyPath, "write");
1997
+ await assertNotSymlink(legacyPath, legacyId);
1998
+ await assertEntityContentUnchanged(deps, legacyPath, legacyContent, legacyId);
1999
+ await unlink(legacyPath);
2000
+ return { deferred: false, progressed: true };
2001
+ }
2002
+ if (!legacyExists) return { deferred: false, progressed: false };
2003
+ if (!await refreshMigrationLock() || !await refreshEntityLock()) {
2004
+ throw new Error("Lost entity canonical-id migration lock.");
2005
+ }
2006
+ const entityEncrypted = await deps.isEncryptedStorageFile(legacyPath);
2007
+ const entityContent = await deps.readStorageSecureFile(legacyPath);
2008
+ await assertNotSymlink(legacyPath, legacyId);
2009
+ await assertEntityContentUnchanged(deps, legacyPath, entityContent, legacyId);
2010
+ let canonicalFingerprintAfterWrite = null;
2011
+ try {
2012
+ await deps.writeStorageSecureFile(canonicalPath, entityContent, entityEncrypted);
2013
+ canonicalFingerprintAfterWrite = await fingerprintPath(canonicalPath);
2014
+ if (await deps.readStorageSecureFile(canonicalPath) !== entityContent) {
2015
+ throw new Error(`Cannot verify migrated entity id ${canonicalId}.`);
2016
+ }
2017
+ if (!await refreshMigrationLock() || !await refreshEntityLock()) {
2018
+ throw new Error("Lost entity canonical-id migration lock.");
2019
+ }
2020
+ await deps.snapshotBeforeWrite(legacyPath, "write");
2021
+ await assertNotSymlink(legacyPath, legacyId);
2022
+ await assertEntityContentUnchanged(deps, legacyPath, entityContent, legacyId);
2023
+ await unlink(legacyPath);
2024
+ } catch (error) {
2025
+ if (!canonicalExists && canonicalFingerprintAfterWrite !== null) {
2026
+ try {
2027
+ if (await fingerprintPath(canonicalPath) === canonicalFingerprintAfterWrite) {
2028
+ await assertNotSymlink(canonicalPath, canonicalId);
2029
+ await unlink(canonicalPath);
2030
+ }
2031
+ } catch {
2032
+ }
2033
+ }
2034
+ throw error;
2035
+ }
2036
+ return { deferred: false, progressed: true };
2037
+ });
2038
+ }
2039
+ async function migrateLegacyEntityCanonicalIds(deps) {
2040
+ return withHeldFileLock(
2041
+ lockPath(deps),
2042
+ {
2043
+ staleMs: ENTITY_CANONICAL_ID_MIGRATION_LOCK_STALE_MS,
2044
+ maxWaitMs: ENTITY_CANONICAL_ID_MIGRATION_LOCK_MAX_WAIT_MS
2045
+ },
2046
+ async (acquired, lock) => {
2047
+ if (!acquired) throw new Error("Timed out waiting for active entity canonical-id migration.");
2048
+ await deps.validateMemoryScanRoots?.();
2049
+ await readSafeEntityEntries(deps.entitiesDir);
2050
+ let state = await readState(deps);
2051
+ if (!state) {
2052
+ state = {
2053
+ version: ENTITY_CANONICAL_ID_MIGRATION_VERSION,
2054
+ complete: false,
2055
+ mappings: {}
2056
+ };
2057
+ }
2058
+ const previousMappings = state.mappings;
2059
+ const collapsedMappings = collapseMappings(previousMappings);
2060
+ const mappingsChanged = Object.keys(collapsedMappings).length !== Object.keys(previousMappings).length || Object.entries(collapsedMappings).some(
2061
+ ([legacyId, canonicalId]) => previousMappings[legacyId] !== canonicalId
2062
+ );
2063
+ state = { ...state, mappings: collapsedMappings };
2064
+ for (let migrationPass = 0; migrationPass < ENTITY_MAPPING_RESCAN_MAX_PASSES; migrationPass += 1) {
2065
+ if (!await lock.refresh()) throw new Error("Lost entity canonical-id migration lock.");
2066
+ const discoveredBefore = rejectMappingCycles(
2067
+ state.mappings,
2068
+ await discoverMappings(deps, state.mappings)
2069
+ );
2070
+ const mergedBefore = collapseMappings(mergeDiscoveredMappings(state.mappings, discoveredBefore));
2071
+ if (state.complete && Object.keys(discoveredBefore).length === 0 && !mappingsChanged) {
2072
+ if (Object.keys(state.mappings).length === 0) return deps.readMigrationFingerprint?.();
2073
+ const rewroteColdMemory2 = await rewriteKnownReferences(
2074
+ deps,
2075
+ state.mappings,
2076
+ () => lock.refresh()
2077
+ );
2078
+ deps.invalidateKnowledgeIndexCache();
2079
+ deps.invalidateAllMemoriesCache();
2080
+ if (rewroteColdMemory2) deps.invalidateColdMemoriesCache();
2081
+ deps.bumpMemoryStatusVersion();
2082
+ return deps.readMigrationFingerprint?.();
2083
+ }
2084
+ if (state.complete || Object.keys(discoveredBefore).length > 0 || Object.keys(mergedBefore).length !== Object.keys(state.mappings).length) {
2085
+ state = { ...state, complete: false, mappings: mergedBefore };
2086
+ await writeState(deps, state);
2087
+ }
2088
+ if (Object.keys(state.mappings).length === 0) {
2089
+ if (!await lock.refresh()) throw new Error("Lost entity canonical-id migration lock.");
2090
+ const discoveredAfter2 = rejectMappingCycles(
2091
+ state.mappings,
2092
+ await discoverMappings(deps, state.mappings)
2093
+ );
2094
+ if (Object.keys(discoveredAfter2).length === 0) {
2095
+ await writeState(deps, { ...state, complete: true });
2096
+ return deps.readMigrationFingerprint?.();
2097
+ }
2098
+ state = {
2099
+ ...state,
2100
+ complete: false,
2101
+ mappings: collapseMappings(mergeDiscoveredMappings(state.mappings, discoveredAfter2))
2102
+ };
2103
+ await writeState(deps, state);
2104
+ continue;
2105
+ }
2106
+ let pendingMappings = Object.entries(state.mappings);
2107
+ while (pendingMappings.length > 0) {
2108
+ const deferredMappings = [];
2109
+ let progressed = false;
2110
+ for (const [legacyId, canonicalId] of pendingMappings) {
2111
+ const result = await migrateEntityFilePair(
2112
+ deps,
2113
+ legacyId,
2114
+ canonicalId,
2115
+ () => lock.refresh()
2116
+ );
2117
+ if (result.deferred) {
2118
+ deferredMappings.push([legacyId, canonicalId]);
2119
+ }
2120
+ progressed ||= result.progressed;
2121
+ }
2122
+ if (deferredMappings.length === 0) break;
2123
+ if (!progressed) {
2124
+ const [legacyId, canonicalId] = deferredMappings[0];
2125
+ throw new Error(
2126
+ `Cannot migrate legacy entity id ${legacyId}: both files are missing and no intermediate mapping can advance migration.`
2127
+ );
2128
+ }
2129
+ pendingMappings = deferredMappings;
2130
+ }
2131
+ const rewroteColdMemory = await rewriteKnownReferences(
2132
+ deps,
2133
+ state.mappings,
2134
+ () => lock.refresh()
2135
+ );
2136
+ deps.invalidateKnowledgeIndexCache();
2137
+ deps.invalidateAllMemoriesCache();
2138
+ if (rewroteColdMemory) deps.invalidateColdMemoriesCache();
2139
+ deps.bumpMemoryStatusVersion();
2140
+ if (!await lock.refresh()) throw new Error("Lost entity canonical-id migration lock.");
2141
+ const discoveredAfter = rejectMappingCycles(
2142
+ state.mappings,
2143
+ await discoverMappings(deps, state.mappings)
2144
+ );
2145
+ if (Object.keys(discoveredAfter).length === 0) {
2146
+ await writeState(deps, { ...state, complete: true });
2147
+ return deps.readMigrationFingerprint?.();
2148
+ }
2149
+ state = {
2150
+ ...state,
2151
+ complete: false,
2152
+ mappings: collapseMappings(mergeDiscoveredMappings(state.mappings, discoveredAfter))
2153
+ };
2154
+ await writeState(deps, state);
2155
+ }
2156
+ throw new Error("Entity canonical-id migration mappings changed while migration was running; retry migration.");
2157
+ }
2158
+ );
2159
+ }
2160
+
2161
+ // src/storage/entity-store.ts
730
2162
  var EntityStore = class {
731
2163
  constructor(deps) {
732
2164
  this.deps = deps;
@@ -738,6 +2170,12 @@ var EntityStore = class {
738
2170
  }
739
2171
  async writeEntity(name, type, facts, options = {}) {
740
2172
  await this.deps.ensureDirectories();
2173
+ return withEntityCanonicalMutationLock(
2174
+ path4.join(this.deps.baseDir, "state"),
2175
+ () => this.writeEntityUnlocked(name, type, facts, options)
2176
+ );
2177
+ }
2178
+ async writeEntityUnlocked(name, type, facts, options = {}) {
741
2179
  if (typeof name !== "string" || !name.trim() || typeof type !== "string" || !type.trim()) {
742
2180
  log.warn("writeEntity: invalid entity payload, skipping", {
743
2181
  nameType: typeof name,
@@ -754,7 +2192,7 @@ var EntityStore = class {
754
2192
  log.debug(`fuzzy match: "${normalized}" \u2192 existing "${match}"`);
755
2193
  normalized = match;
756
2194
  }
757
- const filePath = path3.join(this.deps.entitiesDir, `${normalized}.md`);
2195
+ const filePath = path4.join(this.deps.entitiesDir, `${normalized}.md`);
758
2196
  let entity = {
759
2197
  name,
760
2198
  type,
@@ -855,7 +2293,7 @@ var EntityStore = class {
855
2293
  /** Return sorted list of entity filenames (without .md extension) */
856
2294
  async listEntityNames() {
857
2295
  try {
858
- const entries = await readdir2(this.deps.entitiesDir);
2296
+ const entries = await readdir3(this.deps.entitiesDir);
859
2297
  return entries.filter((e) => e.endsWith(".md")).map((e) => e.replace(".md", "")).sort();
860
2298
  } catch {
861
2299
  return [];
@@ -865,7 +2303,13 @@ var EntityStore = class {
865
2303
  * Set or rewrite the synthesis layer of an entity file.
866
2304
  */
867
2305
  async updateEntitySynthesis(name, synthesis, options = {}) {
868
- const filePath = path3.join(this.deps.entitiesDir, `${name}.md`);
2306
+ return withEntityCanonicalMutationLock(
2307
+ path4.join(this.deps.baseDir, "state"),
2308
+ () => this.updateEntitySynthesisUnlocked(name, synthesis, options)
2309
+ );
2310
+ }
2311
+ async updateEntitySynthesisUnlocked(name, synthesis, options = {}) {
2312
+ const filePath = path4.join(this.deps.entitiesDir, `${name}.md`);
869
2313
  let entity;
870
2314
  try {
871
2315
  const content = await this.deps.readStorageSecureFile(filePath);
@@ -907,7 +2351,7 @@ var EntityStore = class {
907
2351
  const cached = getCachedEntities(this.deps.baseDir, currentVersion, cacheKey);
908
2352
  if (cached) return cached;
909
2353
  try {
910
- const entries = await readdir2(this.deps.entitiesDir);
2354
+ const entries = await readdir3(this.deps.entitiesDir);
911
2355
  const mdFiles = entries.filter((e) => e.endsWith(".md"));
912
2356
  if (mdFiles.length === 0) return [];
913
2357
  const BATCH_SIZE = 100;
@@ -917,7 +2361,7 @@ var EntityStore = class {
917
2361
  const results = await Promise.all(
918
2362
  batch.map(async (entry) => {
919
2363
  try {
920
- return await this.deps.readStorageSecureFile(path3.join(this.deps.entitiesDir, entry));
2364
+ return await this.deps.readStorageSecureFile(path4.join(this.deps.entitiesDir, entry));
921
2365
  } catch (err) {
922
2366
  if (err instanceof SecureStoreLockedError) throw err;
923
2367
  if (!isErrnoCode(err, "ENOENT")) throw err;
@@ -990,9 +2434,15 @@ ${rows.join("\n")}
990
2434
  * Returns count of files merged.
991
2435
  */
992
2436
  async mergeFragmentedEntities() {
2437
+ return withEntityCanonicalMutationLock(
2438
+ path4.join(this.deps.baseDir, "state"),
2439
+ () => this.mergeFragmentedEntitiesUnlocked()
2440
+ );
2441
+ }
2442
+ async mergeFragmentedEntitiesUnlocked() {
993
2443
  let merged = 0;
994
2444
  try {
995
- const entries = await readdir2(this.deps.entitiesDir);
2445
+ const entries = await readdir3(this.deps.entitiesDir);
996
2446
  const mdFiles = entries.filter((e) => e.endsWith(".md"));
997
2447
  const groups = /* @__PURE__ */ new Map();
998
2448
  for (const file of mdFiles) {
@@ -1030,7 +2480,7 @@ ${rows.join("\n")}
1030
2480
  extraSections: []
1031
2481
  };
1032
2482
  for (const file of files) {
1033
- const filePath = path3.join(this.deps.entitiesDir, file);
2483
+ const filePath = path4.join(this.deps.entitiesDir, file);
1034
2484
  try {
1035
2485
  const content = await this.deps.readStorageSecureFile(filePath);
1036
2486
  const parsed = parseEntityFile(content, this.deps.entitySchemas);
@@ -1161,13 +2611,13 @@ ${rows.join("\n")}
1161
2611
  }
1162
2612
  mergedEntity.created = mergedEntity.created || mergedEntity.updated || (/* @__PURE__ */ new Date()).toISOString();
1163
2613
  mergedEntity.updated = mergedEntity.updated || (/* @__PURE__ */ new Date()).toISOString();
1164
- const canonicalPath = path3.join(this.deps.entitiesDir, `${canonical}.md`);
2614
+ const canonicalPath = path4.join(this.deps.entitiesDir, `${canonical}.md`);
1165
2615
  await this.deps.writeStorageSecureFile(canonicalPath, serializeEntityFile(mergedEntity, this.deps.entitySchemas));
1166
2616
  for (const file of files) {
1167
- const filePath = path3.join(this.deps.entitiesDir, file);
2617
+ const filePath = path4.join(this.deps.entitiesDir, file);
1168
2618
  if (filePath !== canonicalPath) {
1169
2619
  try {
1170
- await unlink(filePath);
2620
+ await unlink2(filePath);
1171
2621
  merged++;
1172
2622
  log.debug(`merged entity ${file} \u2192 ${canonical}.md`);
1173
2623
  } catch {
@@ -1183,8 +2633,8 @@ ${rows.join("\n")}
1183
2633
  };
1184
2634
 
1185
2635
  // src/storage/identity-continuity-store.ts
1186
- import { readdir as readdir3 } from "fs/promises";
1187
- import path4 from "path";
2636
+ import { readdir as readdir4 } from "fs/promises";
2637
+ import path5 from "path";
1188
2638
  var IdentityContinuityStore = class {
1189
2639
  constructor(deps) {
1190
2640
  this.deps = deps;
@@ -1209,7 +2659,7 @@ var IdentityContinuityStore = class {
1209
2659
  const date = nowIso.slice(0, 10);
1210
2660
  const id = this.deps.generateId("incident");
1211
2661
  const incident = createContinuityIncidentRecord(id, input, nowIso);
1212
- const filePath = path4.join(this.deps.identityIncidentsDir, `${date}-${id}.md`);
2662
+ const filePath = path5.join(this.deps.identityIncidentsDir, `${date}-${id}.md`);
1213
2663
  await this.deps.writeStorageSecureFile(filePath, serializeContinuityIncident(incident));
1214
2664
  return { ...incident, filePath };
1215
2665
  }
@@ -1222,7 +2672,7 @@ var IdentityContinuityStore = class {
1222
2672
  const incidents = [];
1223
2673
  for (const file of candidates) {
1224
2674
  if (incidents.length >= cappedLimit) break;
1225
- const filePath = path4.join(this.deps.identityIncidentsDir, file);
2675
+ const filePath = path5.join(this.deps.identityIncidentsDir, file);
1226
2676
  try {
1227
2677
  const raw = await this.deps.readStorageSecureFile(filePath);
1228
2678
  const parsed = parseContinuityIncident(raw);
@@ -1253,7 +2703,7 @@ var IdentityContinuityStore = class {
1253
2703
  await this.deps.ensureDirectories();
1254
2704
  const safeKey = this.sanitizeIdentityAuditKey(key);
1255
2705
  const dir = period === "weekly" ? this.deps.identityAuditsWeeklyDir : this.deps.identityAuditsMonthlyDir;
1256
- const filePath = path4.join(dir, `${safeKey}.md`);
2706
+ const filePath = path5.join(dir, `${safeKey}.md`);
1257
2707
  await this.deps.writeStorageSecureFile(filePath, content);
1258
2708
  return filePath;
1259
2709
  }
@@ -1261,7 +2711,7 @@ var IdentityContinuityStore = class {
1261
2711
  try {
1262
2712
  const safeKey = this.sanitizeIdentityAuditKey(key);
1263
2713
  const dir = period === "weekly" ? this.deps.identityAuditsWeeklyDir : this.deps.identityAuditsMonthlyDir;
1264
- return await this.deps.readStorageSecureFile(path4.join(dir, `${safeKey}.md`));
2714
+ return await this.deps.readStorageSecureFile(path5.join(dir, `${safeKey}.md`));
1265
2715
  } catch (err) {
1266
2716
  if (err instanceof Error && err.message === "Invalid identity audit key") return null;
1267
2717
  if (!isErrnoCode(err, "ENOENT")) throw err;
@@ -1300,7 +2750,7 @@ var IdentityContinuityStore = class {
1300
2750
  return loop;
1301
2751
  }
1302
2752
  async readContinuityIncidentFileNames() {
1303
- const files = await readdir3(this.deps.identityIncidentsDir);
2753
+ const files = await readdir4(this.deps.identityIncidentsDir);
1304
2754
  return files.filter((file) => file.endsWith(".md")).sort().reverse();
1305
2755
  }
1306
2756
  async readContinuityIncidentFile(filePath) {
@@ -1317,12 +2767,12 @@ var IdentityContinuityStore = class {
1317
2767
  const fileNames = await this.readContinuityIncidentFileNames();
1318
2768
  const directMatch = fileNames.find((name) => name.endsWith(`-${id}.md`));
1319
2769
  if (directMatch) {
1320
- const directPath = path4.join(this.deps.identityIncidentsDir, directMatch);
2770
+ const directPath = path5.join(this.deps.identityIncidentsDir, directMatch);
1321
2771
  const parsed = await this.readContinuityIncidentFile(directPath);
1322
2772
  if (parsed?.id === id) return directPath;
1323
2773
  }
1324
2774
  for (const fileName of fileNames) {
1325
- const filePath = path4.join(this.deps.identityIncidentsDir, fileName);
2775
+ const filePath = path5.join(this.deps.identityIncidentsDir, fileName);
1326
2776
  const parsed = await this.readContinuityIncidentFile(filePath);
1327
2777
  if (parsed?.id === id) return filePath;
1328
2778
  }
@@ -1337,6 +2787,127 @@ var IdentityContinuityStore = class {
1337
2787
  }
1338
2788
  };
1339
2789
 
2790
+ // src/storage/entity-canonical-id-migration-adapter.ts
2791
+ async function runLegacyEntityCanonicalIdMigration(host, parseEntityFile2, serializeEntityFile2, serializeMemoryWithEntityRef2) {
2792
+ const readMigrationFingerprint = () => getFingerprint(host.baseDir, host.entitiesDir, () => host.getCorpusScanVersion());
2793
+ const completionFingerprint = await migrateLegacyEntityCanonicalIds({
2794
+ stateDir: host.stateDir,
2795
+ entitiesDir: host.entitiesDir,
2796
+ normalizeEntityName: host.normalizeEntityName.bind(host),
2797
+ resolveEntityFilePath: host.resolveEntityFilePath.bind(host),
2798
+ readStorageSecureFile: host.readStorageSecureFile.bind(host),
2799
+ writeStorageSecureFile: host.writeStorageSecureFile.bind(host),
2800
+ isEncryptedStorageFile: host.isEncryptedFileHeader.bind(host),
2801
+ snapshotBeforeWrite: host.snapshotBeforeWrite.bind(host),
2802
+ parseEntityFile: parseEntityFile2,
2803
+ serializeEntityFile: serializeEntityFile2,
2804
+ serializeMemoryWithEntityRef: serializeMemoryWithEntityRef2,
2805
+ readMemoryByPath: host.readMemoryByPath.bind(host),
2806
+ readAllMemories: host.readAllMemories.bind(host),
2807
+ readAllColdMemories: host.readAllColdMemories.bind(host),
2808
+ readArchivedMemories: host.readArchivedMemories.bind(host),
2809
+ validateMemoryScanRoots: () => validateRoots(host.baseDir, host.entitiesDir, host.stateDir, host.archiveDir),
2810
+ rewriteProjectedEntityReferences: (mappings) => rewriteProjectedEntityReferences(host.baseDir, mappings),
2811
+ rewriteProjectedMemoryEntityReference: (memoryId, previousEntityRef, nextEntityRef) => rewriteProjectedMemoryEntityReference(host.baseDir, memoryId, previousEntityRef, nextEntityRef),
2812
+ invalidateKnowledgeIndexCache: host.invalidateKnowledgeIndexCache.bind(host),
2813
+ invalidateAllMemoriesCache: host.invalidateAllMemoriesCache.bind(host),
2814
+ invalidateColdMemoriesCache: host.invalidateColdMemoriesCache.bind(host),
2815
+ bumpMemoryStatusVersion: host.bumpMemoryStatusVersion.bind(host),
2816
+ readMigrationFingerprint
2817
+ });
2818
+ return completionFingerprint ?? readMigrationFingerprint();
2819
+ }
2820
+
2821
+ // src/storage/entity-canonical-id-migration-runner.ts
2822
+ var EntityCanonicalIdMigrationRunner = class {
2823
+ constructor(canRun, runMigration, readFingerprint = async () => "static") {
2824
+ this.canRun = canRun;
2825
+ this.runMigration = runMigration;
2826
+ this.readFingerprint = readFingerprint;
2827
+ }
2828
+ canRun;
2829
+ runMigration;
2830
+ readFingerprint;
2831
+ inFlight = null;
2832
+ directoriesInitialized = false;
2833
+ migrationComplete = false;
2834
+ completedFingerprint = null;
2835
+ async markDirectoriesInitialized() {
2836
+ this.directoriesInitialized = true;
2837
+ await this.ensure();
2838
+ }
2839
+ ensure() {
2840
+ if (!this.canRun()) return Promise.resolve();
2841
+ if (this.inFlight) return this.inFlight;
2842
+ const migration = this.runOrReuse();
2843
+ this.inFlight = migration;
2844
+ void migration.then(
2845
+ () => this.clearInFlight(migration),
2846
+ () => this.clearInFlight(migration)
2847
+ );
2848
+ return migration;
2849
+ }
2850
+ triggerAfterUnlock() {
2851
+ if (!this.directoriesInitialized) return Promise.resolve();
2852
+ return this.ensure();
2853
+ }
2854
+ async runOrReuse() {
2855
+ let fingerprintAtStart = await this.readFingerprint();
2856
+ if (this.migrationComplete && fingerprintAtStart === this.completedFingerprint) return;
2857
+ for (let attempt = 0; attempt < 3; attempt += 1) {
2858
+ const completionFingerprint = await this.runMigration();
2859
+ const fingerprintAfterMigration = await this.readFingerprint();
2860
+ const fingerprintAfterStabilityRead = await this.readFingerprint();
2861
+ const returnedFingerprint = typeof completionFingerprint === "string" ? completionFingerprint : fingerprintAfterMigration;
2862
+ if (returnedFingerprint === fingerprintAfterMigration && fingerprintAfterMigration === fingerprintAfterStabilityRead && (typeof completionFingerprint === "string" || fingerprintAfterMigration === fingerprintAtStart)) {
2863
+ this.migrationComplete = true;
2864
+ this.completedFingerprint = fingerprintAfterStabilityRead;
2865
+ return;
2866
+ }
2867
+ fingerprintAtStart = fingerprintAfterStabilityRead;
2868
+ }
2869
+ this.migrationComplete = false;
2870
+ this.completedFingerprint = null;
2871
+ throw new Error("Entity canonical-id migration fingerprint changed while migration was completing; retry migration.");
2872
+ }
2873
+ clearInFlight(migration) {
2874
+ if (this.inFlight === migration) this.inFlight = null;
2875
+ }
2876
+ };
2877
+
2878
+ // src/storage/memory-migration-serialization.ts
2879
+ function serializeMemoryWithEntityRef(memory, entityRef, fallback) {
2880
+ const rawFrontmatter = readRawFrontmatter(memory);
2881
+ if (rawFrontmatter === void 0) return fallback(memory, entityRef);
2882
+ const lines = rawFrontmatter.split("\n");
2883
+ let entityRefLine = -1;
2884
+ for (let index = 0; index < lines.length; index += 1) {
2885
+ if (/^\s*entityRef\s*:/.test(lines[index] ?? "")) entityRefLine = index;
2886
+ }
2887
+ if (entityRefLine >= 0) {
2888
+ const indent = lines[entityRefLine].match(/^\s*/)?.[0] ?? "";
2889
+ lines[entityRefLine] = `${indent}entityRef: ${entityRef}`;
2890
+ } else {
2891
+ lines.push(`entityRef: ${entityRef}`);
2892
+ }
2893
+ return `---
2894
+ ${lines.join("\n")}
2895
+ ---
2896
+
2897
+ ${memory.content}
2898
+ `;
2899
+ }
2900
+ function createMemoryEntityRefSerializer(serializeFrontmatter2) {
2901
+ return (memory, entityRef) => serializeMemoryWithEntityRef(
2902
+ memory,
2903
+ entityRef,
2904
+ (fallbackMemory, fallbackEntityRef) => `${serializeFrontmatter2({ ...fallbackMemory.frontmatter, entityRef: fallbackEntityRef })}
2905
+
2906
+ ${fallbackMemory.content}
2907
+ `
2908
+ );
2909
+ }
2910
+
1340
2911
  // src/utils/yaml-scalar.ts
1341
2912
  function decodeYamlScalar(value) {
1342
2913
  const trimmed = value.trim();
@@ -1352,9 +2923,9 @@ function decodeYamlScalar(value) {
1352
2923
  }
1353
2924
 
1354
2925
  // src/orchestration/qmd-result-resolver.ts
1355
- import path5 from "path";
2926
+ import path6 from "path";
1356
2927
  function qmdCollectionPathParts(resultPath) {
1357
- if (!resultPath || path5.isAbsolute(resultPath)) return null;
2928
+ if (!resultPath || path6.isAbsolute(resultPath)) return null;
1358
2929
  const normalized = resultPath.replace(/\\/g, "/").replace(/^\/+/, "");
1359
2930
  const slashIndex = normalized.indexOf("/");
1360
2931
  if (slashIndex <= 0 || slashIndex >= normalized.length - 1) return null;
@@ -1367,9 +2938,9 @@ function qmdCollectionPathParts(resultPath) {
1367
2938
  }
1368
2939
  function qmdResultPathCandidates(storageDir, resultPath) {
1369
2940
  const candidates = /* @__PURE__ */ new Set();
1370
- const storageRoot = path5.resolve(storageDir);
2941
+ const storageRoot = path6.resolve(storageDir);
1371
2942
  const addCandidate = (candidate) => {
1372
- const resolved = path5.resolve(candidate);
2943
+ const resolved = path6.resolve(candidate);
1373
2944
  if (isPathInsideStorageRoot(storageRoot, resolved)) {
1374
2945
  candidates.add(resolved);
1375
2946
  }
@@ -1377,18 +2948,18 @@ function qmdResultPathCandidates(storageDir, resultPath) {
1377
2948
  const addRelativeCandidates = (relativePath) => {
1378
2949
  const normalized = relativePath.replace(/\\/g, "/").replace(/^\/+/, "");
1379
2950
  if (!normalized) return;
1380
- addCandidate(path5.join(storageRoot, normalized));
2951
+ addCandidate(path6.join(storageRoot, normalized));
1381
2952
  if (/^\d{4}-\d{2}-\d{2}\//.test(normalized)) {
1382
- addCandidate(path5.join(storageRoot, "facts", normalized));
2953
+ addCandidate(path6.join(storageRoot, "facts", normalized));
1383
2954
  }
1384
2955
  };
1385
- if (path5.isAbsolute(resultPath)) {
2956
+ if (path6.isAbsolute(resultPath)) {
1386
2957
  addCandidate(resultPath);
1387
- const relative2 = path5.relative(storageRoot, path5.resolve(resultPath));
1388
- if (relative2 && !relative2.startsWith("..") && !path5.isAbsolute(relative2)) {
1389
- const normalized = relative2.split(path5.sep).join("/");
2958
+ const relative2 = path6.relative(storageRoot, path6.resolve(resultPath));
2959
+ if (relative2 && !relative2.startsWith("..") && !path6.isAbsolute(relative2)) {
2960
+ const normalized = relative2.split(path6.sep).join("/");
1390
2961
  if (/^\d{4}-\d{2}-\d{2}\//.test(normalized)) {
1391
- addCandidate(path5.join(storageRoot, "facts", normalized));
2962
+ addCandidate(path6.join(storageRoot, "facts", normalized));
1392
2963
  }
1393
2964
  }
1394
2965
  } else {
@@ -1423,7 +2994,7 @@ var QmdResultResolver = class {
1423
2994
  const seenStorageDirs = /* @__PURE__ */ new Set();
1424
2995
  const addStorage = (storage) => {
1425
2996
  const storageDir = storageDirOrNull(storage);
1426
- const storageKey = storageDir ? path5.resolve(storageDir) : `storage-without-dir-${storages.length}`;
2997
+ const storageKey = storageDir ? path6.resolve(storageDir) : `storage-without-dir-${storages.length}`;
1427
2998
  if (seenStorageDirs.has(storageKey)) return;
1428
2999
  seenStorageDirs.add(storageKey);
1429
3000
  storages.push(storage);
@@ -1453,7 +3024,7 @@ var QmdResultResolver = class {
1453
3024
  continue;
1454
3025
  }
1455
3026
  try {
1456
- const coldRoot = path5.join(storageDir, "cold");
3027
+ const coldRoot = path6.join(storageDir, "cold");
1457
3028
  for (const candidate of qmdResultPathCandidates(
1458
3029
  coldRoot,
1459
3030
  parts.relativePath
@@ -1512,9 +3083,9 @@ var QmdResultResolver = class {
1512
3083
  error: err.message
1513
3084
  });
1514
3085
  }
1515
- if (!path5.isAbsolute(resultPath)) return null;
3086
+ if (!path6.isAbsolute(resultPath)) return null;
1516
3087
  }
1517
- if (path5.isAbsolute(resultPath)) {
3088
+ if (path6.isAbsolute(resultPath)) {
1518
3089
  if (!fallbackStorageDir) {
1519
3090
  return await fallbackStorage.readMemoryByPath(resultPath);
1520
3091
  }
@@ -1554,7 +3125,7 @@ var QmdResultResolver = class {
1554
3125
  );
1555
3126
  if (!memory) return null;
1556
3127
  let ownerNamespace = null;
1557
- if (path5.isAbsolute(memory.path)) {
3128
+ if (path6.isAbsolute(memory.path)) {
1558
3129
  const ownerStorage = await this.storageForAbsoluteQmdResultPath(
1559
3130
  memory.path,
1560
3131
  fallbackStorage,
@@ -1578,17 +3149,17 @@ var QmdResultResolver = class {
1578
3149
  };
1579
3150
  }
1580
3151
  async storageForAbsoluteQmdResultPath(resultPath, fallbackStorage, recallNamespaces = []) {
1581
- const resolvedPath = path5.resolve(resultPath);
3152
+ const resolvedPath = path6.resolve(resultPath);
1582
3153
  const config = this.getConfig();
1583
- const memoryRoot = path5.resolve(config.memoryDir);
1584
- const namespacesRoot = path5.join(memoryRoot, "namespaces");
3154
+ const memoryRoot = path6.resolve(config.memoryDir);
3155
+ const namespacesRoot = path6.join(memoryRoot, "namespaces");
1585
3156
  const fallbackStorageDir = storageDirOrNull(fallbackStorage);
1586
3157
  const matches = [];
1587
3158
  const seenDirs = /* @__PURE__ */ new Set();
1588
3159
  const maybeAddStorage = (storage, namespace) => {
1589
3160
  const storageDir = storageDirOrNull(storage);
1590
3161
  if (!storageDir) return;
1591
- const candidateRoot = path5.resolve(storageDir);
3162
+ const candidateRoot = path6.resolve(storageDir);
1592
3163
  if (seenDirs.has(candidateRoot)) return;
1593
3164
  if (!isPathInsideStorageRoot(candidateRoot, resolvedPath)) return;
1594
3165
  if (candidateRoot === memoryRoot && isPathInsideStorageRoot(namespacesRoot, resolvedPath)) {
@@ -1606,7 +3177,7 @@ var QmdResultResolver = class {
1606
3177
  candidateNamespaces.add(ns);
1607
3178
  }
1608
3179
  if (isPathInsideStorageRoot(namespacesRoot, resolvedPath)) {
1609
- const relativeToNamespaces = path5.relative(namespacesRoot, resolvedPath);
3180
+ const relativeToNamespaces = path6.relative(namespacesRoot, resolvedPath);
1610
3181
  const [namespaceSegment] = relativeToNamespaces.split(/[\\/]/);
1611
3182
  if (namespaceSegment) {
1612
3183
  candidateNamespaces.add(
@@ -2255,7 +3826,7 @@ function fuseDay(date, inputs, options = {}) {
2255
3826
 
2256
3827
  // src/wearables/fusion/store.ts
2257
3828
  import { createHash as createHash2 } from "crypto";
2258
- import * as path6 from "path";
3829
+ import * as path7 from "path";
2259
3830
  var FUSION_KIND = "wearable-fusion";
2260
3831
  function hashFusionBody(conversations) {
2261
3832
  return createHash2("sha256").update(JSON.stringify(conversations), "utf-8").digest("hex");
@@ -2442,7 +4013,7 @@ var FusionArtifactStore = class {
2442
4013
  `invalid wearable fusion date '${String(date)}' \u2014 expected YYYY-MM-DD`
2443
4014
  );
2444
4015
  }
2445
- return path6.join(this.wearablesDir, FUSION_DIR_NAME, `${date}.md`);
4016
+ return path7.join(this.wearablesDir, FUSION_DIR_NAME, `${date}.md`);
2446
4017
  }
2447
4018
  async writeFusedDay(date, serialized) {
2448
4019
  const filePath = this.fusedDayPath(date);
@@ -2479,7 +4050,7 @@ var FusionArtifactStore = class {
2479
4050
  }
2480
4051
  /** List dates with stored fused artifacts, newest first. */
2481
4052
  async listFusedDays() {
2482
- const fusionDir = path6.join(this.wearablesDir, FUSION_DIR_NAME);
4053
+ const fusionDir = path7.join(this.wearablesDir, FUSION_DIR_NAME);
2483
4054
  await this.assertPathContained(fusionDir);
2484
4055
  let entries;
2485
4056
  try {
@@ -2523,10 +4094,10 @@ var FusionArtifactStore = class {
2523
4094
  try {
2524
4095
  rootReal = await this.io.realpath(this.memoryDir);
2525
4096
  } catch {
2526
- rootReal = path6.resolve(this.memoryDir);
4097
+ rootReal = path7.resolve(this.memoryDir);
2527
4098
  }
2528
4099
  await this.assertNoEscape(rootReal, this.wearablesDir);
2529
- await this.assertNoEscape(rootReal, path6.dirname(targetPath));
4100
+ await this.assertNoEscape(rootReal, path7.dirname(targetPath));
2530
4101
  await this.assertNoEscape(rootReal, targetPath);
2531
4102
  await this.assertFusionDirNotSymlinked();
2532
4103
  }
@@ -2540,7 +4111,7 @@ var FusionArtifactStore = class {
2540
4111
  * (a fresh write creates a real directory lexically under the root).
2541
4112
  */
2542
4113
  async assertFusionDirNotSymlinked() {
2543
- const fusionDir = path6.join(this.wearablesDir, FUSION_DIR_NAME);
4114
+ const fusionDir = path7.join(this.wearablesDir, FUSION_DIR_NAME);
2544
4115
  let stat4;
2545
4116
  try {
2546
4117
  stat4 = await this.io.lstat(fusionDir);
@@ -2676,7 +4247,7 @@ function reconstructFusionInputs(date, dayTranscripts) {
2676
4247
 
2677
4248
  // src/meetings/store.ts
2678
4249
  import { createHash as createHash3 } from "crypto";
2679
- import * as path7 from "path";
4250
+ import * as path8 from "path";
2680
4251
  var MEETINGS_DIR_NAME = "meetings";
2681
4252
  var MEETING_KIND = "meeting";
2682
4253
  var MEETING_FORMAT_VERSION = 1;
@@ -2845,7 +4416,7 @@ var MeetingRecordStore = class {
2845
4416
  constructor(memoryDir, io) {
2846
4417
  this.memoryDir = memoryDir;
2847
4418
  this.io = io;
2848
- this.meetingsDir = path7.join(memoryDir, MEETINGS_DIR_NAME);
4419
+ this.meetingsDir = path8.join(memoryDir, MEETINGS_DIR_NAME);
2849
4420
  }
2850
4421
  memoryDir;
2851
4422
  io;
@@ -2861,7 +4432,7 @@ var MeetingRecordStore = class {
2861
4432
  if (idDate !== date) {
2862
4433
  throw new Error(`meeting id '${id}' does not belong to date '${date}'`);
2863
4434
  }
2864
- return path7.join(this.meetingsDir, date, `${id}.md`);
4435
+ return path8.join(this.meetingsDir, date, `${id}.md`);
2865
4436
  }
2866
4437
  /** Idempotently persist a record: skip the write when contentHash is unchanged. */
2867
4438
  async saveMeetingRecord(record) {
@@ -2892,7 +4463,7 @@ var MeetingRecordStore = class {
2892
4463
  if (!isValidTranscriptDate(date)) {
2893
4464
  throw new Error(`invalid meeting date '${String(date)}' \u2014 expected YYYY-MM-DD`);
2894
4465
  }
2895
- const dayDir = path7.join(this.meetingsDir, date);
4466
+ const dayDir = path8.join(this.meetingsDir, date);
2896
4467
  await this.assertPathContained(dayDir);
2897
4468
  let entries;
2898
4469
  try {
@@ -2960,10 +4531,10 @@ var MeetingRecordStore = class {
2960
4531
  try {
2961
4532
  rootReal = await this.io.realpath(this.memoryDir);
2962
4533
  } catch {
2963
- rootReal = path7.resolve(this.memoryDir);
4534
+ rootReal = path8.resolve(this.memoryDir);
2964
4535
  }
2965
4536
  await this.assertNoEscape(rootReal, this.meetingsDir);
2966
- await this.assertNoEscape(rootReal, path7.dirname(targetPath));
4537
+ await this.assertNoEscape(rootReal, path8.dirname(targetPath));
2967
4538
  await this.assertNoEscape(rootReal, targetPath);
2968
4539
  await this.assertNotSymlink(this.meetingsDir, "directory");
2969
4540
  const dayDir = this.dayDirWithin(targetPath);
@@ -2973,11 +4544,11 @@ var MeetingRecordStore = class {
2973
4544
  /** The `<meetings>/<date>` directory on the path to `targetPath`, or null when
2974
4545
  * `targetPath` is the meetings root itself. */
2975
4546
  dayDirWithin(targetPath) {
2976
- const rel = path7.relative(this.meetingsDir, targetPath);
2977
- if (rel === "" || rel.startsWith("..") || path7.isAbsolute(rel)) return null;
2978
- const first = rel.split(path7.sep)[0];
4547
+ const rel = path8.relative(this.meetingsDir, targetPath);
4548
+ if (rel === "" || rel.startsWith("..") || path8.isAbsolute(rel)) return null;
4549
+ const first = rel.split(path8.sep)[0];
2979
4550
  if (first === void 0 || first.length === 0) return null;
2980
- return path7.join(this.meetingsDir, first);
4551
+ return path8.join(this.meetingsDir, first);
2981
4552
  }
2982
4553
  async assertNotSymlink(target, kind) {
2983
4554
  let stat4;
@@ -2988,7 +4559,7 @@ var MeetingRecordStore = class {
2988
4559
  throw err;
2989
4560
  }
2990
4561
  if (stat4.isSymbolicLink) {
2991
- const label = path7.relative(this.memoryDir, target) || MEETINGS_DIR_NAME;
4562
+ const label = path8.relative(this.memoryDir, target) || MEETINGS_DIR_NAME;
2992
4563
  throw new Error(
2993
4564
  `meetings ${kind} '${label}' is a symbolic link \u2014 refusing to follow it even when it resolves inside the memory dir (AGENTS.md pattern #3)`
2994
4565
  );
@@ -3406,7 +4977,7 @@ function isEntitySynthesisStale(entity) {
3406
4977
 
3407
4978
  // src/storage/content-hash-index.ts
3408
4979
  import { mkdir, stat as stat2 } from "fs/promises";
3409
- import path8 from "path";
4980
+ import path9 from "path";
3410
4981
  var CONTENT_HASH_INDEX_LOCK_STALE_MS = 3e4;
3411
4982
  var CONTENT_HASH_INDEX_RETRY_MAX_ATTEMPTS = 5;
3412
4983
  var CONTENT_HASH_INDEX_RETRY_BASE_MS = 500;
@@ -3466,8 +5037,8 @@ var ContentHashIndex = class _ContentHashIndex {
3466
5037
  * re-read on the hot path.
3467
5038
  */
3468
5039
  lastSyncedFingerprint = null;
3469
- constructor(stateDir, secureStoreKeyProvider = () => null, secureStoreWriteKeyProvider = secureStoreKeyProvider, memoryDir = path8.dirname(stateDir), lockOptions = {}) {
3470
- this.filePath = path8.join(stateDir, "fact-hashes.txt");
5040
+ constructor(stateDir, secureStoreKeyProvider = () => null, secureStoreWriteKeyProvider = secureStoreKeyProvider, memoryDir = path9.dirname(stateDir), lockOptions = {}) {
5041
+ this.filePath = path9.join(stateDir, "fact-hashes.txt");
3471
5042
  this.secureStoreKeyProvider = secureStoreKeyProvider;
3472
5043
  this.secureStoreWriteKeyProvider = secureStoreWriteKeyProvider;
3473
5044
  this.memoryDir = memoryDir;
@@ -3559,7 +5130,7 @@ var ContentHashIndex = class _ContentHashIndex {
3559
5130
  /** Persist index to disk if changed (plain whole-file overwrite). */
3560
5131
  async save() {
3561
5132
  if (!this.dirty) return;
3562
- await mkdir(path8.dirname(this.filePath), { recursive: true });
5133
+ await mkdir(path9.dirname(this.filePath), { recursive: true });
3563
5134
  const publishedAdded = new Set(this.added);
3564
5135
  const publishedRemoved = new Set(this.removed);
3565
5136
  const serialized = [...this.hashes].join("\n") + "\n";
@@ -3606,7 +5177,7 @@ var ContentHashIndex = class _ContentHashIndex {
3606
5177
  */
3607
5178
  async saveMergingWithDisk() {
3608
5179
  if (!this.dirty) return;
3609
- await mkdir(path8.dirname(this.filePath), { recursive: true });
5180
+ await mkdir(path9.dirname(this.filePath), { recursive: true });
3610
5181
  const publish = async () => {
3611
5182
  const publishedAdded = new Set(this.added);
3612
5183
  const publishedRemoved = new Set(this.removed);
@@ -3625,7 +5196,7 @@ var ContentHashIndex = class _ContentHashIndex {
3625
5196
  if (err instanceof SecureStoreLockedError) throw err;
3626
5197
  if (!isErrnoCode(err, "ENOENT")) throw err;
3627
5198
  }
3628
- await mkdir(path8.dirname(this.filePath), { recursive: true });
5199
+ await mkdir(path9.dirname(this.filePath), { recursive: true });
3629
5200
  await writeMaybeEncryptedFile(
3630
5201
  this.filePath,
3631
5202
  [...merged].join("\n") + "\n",
@@ -3692,7 +5263,7 @@ var ContentHashIndex = class _ContentHashIndex {
3692
5263
  * fired retry) simply yields `acquired=false` after the bounded wait.
3693
5264
  */
3694
5265
  async rebuildUnderLock(populate) {
3695
- await mkdir(path8.dirname(this.filePath), { recursive: true });
5266
+ await mkdir(path9.dirname(this.filePath), { recursive: true });
3696
5267
  let published = false;
3697
5268
  await withHeldFileLock(
3698
5269
  `${this.filePath}.lock`,
@@ -4493,17 +6064,17 @@ function inferEntityTypeFromContent(content) {
4493
6064
  }
4494
6065
  var KNOWN_ENTITY_FILENAME_PREFIXES = /* @__PURE__ */ new Set(["company", "other", "person", "place", "project", "tool", "topic"]);
4495
6066
  function inferEntityTypeFromFilename(pathRel) {
4496
- const basename = path9.basename(pathRel, ".md").toLowerCase();
6067
+ const basename = path10.basename(pathRel, ".md").toLowerCase();
4497
6068
  const separator = basename.indexOf("-");
4498
6069
  if (separator <= 0) return void 0;
4499
6070
  const candidate = basename.slice(0, separator);
4500
6071
  return KNOWN_ENTITY_FILENAME_PREFIXES.has(candidate) ? candidate : void 0;
4501
6072
  }
4502
6073
  function normalizeFrontmatterForPath(frontmatter, pathRel, content = "") {
4503
- const normalizedPath = pathRel.split(path9.sep).join("/");
6074
+ const normalizedPath = pathRel.split(path10.sep).join("/");
4504
6075
  let normalizedFrontmatter = frontmatter;
4505
6076
  if (normalizedPath === "entities" || normalizedPath.startsWith("entities/") || normalizedPath.includes("/entities/")) {
4506
- const basename = path9.basename(pathRel, ".md");
6077
+ const basename = path10.basename(pathRel, ".md");
4507
6078
  const inferredType = inferEntityTypeFromContent(content) || inferEntityTypeFromFilename(pathRel) || "entity";
4508
6079
  const existingTags = Array.isArray(frontmatter.tags) ? frontmatter.tags : [];
4509
6080
  normalizedFrontmatter = {
@@ -4524,27 +6095,6 @@ function normalizeFrontmatterForPath(frontmatter, pathRel, content = "") {
4524
6095
  function inferCurrentStateStatus(frontmatter, pathRel, fallbackStatus) {
4525
6096
  return inferMemoryStatus(frontmatter, pathRel, fallbackStatus);
4526
6097
  }
4527
- var BUILTIN_ALIASES = {
4528
- openclaw: "openclaw",
4529
- "open-claw": "openclaw"
4530
- };
4531
- function normalizeEntityName(raw, type, aliases) {
4532
- const rawStr = typeof raw === "string" ? raw : "";
4533
- const typeStr = typeof type === "string" && type.trim().length > 0 ? type : "entity";
4534
- let name = rawStr.toLowerCase().trim();
4535
- const typePrefix = `${typeStr.toLowerCase()}-`;
4536
- if (name.startsWith(typePrefix)) {
4537
- name = name.slice(typePrefix.length);
4538
- }
4539
- let normalized = name.replace(/[^a-z0-9]+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
4540
- const userAlias = aliases !== void 0 && Object.hasOwn(aliases, normalized) ? aliases[normalized] : void 0;
4541
- if (typeof userAlias === "string" && userAlias.length > 0) {
4542
- normalized = userAlias;
4543
- } else if (Object.hasOwn(BUILTIN_ALIASES, normalized)) {
4544
- normalized = BUILTIN_ALIASES[normalized];
4545
- }
4546
- return `${typeStr.toLowerCase()}-${normalized}`;
4547
- }
4548
6098
  function levenshtein(a, b) {
4549
6099
  const m = a.length;
4550
6100
  const n = b.length;
@@ -4990,6 +6540,7 @@ var StorageManager3 = class _StorageManager {
4990
6540
  this.entitySchemas = entitySchemas;
4991
6541
  this.hotMemoriesCacheEnabled = hotMemoriesCacheEnabledOverride ?? _StorageManager.hotMemoriesCacheDefaultByDir.get(baseDir) ?? _StorageManager.hotMemoriesCacheDefault;
4992
6542
  this.loadAliasesSync();
6543
+ this.loadHistoricalEntityCanonicalIdsSync();
4993
6544
  }
4994
6545
  baseDir;
4995
6546
  entitySchemas;
@@ -5169,8 +6720,8 @@ var StorageManager3 = class _StorageManager {
5169
6720
  }
5170
6721
  /** Whether `filePath` resolves to `stateDir` itself or a path contained in it. */
5171
6722
  isStateFilePath(filePath) {
5172
- const rel = path9.relative(this.stateDir, path9.resolve(filePath));
5173
- return rel === "" || !rel.startsWith("..") && !path9.isAbsolute(rel);
6723
+ const rel = path10.relative(this.stateDir, path10.resolve(filePath));
6724
+ return rel === "" || !rel.startsWith("..") && !path10.isAbsolute(rel);
5174
6725
  }
5175
6726
  // ── Tombstone store (issue #1579) ───────────────────────────────────────
5176
6727
  // Instance-scoped (rule 11) + namespace-scoped (rule 42) tombstone index.
@@ -5213,17 +6764,34 @@ var StorageManager3 = class _StorageManager {
5213
6764
  * Set or clear the at-rest encryption key.
5214
6765
  *
5215
6766
  * Pass a 32-byte Buffer to enable encryption; pass null to clear
5216
- * (lock) the store. The caller is responsible for key lifecycle —
6767
+ * (lock) the store. The caller is responsible for key lifecycle —
5217
6768
  * this method does not zero the buffer on replacement; the keyring
5218
- * module (`keyring.ts`) owns zeroization.
6769
+ * module (`keyring.ts`) owns zeroization. The setter remains synchronous
6770
+ * for existing consumers; call `setSecureStoreKeyAndWait` when unlock must
6771
+ * await migration.
5219
6772
  */
5220
6773
  setSecureStoreKey(key, encryptOnWrite = true) {
6774
+ if (!this.applySecureStoreKey(key, encryptOnWrite) || key === null) return;
6775
+ void this.entityCanonicalIdMigration.triggerAfterUnlock().catch((error) => {
6776
+ log.warn(
6777
+ `secure-store unlock migration failed: ${error instanceof Error ? error.message : String(error)}`
6778
+ );
6779
+ });
6780
+ }
6781
+ async setSecureStoreKeyAndWait(key, encryptOnWrite = true) {
6782
+ if (!this.applySecureStoreKey(key, encryptOnWrite) || key === null) return;
6783
+ await this.entityCanonicalIdMigration.triggerAfterUnlock();
6784
+ }
6785
+ applySecureStoreKey(key, encryptOnWrite) {
6786
+ const sameKey = this._secureStoreKey === key || this._secureStoreKey !== null && key !== null && this._secureStoreKey.equals(key);
6787
+ if (sameKey && this._secureStoreEncryptOnWrite === encryptOnWrite) return false;
5221
6788
  this._secureStoreKey = key;
5222
6789
  this._secureStoreEncryptOnWrite = encryptOnWrite;
5223
6790
  invalidateAllForDir(this.baseDir);
5224
6791
  this.invalidateKnowledgeIndexCache();
5225
6792
  this.secureFileEncryptionSniffCache.clear();
5226
6793
  this.behaviorSignalsKeyCache = null;
6794
+ return true;
5227
6795
  }
5228
6796
  getEntityCacheSecureStoreKey() {
5229
6797
  if (!this._secureStoreKey) return "secure-store:locked";
@@ -5270,8 +6838,8 @@ var StorageManager3 = class _StorageManager {
5270
6838
  * /srv/cold/remnic), skipping the patch and stranding a stale hot entry.
5271
6839
  */
5272
6840
  isColdOrArchiveTierPath(p) {
5273
- const rel = path9.relative(this.baseDir, p);
5274
- return rel === "cold" || rel === "archive" || rel.startsWith(`cold${path9.sep}`) || rel.startsWith(`archive${path9.sep}`);
6841
+ const rel = path10.relative(this.baseDir, p);
6842
+ return rel === "cold" || rel === "archive" || rel.startsWith(`cold${path10.sep}`) || rel.startsWith(`archive${path10.sep}`);
5275
6843
  }
5276
6844
  /**
5277
6845
  * Mark the secure-store as required for this storage instance.
@@ -5358,7 +6926,7 @@ var StorageManager3 = class _StorageManager {
5358
6926
  void 0,
5359
6927
  this.baseDir
5360
6928
  );
5361
- const rel = path9.relative(this.baseDir, filePath).split(path9.sep).join("/");
6929
+ const rel = path10.relative(this.baseDir, filePath).split(path10.sep).join("/");
5362
6930
  return `${rel}:${version.versionId}`;
5363
6931
  } catch (err) {
5364
6932
  log.warn(
@@ -5438,13 +7006,13 @@ var StorageManager3 = class _StorageManager {
5438
7006
  }
5439
7007
  identityFilePath(workspaceDir, namespace) {
5440
7008
  const rawNamespace = typeof namespace === "string" ? namespace.trim() : "";
5441
- if (!rawNamespace) return path9.join(workspaceDir, "IDENTITY.md");
7009
+ if (!rawNamespace) return path10.join(workspaceDir, "IDENTITY.md");
5442
7010
  const safeNamespace = rawNamespace.replace(/[^a-zA-Z0-9._-]/g, "-");
5443
- return path9.join(workspaceDir, `IDENTITY.${safeNamespace}.md`);
7011
+ return path10.join(workspaceDir, `IDENTITY.${safeNamespace}.md`);
5444
7012
  }
5445
7013
  versionFilePath(kind) {
5446
7014
  const fileName = kind === "memory-status" ? ".memory-status-version.log" : kind === "artifact-write" ? ".artifact-write-version.log" : kind === "cold-write" ? ".cold-write-version.log" : ".memory-corpus-version.log";
5447
- return path9.join(this.stateDir, fileName);
7015
+ return path10.join(this.stateDir, fileName);
5448
7016
  }
5449
7017
  bumpSharedVersion(kind, fallbackMap) {
5450
7018
  const filePath = this.versionFilePath(kind);
@@ -5536,7 +7104,7 @@ var StorageManager3 = class _StorageManager {
5536
7104
  // memories.
5537
7105
  // -------------------------------------------------------------------------
5538
7106
  get wearablesDir() {
5539
- return path9.join(this.baseDir, WEARABLES_DIR_NAME);
7107
+ return path10.join(this.baseDir, WEARABLES_DIR_NAME);
5540
7108
  }
5541
7109
  /**
5542
7110
  * Resolve the on-disk path for a source/day transcript. Throws on
@@ -5552,7 +7120,7 @@ var StorageManager3 = class _StorageManager {
5552
7120
  if (!isValidTranscriptDate(date)) {
5553
7121
  throw new Error(`invalid wearable transcript date '${String(date)}' \u2014 expected YYYY-MM-DD`);
5554
7122
  }
5555
- return path9.join(this.wearablesDir, sourceId, `${date}.md`);
7123
+ return path10.join(this.wearablesDir, sourceId, `${date}.md`);
5556
7124
  }
5557
7125
  async writeWearableDayTranscript(sourceId, date, serialized) {
5558
7126
  const targetPath = this.wearableTranscriptPath(sourceId, date);
@@ -5578,10 +7146,10 @@ var StorageManager3 = class _StorageManager {
5578
7146
  return this._fusionStore = new FusionArtifactStore(this.wearablesDir, this.baseDir, {
5579
7147
  writeFile: (p, c) => this.writeStorageSecureFile(p, c),
5580
7148
  readFile: (p) => readMaybeEncryptedFile(p, this._secureStoreKey, this.baseDir),
5581
- readDir: (d) => readdir4(d),
5582
- deleteFile: (p) => unlink2(p),
5583
- realpath: (p) => realpath2(p),
5584
- lstat: (p) => lstat2(p).then((st) => ({ isSymbolicLink: st.isSymbolicLink() }))
7149
+ readDir: (d) => readdir5(d),
7150
+ deleteFile: (p) => unlink3(p),
7151
+ realpath: (p) => realpath3(p),
7152
+ lstat: (p) => lstat3(p).then((st) => ({ isSymbolicLink: st.isSymbolicLink() }))
5585
7153
  });
5586
7154
  }
5587
7155
  _meetingRecordStore;
@@ -5596,10 +7164,10 @@ var StorageManager3 = class _StorageManager {
5596
7164
  return this._meetingRecordStore = new MeetingRecordStore(this.baseDir, {
5597
7165
  writeFile: (p, c) => this.writeStorageSecureFile(p, c),
5598
7166
  readFile: (p) => readMaybeEncryptedFile(p, this._secureStoreKey, this.baseDir),
5599
- readDir: (d) => readdir4(d),
5600
- deleteFile: (p) => unlink2(p),
5601
- realpath: (p) => realpath2(p),
5602
- lstat: (p) => lstat2(p).then((st) => ({ isSymbolicLink: st.isSymbolicLink() }))
7167
+ readDir: (d) => readdir5(d),
7168
+ deleteFile: (p) => unlink3(p),
7169
+ realpath: (p) => realpath3(p),
7170
+ lstat: (p) => lstat3(p).then((st) => ({ isSymbolicLink: st.isSymbolicLink() }))
5603
7171
  });
5604
7172
  }
5605
7173
  /**
@@ -5668,25 +7236,25 @@ var StorageManager3 = class _StorageManager {
5668
7236
  });
5669
7237
  }
5670
7238
  get factsDir() {
5671
- return path9.join(this.baseDir, "facts");
7239
+ return path10.join(this.baseDir, "facts");
5672
7240
  }
5673
7241
  get correctionsDir() {
5674
- return path9.join(this.baseDir, "corrections");
7242
+ return path10.join(this.baseDir, "corrections");
5675
7243
  }
5676
7244
  get proceduresDir() {
5677
- return path9.join(this.baseDir, "procedures");
7245
+ return path10.join(this.baseDir, "procedures");
5678
7246
  }
5679
7247
  get reasoningTracesDir() {
5680
- return path9.join(this.baseDir, "reasoning-traces");
7248
+ return path10.join(this.baseDir, "reasoning-traces");
5681
7249
  }
5682
7250
  get entitiesDir() {
5683
- return path9.join(this.baseDir, "entities");
7251
+ return path10.join(this.baseDir, "entities");
5684
7252
  }
5685
7253
  resolveEntityFilePath(name) {
5686
7254
  if (typeof name !== "string") return null;
5687
- const filePath = path9.resolve(this.entitiesDir, `${name}.md`);
5688
- const relative2 = path9.relative(this.entitiesDir, filePath);
5689
- if (relative2 === "" || relative2.startsWith("..") || path9.isAbsolute(relative2)) {
7255
+ const filePath = path10.resolve(this.entitiesDir, `${name}.md`);
7256
+ const relative2 = path10.relative(this.entitiesDir, filePath);
7257
+ if (relative2 === "" || relative2.startsWith("..") || path10.isAbsolute(relative2)) {
5690
7258
  return null;
5691
7259
  }
5692
7260
  return filePath;
@@ -5707,10 +7275,10 @@ var StorageManager3 = class _StorageManager {
5707
7275
  });
5708
7276
  }
5709
7277
  assertManagedStoragePath(filePath, method) {
5710
- const resolved = path9.resolve(filePath);
5711
- const base = path9.resolve(this.baseDir);
5712
- const rel = path9.relative(base, resolved);
5713
- if (rel === "" || rel === ".." || rel.startsWith(`..${path9.sep}`) || path9.isAbsolute(rel)) {
7278
+ const resolved = path10.resolve(filePath);
7279
+ const base = path10.resolve(this.baseDir);
7280
+ const rel = path10.relative(base, resolved);
7281
+ if (rel === "" || rel === ".." || rel.startsWith(`..${path10.sep}`) || path10.isAbsolute(rel)) {
5714
7282
  throw new Error(`${method}: file path escapes memory dir`);
5715
7283
  }
5716
7284
  return resolved;
@@ -5722,7 +7290,7 @@ var StorageManager3 = class _StorageManager {
5722
7290
  async digestOfflineSyncFile(filePath) {
5723
7291
  const target = this.assertManagedStoragePath(filePath, "storage.digestOfflineSyncFile");
5724
7292
  const st = await stat3(target);
5725
- const relPath = path9.relative(this.baseDir, target).split(path9.sep).join("/");
7293
+ const relPath = path10.relative(this.baseDir, target).split(path10.sep).join("/");
5726
7294
  const cache = await this.loadOfflineSyncDigestCache();
5727
7295
  const cached = cache.get(relPath);
5728
7296
  if (cached && cached.statBytes === st.size && cached.mtimeMs === st.mtimeMs && cached.ctimeMs === st.ctimeMs && !cached.encrypted) {
@@ -5768,7 +7336,7 @@ var StorageManager3 = class _StorageManager {
5768
7336
  async readOfflineSyncDigestCache() {
5769
7337
  const cache = /* @__PURE__ */ new Map();
5770
7338
  try {
5771
- const raw = await readFile(this.offlineSyncDigestCachePath, "utf-8");
7339
+ const raw = await readFile2(this.offlineSyncDigestCachePath, "utf-8");
5772
7340
  const parsed = JSON.parse(raw);
5773
7341
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return cache;
5774
7342
  const entries = parsed.entries;
@@ -5783,7 +7351,7 @@ var StorageManager3 = class _StorageManager {
5783
7351
  const bytes = typeof record.bytes === "number" ? record.bytes : NaN;
5784
7352
  const sha256 = typeof record.sha256 === "string" ? record.sha256 : "";
5785
7353
  const encrypted = record.encrypted === true;
5786
- if (cachePath.length === 0 || cachePath === ".." || cachePath.startsWith("../") || path9.isAbsolute(cachePath) || !Number.isFinite(statBytes) || !Number.isFinite(mtimeMs) || !Number.isFinite(ctimeMs) || !Number.isFinite(bytes) || !/^[a-f0-9]{64}$/i.test(sha256)) {
7354
+ if (cachePath.length === 0 || cachePath === ".." || cachePath.startsWith("../") || path10.isAbsolute(cachePath) || !Number.isFinite(statBytes) || !Number.isFinite(mtimeMs) || !Number.isFinite(ctimeMs) || !Number.isFinite(bytes) || !/^[a-f0-9]{64}$/i.test(sha256)) {
5787
7355
  continue;
5788
7356
  }
5789
7357
  cache.set(cachePath, { statBytes, mtimeMs, ctimeMs, encrypted, sha256, bytes });
@@ -5825,8 +7393,8 @@ var StorageManager3 = class _StorageManager {
5825
7393
  const cache = this.offlineSyncDigestCache;
5826
7394
  if (!cache) return;
5827
7395
  const entries = [...cache.entries()].sort(([a], [b]) => a.localeCompare(b)).map(([entryPath, entry]) => ({ path: entryPath, ...entry }));
5828
- await mkdir2(path9.dirname(this.offlineSyncDigestCachePath), { recursive: true });
5829
- await writeFile(this.offlineSyncDigestCachePath, `${JSON.stringify({ version: 1, entries })}
7396
+ await mkdir2(path10.dirname(this.offlineSyncDigestCachePath), { recursive: true });
7397
+ await writeFile2(this.offlineSyncDigestCachePath, `${JSON.stringify({ version: 1, entries })}
5830
7398
  `, "utf-8");
5831
7399
  }).catch((err) => {
5832
7400
  log.warn(
@@ -5860,7 +7428,7 @@ var StorageManager3 = class _StorageManager {
5860
7428
  }
5861
7429
  async deleteOfflineSyncFile(filePath) {
5862
7430
  const target = this.assertManagedStoragePath(filePath, "storage.deleteOfflineSyncFile");
5863
- await unlink2(target).catch((error) => {
7431
+ await unlink3(target).catch((error) => {
5864
7432
  if (isErrnoCode(error, "ENOENT")) return;
5865
7433
  throw error;
5866
7434
  });
@@ -5870,10 +7438,10 @@ var StorageManager3 = class _StorageManager {
5870
7438
  this.invalidateAllMemoriesCache();
5871
7439
  this.invalidateKnowledgeIndexCache();
5872
7440
  this.factHashIndexAuthoritative = false;
5873
- if (filePath.includes(`${path9.sep}cold${path9.sep}`)) {
7441
+ if (filePath.includes(`${path10.sep}cold${path10.sep}`)) {
5874
7442
  this.invalidateColdMemoriesCache();
5875
7443
  }
5876
- if (filePath.includes(`${path9.sep}artifacts${path9.sep}`)) {
7444
+ if (filePath.includes(`${path10.sep}artifacts${path10.sep}`)) {
5877
7445
  this.bumpArtifactWriteVersion();
5878
7446
  }
5879
7447
  this.bumpMemoryStatusVersion();
@@ -5944,7 +7512,7 @@ var StorageManager3 = class _StorageManager {
5944
7512
  }
5945
7513
  async appendStorageSecureFileUnlocked(filePath, content) {
5946
7514
  const writeKey = this.resolveWriteKey();
5947
- await mkdir2(path9.dirname(filePath), { recursive: true });
7515
+ await mkdir2(path10.dirname(filePath), { recursive: true });
5948
7516
  if (writeKey === null) {
5949
7517
  try {
5950
7518
  if (await this.isEncryptedFileHeader(filePath)) {
@@ -5970,13 +7538,13 @@ var StorageManager3 = class _StorageManager {
5970
7538
  this.notifyCatalogWriteForPath(filePath);
5971
7539
  }
5972
7540
  get stateDir() {
5973
- return path9.join(this.baseDir, "state");
7541
+ return path10.join(this.baseDir, "state");
5974
7542
  }
5975
7543
  get offlineSyncDigestCachePath() {
5976
- return path9.join(this.baseDir, ".offline-sync", "digest-cache.v1.json");
7544
+ return path10.join(this.baseDir, ".offline-sync", "digest-cache.v1.json");
5977
7545
  }
5978
7546
  get entitySynthesisQueuePath() {
5979
- return path9.join(this.stateDir, "entity-synthesis-queue.json");
7547
+ return path10.join(this.stateDir, "entity-synthesis-queue.json");
5980
7548
  }
5981
7549
  // ── Tombstone store access (issue #1579) ─────────────────────────────────
5982
7550
  /**
@@ -5986,7 +7554,7 @@ var StorageManager3 = class _StorageManager {
5986
7554
  * helpers are injected into the store).
5987
7555
  */
5988
7556
  get tombstonesPath() {
5989
- return path9.join(this.stateDir, "tombstones.jsonl");
7557
+ return path10.join(this.stateDir, "tombstones.jsonl");
5990
7558
  }
5991
7559
  /**
5992
7560
  * Configure the tombstone invariant for this storage instance. Installed
@@ -6259,55 +7827,55 @@ var StorageManager3 = class _StorageManager {
6259
7827
  return null;
6260
7828
  }
6261
7829
  get questionsDir() {
6262
- return path9.join(this.baseDir, "questions");
7830
+ return path10.join(this.baseDir, "questions");
6263
7831
  }
6264
7832
  get artifactsDir() {
6265
- return path9.join(this.baseDir, "artifacts");
7833
+ return path10.join(this.baseDir, "artifacts");
6266
7834
  }
6267
7835
  get identityDir() {
6268
- return path9.join(this.baseDir, "identity");
7836
+ return path10.join(this.baseDir, "identity");
6269
7837
  }
6270
7838
  get identityAnchorPath() {
6271
- return path9.join(this.identityDir, "identity-anchor.md");
7839
+ return path10.join(this.identityDir, "identity-anchor.md");
6272
7840
  }
6273
7841
  get identityIncidentsDir() {
6274
- return path9.join(this.identityDir, "incidents");
7842
+ return path10.join(this.identityDir, "incidents");
6275
7843
  }
6276
7844
  get identityAuditsWeeklyDir() {
6277
- return path9.join(this.identityDir, "audits", "weekly");
7845
+ return path10.join(this.identityDir, "audits", "weekly");
6278
7846
  }
6279
7847
  get identityAuditsMonthlyDir() {
6280
- return path9.join(this.identityDir, "audits", "monthly");
7848
+ return path10.join(this.identityDir, "audits", "monthly");
6281
7849
  }
6282
7850
  get identityImprovementLoopsPath() {
6283
- return path9.join(this.identityDir, "improvement-loops.md");
7851
+ return path10.join(this.identityDir, "improvement-loops.md");
6284
7852
  }
6285
7853
  get identityReflectionsPath() {
6286
- return path9.join(this.identityDir, "reflections.md");
7854
+ return path10.join(this.identityDir, "reflections.md");
6287
7855
  }
6288
7856
  get profilePath() {
6289
- return path9.join(this.baseDir, "profile.md");
7857
+ return path10.join(this.baseDir, "profile.md");
6290
7858
  }
6291
7859
  get memoryActionsPath() {
6292
- return path9.join(this.stateDir, "memory-actions.jsonl");
7860
+ return path10.join(this.stateDir, "memory-actions.jsonl");
6293
7861
  }
6294
7862
  get memoryLifecycleLedgerPath() {
6295
- return path9.join(this.stateDir, "memory-lifecycle-ledger.jsonl");
7863
+ return path10.join(this.stateDir, "memory-lifecycle-ledger.jsonl");
6296
7864
  }
6297
7865
  get compressionGuidelinesPath() {
6298
- return path9.join(this.stateDir, "compression-guidelines.md");
7866
+ return path10.join(this.stateDir, "compression-guidelines.md");
6299
7867
  }
6300
7868
  get compressionGuidelineDraftPath() {
6301
- return path9.join(this.stateDir, "compression-guidelines.draft.md");
7869
+ return path10.join(this.stateDir, "compression-guidelines.draft.md");
6302
7870
  }
6303
7871
  get compressionGuidelineStatePath() {
6304
- return path9.join(this.stateDir, "compression-guideline-state.json");
7872
+ return path10.join(this.stateDir, "compression-guideline-state.json");
6305
7873
  }
6306
7874
  get compressionGuidelineDraftStatePath() {
6307
- return path9.join(this.stateDir, "compression-guideline-draft-state.json");
7875
+ return path10.join(this.stateDir, "compression-guideline-draft-state.json");
6308
7876
  }
6309
7877
  get behaviorSignalsPath() {
6310
- return path9.join(this.stateDir, "behavior-signals.jsonl");
7878
+ return path10.join(this.stateDir, "behavior-signals.jsonl");
6311
7879
  }
6312
7880
  /**
6313
7881
  * In-memory dedup key set for behavior-signals appends (issue #1909),
@@ -6339,7 +7907,7 @@ var StorageManager3 = class _StorageManager {
6339
7907
  * governance sweeps can treat it uniformly.
6340
7908
  */
6341
7909
  get bufferSurpriseLedgerPath() {
6342
- return path9.join(this.stateDir, "buffer-surprise-ledger.jsonl");
7910
+ return path10.join(this.stateDir, "buffer-surprise-ledger.jsonl");
6343
7911
  }
6344
7912
  /**
6345
7913
  * Entity alias table loaded from THIS store's config/aliases.json.
@@ -6349,8 +7917,17 @@ var StorageManager3 = class _StorageManager {
6349
7917
  * store loaded last rewrite every other store's canonical entity ids.
6350
7918
  */
6351
7919
  userAliases = {};
7920
+ historicalEntityCanonicalIds = {};
7921
+ entityCanonicalIdMigration = new EntityCanonicalIdMigrationRunner(
7922
+ () => !(this._secureStoreRequired && !this.isSecureStoreUnlocked()),
7923
+ () => this.runLegacyEntityCanonicalIdMigration(),
7924
+ () => getFingerprint(this.baseDir, this.entitiesDir, () => this.getCorpusScanVersion())
7925
+ );
6352
7926
  normalizeEntityName(raw, type) {
6353
- return this.entityStore.normalizeEntityName(raw, type);
7927
+ return resolveHistoricalEntityCanonicalId(
7928
+ this.entityStore.normalizeEntityName(raw, type),
7929
+ this.historicalEntityCanonicalIds
7930
+ );
6354
7931
  }
6355
7932
  /**
6356
7933
  * Read-only view of this store's user alias table, for call sites that
@@ -6370,10 +7947,10 @@ var StorageManager3 = class _StorageManager {
6370
7947
  this.loadAliasesSync();
6371
7948
  }
6372
7949
  loadAliasesSync() {
6373
- const aliasPath = path9.join(this.baseDir, "config", "aliases.json");
7950
+ const aliasPath = path10.join(this.baseDir, "config", "aliases.json");
6374
7951
  this.userAliases = {};
6375
7952
  try {
6376
- const raw = readFileSync(aliasPath, "utf-8");
7953
+ const raw = readFileSync2(aliasPath, "utf-8");
6377
7954
  const parsed = JSON.parse(raw);
6378
7955
  if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
6379
7956
  const cleaned = {};
@@ -6391,11 +7968,26 @@ var StorageManager3 = class _StorageManager {
6391
7968
  log.debug("no config/aliases.json found \u2014 using built-in aliases only");
6392
7969
  }
6393
7970
  }
7971
+ loadHistoricalEntityCanonicalIdsSync() {
7972
+ this.historicalEntityCanonicalIds = loadHistoricalEntityCanonicalIds(this.stateDir);
7973
+ }
7974
+ async runLegacyEntityCanonicalIdMigration() {
7975
+ const completionFingerprint = await runLegacyEntityCanonicalIdMigration(
7976
+ this,
7977
+ (content) => parseEntityFile(content, this.entitySchemas),
7978
+ (entity) => serializeEntityFile(entity, this.entitySchemas),
7979
+ createMemoryEntityRefSerializer(serializeFrontmatter)
7980
+ );
7981
+ this.loadHistoricalEntityCanonicalIdsSync();
7982
+ return completionFingerprint;
7983
+ }
6394
7984
  async ensureDirectories() {
7985
+ await mkdir2(this.baseDir, { recursive: true });
7986
+ await validateRoots(this.baseDir, this.entitiesDir, this.stateDir, this.archiveDir);
6395
7987
  const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
6396
- await mkdir2(path9.join(this.factsDir, today), { recursive: true });
6397
- await mkdir2(path9.join(this.proceduresDir, today), { recursive: true });
6398
- await mkdir2(path9.join(this.reasoningTracesDir, today), { recursive: true });
7988
+ await mkdir2(path10.join(this.factsDir, today), { recursive: true });
7989
+ await mkdir2(path10.join(this.proceduresDir, today), { recursive: true });
7990
+ await mkdir2(path10.join(this.reasoningTracesDir, today), { recursive: true });
6399
7991
  await mkdir2(this.correctionsDir, { recursive: true });
6400
7992
  await mkdir2(this.entitiesDir, { recursive: true });
6401
7993
  await mkdir2(this.stateDir, { recursive: true });
@@ -6405,10 +7997,12 @@ var StorageManager3 = class _StorageManager {
6405
7997
  await mkdir2(this.identityIncidentsDir, { recursive: true });
6406
7998
  await mkdir2(this.identityAuditsWeeklyDir, { recursive: true });
6407
7999
  await mkdir2(this.identityAuditsMonthlyDir, { recursive: true });
6408
- await mkdir2(path9.join(this.baseDir, "config"), { recursive: true });
8000
+ await mkdir2(path10.join(this.baseDir, "config"), { recursive: true });
8001
+ await this.entityCanonicalIdMigration.ensure();
6409
8002
  if (this.hotMemoriesCacheEnabled && this.getMemoryCorpusVersion() === 0) {
6410
8003
  this.bumpMemoryCorpusVersion();
6411
8004
  }
8005
+ await this.entityCanonicalIdMigration.markDirectoriesInitialized();
6412
8006
  }
6413
8007
  /**
6414
8008
  * Resolve the on-disk write path for a memory of the given category, creating
@@ -6425,11 +8019,11 @@ var StorageManager3 = class _StorageManager {
6425
8019
  async resolveCategoryWritePath(category, id, today) {
6426
8020
  if (category === "correction") {
6427
8021
  await mkdir2(this.correctionsDir, { recursive: true });
6428
- return path9.join(this.correctionsDir, `${id}.md`);
8022
+ return path10.join(this.correctionsDir, `${id}.md`);
6429
8023
  }
6430
- const datedDir = path9.join(getCategoryDir(this.baseDir, category), today);
8024
+ const datedDir = path10.join(getCategoryDir(this.baseDir, category), today);
6431
8025
  await mkdir2(datedDir, { recursive: true });
6432
- return path9.join(datedDir, `${id}.md`);
8026
+ return path10.join(datedDir, `${id}.md`);
6433
8027
  }
6434
8028
  async writeMemory(category, content, options = {}) {
6435
8029
  await this.ensureDirectories();
@@ -6734,7 +8328,7 @@ ${sanitized.text}
6734
8328
  await this.ensureDirectories();
6735
8329
  const now = /* @__PURE__ */ new Date();
6736
8330
  const day = now.toISOString().slice(0, 10);
6737
- const dir = path9.join(this.artifactsDir, day);
8331
+ const dir = path10.join(this.artifactsDir, day);
6738
8332
  await mkdir2(dir, { recursive: true });
6739
8333
  const id = `artifact-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`;
6740
8334
  const fm = {
@@ -6759,7 +8353,7 @@ ${sanitized.text}
6759
8353
  log.warn(`artifact content rejected for ${id}; violations=${sanitized.violations.join(", ")}`);
6760
8354
  return "";
6761
8355
  }
6762
- const filePath = path9.join(dir, `${id}.md`);
8356
+ const filePath = path10.join(dir, `${id}.md`);
6763
8357
  await this.writeStorageSecureFile(filePath, `${serializeFrontmatter(fm)}
6764
8358
 
6765
8359
  ${sanitized.text}
@@ -6812,14 +8406,12 @@ ${sanitized.text}
6812
8406
  }
6813
8407
  }
6814
8408
  async writeProfile(content) {
8409
+ const stampedContent = renderProfileWithLastUpdated(content, (/* @__PURE__ */ new Date()).toISOString());
6815
8410
  await this.ensureDirectories();
6816
8411
  await this.snapshotBeforeWrite(this.profilePath, "consolidation");
6817
- await this.writeStorageSecureFile(this.profilePath, content);
8412
+ await this.writeStorageSecureFile(this.profilePath, stampedContent);
6818
8413
  log.debug("updated profile.md");
6819
8414
  }
6820
- /**
6821
- * Normalize a string for fuzzy profile dedup: lowercase, strip punctuation, collapse whitespace.
6822
- */
6823
8415
  static normalizeForDedup(s) {
6824
8416
  if (typeof s !== "string") return "";
6825
8417
  return s.toLowerCase().replace(/[^a-z0-9\s]/g, " ").replace(/\s+/g, " ").trim();
@@ -6855,15 +8447,12 @@ ${sanitized.text}
6855
8447
  const content = [
6856
8448
  "# Behavioral Profile",
6857
8449
  "",
6858
- `*Last updated: ${(/* @__PURE__ */ new Date()).toISOString()}*`,
6859
- "",
6860
8450
  ...newBullets.map((b) => `- ${b}`),
6861
8451
  ""
6862
8452
  ].join("\n");
6863
8453
  await this.writeProfile(content);
6864
8454
  } else {
6865
- const updatedTimestamp = existing.replace(/\*Last updated:.*\*/, `*Last updated: ${(/* @__PURE__ */ new Date()).toISOString()}*`);
6866
- const withBullets = updatedTimestamp.trimEnd() + "\n" + newBullets.map((b) => `- ${b}`).join("\n") + "\n";
8455
+ const withBullets = existing.trimEnd() + "\n" + newBullets.map((b) => `- ${b}`).join("\n") + "\n";
6867
8456
  await this.writeProfile(withBullets);
6868
8457
  }
6869
8458
  }
@@ -7035,7 +8624,7 @@ ${sanitized.text}
7035
8624
  * per-process in-memory cache safe across process boundaries.
7036
8625
  */
7037
8626
  invalidateColdMemoriesCache() {
7038
- const coldRoot = path9.join(this.baseDir, "cold");
8627
+ const coldRoot = path10.join(this.baseDir, "cold");
7039
8628
  _StorageManager.coldMemoriesCache.delete(coldRoot);
7040
8629
  this.bumpColdWriteVersion();
7041
8630
  invalidateAllForDir(this.baseDir);
@@ -7095,7 +8684,7 @@ ${sanitized.text}
7095
8684
  const raw = await readMaybeEncryptedFile(fullPath, this._secureStoreKey, this.baseDir);
7096
8685
  const parsed = parseFrontmatter(raw);
7097
8686
  if (!parsed) return null;
7098
- return {
8687
+ return rememberRawFrontmatter({
7099
8688
  path: fullPath,
7100
8689
  frontmatter: normalizeFrontmatterForPath(
7101
8690
  parsed.frontmatter,
@@ -7103,7 +8692,7 @@ ${sanitized.text}
7103
8692
  parsed.content
7104
8693
  ),
7105
8694
  content: parsed.content
7106
- };
8695
+ }, raw);
7107
8696
  } catch (err) {
7108
8697
  if (err instanceof SecureStoreLockedError) throw err;
7109
8698
  return null;
@@ -7150,7 +8739,7 @@ ${sanitized.text}
7150
8739
  const correctionPaths = [];
7151
8740
  const factPaths = [];
7152
8741
  for (const filePath of filePaths) {
7153
- if (filePath === this.correctionsDir || filePath.startsWith(`${this.correctionsDir}${path9.sep}`)) {
8742
+ if (filePath === this.correctionsDir || filePath.startsWith(`${this.correctionsDir}${path10.sep}`)) {
7154
8743
  correctionPaths.push(filePath);
7155
8744
  } else {
7156
8745
  factPaths.push(filePath);
@@ -7211,9 +8800,9 @@ ${sanitized.text}
7211
8800
  const root = this.archiveDir;
7212
8801
  const readDir = async (dir) => {
7213
8802
  try {
7214
- const entries = await readdir4(dir, { withFileTypes: true });
8803
+ const entries = await readdir5(dir, { withFileTypes: true });
7215
8804
  for (const entry of entries) {
7216
- const fullPath = path9.join(dir, entry.name);
8805
+ const fullPath = path10.join(dir, entry.name);
7217
8806
  if (entry.isDirectory()) {
7218
8807
  await readDir(fullPath);
7219
8808
  } else if (entry.name.endsWith(".md")) {
@@ -7221,7 +8810,7 @@ ${sanitized.text}
7221
8810
  const raw = await readMaybeEncryptedFile(fullPath, this._secureStoreKey, this.baseDir);
7222
8811
  const parsed = parseFrontmatter(raw);
7223
8812
  if (parsed) {
7224
- memories.push({
8813
+ memories.push(rememberRawFrontmatter({
7225
8814
  path: fullPath,
7226
8815
  frontmatter: normalizeFrontmatterForPath(
7227
8816
  parsed.frontmatter,
@@ -7229,7 +8818,7 @@ ${sanitized.text}
7229
8818
  parsed.content
7230
8819
  ),
7231
8820
  content: parsed.content
7232
- });
8821
+ }, raw));
7233
8822
  }
7234
8823
  } catch (err) {
7235
8824
  if (err instanceof SecureStoreLockedError) throw err;
@@ -7246,7 +8835,7 @@ ${sanitized.text}
7246
8835
  return this.memoryReadStore.readMemoryByPath(filePath);
7247
8836
  }
7248
8837
  resolveTierRootDir(tier) {
7249
- return tier === "cold" ? path9.join(this.baseDir, "cold") : this.baseDir;
8838
+ return tier === "cold" ? path10.join(this.baseDir, "cold") : this.baseDir;
7250
8839
  }
7251
8840
  resolveMemoryDateDir(memory) {
7252
8841
  const preferred = memory.frontmatter.created || memory.frontmatter.updated;
@@ -7261,13 +8850,13 @@ ${sanitized.text}
7261
8850
  buildTierMemoryPath(memory, tier) {
7262
8851
  const root = this.resolveTierRootDir(tier);
7263
8852
  if (this.isArtifactMemory(memory)) {
7264
- return path9.join(root, "artifacts", this.resolveMemoryDateDir(memory), `${memory.frontmatter.id}.md`);
8853
+ return path10.join(root, "artifacts", this.resolveMemoryDateDir(memory), `${memory.frontmatter.id}.md`);
7265
8854
  }
7266
8855
  if (memory.frontmatter.category === "correction") {
7267
- return path9.join(root, "corrections", `${memory.frontmatter.id}.md`);
8856
+ return path10.join(root, "corrections", `${memory.frontmatter.id}.md`);
7268
8857
  }
7269
8858
  const dir = categoryDirName(memory.frontmatter.category);
7270
- return path9.join(root, dir, this.resolveMemoryDateDir(memory), `${memory.frontmatter.id}.md`);
8859
+ return path10.join(root, dir, this.resolveMemoryDateDir(memory), `${memory.frontmatter.id}.md`);
7271
8860
  }
7272
8861
  async writeMemoryFileAtomic(targetPath, memory) {
7273
8862
  const fileContent = `${serializeFrontmatter(memory.frontmatter)}
@@ -7280,11 +8869,11 @@ ${memory.content}
7280
8869
  }
7281
8870
  async moveMemoryToPath(memory, targetPath) {
7282
8871
  await this.writeMemoryFileAtomic(targetPath, memory);
7283
- const sourcePath = path9.resolve(memory.path);
7284
- const destPath = path9.resolve(targetPath);
8872
+ const sourcePath = path10.resolve(memory.path);
8873
+ const destPath = path10.resolve(targetPath);
7285
8874
  if (sourcePath !== destPath) {
7286
8875
  try {
7287
- await unlink2(memory.path);
8876
+ await unlink3(memory.path);
7288
8877
  } catch (err) {
7289
8878
  const message = err instanceof Error ? err.message : String(err);
7290
8879
  if (!message.includes("ENOENT")) {
@@ -7297,15 +8886,15 @@ ${memory.content}
7297
8886
  }
7298
8887
  async migrateMemoryToTier(memory, targetTier) {
7299
8888
  const targetPath = this.buildTierMemoryPath(memory, targetTier);
7300
- const sourcePath = path9.resolve(memory.path);
7301
- const destPath = path9.resolve(targetPath);
8889
+ const sourcePath = path10.resolve(memory.path);
8890
+ const destPath = path10.resolve(targetPath);
7302
8891
  if (sourcePath === destPath) {
7303
8892
  return { changed: false, targetPath };
7304
8893
  }
7305
8894
  const existing = await this.readMemoryByPath(targetPath);
7306
8895
  if (existing?.frontmatter.id === memory.frontmatter.id) {
7307
8896
  try {
7308
- await unlink2(memory.path);
8897
+ await unlink3(memory.path);
7309
8898
  } catch (err) {
7310
8899
  const message = err instanceof Error ? err.message : String(err);
7311
8900
  if (!message.includes("ENOENT")) {
@@ -7325,7 +8914,7 @@ ${memory.content}
7325
8914
  return { changed: true, targetPath };
7326
8915
  }
7327
8916
  get archiveDir() {
7328
- return path9.join(this.baseDir, "archive");
8917
+ return path10.join(this.baseDir, "archive");
7329
8918
  }
7330
8919
  /**
7331
8920
  * Archive a memory by moving it from facts/ to archive/YYYY-MM-DD/.
@@ -7336,7 +8925,7 @@ ${memory.content}
7336
8925
  try {
7337
8926
  const now = lifecycle?.at ?? /* @__PURE__ */ new Date();
7338
8927
  const today = now.toISOString().slice(0, 10);
7339
- const destDir = path9.join(this.archiveDir, today);
8928
+ const destDir = path10.join(this.archiveDir, today);
7340
8929
  await mkdir2(destDir, { recursive: true });
7341
8930
  const updatedFm = {
7342
8931
  ...memory.frontmatter,
@@ -7348,9 +8937,9 @@ ${memory.content}
7348
8937
 
7349
8938
  ${memory.content}
7350
8939
  `;
7351
- const destPath = path9.join(destDir, path9.basename(memory.path));
8940
+ const destPath = path10.join(destDir, path10.basename(memory.path));
7352
8941
  await this.writeStorageSecureFile(destPath, fileContent);
7353
- await unlink2(memory.path);
8942
+ await unlink3(memory.path);
7354
8943
  markProjectedMemoryPathInvalid(this.baseDir, memory.frontmatter.id);
7355
8944
  this.invalidateAllMemoriesCache();
7356
8945
  await this.appendGeneratedMemoryLifecycleEventFailOpen(
@@ -7378,7 +8967,7 @@ ${memory.content}
7378
8967
  }
7379
8968
  async readEntities() {
7380
8969
  try {
7381
- const entries = await readdir4(this.entitiesDir);
8970
+ const entries = await readdir5(this.entitiesDir);
7382
8971
  return entries.filter((e) => e.endsWith(".md")).map((e) => e.replace(".md", ""));
7383
8972
  } catch {
7384
8973
  return [];
@@ -7430,7 +9019,7 @@ ${memory.content}
7430
9019
  const memory = memories.find((m) => m.frontmatter.id === id);
7431
9020
  if (!memory) return false;
7432
9021
  try {
7433
- await unlink2(memory.path);
9022
+ await unlink3(memory.path);
7434
9023
  markProjectedMemoryPathInvalid(this.baseDir, id);
7435
9024
  this.invalidateAllMemoriesCache();
7436
9025
  this.bumpMemoryStatusVersion();
@@ -7496,7 +9085,7 @@ ${memory.content}
7496
9085
  `;
7497
9086
  await this.writeStorageSecureFile(memory.path, fileContent);
7498
9087
  await this.patchHotMemoriesCache({ addedPath: memory.path });
7499
- if (memory.path.includes(`${path9.sep}cold${path9.sep}`)) {
9088
+ if (memory.path.includes(`${path10.sep}cold${path10.sep}`)) {
7500
9089
  this.invalidateColdMemoriesCache();
7501
9090
  }
7502
9091
  try {
@@ -7551,7 +9140,7 @@ ${memory.content}
7551
9140
  const expiresAt = new Date(m.frontmatter.expiresAt).getTime();
7552
9141
  if (expiresAt < now) {
7553
9142
  try {
7554
- await unlink2(m.path);
9143
+ await unlink3(m.path);
7555
9144
  markProjectedMemoryPathInvalid(this.baseDir, m.frontmatter.id);
7556
9145
  this.bumpMemoryCorpusVersion();
7557
9146
  deleted.push(m);
@@ -7567,7 +9156,7 @@ ${memory.content}
7567
9156
  return deleted;
7568
9157
  }
7569
9158
  async loadBuffer() {
7570
- const bufferPath = path9.join(this.stateDir, "buffer.json");
9159
+ const bufferPath = path10.join(this.stateDir, "buffer.json");
7571
9160
  try {
7572
9161
  const raw = await this.readStorageSecureFile(bufferPath);
7573
9162
  return JSON.parse(raw);
@@ -7579,11 +9168,11 @@ ${memory.content}
7579
9168
  }
7580
9169
  async saveBuffer(state) {
7581
9170
  await this.ensureDirectories();
7582
- const bufferPath = path9.join(this.stateDir, "buffer.json");
9171
+ const bufferPath = path10.join(this.stateDir, "buffer.json");
7583
9172
  await this.writeStorageSecureFile(bufferPath, JSON.stringify(state, null, 2));
7584
9173
  }
7585
9174
  async loadMeta() {
7586
- const metaPath = path9.join(this.stateDir, "meta.json");
9175
+ const metaPath = path10.join(this.stateDir, "meta.json");
7587
9176
  try {
7588
9177
  const raw = await this.readStorageSecureFile(metaPath);
7589
9178
  const parsed = JSON.parse(raw);
@@ -7616,7 +9205,7 @@ ${memory.content}
7616
9205
  }
7617
9206
  async saveMeta(state) {
7618
9207
  await this.ensureDirectories();
7619
- const metaPath = path9.join(this.stateDir, "meta.json");
9208
+ const metaPath = path10.join(this.stateDir, "meta.json");
7620
9209
  await this.writeStorageSecureFile(metaPath, JSON.stringify(state, null, 2));
7621
9210
  }
7622
9211
  async appendMemoryActionEvents(events) {
@@ -7683,7 +9272,7 @@ ${memory.content}
7683
9272
  },
7684
9273
  (payload) => this.appendStorageSecureFile(target, payload),
7685
9274
  async () => {
7686
- await mkdir2(path9.dirname(target), { recursive: true });
9275
+ await mkdir2(path10.dirname(target), { recursive: true });
7687
9276
  }
7688
9277
  );
7689
9278
  }
@@ -7781,7 +9370,7 @@ ${memory.content}
7781
9370
  async appendReextractJobs(events) {
7782
9371
  if (events.length === 0) return 0;
7783
9372
  await this.ensureDirectories();
7784
- const filePath = path9.join(this.stateDir, "reextract-jobs.jsonl");
9373
+ const filePath = path10.join(this.stateDir, "reextract-jobs.jsonl");
7785
9374
  const lines = events.map((event) => JSON.stringify(event)).join("\n") + "\n";
7786
9375
  try {
7787
9376
  await this.appendStorageSecureFile(filePath, lines);
@@ -7794,7 +9383,7 @@ ${memory.content}
7794
9383
  }
7795
9384
  async readReextractJobs(limit = 200) {
7796
9385
  const safeLimit = Number.isFinite(limit) ? Math.max(1, Math.min(1e3, Math.floor(limit))) : 200;
7797
- const filePath = path9.join(this.stateDir, "reextract-jobs.jsonl");
9386
+ const filePath = path10.join(this.stateDir, "reextract-jobs.jsonl");
7798
9387
  try {
7799
9388
  const raw = await this.readStorageSecureFile(filePath);
7800
9389
  const lines = raw.split("\n").filter((line) => line.trim().length > 0);
@@ -7955,8 +9544,8 @@ ${memory.content}
7955
9544
  activationState: "active"
7956
9545
  });
7957
9546
  await Promise.all([
7958
- unlink2(this.compressionGuidelineDraftPath).catch(() => void 0),
7959
- unlink2(this.compressionGuidelineDraftStatePath).catch(() => void 0)
9547
+ unlink3(this.compressionGuidelineDraftPath).catch(() => void 0),
9548
+ unlink3(this.compressionGuidelineDraftStatePath).catch(() => void 0)
7960
9549
  ]);
7961
9550
  return true;
7962
9551
  }
@@ -8024,7 +9613,7 @@ ${question}
8024
9613
 
8025
9614
  **Context:** ${context}
8026
9615
  `;
8027
- const filePath = path9.join(this.questionsDir, `${id}.md`);
9616
+ const filePath = path10.join(this.questionsDir, `${id}.md`);
8028
9617
  await this.writeStorageSecureFile(filePath, content);
8029
9618
  log.debug(`wrote question ${id} to ${filePath}`);
8030
9619
  this.invalidateQuestionsCache();
@@ -8042,7 +9631,7 @@ ${question}
8042
9631
  if (!match) return null;
8043
9632
  const frontmatterStr = match[1];
8044
9633
  const body = match[2].trim();
8045
- const id = this.extractFrontmatterValue(frontmatterStr, "id") ?? path9.basename(filePath, ".md");
9634
+ const id = this.extractFrontmatterValue(frontmatterStr, "id") ?? path10.basename(filePath, ".md");
8046
9635
  const created = this.extractFrontmatterValue(frontmatterStr, "created") ?? "";
8047
9636
  const priority = parseFloat(this.extractFrontmatterValue(frontmatterStr, "priority") ?? "0.5");
8048
9637
  const resolved = this.extractFrontmatterValue(frontmatterStr, "resolved") === "true";
@@ -8076,14 +9665,14 @@ ${question}
8076
9665
  async readIdentity(workspaceDir, namespace) {
8077
9666
  const identityPath = this.identityFilePath(workspaceDir, namespace);
8078
9667
  try {
8079
- return await readFile(identityPath, "utf-8");
9668
+ return await readFile2(identityPath, "utf-8");
8080
9669
  } catch {
8081
9670
  return "";
8082
9671
  }
8083
9672
  }
8084
9673
  async writeIdentity(workspaceDir, content, namespace) {
8085
9674
  const identityPath = this.identityFilePath(workspaceDir, namespace);
8086
- await writeFile(identityPath, content, "utf-8");
9675
+ await writeFile2(identityPath, content, "utf-8");
8087
9676
  log.debug(`wrote consolidated IDENTITY.md (${content.length} chars)`);
8088
9677
  }
8089
9678
  /** Max size for IDENTITY.md before we stop appending reflections (15KB leaves room under 20KB gateway limit) */
@@ -8094,22 +9683,22 @@ ${question}
8094
9683
  const identityPath = this.identityFilePath(workspaceDir, opts?.namespace);
8095
9684
  let existing = "";
8096
9685
  try {
8097
- existing = await readFile(identityPath, "utf-8");
9686
+ existing = await readFile2(identityPath, "utf-8");
8098
9687
  } catch {
8099
9688
  }
8100
9689
  const hygiene = opts?.hygiene;
8101
- const rotateEnabled = hygiene?.enabled === true && hygiene.rotateEnabled === true && Array.isArray(hygiene.rotatePaths) && hygiene.rotatePaths.includes(path9.basename(identityPath));
9690
+ const rotateEnabled = hygiene?.enabled === true && hygiene.rotateEnabled === true && Array.isArray(hygiene.rotatePaths) && hygiene.rotatePaths.includes(path10.basename(identityPath));
8102
9691
  if (rotateEnabled) {
8103
9692
  const maxBytes = hygiene.rotateMaxBytes;
8104
9693
  if (existing.length > maxBytes) {
8105
- const archiveDir = path9.join(workspaceDir, hygiene.archiveDir);
9694
+ const archiveDir = path10.join(workspaceDir, hygiene.archiveDir);
8106
9695
  const { newContent } = await rotateMarkdownFileToArchive({
8107
9696
  filePath: identityPath,
8108
9697
  archiveDir,
8109
9698
  archivePrefix: "IDENTITY",
8110
9699
  keepTailChars: hygiene.rotateKeepTailChars
8111
9700
  });
8112
- await writeFile(identityPath, newContent, "utf-8");
9701
+ await writeFile2(identityPath, newContent, "utf-8");
8113
9702
  existing = newContent;
8114
9703
  log.info(`rotated IDENTITY.md to archive (size=${existing.length} chars, maxBytes=${maxBytes})`);
8115
9704
  }
@@ -8142,7 +9731,7 @@ ${question}
8142
9731
 
8143
9732
  ${reflection}
8144
9733
  `;
8145
- await writeFile(identityPath, existing + section, "utf-8");
9734
+ await writeFile2(identityPath, existing + section, "utf-8");
8146
9735
  log.debug(`appended reflection to ${identityPath}`);
8147
9736
  }
8148
9737
  async readIdentityReflections() {
@@ -8198,7 +9787,7 @@ ${reflection}
8198
9787
  * Deduplicates by target+label.
8199
9788
  */
8200
9789
  async addEntityRelationship(name, rel) {
8201
- const filePath = path9.join(this.entitiesDir, `${name}.md`);
9790
+ const filePath = path10.join(this.entitiesDir, `${name}.md`);
8202
9791
  let entity;
8203
9792
  try {
8204
9793
  const content = await this.readStorageSecureFile(filePath);
@@ -8221,7 +9810,7 @@ ${reflection}
8221
9810
  * Prepends to the beginning, prunes oldest entries beyond maxEntries.
8222
9811
  */
8223
9812
  async addEntityActivity(name, entry, maxEntries) {
8224
- const filePath = path9.join(this.entitiesDir, `${name}.md`);
9813
+ const filePath = path10.join(this.entitiesDir, `${name}.md`);
8225
9814
  let entity;
8226
9815
  try {
8227
9816
  const content = await this.readStorageSecureFile(filePath);
@@ -8240,11 +9829,8 @@ ${reflection}
8240
9829
  await this.writeStorageSecureFile(filePath, serializeEntityFile(entity, this.entitySchemas));
8241
9830
  this.invalidateKnowledgeIndexCache();
8242
9831
  }
8243
- /**
8244
- * Add an alias to an entity file. Deduplicates.
8245
- */
8246
9832
  async addEntityAlias(name, alias) {
8247
- const filePath = path9.join(this.entitiesDir, `${name}.md`);
9833
+ const filePath = path10.join(this.entitiesDir, `${name}.md`);
8248
9834
  let entity;
8249
9835
  try {
8250
9836
  const content = await this.readStorageSecureFile(filePath);
@@ -8260,6 +9846,7 @@ ${reflection}
8260
9846
  entity.updated = (/* @__PURE__ */ new Date()).toISOString();
8261
9847
  await this.writeStorageSecureFile(filePath, serializeEntityFile(entity, this.entitySchemas));
8262
9848
  this.invalidateKnowledgeIndexCache();
9849
+ this.bumpMemoryStatusVersion();
8263
9850
  }
8264
9851
  async updateEntitySynthesis(name, synthesis, options = {}) {
8265
9852
  return this.entityStore.updateEntitySynthesis(name, synthesis, options);
@@ -8271,7 +9858,7 @@ ${reflection}
8271
9858
  const updatedAt = (/* @__PURE__ */ new Date()).toISOString();
8272
9859
  let synthesisTimelineCount;
8273
9860
  try {
8274
- const filePath = path9.join(this.entitiesDir, `${name}.md`);
9861
+ const filePath = path10.join(this.entitiesDir, `${name}.md`);
8275
9862
  const content = await this.readStorageSecureFile(filePath);
8276
9863
  synthesisTimelineCount = parseEntityFile(content, this.entitySchemas).timeline.length;
8277
9864
  } catch (err) {
@@ -8354,7 +9941,7 @@ ${reflection}
8354
9941
  if (!raw) continue;
8355
9942
  const serialized = serializeEntityFile(parseEntityFile(raw, this.entitySchemas), this.entitySchemas);
8356
9943
  if (raw.trimEnd() === serialized.trimEnd()) continue;
8357
- await this.writeStorageSecureFile(path9.join(this.entitiesDir, `${entityName}.md`), serialized);
9944
+ await this.writeStorageSecureFile(path10.join(this.entitiesDir, `${entityName}.md`), serialized);
8358
9945
  migrated += 1;
8359
9946
  }
8360
9947
  if (migrated > 0) {
@@ -8422,7 +10009,7 @@ ${reflection}
8422
10009
  const updatedAt = new Date(m.frontmatter.updated).getTime();
8423
10010
  if (updatedAt < cutoff) {
8424
10011
  try {
8425
- await unlink2(m.path);
10012
+ await unlink3(m.path);
8426
10013
  markProjectedMemoryPathInvalid(this.baseDir, m.frontmatter.id);
8427
10014
  this.bumpMemoryCorpusVersion();
8428
10015
  deleted.push(m);
@@ -8447,14 +10034,14 @@ ${reflection}
8447
10034
  if (entries.length === 0) return 0;
8448
10035
  const memories = await this.readAllMemories();
8449
10036
  const memoryMap = new Map(memories.map((m) => [m.frontmatter.id, m]));
8450
- const memoryPathMap = new Map(memories.map((m) => [path9.resolve(m.path), m]));
10037
+ const memoryPathMap = new Map(memories.map((m) => [path10.resolve(m.path), m]));
8451
10038
  let updated = 0;
8452
10039
  const prevVersion = this.getMemoryCorpusVersion();
8453
10040
  const keyId = this.hotCacheKeyId();
8454
10041
  const warm = this.hotMemoriesCacheEnabled && getCachedMemories(this.baseDir, prevVersion, keyId, this.hotCacheTtlMs()) !== null;
8455
10042
  const appliedPatches = /* @__PURE__ */ new Map();
8456
10043
  for (const entry of entries) {
8457
- const memory = entry.memoryPath ? memoryPathMap.get(path9.resolve(entry.memoryPath)) : memoryMap.get(entry.memoryId);
10044
+ const memory = entry.memoryPath ? memoryPathMap.get(path10.resolve(entry.memoryPath)) : memoryMap.get(entry.memoryId);
8458
10045
  if (!memory) continue;
8459
10046
  const newFm = {
8460
10047
  ...memory.frontmatter,
@@ -8470,7 +10057,7 @@ ${memory.content}
8470
10057
  if (warm) {
8471
10058
  updateCacheOnWrite(this.baseDir, { ...memory, frontmatter: newFm }, keyId);
8472
10059
  }
8473
- appliedPatches.set(path9.resolve(memory.path), {
10060
+ appliedPatches.set(path10.resolve(memory.path), {
8474
10061
  accessCount: entry.newCount,
8475
10062
  lastAccessed: entry.lastAccessed
8476
10063
  });
@@ -8486,7 +10073,7 @@ ${memory.content}
8486
10073
  const cur = getCachedMemories(this.baseDir, prevVersion, keyId);
8487
10074
  if (cur) {
8488
10075
  const reapplied = cur.map((m) => {
8489
- const patch = appliedPatches.get(path9.resolve(m.path));
10076
+ const patch = appliedPatches.get(path10.resolve(m.path));
8490
10077
  return patch ? { ...m, frontmatter: { ...m.frontmatter, accessCount: patch.accessCount, lastAccessed: patch.lastAccessed } } : m;
8491
10078
  });
8492
10079
  setCachedMemories(this.baseDir, reapplied, produced, keyId, this.hotCacheTtlMs());
@@ -8518,7 +10105,7 @@ ${memory.content}
8518
10105
  const pathsById = /* @__PURE__ */ new Map();
8519
10106
  const filePathsById = /* @__PURE__ */ new Map();
8520
10107
  for (const filePath of filePaths) {
8521
- const memoryId = path9.basename(filePath, ".md");
10108
+ const memoryId = path10.basename(filePath, ".md");
8522
10109
  if (!wantedIds.has(memoryId)) continue;
8523
10110
  const paths = filePathsById.get(memoryId) ?? [];
8524
10111
  paths.push(filePath);
@@ -8533,7 +10120,7 @@ ${memory.content}
8533
10120
  qmdResultPathCandidates(this.baseDir, preferredPath)
8534
10121
  );
8535
10122
  const directMatch = existingPaths.find(
8536
- (filePath) => directCandidates.has(path9.resolve(filePath))
10123
+ (filePath) => directCandidates.has(path10.resolve(filePath))
8537
10124
  );
8538
10125
  if (directMatch) {
8539
10126
  preferredMatches.push(directMatch);
@@ -8546,7 +10133,7 @@ ${memory.content}
8546
10133
  candidates.add(candidate);
8547
10134
  }
8548
10135
  }
8549
- const match = existingPaths.find((filePath) => candidates.has(path9.resolve(filePath)));
10136
+ const match = existingPaths.find((filePath) => candidates.has(path10.resolve(filePath)));
8550
10137
  if (match) preferredMatches.push(match);
8551
10138
  }
8552
10139
  if (preferredMatches.length > 0) {
@@ -8765,14 +10352,14 @@ Reason: ${reason}`;
8765
10352
  // Memory Summarization (Phase 4A)
8766
10353
  // ---------------------------------------------------------------------------
8767
10354
  get summariesDir() {
8768
- return path9.join(this.baseDir, "summaries");
10355
+ return path10.join(this.baseDir, "summaries");
8769
10356
  }
8770
10357
  /**
8771
10358
  * Write a memory summary.
8772
10359
  */
8773
10360
  async writeSummary(summary) {
8774
10361
  await mkdir2(this.summariesDir, { recursive: true });
8775
- const filePath = path9.join(this.summariesDir, `${summary.id}.json`);
10362
+ const filePath = path10.join(this.summariesDir, `${summary.id}.json`);
8776
10363
  await this.writeStorageSecureFile(filePath, JSON.stringify(summary, null, 2));
8777
10364
  log.debug(`wrote summary ${summary.id}`);
8778
10365
  }
@@ -8781,11 +10368,11 @@ Reason: ${reason}`;
8781
10368
  */
8782
10369
  async readSummaries() {
8783
10370
  try {
8784
- const files = await readdir4(this.summariesDir);
10371
+ const files = await readdir5(this.summariesDir);
8785
10372
  const summaries = [];
8786
10373
  for (const file of files) {
8787
10374
  if (!file.endsWith(".json")) continue;
8788
- const filePath = path9.join(this.summariesDir, file);
10375
+ const filePath = path10.join(this.summariesDir, file);
8789
10376
  const raw = await this.readStorageSecureFile(filePath);
8790
10377
  summaries.push(JSON.parse(raw));
8791
10378
  }
@@ -8847,7 +10434,7 @@ ${memory.content}
8847
10434
  * Save topic scores to meta.json.
8848
10435
  */
8849
10436
  async saveTopics(topics) {
8850
- const metaPath = path9.join(this.stateDir, "topics.json");
10437
+ const metaPath = path10.join(this.stateDir, "topics.json");
8851
10438
  await mkdir2(this.stateDir, { recursive: true });
8852
10439
  await this.writeStorageSecureFile(
8853
10440
  metaPath,
@@ -8859,7 +10446,7 @@ ${memory.content}
8859
10446
  * Load topic scores from meta.json.
8860
10447
  */
8861
10448
  async loadTopics() {
8862
- const metaPath = path9.join(this.stateDir, "topics.json");
10449
+ const metaPath = path10.join(this.stateDir, "topics.json");
8863
10450
  try {
8864
10451
  const raw = await this.readStorageSecureFile(metaPath);
8865
10452
  return JSON.parse(raw);
@@ -8975,11 +10562,10 @@ export {
8975
10562
  parseFrontmatterStringValue,
8976
10563
  parseFrontmatter,
8977
10564
  normalizeFrontmatterForPath,
8978
- normalizeEntityName,
8979
10565
  parseEntityFile,
8980
10566
  serializeEntityFile,
8981
10567
  buildEntitySchemaCacheKey,
8982
10568
  isValidBufferSurpriseEvent,
8983
10569
  StorageManager3 as StorageManager
8984
10570
  };
8985
- //# sourceMappingURL=chunk-UZK7VVPD.js.map
10571
+ //# sourceMappingURL=chunk-Q5VJUNXA.js.map