@remnic/core 9.3.753 → 9.3.755

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 (290) hide show
  1. package/dist/access-admin-ops-surface.d.ts +5 -5
  2. package/dist/access-admin-ops-surface.js +26 -26
  3. package/dist/access-boundary.d.ts +5 -5
  4. package/dist/access-boundary.js +27 -27
  5. package/dist/access-cli.js +75 -75
  6. package/dist/access-http.d.ts +5 -5
  7. package/dist/access-http.js +34 -34
  8. package/dist/access-lcm-surface.d.ts +188 -0
  9. package/dist/access-lcm-surface.js +128 -0
  10. package/dist/access-lcm-surface.js.map +1 -0
  11. package/dist/access-mcp.d.ts +5 -5
  12. package/dist/access-mcp.js +31 -31
  13. package/dist/access-operations-batch.js +28 -28
  14. package/dist/access-operations.d.ts +9 -9
  15. package/dist/access-operations.js +30 -30
  16. package/dist/access-recall-surface.d.ts +5 -5
  17. package/dist/access-recall-surface.js +26 -26
  18. package/dist/access-schema.d.ts +70 -70
  19. package/dist/access-schema.js +6 -6
  20. package/dist/{access-service-MitduesD.d.ts → access-service-C3jkLi2U.d.ts} +7 -67
  21. package/dist/access-service.d.ts +5 -5
  22. package/dist/access-service.js +26 -26
  23. package/dist/access-surface-catalog.d.ts +5 -5
  24. package/dist/action-confidence.d.ts +1 -1
  25. package/dist/active-memory-bridge.d.ts +1 -1
  26. package/dist/active-recall.d.ts +1 -1
  27. package/dist/adapters/index.js +4 -4
  28. package/dist/adapters/registry.js +2 -2
  29. package/dist/{auto-sync-IEBKPGAM.js → auto-sync-G4YKBPOU.js} +5 -5
  30. package/dist/behavior-learner.d.ts +1 -1
  31. package/dist/behavior-signals.d.ts +1 -1
  32. package/dist/bootstrap.d.ts +4 -4
  33. package/dist/briefing.d.ts +1 -1
  34. package/dist/briefing.js +7 -7
  35. package/dist/buffer-surprise-report.d.ts +1 -1
  36. package/dist/buffer.d.ts +1 -1
  37. package/dist/calibration.d.ts +1 -1
  38. package/dist/calibration.js +2 -2
  39. package/dist/capabilities.d.ts +1 -1
  40. package/dist/{catalog-BEmNVRN0.d.ts → catalog-DaKAFbSJ.d.ts} +1 -1
  41. package/dist/causal-behavior.d.ts +1 -1
  42. package/dist/causal-consolidation.d.ts +1 -1
  43. package/dist/causal-consolidation.js +8 -8
  44. package/dist/causal-trajectory-graph.d.ts +1 -1
  45. package/dist/{chunk-HAZVVOYT.js → chunk-24463PIV.js} +2 -2
  46. package/dist/{chunk-GWGWBK5Y.js → chunk-2MR3MFQB.js} +7 -7
  47. package/dist/{chunk-YTU7WKYN.js → chunk-2OZ2JEUP.js} +2 -2
  48. package/dist/{chunk-AU7Q3LSC.js → chunk-2QSZNTDO.js} +4 -4
  49. package/dist/{chunk-EHYB325U.js → chunk-3DOD6ICJ.js} +2 -2
  50. package/dist/{chunk-KYHGLDFU.js → chunk-4LQUYBZM.js} +6 -6
  51. package/dist/{chunk-VUA4S7P6.js → chunk-5J4OL7TJ.js} +4 -4
  52. package/dist/{chunk-TVISHYL5.js → chunk-CIDGUFAL.js} +2 -2
  53. package/dist/{chunk-OUXPVWTZ.js → chunk-FLVL4L3L.js} +5 -5
  54. package/dist/{chunk-3HGZX26P.js → chunk-FOJY75BL.js} +8 -8
  55. package/dist/{chunk-VVSV2QVY.js → chunk-FQLM6ZUP.js} +3 -3
  56. package/dist/{chunk-LZ73Y56P.js → chunk-G7LCG56O.js} +4 -4
  57. package/dist/{chunk-ZECLLIMX.js → chunk-GCEV6SXP.js} +4989 -4960
  58. package/dist/chunk-GCEV6SXP.js.map +1 -0
  59. package/dist/{chunk-ZMHDSIEX.js → chunk-GGYUR4M2.js} +4 -4
  60. package/dist/{chunk-YNBEHUZH.js → chunk-GMWKWA6N.js} +2 -2
  61. package/dist/{chunk-JGPURIEH.js → chunk-GPFXPC2V.js} +2 -2
  62. package/dist/{chunk-E6LENGYV.js → chunk-H6S3DJVE.js} +2 -2
  63. package/dist/{chunk-E3MRYDUQ.js → chunk-I3UWEZTK.js} +2 -2
  64. package/dist/{chunk-ZIFPFKB2.js → chunk-I6IAJCJS.js} +2 -2
  65. package/dist/{chunk-JES2O5Q6.js → chunk-JITAVROY.js} +4 -4
  66. package/dist/{chunk-DKIZ4BUQ.js → chunk-KKOCFUI5.js} +7 -7
  67. package/dist/{chunk-LQ6JI4VH.js → chunk-LD53WPMU.js} +4 -4
  68. package/dist/{chunk-N3VE7OCY.js → chunk-LFKEFIJA.js} +2 -2
  69. package/dist/{chunk-EEO4YWQ7.js → chunk-N4AGSRVA.js} +2 -2
  70. package/dist/{chunk-QIRZI3C3.js → chunk-NCNOYM6F.js} +2 -2
  71. package/dist/{chunk-3ZIKDH6C.js → chunk-OCFITZRV.js} +4 -4
  72. package/dist/{chunk-ITLJATQI.js → chunk-PJ7DIEFC.js} +2 -2
  73. package/dist/{chunk-OZMBT7N3.js → chunk-PJQMISPD.js} +2 -2
  74. package/dist/{chunk-XOPLMSVV.js → chunk-S6UCPBPL.js} +2 -2
  75. package/dist/{chunk-243P7YYV.js → chunk-SP42M3XP.js} +2 -2
  76. package/dist/{chunk-DCWIQFNA.js → chunk-T422SYM6.js} +5 -5
  77. package/dist/{chunk-AXBRVBT6.js → chunk-T6WHI3JW.js} +2 -2
  78. package/dist/{chunk-5CEJH5ZN.js → chunk-TAPSNIMA.js} +4 -4
  79. package/dist/{chunk-3NN73CM7.js → chunk-TH7WMHVK.js} +2 -2
  80. package/dist/{chunk-RNWWAS5V.js → chunk-TJATYB3F.js} +11 -11
  81. package/dist/{chunk-C3IHRWIC.js → chunk-UQJ6YTKR.js} +2 -2
  82. package/dist/{chunk-PN5AMCK2.js → chunk-VL5QHTJI.js} +56 -56
  83. package/dist/{chunk-34THARMH.js → chunk-XBM5DG4O.js} +665 -577
  84. package/dist/chunk-XBM5DG4O.js.map +1 -0
  85. package/dist/{chunk-BWOEYBRB.js → chunk-XCXN3D2U.js} +2 -2
  86. package/dist/{chunk-KY4WOZ3P.js → chunk-XD6JVK5P.js} +42 -42
  87. package/dist/{chunk-WRFKZEO6.js → chunk-YQGHW5ML.js} +4 -4
  88. package/dist/{cli-DqonYBZ0.d.ts → cli-BJQ2ahrh.d.ts} +3 -3
  89. package/dist/cli.d.ts +6 -6
  90. package/dist/cli.js +55 -55
  91. package/dist/compounding/engine.d.ts +1 -1
  92. package/dist/compounding/engine.js +7 -7
  93. package/dist/compounding/preference-consolidator.d.ts +1 -1
  94. package/dist/compression-optimizer.d.ts +1 -1
  95. package/dist/config.d.ts +1 -1
  96. package/dist/connectors/codex-materialize-runner.d.ts +1 -1
  97. package/dist/connectors/codex-materialize-runner.js +7 -7
  98. package/dist/connectors/codex-materialize.d.ts +1 -1
  99. package/dist/connectors/index.d.ts +1 -1
  100. package/dist/connectors/index.js +7 -7
  101. package/dist/consolidation-provenance-check.d.ts +1 -1
  102. package/dist/consolidation-undo.d.ts +1 -1
  103. package/dist/contradiction/index.d.ts +1 -1
  104. package/dist/conversation-index/backend.d.ts +1 -1
  105. package/dist/conversation-index/backend.js +2 -2
  106. package/dist/conversation-index/chunker.d.ts +1 -1
  107. package/dist/conversation-index/faiss-adapter.d.ts +1 -1
  108. package/dist/conversation-index/indexer.d.ts +1 -1
  109. package/dist/conversation-index/search.d.ts +1 -1
  110. package/dist/day-summary.d.ts +1 -1
  111. package/dist/delinearize.d.ts +1 -1
  112. package/dist/direct-answer-wiring.d.ts +1 -1
  113. package/dist/direct-answer.d.ts +1 -1
  114. package/dist/embedding-fallback.d.ts +1 -1
  115. package/dist/enrichment/index.d.ts +1 -1
  116. package/dist/entity-retrieval.d.ts +1 -1
  117. package/dist/entity-retrieval.js +7 -7
  118. package/dist/entity-schema.d.ts +1 -1
  119. package/dist/explicit-capture.d.ts +4 -4
  120. package/dist/extraction-faithfulness.d.ts +1 -1
  121. package/dist/extraction-faithfulness.js +3 -3
  122. package/dist/extraction-judge-telemetry.d.ts +1 -1
  123. package/dist/extraction-judge-training.d.ts +1 -1
  124. package/dist/extraction-judge.d.ts +1 -1
  125. package/dist/extraction-judge.js +3 -3
  126. package/dist/extraction.d.ts +1 -1
  127. package/dist/extraction.js +3 -3
  128. package/dist/fallback-llm.d.ts +1 -1
  129. package/dist/fallback-llm.js +2 -2
  130. package/dist/graph-dashboard-diff.d.ts +1 -1
  131. package/dist/graph-dashboard-key.d.ts +1 -1
  132. package/dist/graph-dashboard-parser.d.ts +1 -1
  133. package/dist/graph-edge-reinforcement.d.ts +1 -1
  134. package/dist/graph-snapshot.d.ts +1 -1
  135. package/dist/graph.d.ts +1 -1
  136. package/dist/identity-continuity.d.ts +1 -1
  137. package/dist/importance.d.ts +1 -1
  138. package/dist/index.d.ts +9 -9
  139. package/dist/index.js +149 -149
  140. package/dist/intent.d.ts +1 -1
  141. package/dist/lcm/engine.d.ts +1 -1
  142. package/dist/lcm/engine.js +2 -2
  143. package/dist/lcm/index.d.ts +1 -1
  144. package/dist/lcm/index.js +4 -4
  145. package/dist/lcm/tools.d.ts +1 -1
  146. package/dist/lifecycle.d.ts +1 -1
  147. package/dist/live-connectors-runner.d.ts +1 -1
  148. package/dist/local-llm.d.ts +1 -1
  149. package/dist/local-model-endpoint.d.ts +1 -1
  150. package/dist/maintenance/memory-governance.d.ts +1 -1
  151. package/dist/maintenance/memory-governance.js +7 -7
  152. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +7 -7
  153. package/dist/maintenance/rebuild-memory-projection.js +8 -8
  154. package/dist/mcp-memory-inspector-app.d.ts +5 -5
  155. package/dist/memory-action-policy.d.ts +1 -1
  156. package/dist/memory-cache.d.ts +1 -1
  157. package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
  158. package/dist/memory-projection-store.d.ts +1 -1
  159. package/dist/memory-provenance.d.ts +1 -1
  160. package/dist/memory-worth-outcomes.d.ts +1 -1
  161. package/dist/models-json.d.ts +1 -1
  162. package/dist/namespaces/migrate.d.ts +2 -2
  163. package/dist/namespaces/migrate.js +17 -17
  164. package/dist/namespaces/principal.d.ts +1 -1
  165. package/dist/namespaces/search.d.ts +1 -1
  166. package/dist/namespaces/search.js +9 -9
  167. package/dist/namespaces/storage.d.ts +2 -2
  168. package/dist/namespaces/storage.js +7 -7
  169. package/dist/native-knowledge.d.ts +1 -1
  170. package/dist/operator-toolkit.d.ts +1 -1
  171. package/dist/operator-toolkit.js +21 -21
  172. package/dist/orchestration/compression-guideline-coordinator.d.ts +1 -1
  173. package/dist/orchestration/maintenance.d.ts +2 -2
  174. package/dist/orchestration/maintenance.js +9 -9
  175. package/dist/{orchestrator-D7ZGOQLX.d.ts → orchestrator-Xm6sK5jw.d.ts} +3 -3
  176. package/dist/orchestrator.d.ts +4 -4
  177. package/dist/orchestrator.js +75 -75
  178. package/dist/patterns-cli.d.ts +1 -1
  179. package/dist/policy-runtime.d.ts +1 -1
  180. package/dist/provenance.d.ts +1 -1
  181. package/dist/qmd-recall-cache.d.ts +1 -1
  182. package/dist/qmd.d.ts +1 -1
  183. package/dist/recall-disclosure-escalation.d.ts +1 -1
  184. package/dist/recall-explain-renderer.d.ts +1 -1
  185. package/dist/recall-planner-llm.d.ts +1 -1
  186. package/dist/recall-planner-llm.js +2 -2
  187. package/dist/recall-state.d.ts +1 -1
  188. package/dist/recall-tag-filter.d.ts +1 -1
  189. package/dist/recall-xray-cli.d.ts +1 -1
  190. package/dist/recall-xray-renderer.d.ts +1 -1
  191. package/dist/recall-xray.d.ts +1 -1
  192. package/dist/resolve-auth-token.d.ts +1 -1
  193. package/dist/retrieval-agents.d.ts +1 -1
  194. package/dist/retrieval-tiers.d.ts +1 -1
  195. package/dist/routing/engine.d.ts +1 -1
  196. package/dist/routing/store.d.ts +1 -1
  197. package/dist/schemas.d.ts +100 -100
  198. package/dist/search/embed-helper.d.ts +1 -1
  199. package/dist/search/factory.d.ts +1 -1
  200. package/dist/search/factory.js +8 -8
  201. package/dist/search/index.d.ts +1 -1
  202. package/dist/search/index.js +13 -13
  203. package/dist/search/lancedb-backend.d.ts +1 -1
  204. package/dist/search/lancedb-backend.js +2 -2
  205. package/dist/search/meilisearch-backend.d.ts +1 -1
  206. package/dist/search/meilisearch-backend.js +2 -2
  207. package/dist/search/noop-backend.d.ts +1 -1
  208. package/dist/search/orama-backend.d.ts +1 -1
  209. package/dist/search/orama-backend.js +2 -2
  210. package/dist/search/port.d.ts +1 -1
  211. package/dist/search/remote-backend.d.ts +1 -1
  212. package/dist/{semantic-consolidation-7Sndms2M.d.ts → semantic-consolidation-bfXJNKVf.d.ts} +1 -1
  213. package/dist/semantic-consolidation.d.ts +2 -2
  214. package/dist/semantic-consolidation.js +8 -8
  215. package/dist/semantic-rule-promotion.js +7 -7
  216. package/dist/semantic-rule-verifier.d.ts +1 -1
  217. package/dist/semantic-rule-verifier.js +7 -7
  218. package/dist/session-observer-bands.d.ts +1 -1
  219. package/dist/session-observer-state.d.ts +1 -1
  220. package/dist/shared-context/manager.d.ts +9 -9
  221. package/dist/signal.d.ts +1 -1
  222. package/dist/storage.d.ts +11 -21
  223. package/dist/storage.js +14 -6
  224. package/dist/summarizer.d.ts +1 -1
  225. package/dist/summarizer.js +3 -3
  226. package/dist/summary-snapshot.d.ts +1 -1
  227. package/dist/temporal-supersession.d.ts +1 -1
  228. package/dist/temporal-validity.d.ts +1 -1
  229. package/dist/threading.d.ts +1 -1
  230. package/dist/tier-migration.d.ts +1 -1
  231. package/dist/tier-routing.d.ts +1 -1
  232. package/dist/topics.d.ts +1 -1
  233. package/dist/transcript.d.ts +1 -1
  234. package/dist/transfer/autodetect.js +1 -1
  235. package/dist/transfer/backup.js +1 -1
  236. package/dist/transfer/capsule-export.js +2 -2
  237. package/dist/transfer/types.d.ts +66 -66
  238. package/dist/trust-score-stage.d.ts +1 -1
  239. package/dist/trust-score.d.ts +1 -1
  240. package/dist/{types-DTEFxFuL.d.ts → types-D1iBqhJA.d.ts} +1 -1
  241. package/dist/types.d.ts +1 -1
  242. package/dist/utility-runtime.d.ts +1 -1
  243. package/dist/verified-recall.js +7 -7
  244. package/package.json +2 -2
  245. package/src/access-lcm-surface.ts +517 -0
  246. package/src/access-service.ts +21 -417
  247. package/src/storage/entity-store.ts +672 -0
  248. package/src/storage.ts +45 -565
  249. package/dist/chunk-34THARMH.js.map +0 -1
  250. package/dist/chunk-ZECLLIMX.js.map +0 -1
  251. /package/dist/{auto-sync-IEBKPGAM.js.map → auto-sync-G4YKBPOU.js.map} +0 -0
  252. /package/dist/{chunk-HAZVVOYT.js.map → chunk-24463PIV.js.map} +0 -0
  253. /package/dist/{chunk-GWGWBK5Y.js.map → chunk-2MR3MFQB.js.map} +0 -0
  254. /package/dist/{chunk-YTU7WKYN.js.map → chunk-2OZ2JEUP.js.map} +0 -0
  255. /package/dist/{chunk-AU7Q3LSC.js.map → chunk-2QSZNTDO.js.map} +0 -0
  256. /package/dist/{chunk-EHYB325U.js.map → chunk-3DOD6ICJ.js.map} +0 -0
  257. /package/dist/{chunk-KYHGLDFU.js.map → chunk-4LQUYBZM.js.map} +0 -0
  258. /package/dist/{chunk-VUA4S7P6.js.map → chunk-5J4OL7TJ.js.map} +0 -0
  259. /package/dist/{chunk-TVISHYL5.js.map → chunk-CIDGUFAL.js.map} +0 -0
  260. /package/dist/{chunk-OUXPVWTZ.js.map → chunk-FLVL4L3L.js.map} +0 -0
  261. /package/dist/{chunk-3HGZX26P.js.map → chunk-FOJY75BL.js.map} +0 -0
  262. /package/dist/{chunk-VVSV2QVY.js.map → chunk-FQLM6ZUP.js.map} +0 -0
  263. /package/dist/{chunk-LZ73Y56P.js.map → chunk-G7LCG56O.js.map} +0 -0
  264. /package/dist/{chunk-ZMHDSIEX.js.map → chunk-GGYUR4M2.js.map} +0 -0
  265. /package/dist/{chunk-YNBEHUZH.js.map → chunk-GMWKWA6N.js.map} +0 -0
  266. /package/dist/{chunk-JGPURIEH.js.map → chunk-GPFXPC2V.js.map} +0 -0
  267. /package/dist/{chunk-E6LENGYV.js.map → chunk-H6S3DJVE.js.map} +0 -0
  268. /package/dist/{chunk-E3MRYDUQ.js.map → chunk-I3UWEZTK.js.map} +0 -0
  269. /package/dist/{chunk-ZIFPFKB2.js.map → chunk-I6IAJCJS.js.map} +0 -0
  270. /package/dist/{chunk-JES2O5Q6.js.map → chunk-JITAVROY.js.map} +0 -0
  271. /package/dist/{chunk-DKIZ4BUQ.js.map → chunk-KKOCFUI5.js.map} +0 -0
  272. /package/dist/{chunk-LQ6JI4VH.js.map → chunk-LD53WPMU.js.map} +0 -0
  273. /package/dist/{chunk-N3VE7OCY.js.map → chunk-LFKEFIJA.js.map} +0 -0
  274. /package/dist/{chunk-EEO4YWQ7.js.map → chunk-N4AGSRVA.js.map} +0 -0
  275. /package/dist/{chunk-QIRZI3C3.js.map → chunk-NCNOYM6F.js.map} +0 -0
  276. /package/dist/{chunk-3ZIKDH6C.js.map → chunk-OCFITZRV.js.map} +0 -0
  277. /package/dist/{chunk-ITLJATQI.js.map → chunk-PJ7DIEFC.js.map} +0 -0
  278. /package/dist/{chunk-OZMBT7N3.js.map → chunk-PJQMISPD.js.map} +0 -0
  279. /package/dist/{chunk-XOPLMSVV.js.map → chunk-S6UCPBPL.js.map} +0 -0
  280. /package/dist/{chunk-243P7YYV.js.map → chunk-SP42M3XP.js.map} +0 -0
  281. /package/dist/{chunk-DCWIQFNA.js.map → chunk-T422SYM6.js.map} +0 -0
  282. /package/dist/{chunk-AXBRVBT6.js.map → chunk-T6WHI3JW.js.map} +0 -0
  283. /package/dist/{chunk-5CEJH5ZN.js.map → chunk-TAPSNIMA.js.map} +0 -0
  284. /package/dist/{chunk-3NN73CM7.js.map → chunk-TH7WMHVK.js.map} +0 -0
  285. /package/dist/{chunk-RNWWAS5V.js.map → chunk-TJATYB3F.js.map} +0 -0
  286. /package/dist/{chunk-C3IHRWIC.js.map → chunk-UQJ6YTKR.js.map} +0 -0
  287. /package/dist/{chunk-PN5AMCK2.js.map → chunk-VL5QHTJI.js.map} +0 -0
  288. /package/dist/{chunk-BWOEYBRB.js.map → chunk-XCXN3D2U.js.map} +0 -0
  289. /package/dist/{chunk-KY4WOZ3P.js.map → chunk-XD6JVK5P.js.map} +0 -0
  290. /package/dist/{chunk-WRFKZEO6.js.map → chunk-YQGHW5ML.js.map} +0 -0
@@ -1,12 +1,12 @@
1
+ import {
2
+ WEARABLES_DIR_NAME,
3
+ isValidTranscriptDate
4
+ } from "./chunk-M7XQSUBB.js";
1
5
  import {
2
6
  TombstoneStore,
3
7
  buildRetiredFactTombstoneInputs,
4
8
  collectRetiredMemoriesForRebuild
5
9
  } from "./chunk-L2B3EE7B.js";
6
- import {
7
- WEARABLES_DIR_NAME,
8
- isValidTranscriptDate
9
- } from "./chunk-M7XQSUBB.js";
10
10
  import {
11
11
  isErrnoCode
12
12
  } from "./chunk-5UZXUTVO.js";
@@ -28,6 +28,10 @@ import {
28
28
  SPECULATIVE_TTL_DAYS,
29
29
  confidenceTier
30
30
  } from "./chunk-JS2HKKOK.js";
31
+ import {
32
+ normalizeProjectionPreview,
33
+ normalizeProjectionTags
34
+ } from "./chunk-SCU65EZI.js";
31
35
  import {
32
36
  readProjectedGovernanceRecord,
33
37
  readProjectedMemoryBrowse,
@@ -45,10 +49,6 @@ import {
45
49
  sortMemoryLifecycleEvents,
46
50
  toMemoryPathRel
47
51
  } from "./chunk-RULE4VG5.js";
48
- import {
49
- normalizeProjectionPreview,
50
- normalizeProjectionTags
51
- } from "./chunk-SCU65EZI.js";
52
52
  import {
53
53
  rotateMarkdownFileToArchive
54
54
  } from "./chunk-DM2T26WE.js";
@@ -64,7 +64,7 @@ import {
64
64
  import {
65
65
  parseFaithfulnessField,
66
66
  serializeFaithfulnessFields
67
- } from "./chunk-YTU7WKYN.js";
67
+ } from "./chunk-2OZ2JEUP.js";
68
68
  import {
69
69
  isConsolidationOperator,
70
70
  isValidDerivedFromEntry
@@ -112,10 +112,489 @@ import {
112
112
  } from "./chunk-VS2IYZRU.js";
113
113
 
114
114
  // src/storage.ts
115
- import { access, lstat, readdir, readFile, realpath, stat, writeFile, mkdir, unlink, appendFile, open } from "fs/promises";
116
- import { appendFileSync, createReadStream, mkdirSync, readFileSync, statSync } from "fs";
117
- import { createHash } from "crypto";
118
- import path from "path";
115
+ import { access, lstat, readdir as readdir2, readFile, realpath, stat, writeFile, mkdir, unlink as unlink2, appendFile, open } from "fs/promises";
116
+ import { appendFileSync, createReadStream, mkdirSync, readFileSync, statSync } from "fs";
117
+ import { createHash } from "crypto";
118
+ import path2 from "path";
119
+
120
+ // src/storage/entity-store.ts
121
+ import { readdir, unlink } from "fs/promises";
122
+ import path from "path";
123
+ var EntityStore = class {
124
+ constructor(deps) {
125
+ this.deps = deps;
126
+ }
127
+ deps;
128
+ /** Normalize an entity name using this store's alias table. */
129
+ normalizeEntityName(raw, type) {
130
+ return normalizeEntityName(raw, type, this.deps.userAliases);
131
+ }
132
+ async writeEntity(name, type, facts, options = {}) {
133
+ await this.deps.ensureDirectories();
134
+ if (typeof name !== "string" || !name.trim() || typeof type !== "string" || !type.trim()) {
135
+ log.warn("writeEntity: invalid entity payload, skipping", {
136
+ nameType: typeof name,
137
+ typeType: typeof type
138
+ });
139
+ return "";
140
+ }
141
+ const safeFacts = Array.isArray(facts) ? [...new Set(
142
+ facts.filter((fact) => typeof fact === "string").map((fact) => fact.trim()).filter((fact) => fact.length > 0)
143
+ )] : [];
144
+ let normalized = this.deps.normalizeEntityName(name, type);
145
+ const match = await this.deps.findMatchingEntity(name, type);
146
+ if (match && match !== normalized) {
147
+ log.debug(`fuzzy match: "${normalized}" \u2192 existing "${match}"`);
148
+ normalized = match;
149
+ }
150
+ const filePath = path.join(this.deps.entitiesDir, `${normalized}.md`);
151
+ let entity = {
152
+ name,
153
+ type,
154
+ created: "",
155
+ updated: (/* @__PURE__ */ new Date()).toISOString(),
156
+ facts: [],
157
+ summary: void 0,
158
+ synthesis: void 0,
159
+ synthesisUpdatedAt: void 0,
160
+ synthesisVersion: void 0,
161
+ synthesisStructuredFactCount: void 0,
162
+ synthesisStructuredFactDigest: void 0,
163
+ timeline: [],
164
+ relationships: [],
165
+ activity: [],
166
+ aliases: []
167
+ };
168
+ try {
169
+ const existing = await this.deps.readStorageSecureFile(filePath);
170
+ entity = parseEntityFile(existing, this.deps.entitySchemas);
171
+ } catch (err) {
172
+ if (err instanceof SecureStoreLockedError) throw err;
173
+ if (!isErrnoCode(err, "ENOENT")) throw err;
174
+ }
175
+ const timestamp = options.timestamp?.trim() || (/* @__PURE__ */ new Date()).toISOString();
176
+ const source = options.source?.trim() || void 0;
177
+ const sessionKey = options.sessionKey?.trim() || void 0;
178
+ const principal = options.principal?.trim() || void 0;
179
+ const structuredSectionMap = new Map(
180
+ (entity.structuredSections ?? []).map((section) => [section.key, {
181
+ ...section,
182
+ facts: [...section.facts]
183
+ }])
184
+ );
185
+ for (const section of options.structuredSections ?? []) {
186
+ const normalizedSection = normalizeEntityStructuredSection(type, section, this.deps.entitySchemas);
187
+ const normalizedFacts = normalizeStructuredSectionFacts(section.facts);
188
+ if (normalizedFacts.length === 0) continue;
189
+ const existingSection = structuredSectionMap.get(normalizedSection.key);
190
+ if (!existingSection) {
191
+ structuredSectionMap.set(normalizedSection.key, {
192
+ key: normalizedSection.key,
193
+ title: normalizedSection.title,
194
+ facts: normalizedFacts
195
+ });
196
+ continue;
197
+ }
198
+ existingSection.facts = normalizeStructuredSectionFacts([...existingSection.facts, ...normalizedFacts]);
199
+ if (!existingSection.title.trim() && normalizedSection.title.trim()) {
200
+ existingSection.title = normalizedSection.title;
201
+ }
202
+ }
203
+ for (const fact of safeFacts) {
204
+ const nextEntry = {
205
+ timestamp,
206
+ text: fact,
207
+ ...source ? { source } : {},
208
+ ...sessionKey ? { sessionKey } : {},
209
+ ...principal ? { principal } : {}
210
+ };
211
+ const alreadyPresent = entity.timeline.some(
212
+ (entry) => entry.timestamp === nextEntry.timestamp && entry.text === nextEntry.text && entry.source === nextEntry.source && entry.sessionKey === nextEntry.sessionKey && entry.principal === nextEntry.principal
213
+ );
214
+ if (alreadyPresent) continue;
215
+ entity.timeline.push(nextEntry);
216
+ }
217
+ entity.structuredSections = sortStructuredSectionsBySchema(
218
+ type,
219
+ Array.from(structuredSectionMap.values()).filter((section) => section.facts.length > 0),
220
+ this.deps.entitySchemas
221
+ );
222
+ entity.facts = compileEntityFacts(entity.timeline, entity.structuredSections);
223
+ entity.summary = entity.synthesis || entity.summary;
224
+ entity.name = name;
225
+ entity.type = type;
226
+ entity.created = entity.created || timestamp;
227
+ entity.updated = (/* @__PURE__ */ new Date()).toISOString();
228
+ await this.deps.snapshotBeforeWrite(filePath, "write");
229
+ await this.deps.writeStorageSecureFile(filePath, serializeEntityFile(entity, this.deps.entitySchemas));
230
+ this.deps.invalidateKnowledgeIndexCache();
231
+ this.deps.bumpMemoryStatusVersion();
232
+ log.debug(`wrote entity ${normalized}`);
233
+ return normalized;
234
+ }
235
+ async readEntity(name) {
236
+ const filePath = this.deps.resolveEntityFilePath(name);
237
+ if (filePath === null) {
238
+ return "";
239
+ }
240
+ try {
241
+ return await this.deps.readStorageSecureFile(filePath);
242
+ } catch (err) {
243
+ if (err instanceof SecureStoreLockedError) throw err;
244
+ if (!isErrnoCode(err, "ENOENT")) throw err;
245
+ return "";
246
+ }
247
+ }
248
+ /** Return sorted list of entity filenames (without .md extension) */
249
+ async listEntityNames() {
250
+ try {
251
+ const entries = await readdir(this.deps.entitiesDir);
252
+ return entries.filter((e) => e.endsWith(".md")).map((e) => e.replace(".md", "")).sort();
253
+ } catch {
254
+ return [];
255
+ }
256
+ }
257
+ /**
258
+ * Set or rewrite the synthesis layer of an entity file.
259
+ */
260
+ async updateEntitySynthesis(name, synthesis, options = {}) {
261
+ const filePath = path.join(this.deps.entitiesDir, `${name}.md`);
262
+ let entity;
263
+ try {
264
+ const content = await this.deps.readStorageSecureFile(filePath);
265
+ entity = parseEntityFile(content, this.deps.entitySchemas);
266
+ } catch (err) {
267
+ if (err instanceof SecureStoreLockedError) throw err;
268
+ if (!isErrnoCode(err, "ENOENT")) throw err;
269
+ log.debug(`updateEntitySynthesis: entity file ${name}.md not found`);
270
+ return;
271
+ }
272
+ const updatedAt = options.updatedAt?.trim() || entity.synthesisUpdatedAt?.trim() || void 0;
273
+ const entityUpdatedAt = options.entityUpdatedAt?.trim() || updatedAt || entity.updated || (/* @__PURE__ */ new Date()).toISOString();
274
+ const synthesisTimelineCount = Number.isInteger(options.synthesisTimelineCount) && (options.synthesisTimelineCount ?? 0) >= 0 ? options.synthesisTimelineCount : void 0;
275
+ const synthesisStructuredFactCount = Number.isInteger(options.synthesisStructuredFactCount) && (options.synthesisStructuredFactCount ?? 0) >= 0 ? options.synthesisStructuredFactCount : countEntityStructuredFacts(entity);
276
+ const synthesisStructuredFactDigest = options.synthesisStructuredFactDigest?.trim() || fingerprintEntityStructuredFacts(entity);
277
+ entity.synthesis = synthesis.trim();
278
+ entity.summary = entity.synthesis;
279
+ entity.synthesisUpdatedAt = updatedAt;
280
+ entity.synthesisTimelineCount = synthesisTimelineCount;
281
+ entity.synthesisStructuredFactCount = synthesisStructuredFactCount;
282
+ entity.synthesisStructuredFactDigest = synthesisStructuredFactDigest;
283
+ entity.synthesisVersion = Math.max(0, entity.synthesisVersion ?? 0) + (options.incrementVersion === false ? 0 : 1);
284
+ entity.updated = entityUpdatedAt;
285
+ await this.deps.writeStorageSecureFile(filePath, serializeEntityFile(entity, this.deps.entitySchemas));
286
+ await this.deps.removeEntitySynthesisQueueEntries([
287
+ .../* @__PURE__ */ new Set([name, this.deps.normalizeEntityName(entity.name, entity.type)])
288
+ ]);
289
+ this.deps.invalidateKnowledgeIndexCache();
290
+ this.deps.bumpMemoryStatusVersion();
291
+ }
292
+ /**
293
+ * Read all entity files and return lightweight EntityFile objects.
294
+ * Parsing is fast (~50-100ms for ~1,800 files) since entity files are small.
295
+ */
296
+ async readAllEntityFiles() {
297
+ const currentVersion = this.deps.getMemoryStatusVersion();
298
+ const schemaCacheKey = buildEntitySchemaCacheKey(this.deps.entitySchemas);
299
+ const cacheKey = `${this.deps.getEntityCacheSecureStoreKey()}\0${schemaCacheKey}`;
300
+ const cached = getCachedEntities(this.deps.baseDir, currentVersion, cacheKey);
301
+ if (cached) return cached;
302
+ try {
303
+ const entries = await readdir(this.deps.entitiesDir);
304
+ const mdFiles = entries.filter((e) => e.endsWith(".md"));
305
+ if (mdFiles.length === 0) return [];
306
+ const BATCH_SIZE = 100;
307
+ const entities = [];
308
+ for (let i = 0; i < mdFiles.length; i += BATCH_SIZE) {
309
+ const batch = mdFiles.slice(i, i + BATCH_SIZE);
310
+ const results = await Promise.all(
311
+ batch.map(async (entry) => {
312
+ try {
313
+ return await this.deps.readStorageSecureFile(path.join(this.deps.entitiesDir, entry));
314
+ } catch (err) {
315
+ if (err instanceof SecureStoreLockedError) throw err;
316
+ if (!isErrnoCode(err, "ENOENT")) throw err;
317
+ return null;
318
+ }
319
+ })
320
+ );
321
+ for (const content of results) {
322
+ if (content !== null) entities.push(parseEntityFile(content, this.deps.entitySchemas));
323
+ }
324
+ }
325
+ setCachedEntities(this.deps.baseDir, entities, currentVersion, cacheKey);
326
+ return entities;
327
+ } catch (err) {
328
+ if (err instanceof SecureStoreLockedError || !isErrnoCode(err, "ENOENT")) throw err;
329
+ return [];
330
+ }
331
+ }
332
+ /**
333
+ * Build the Knowledge Index: a compact markdown table of top-scored entities.
334
+ * Respects maxEntities and maxChars limits from config.
335
+ */
336
+ async buildKnowledgeIndex(config, overrides) {
337
+ const useDefaultLimits = overrides?.maxEntities === void 0 && overrides?.maxChars === void 0;
338
+ if (useDefaultLimits && this.deps.knowledgeIndexCache && Date.now() - this.deps.knowledgeIndexCache.builtAt < StorageManager.KNOWLEDGE_INDEX_CACHE_TTL_MS) {
339
+ return { result: this.deps.knowledgeIndexCache.result, cached: true };
340
+ }
341
+ const entities = await this.deps.readAllEntityFiles();
342
+ if (entities.length === 0) {
343
+ if (useDefaultLimits) this.deps.knowledgeIndexCache = { result: "", builtAt: Date.now() };
344
+ return { result: "", cached: false };
345
+ }
346
+ const now = /* @__PURE__ */ new Date();
347
+ const scored = entities.map((e) => ({
348
+ name: e.name,
349
+ type: e.type,
350
+ score: StorageManager.scoreEntity(e, now),
351
+ factCount: e.facts.length,
352
+ summary: e.synthesis ?? e.summary,
353
+ topRelationships: e.relationships.slice(0, 3).map((r) => r.target)
354
+ }));
355
+ scored.sort((a, b) => b.score - a.score);
356
+ const maxEntities = typeof overrides?.maxEntities === "number" ? Math.max(0, Math.floor(overrides.maxEntities)) : config.knowledgeIndexMaxEntities;
357
+ const topN = scored.slice(0, maxEntities);
358
+ if (topN.length === 0) {
359
+ if (useDefaultLimits) this.deps.knowledgeIndexCache = { result: "", builtAt: Date.now() };
360
+ return { result: "", cached: false };
361
+ }
362
+ const header = "## Knowledge Index\n\n| Entity | Type | Summary | Connected to |\n|--------|------|---------|-------------|";
363
+ const rows = [];
364
+ let totalChars = header.length;
365
+ const maxChars = typeof overrides?.maxChars === "number" ? Math.max(0, Math.floor(overrides.maxChars)) : config.knowledgeIndexMaxChars;
366
+ for (const entity of topN) {
367
+ const summary = entity.summary || `${entity.factCount} facts`;
368
+ const connected = entity.topRelationships.length > 0 ? entity.topRelationships.join(", ") : "\u2014";
369
+ const row = `| ${entity.name} | ${entity.type} | ${summary} | ${connected} |`;
370
+ if (totalChars + row.length + 1 > maxChars) break;
371
+ rows.push(row);
372
+ totalChars += row.length + 1;
373
+ }
374
+ const result = rows.length === 0 ? "" : `${header}
375
+ ${rows.join("\n")}
376
+ `;
377
+ if (useDefaultLimits) this.deps.knowledgeIndexCache = { result, builtAt: Date.now() };
378
+ return { result, cached: false };
379
+ }
380
+ /**
381
+ * Merge fragmented entity files that resolve to the same canonical name.
382
+ * Preserves relationships, activity, aliases, and summary from all fragments.
383
+ * Returns count of files merged.
384
+ */
385
+ async mergeFragmentedEntities() {
386
+ let merged = 0;
387
+ try {
388
+ const entries = await readdir(this.deps.entitiesDir);
389
+ const mdFiles = entries.filter((e) => e.endsWith(".md"));
390
+ const groups = /* @__PURE__ */ new Map();
391
+ for (const file of mdFiles) {
392
+ const baseName = file.replace(".md", "");
393
+ const dashIdx = baseName.indexOf("-");
394
+ if (dashIdx === -1) continue;
395
+ const type = baseName.slice(0, dashIdx);
396
+ const restOfName = baseName.slice(dashIdx + 1);
397
+ const canonical = this.deps.normalizeEntityName(restOfName, type);
398
+ if (!groups.has(canonical)) groups.set(canonical, []);
399
+ groups.get(canonical).push(file);
400
+ }
401
+ for (const [canonical, files] of groups) {
402
+ if (files.length <= 1) continue;
403
+ const mergedEntity = {
404
+ name: "",
405
+ type: "other",
406
+ created: "",
407
+ updated: "",
408
+ extraFrontmatterLines: [],
409
+ preSectionLines: [],
410
+ facts: [],
411
+ summary: void 0,
412
+ synthesis: void 0,
413
+ synthesisUpdatedAt: void 0,
414
+ synthesisTimelineCount: void 0,
415
+ synthesisStructuredFactCount: void 0,
416
+ synthesisStructuredFactDigest: void 0,
417
+ synthesisVersion: void 0,
418
+ timeline: [],
419
+ relationships: [],
420
+ activity: [],
421
+ aliases: [],
422
+ structuredSections: [],
423
+ extraSections: []
424
+ };
425
+ for (const file of files) {
426
+ const filePath = path.join(this.deps.entitiesDir, file);
427
+ try {
428
+ const content = await this.deps.readStorageSecureFile(filePath);
429
+ const parsed = parseEntityFile(content, this.deps.entitySchemas);
430
+ if (!mergedEntity.type || mergedEntity.type === "other") {
431
+ mergedEntity.type = parsed.type;
432
+ }
433
+ if (!mergedEntity.updated || compareEntityTimestamps(parsed.updated, mergedEntity.updated) > 0) {
434
+ mergedEntity.updated = parsed.updated;
435
+ }
436
+ const parsedCreated = parsed.created || parsed.updated;
437
+ const mergedCreated = mergedEntity.created?.trim() || "";
438
+ const parsedCreatedMs = parsedCreated ? Date.parse(parsedCreated) : Number.NaN;
439
+ const mergedCreatedMs = mergedCreated ? Date.parse(mergedCreated) : Number.NaN;
440
+ const parsedCreatedIsValid = Number.isFinite(parsedCreatedMs);
441
+ const mergedCreatedIsValid = Number.isFinite(mergedCreatedMs);
442
+ if (parsedCreated && (!mergedCreated || parsedCreatedIsValid && !mergedCreatedIsValid || parsedCreatedIsValid && mergedCreatedIsValid && parsedCreatedMs < mergedCreatedMs || !parsedCreatedIsValid && !mergedCreatedIsValid && compareEntityTimestamps(parsedCreated, mergedCreated) < 0)) {
443
+ mergedEntity.created = parsedCreated;
444
+ }
445
+ if (parsed.name.length > mergedEntity.name.length) {
446
+ mergedEntity.name = parsed.name;
447
+ }
448
+ const parsedSynthesisUpdatedAt = parsed.synthesisUpdatedAt?.trim() || void 0;
449
+ const mergedSynthesisUpdatedAt = mergedEntity.synthesisUpdatedAt?.trim() || void 0;
450
+ if (parsed.synthesis && (!mergedEntity.synthesis || !mergedSynthesisUpdatedAt && Boolean(parsedSynthesisUpdatedAt) || Boolean(mergedSynthesisUpdatedAt) && Boolean(parsedSynthesisUpdatedAt) && compareEntityTimestamps(parsedSynthesisUpdatedAt, mergedSynthesisUpdatedAt) > 0)) {
451
+ mergedEntity.synthesis = parsed.synthesis;
452
+ mergedEntity.summary = parsed.synthesis;
453
+ mergedEntity.synthesisUpdatedAt = parsedSynthesisUpdatedAt;
454
+ mergedEntity.synthesisTimelineCount = parsed.synthesisTimelineCount;
455
+ mergedEntity.synthesisStructuredFactCount = parsed.synthesisStructuredFactCount;
456
+ mergedEntity.synthesisStructuredFactDigest = parsed.synthesisStructuredFactDigest;
457
+ mergedEntity.synthesisVersion = parsed.synthesisVersion;
458
+ } else if (!mergedEntity.summary && parsed.summary) {
459
+ mergedEntity.summary = parsed.summary;
460
+ mergedEntity.synthesis = parsed.summary;
461
+ mergedEntity.synthesisUpdatedAt = parsedSynthesisUpdatedAt;
462
+ mergedEntity.synthesisTimelineCount = parsed.synthesisTimelineCount;
463
+ mergedEntity.synthesisStructuredFactCount = parsed.synthesisStructuredFactCount;
464
+ mergedEntity.synthesisStructuredFactDigest = parsed.synthesisStructuredFactDigest;
465
+ mergedEntity.synthesisVersion = parsed.synthesisVersion;
466
+ }
467
+ mergedEntity.timeline.push(...parsed.timeline);
468
+ mergedEntity.relationships.push(...parsed.relationships);
469
+ mergedEntity.activity.push(...parsed.activity);
470
+ mergedEntity.aliases.push(...parsed.aliases);
471
+ const mergedStructuredSectionMap = new Map(
472
+ (mergedEntity.structuredSections ?? []).map((section) => [section.key, {
473
+ ...section,
474
+ facts: [...section.facts]
475
+ }])
476
+ );
477
+ for (const section of parsed.structuredSections ?? []) {
478
+ const existingSection = mergedStructuredSectionMap.get(section.key);
479
+ if (!existingSection) {
480
+ mergedStructuredSectionMap.set(section.key, {
481
+ key: section.key,
482
+ title: section.title,
483
+ facts: [...new Set(section.facts.map((fact) => fact.trim()).filter((fact) => fact.length > 0))]
484
+ });
485
+ continue;
486
+ }
487
+ const mergedFacts = new Set(existingSection.facts.map((fact) => fact.trim()));
488
+ for (const fact of section.facts) {
489
+ const trimmed = fact.trim();
490
+ if (!trimmed) continue;
491
+ mergedFacts.add(trimmed);
492
+ }
493
+ existingSection.facts = Array.from(mergedFacts);
494
+ if (!existingSection.title.trim() && section.title.trim()) {
495
+ existingSection.title = section.title;
496
+ }
497
+ }
498
+ mergedEntity.structuredSections = Array.from(mergedStructuredSectionMap.values());
499
+ mergedEntity.extraFrontmatterLines.push(...parsed.extraFrontmatterLines ?? []);
500
+ mergedEntity.preSectionLines.push(...parsed.preSectionLines ?? []);
501
+ mergedEntity.extraSections.push(...(parsed.extraSections ?? []).map((section) => ({
502
+ title: section.title,
503
+ lines: [...section.lines]
504
+ })));
505
+ } catch (err) {
506
+ if (err instanceof SecureStoreLockedError) throw err;
507
+ if (!isErrnoCode(err, "ENOENT")) throw err;
508
+ }
509
+ }
510
+ const timelineKeys = /* @__PURE__ */ new Set();
511
+ mergedEntity.timeline = mergedEntity.timeline.filter((entry) => {
512
+ const key = JSON.stringify([
513
+ entry.timestamp,
514
+ entry.source ?? "",
515
+ entry.sessionKey ?? "",
516
+ entry.principal ?? "",
517
+ entry.text
518
+ ]);
519
+ if (timelineKeys.has(key)) return false;
520
+ timelineKeys.add(key);
521
+ return true;
522
+ });
523
+ const relKeys = /* @__PURE__ */ new Set();
524
+ mergedEntity.relationships = mergedEntity.relationships.filter((r) => {
525
+ const key = `${r.target}::${r.label}`;
526
+ if (relKeys.has(key)) return false;
527
+ relKeys.add(key);
528
+ return true;
529
+ });
530
+ const actKeys = /* @__PURE__ */ new Set();
531
+ mergedEntity.activity = mergedEntity.activity.filter((a) => {
532
+ const key = `${a.date}::${a.note}`;
533
+ if (actKeys.has(key)) return false;
534
+ actKeys.add(key);
535
+ return true;
536
+ }).sort((a, b) => b.date.localeCompare(a.date));
537
+ mergedEntity.aliases = [...new Set(mergedEntity.aliases)];
538
+ mergedEntity.structuredSections = sortStructuredSectionsBySchema(
539
+ mergedEntity.type,
540
+ mergedEntity.structuredSections ?? [],
541
+ this.deps.entitySchemas
542
+ );
543
+ mergedEntity.facts = compileEntityFacts(mergedEntity.timeline, mergedEntity.structuredSections);
544
+ const extraSectionKeys = /* @__PURE__ */ new Set();
545
+ mergedEntity.extraSections = (mergedEntity.extraSections ?? []).filter((section) => {
546
+ const key = `${section.title}::${section.lines.join("\n")}`;
547
+ if (extraSectionKeys.has(key)) return false;
548
+ extraSectionKeys.add(key);
549
+ return true;
550
+ });
551
+ if (!mergedEntity.name) {
552
+ const dashIdx = canonical.indexOf("-");
553
+ mergedEntity.name = dashIdx !== -1 ? canonical.slice(dashIdx + 1) : canonical;
554
+ }
555
+ mergedEntity.created = mergedEntity.created || mergedEntity.updated || (/* @__PURE__ */ new Date()).toISOString();
556
+ mergedEntity.updated = mergedEntity.updated || (/* @__PURE__ */ new Date()).toISOString();
557
+ const canonicalPath = path.join(this.deps.entitiesDir, `${canonical}.md`);
558
+ await this.deps.writeStorageSecureFile(canonicalPath, serializeEntityFile(mergedEntity, this.deps.entitySchemas));
559
+ for (const file of files) {
560
+ const filePath = path.join(this.deps.entitiesDir, file);
561
+ if (filePath !== canonicalPath) {
562
+ try {
563
+ await unlink(filePath);
564
+ merged++;
565
+ log.debug(`merged entity ${file} \u2192 ${canonical}.md`);
566
+ } catch {
567
+ }
568
+ }
569
+ }
570
+ }
571
+ } catch (err) {
572
+ if (err instanceof SecureStoreLockedError || !isErrnoCode(err, "ENOENT")) throw err;
573
+ }
574
+ return merged;
575
+ }
576
+ };
577
+
578
+ // src/orchestration/self-deps.ts
579
+ function selfDeps(self) {
580
+ const source = self;
581
+ return new Proxy(/* @__PURE__ */ Object.create(null), {
582
+ get(_target, prop) {
583
+ const value = source[prop];
584
+ return typeof value === "function" ? value.bind(self) : value;
585
+ },
586
+ set(_target, prop, value) {
587
+ if (!(prop in source)) return false;
588
+ source[prop] = value;
589
+ return true;
590
+ },
591
+ has(_target, prop) {
592
+ return prop in source;
593
+ }
594
+ });
595
+ }
596
+
597
+ // src/storage.ts
119
598
  var ARTIFACT_SEARCH_STOPWORDS = /* @__PURE__ */ new Set([
120
599
  "a",
121
600
  "an",
@@ -720,17 +1199,17 @@ var KNOWN_ENTITY_FILENAME_PREFIXES = /* @__PURE__ */ new Set([
720
1199
  "topic"
721
1200
  ]);
722
1201
  function inferEntityTypeFromFilename(pathRel) {
723
- const basename = path.basename(pathRel, ".md").toLowerCase();
1202
+ const basename = path2.basename(pathRel, ".md").toLowerCase();
724
1203
  const separator = basename.indexOf("-");
725
1204
  if (separator <= 0) return void 0;
726
1205
  const candidate = basename.slice(0, separator);
727
1206
  return KNOWN_ENTITY_FILENAME_PREFIXES.has(candidate) ? candidate : void 0;
728
1207
  }
729
1208
  function normalizeFrontmatterForPath(frontmatter, pathRel, content = "") {
730
- const normalizedPath = pathRel.split(path.sep).join("/");
1209
+ const normalizedPath = pathRel.split(path2.sep).join("/");
731
1210
  let normalizedFrontmatter = frontmatter;
732
1211
  if (normalizedPath === "entities" || normalizedPath.startsWith("entities/") || normalizedPath.includes("/entities/")) {
733
- const basename = path.basename(pathRel, ".md");
1212
+ const basename = path2.basename(pathRel, ".md");
734
1213
  const inferredType = inferEntityTypeFromContent(content) || inferEntityTypeFromFilename(pathRel) || "entity";
735
1214
  const existingTags = Array.isArray(frontmatter.tags) ? frontmatter.tags : [];
736
1215
  normalizedFrontmatter = {
@@ -797,8 +1276,8 @@ var ContentHashIndex = class _ContentHashIndex {
797
1276
  secureStoreKeyProvider;
798
1277
  secureStoreWriteKeyProvider;
799
1278
  memoryDir;
800
- constructor(stateDir, secureStoreKeyProvider = () => null, secureStoreWriteKeyProvider = secureStoreKeyProvider, memoryDir = path.dirname(stateDir)) {
801
- this.filePath = path.join(stateDir, "fact-hashes.txt");
1279
+ constructor(stateDir, secureStoreKeyProvider = () => null, secureStoreWriteKeyProvider = secureStoreKeyProvider, memoryDir = path2.dirname(stateDir)) {
1280
+ this.filePath = path2.join(stateDir, "fact-hashes.txt");
802
1281
  this.secureStoreKeyProvider = secureStoreKeyProvider;
803
1282
  this.secureStoreWriteKeyProvider = secureStoreWriteKeyProvider;
804
1283
  this.memoryDir = memoryDir;
@@ -845,7 +1324,7 @@ var ContentHashIndex = class _ContentHashIndex {
845
1324
  /** Persist index to disk if changed. */
846
1325
  async save() {
847
1326
  if (!this.dirty) return;
848
- await mkdir(path.dirname(this.filePath), { recursive: true });
1327
+ await mkdir(path2.dirname(this.filePath), { recursive: true });
849
1328
  await writeMaybeEncryptedFile(
850
1329
  this.filePath,
851
1330
  [...this.hashes].join("\n") + "\n",
@@ -1708,9 +2187,10 @@ var StorageManager = class _StorageManager {
1708
2187
  baseDir;
1709
2188
  entitySchemas;
1710
2189
  knowledgeIndexCache = null;
2190
+ artifactIndexCache = null;
2191
+ /** Read by storage/entity-store.ts (decomposition), hence not `private`. */
1711
2192
  static KNOWLEDGE_INDEX_CACHE_TTL_MS = 6e5;
1712
2193
  // 10 minutes (entity mutations invalidate)
1713
- artifactIndexCache = null;
1714
2194
  static ARTIFACT_INDEX_CACHE_TTL_MS = 6e4;
1715
2195
  // 1 minute
1716
2196
  static artifactWriteVersionByDir = /* @__PURE__ */ new Map();
@@ -1905,7 +2385,7 @@ var StorageManager = class _StorageManager {
1905
2385
  void 0,
1906
2386
  this.baseDir
1907
2387
  );
1908
- const rel = path.relative(this.baseDir, filePath).split(path.sep).join("/");
2388
+ const rel = path2.relative(this.baseDir, filePath).split(path2.sep).join("/");
1909
2389
  return `${rel}:${version.versionId}`;
1910
2390
  } catch (err) {
1911
2391
  log.warn(
@@ -1915,18 +2395,28 @@ var StorageManager = class _StorageManager {
1915
2395
  }
1916
2396
  }
1917
2397
  /** The root directory of this storage instance. */
2398
+ /** EntityStore (storage.ts decomposition). Lazy; selfDeps live wiring. */
2399
+ _entityStore;
2400
+ get entityStore() {
2401
+ if (!this._entityStore) {
2402
+ this._entityStore = new EntityStore(
2403
+ selfDeps(this)
2404
+ );
2405
+ }
2406
+ return this._entityStore;
2407
+ }
1918
2408
  get dir() {
1919
2409
  return this.baseDir;
1920
2410
  }
1921
2411
  identityFilePath(workspaceDir, namespace) {
1922
2412
  const rawNamespace = typeof namespace === "string" ? namespace.trim() : "";
1923
- if (!rawNamespace) return path.join(workspaceDir, "IDENTITY.md");
2413
+ if (!rawNamespace) return path2.join(workspaceDir, "IDENTITY.md");
1924
2414
  const safeNamespace = rawNamespace.replace(/[^a-zA-Z0-9._-]/g, "-");
1925
- return path.join(workspaceDir, `IDENTITY.${safeNamespace}.md`);
2415
+ return path2.join(workspaceDir, `IDENTITY.${safeNamespace}.md`);
1926
2416
  }
1927
2417
  versionFilePath(kind) {
1928
2418
  const fileName = kind === "memory-status" ? ".memory-status-version.log" : kind === "artifact-write" ? ".artifact-write-version.log" : ".cold-write-version.log";
1929
- return path.join(this.stateDir, fileName);
2419
+ return path2.join(this.stateDir, fileName);
1930
2420
  }
1931
2421
  bumpSharedVersion(kind, fallbackMap) {
1932
2422
  const filePath = this.versionFilePath(kind);
@@ -1973,7 +2463,7 @@ var StorageManager = class _StorageManager {
1973
2463
  // memories.
1974
2464
  // -------------------------------------------------------------------------
1975
2465
  get wearablesDir() {
1976
- return path.join(this.baseDir, WEARABLES_DIR_NAME);
2466
+ return path2.join(this.baseDir, WEARABLES_DIR_NAME);
1977
2467
  }
1978
2468
  /**
1979
2469
  * Resolve the on-disk path for a source/day transcript. Throws on
@@ -1991,7 +2481,7 @@ var StorageManager = class _StorageManager {
1991
2481
  `invalid wearable transcript date '${String(date)}' \u2014 expected YYYY-MM-DD`
1992
2482
  );
1993
2483
  }
1994
- return path.join(this.wearablesDir, sourceId, `${date}.md`);
2484
+ return path2.join(this.wearablesDir, sourceId, `${date}.md`);
1995
2485
  }
1996
2486
  async writeWearableDayTranscript(sourceId, date, serialized) {
1997
2487
  const targetPath = this.wearableTranscriptPath(sourceId, date);
@@ -2018,7 +2508,7 @@ var StorageManager = class _StorageManager {
2018
2508
  sources = [sourceId];
2019
2509
  } else {
2020
2510
  try {
2021
- const entries = await readdir(this.wearablesDir, { withFileTypes: true });
2511
+ const entries = await readdir2(this.wearablesDir, { withFileTypes: true });
2022
2512
  sources = entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name);
2023
2513
  } catch (err) {
2024
2514
  if (err.code === "ENOENT") return [];
@@ -2029,7 +2519,7 @@ var StorageManager = class _StorageManager {
2029
2519
  if (!/^[a-z][a-z0-9-]{0,63}$/.test(source)) continue;
2030
2520
  let entries;
2031
2521
  try {
2032
- entries = await readdir(path.join(this.wearablesDir, source));
2522
+ entries = await readdir2(path2.join(this.wearablesDir, source));
2033
2523
  } catch (err) {
2034
2524
  if (err.code === "ENOENT") continue;
2035
2525
  throw err;
@@ -2116,25 +2606,25 @@ var StorageManager = class _StorageManager {
2116
2606
  });
2117
2607
  }
2118
2608
  get factsDir() {
2119
- return path.join(this.baseDir, "facts");
2609
+ return path2.join(this.baseDir, "facts");
2120
2610
  }
2121
2611
  get correctionsDir() {
2122
- return path.join(this.baseDir, "corrections");
2612
+ return path2.join(this.baseDir, "corrections");
2123
2613
  }
2124
2614
  get proceduresDir() {
2125
- return path.join(this.baseDir, "procedures");
2615
+ return path2.join(this.baseDir, "procedures");
2126
2616
  }
2127
2617
  get reasoningTracesDir() {
2128
- return path.join(this.baseDir, "reasoning-traces");
2618
+ return path2.join(this.baseDir, "reasoning-traces");
2129
2619
  }
2130
2620
  get entitiesDir() {
2131
- return path.join(this.baseDir, "entities");
2621
+ return path2.join(this.baseDir, "entities");
2132
2622
  }
2133
2623
  resolveEntityFilePath(name) {
2134
2624
  if (typeof name !== "string") return null;
2135
- const filePath = path.resolve(this.entitiesDir, `${name}.md`);
2136
- const relative = path.relative(this.entitiesDir, filePath);
2137
- if (relative === "" || relative.startsWith("..") || path.isAbsolute(relative)) {
2625
+ const filePath = path2.resolve(this.entitiesDir, `${name}.md`);
2626
+ const relative = path2.relative(this.entitiesDir, filePath);
2627
+ if (relative === "" || relative.startsWith("..") || path2.isAbsolute(relative)) {
2138
2628
  return null;
2139
2629
  }
2140
2630
  return filePath;
@@ -2149,10 +2639,10 @@ var StorageManager = class _StorageManager {
2149
2639
  return writeMaybeEncryptedFileFromChunks(filePath, chunks, this.resolveWriteKey(), {}, this.baseDir).then(() => this.notifyCatalogWrite());
2150
2640
  }
2151
2641
  assertManagedStoragePath(filePath, method) {
2152
- const resolved = path.resolve(filePath);
2153
- const base = path.resolve(this.baseDir);
2154
- const rel = path.relative(base, resolved);
2155
- if (rel === "" || rel === ".." || rel.startsWith(`..${path.sep}`) || path.isAbsolute(rel)) {
2642
+ const resolved = path2.resolve(filePath);
2643
+ const base = path2.resolve(this.baseDir);
2644
+ const rel = path2.relative(base, resolved);
2645
+ if (rel === "" || rel === ".." || rel.startsWith(`..${path2.sep}`) || path2.isAbsolute(rel)) {
2156
2646
  throw new Error(`${method}: file path escapes memory dir`);
2157
2647
  }
2158
2648
  return resolved;
@@ -2164,7 +2654,7 @@ var StorageManager = class _StorageManager {
2164
2654
  async digestOfflineSyncFile(filePath) {
2165
2655
  const target = this.assertManagedStoragePath(filePath, "storage.digestOfflineSyncFile");
2166
2656
  const st = await stat(target);
2167
- const relPath = path.relative(this.baseDir, target).split(path.sep).join("/");
2657
+ const relPath = path2.relative(this.baseDir, target).split(path2.sep).join("/");
2168
2658
  const cache = await this.loadOfflineSyncDigestCache();
2169
2659
  const cached = cache.get(relPath);
2170
2660
  if (cached && cached.statBytes === st.size && cached.mtimeMs === st.mtimeMs && cached.ctimeMs === st.ctimeMs && !cached.encrypted) {
@@ -2225,7 +2715,7 @@ var StorageManager = class _StorageManager {
2225
2715
  const bytes = typeof record.bytes === "number" ? record.bytes : NaN;
2226
2716
  const sha256 = typeof record.sha256 === "string" ? record.sha256 : "";
2227
2717
  const encrypted = record.encrypted === true;
2228
- if (cachePath.length === 0 || cachePath === ".." || cachePath.startsWith("../") || path.isAbsolute(cachePath) || !Number.isFinite(statBytes) || !Number.isFinite(mtimeMs) || !Number.isFinite(ctimeMs) || !Number.isFinite(bytes) || !/^[a-f0-9]{64}$/i.test(sha256)) {
2718
+ if (cachePath.length === 0 || cachePath === ".." || cachePath.startsWith("../") || path2.isAbsolute(cachePath) || !Number.isFinite(statBytes) || !Number.isFinite(mtimeMs) || !Number.isFinite(ctimeMs) || !Number.isFinite(bytes) || !/^[a-f0-9]{64}$/i.test(sha256)) {
2229
2719
  continue;
2230
2720
  }
2231
2721
  cache.set(cachePath, { statBytes, mtimeMs, ctimeMs, encrypted, sha256, bytes });
@@ -2267,7 +2757,7 @@ var StorageManager = class _StorageManager {
2267
2757
  const cache = this.offlineSyncDigestCache;
2268
2758
  if (!cache) return;
2269
2759
  const entries = [...cache.entries()].sort(([a], [b]) => a.localeCompare(b)).map(([entryPath, entry]) => ({ path: entryPath, ...entry }));
2270
- await mkdir(path.dirname(this.offlineSyncDigestCachePath), { recursive: true });
2760
+ await mkdir(path2.dirname(this.offlineSyncDigestCachePath), { recursive: true });
2271
2761
  await writeFile(
2272
2762
  this.offlineSyncDigestCachePath,
2273
2763
  `${JSON.stringify({ version: 1, entries })}
@@ -2306,7 +2796,7 @@ var StorageManager = class _StorageManager {
2306
2796
  }
2307
2797
  async deleteOfflineSyncFile(filePath) {
2308
2798
  const target = this.assertManagedStoragePath(filePath, "storage.deleteOfflineSyncFile");
2309
- await unlink(target).catch((error) => {
2799
+ await unlink2(target).catch((error) => {
2310
2800
  if (isErrnoCode(error, "ENOENT")) return;
2311
2801
  throw error;
2312
2802
  });
@@ -2316,14 +2806,14 @@ var StorageManager = class _StorageManager {
2316
2806
  this.invalidateAllMemoriesCache();
2317
2807
  this.invalidateKnowledgeIndexCache();
2318
2808
  this.factHashIndexAuthoritative = false;
2319
- await unlink(this.factHashIndexReadyPath).catch((error) => {
2809
+ await unlink2(this.factHashIndexReadyPath).catch((error) => {
2320
2810
  if (isErrnoCode(error, "ENOENT")) return;
2321
2811
  throw error;
2322
2812
  });
2323
- if (filePath.includes(`${path.sep}cold${path.sep}`)) {
2813
+ if (filePath.includes(`${path2.sep}cold${path2.sep}`)) {
2324
2814
  this.invalidateColdMemoriesCache();
2325
2815
  }
2326
- if (filePath.includes(`${path.sep}artifacts${path.sep}`)) {
2816
+ if (filePath.includes(`${path2.sep}artifacts${path2.sep}`)) {
2327
2817
  this.bumpArtifactWriteVersion();
2328
2818
  }
2329
2819
  this.bumpMemoryStatusVersion();
@@ -2351,7 +2841,7 @@ var StorageManager = class _StorageManager {
2351
2841
  }
2352
2842
  async appendStorageSecureFileUnlocked(filePath, content) {
2353
2843
  const writeKey = this.resolveWriteKey();
2354
- await mkdir(path.dirname(filePath), { recursive: true });
2844
+ await mkdir(path2.dirname(filePath), { recursive: true });
2355
2845
  if (writeKey === null) {
2356
2846
  try {
2357
2847
  if (isEncryptedFile(await readFile(filePath))) {
@@ -2377,16 +2867,16 @@ var StorageManager = class _StorageManager {
2377
2867
  this.notifyCatalogWrite();
2378
2868
  }
2379
2869
  get stateDir() {
2380
- return path.join(this.baseDir, "state");
2870
+ return path2.join(this.baseDir, "state");
2381
2871
  }
2382
2872
  get offlineSyncDigestCachePath() {
2383
- return path.join(this.baseDir, ".offline-sync", "digest-cache.v1.json");
2873
+ return path2.join(this.baseDir, ".offline-sync", "digest-cache.v1.json");
2384
2874
  }
2385
2875
  get entitySynthesisQueuePath() {
2386
- return path.join(this.stateDir, "entity-synthesis-queue.json");
2876
+ return path2.join(this.stateDir, "entity-synthesis-queue.json");
2387
2877
  }
2388
2878
  get factHashIndexReadyPath() {
2389
- return path.join(this.stateDir, "fact-hashes.ready");
2879
+ return path2.join(this.stateDir, "fact-hashes.ready");
2390
2880
  }
2391
2881
  // ── Tombstone store access (issue #1579) ─────────────────────────────────
2392
2882
  /**
@@ -2396,7 +2886,7 @@ var StorageManager = class _StorageManager {
2396
2886
  * helpers are injected into the store).
2397
2887
  */
2398
2888
  get tombstonesPath() {
2399
- return path.join(this.stateDir, "tombstones.jsonl");
2889
+ return path2.join(this.stateDir, "tombstones.jsonl");
2400
2890
  }
2401
2891
  /**
2402
2892
  * Configure the tombstone invariant for this storage instance. Installed
@@ -2595,7 +3085,7 @@ var StorageManager = class _StorageManager {
2595
3085
  );
2596
3086
  }
2597
3087
  await factHashIndex.save();
2598
- await mkdir(path.dirname(this.factHashIndexReadyPath), { recursive: true });
3088
+ await mkdir(path2.dirname(this.factHashIndexReadyPath), { recursive: true });
2599
3089
  await writeFile(this.factHashIndexReadyPath, "v1\n", "utf-8");
2600
3090
  this.factHashIndexAuthoritative = true;
2601
3091
  })().finally(() => {
@@ -2604,55 +3094,55 @@ var StorageManager = class _StorageManager {
2604
3094
  await this.factHashIndexAuthoritativePromise;
2605
3095
  }
2606
3096
  get questionsDir() {
2607
- return path.join(this.baseDir, "questions");
3097
+ return path2.join(this.baseDir, "questions");
2608
3098
  }
2609
3099
  get artifactsDir() {
2610
- return path.join(this.baseDir, "artifacts");
3100
+ return path2.join(this.baseDir, "artifacts");
2611
3101
  }
2612
3102
  get identityDir() {
2613
- return path.join(this.baseDir, "identity");
3103
+ return path2.join(this.baseDir, "identity");
2614
3104
  }
2615
3105
  get identityAnchorPath() {
2616
- return path.join(this.identityDir, "identity-anchor.md");
3106
+ return path2.join(this.identityDir, "identity-anchor.md");
2617
3107
  }
2618
3108
  get identityIncidentsDir() {
2619
- return path.join(this.identityDir, "incidents");
3109
+ return path2.join(this.identityDir, "incidents");
2620
3110
  }
2621
3111
  get identityAuditsWeeklyDir() {
2622
- return path.join(this.identityDir, "audits", "weekly");
3112
+ return path2.join(this.identityDir, "audits", "weekly");
2623
3113
  }
2624
3114
  get identityAuditsMonthlyDir() {
2625
- return path.join(this.identityDir, "audits", "monthly");
3115
+ return path2.join(this.identityDir, "audits", "monthly");
2626
3116
  }
2627
3117
  get identityImprovementLoopsPath() {
2628
- return path.join(this.identityDir, "improvement-loops.md");
3118
+ return path2.join(this.identityDir, "improvement-loops.md");
2629
3119
  }
2630
3120
  get identityReflectionsPath() {
2631
- return path.join(this.identityDir, "reflections.md");
3121
+ return path2.join(this.identityDir, "reflections.md");
2632
3122
  }
2633
3123
  get profilePath() {
2634
- return path.join(this.baseDir, "profile.md");
3124
+ return path2.join(this.baseDir, "profile.md");
2635
3125
  }
2636
3126
  get memoryActionsPath() {
2637
- return path.join(this.stateDir, "memory-actions.jsonl");
3127
+ return path2.join(this.stateDir, "memory-actions.jsonl");
2638
3128
  }
2639
3129
  get memoryLifecycleLedgerPath() {
2640
- return path.join(this.stateDir, "memory-lifecycle-ledger.jsonl");
3130
+ return path2.join(this.stateDir, "memory-lifecycle-ledger.jsonl");
2641
3131
  }
2642
3132
  get compressionGuidelinesPath() {
2643
- return path.join(this.stateDir, "compression-guidelines.md");
3133
+ return path2.join(this.stateDir, "compression-guidelines.md");
2644
3134
  }
2645
3135
  get compressionGuidelineDraftPath() {
2646
- return path.join(this.stateDir, "compression-guidelines.draft.md");
3136
+ return path2.join(this.stateDir, "compression-guidelines.draft.md");
2647
3137
  }
2648
3138
  get compressionGuidelineStatePath() {
2649
- return path.join(this.stateDir, "compression-guideline-state.json");
3139
+ return path2.join(this.stateDir, "compression-guideline-state.json");
2650
3140
  }
2651
3141
  get compressionGuidelineDraftStatePath() {
2652
- return path.join(this.stateDir, "compression-guideline-draft-state.json");
3142
+ return path2.join(this.stateDir, "compression-guideline-draft-state.json");
2653
3143
  }
2654
3144
  get behaviorSignalsPath() {
2655
- return path.join(this.stateDir, "behavior-signals.jsonl");
3145
+ return path2.join(this.stateDir, "behavior-signals.jsonl");
2656
3146
  }
2657
3147
  /**
2658
3148
  * Buffer surprise telemetry ledger (issue #563 PR 3).
@@ -2665,7 +3155,7 @@ var StorageManager = class _StorageManager {
2665
3155
  * governance sweeps can treat it uniformly.
2666
3156
  */
2667
3157
  get bufferSurpriseLedgerPath() {
2668
- return path.join(this.stateDir, "buffer-surprise-ledger.jsonl");
3158
+ return path2.join(this.stateDir, "buffer-surprise-ledger.jsonl");
2669
3159
  }
2670
3160
  /**
2671
3161
  * Entity alias table loaded from THIS store's config/aliases.json.
@@ -2675,9 +3165,11 @@ var StorageManager = class _StorageManager {
2675
3165
  * store loaded last rewrite every other store's canonical entity ids.
2676
3166
  */
2677
3167
  userAliases = {};
2678
- /** Normalize an entity name using this store's alias table. */
2679
3168
  normalizeEntityName(raw, type) {
2680
- return normalizeEntityName(raw, type, this.userAliases);
3169
+ return this.entityStore.normalizeEntityName(
3170
+ raw,
3171
+ type
3172
+ );
2681
3173
  }
2682
3174
  /**
2683
3175
  * Read-only view of this store's user alias table, for call sites that
@@ -2697,7 +3189,7 @@ var StorageManager = class _StorageManager {
2697
3189
  this.loadAliasesSync();
2698
3190
  }
2699
3191
  loadAliasesSync() {
2700
- const aliasPath = path.join(this.baseDir, "config", "aliases.json");
3192
+ const aliasPath = path2.join(this.baseDir, "config", "aliases.json");
2701
3193
  this.userAliases = {};
2702
3194
  try {
2703
3195
  const raw = readFileSync(aliasPath, "utf-8");
@@ -2722,9 +3214,9 @@ var StorageManager = class _StorageManager {
2722
3214
  }
2723
3215
  async ensureDirectories() {
2724
3216
  const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
2725
- await mkdir(path.join(this.factsDir, today), { recursive: true });
2726
- await mkdir(path.join(this.proceduresDir, today), { recursive: true });
2727
- await mkdir(path.join(this.reasoningTracesDir, today), { recursive: true });
3217
+ await mkdir(path2.join(this.factsDir, today), { recursive: true });
3218
+ await mkdir(path2.join(this.proceduresDir, today), { recursive: true });
3219
+ await mkdir(path2.join(this.reasoningTracesDir, today), { recursive: true });
2728
3220
  await mkdir(this.correctionsDir, { recursive: true });
2729
3221
  await mkdir(this.entitiesDir, { recursive: true });
2730
3222
  await mkdir(this.stateDir, { recursive: true });
@@ -2734,7 +3226,7 @@ var StorageManager = class _StorageManager {
2734
3226
  await mkdir(this.identityIncidentsDir, { recursive: true });
2735
3227
  await mkdir(this.identityAuditsWeeklyDir, { recursive: true });
2736
3228
  await mkdir(this.identityAuditsMonthlyDir, { recursive: true });
2737
- await mkdir(path.join(this.baseDir, "config"), { recursive: true });
3229
+ await mkdir(path2.join(this.baseDir, "config"), { recursive: true });
2738
3230
  }
2739
3231
  /**
2740
3232
  * Resolve the on-disk write path for a memory of the given category, creating
@@ -2751,11 +3243,11 @@ var StorageManager = class _StorageManager {
2751
3243
  async resolveCategoryWritePath(category, id, today) {
2752
3244
  if (category === "correction") {
2753
3245
  await mkdir(this.correctionsDir, { recursive: true });
2754
- return path.join(this.correctionsDir, `${id}.md`);
3246
+ return path2.join(this.correctionsDir, `${id}.md`);
2755
3247
  }
2756
- const datedDir = path.join(getCategoryDir(this.baseDir, category), today);
3248
+ const datedDir = path2.join(getCategoryDir(this.baseDir, category), today);
2757
3249
  await mkdir(datedDir, { recursive: true });
2758
- return path.join(datedDir, `${id}.md`);
3250
+ return path2.join(datedDir, `${id}.md`);
2759
3251
  }
2760
3252
  async writeMemory(category, content, options = {}) {
2761
3253
  await this.ensureDirectories();
@@ -3005,7 +3497,7 @@ ${sanitized.text}
3005
3497
  await this.ensureDirectories();
3006
3498
  const now = /* @__PURE__ */ new Date();
3007
3499
  const day = now.toISOString().slice(0, 10);
3008
- const dir = path.join(this.artifactsDir, day);
3500
+ const dir = path2.join(this.artifactsDir, day);
3009
3501
  await mkdir(dir, { recursive: true });
3010
3502
  const id = `artifact-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`;
3011
3503
  const fm = {
@@ -3029,7 +3521,7 @@ ${sanitized.text}
3029
3521
  log.warn(`artifact content rejected for ${id}; violations=${sanitized.violations.join(", ")}`);
3030
3522
  return "";
3031
3523
  }
3032
- const filePath = path.join(dir, `${id}.md`);
3524
+ const filePath = path2.join(dir, `${id}.md`);
3033
3525
  await this.writeStorageSecureFile(filePath, `${serializeFrontmatter(fm)}
3034
3526
 
3035
3527
  ${sanitized.text}
@@ -3055,9 +3547,9 @@ ${sanitized.text}
3055
3547
  const artifacts = [];
3056
3548
  const readDir = async (dir) => {
3057
3549
  try {
3058
- const entries = await readdir(dir, { withFileTypes: true });
3550
+ const entries = await readdir2(dir, { withFileTypes: true });
3059
3551
  for (const entry of entries) {
3060
- const fullPath = path.join(dir, entry.name);
3552
+ const fullPath = path2.join(dir, entry.name);
3061
3553
  if (entry.isDirectory()) {
3062
3554
  await readDir(fullPath);
3063
3555
  continue;
@@ -3106,107 +3598,12 @@ ${sanitized.text}
3106
3598
  return hits.slice(0, maxResults).map((h) => h.memory);
3107
3599
  }
3108
3600
  async writeEntity(name, type, facts, options = {}) {
3109
- await this.ensureDirectories();
3110
- if (typeof name !== "string" || !name.trim() || typeof type !== "string" || !type.trim()) {
3111
- log.warn("writeEntity: invalid entity payload, skipping", {
3112
- nameType: typeof name,
3113
- typeType: typeof type
3114
- });
3115
- return "";
3116
- }
3117
- const safeFacts = Array.isArray(facts) ? [...new Set(
3118
- facts.filter((fact) => typeof fact === "string").map((fact) => fact.trim()).filter((fact) => fact.length > 0)
3119
- )] : [];
3120
- let normalized = this.normalizeEntityName(name, type);
3121
- const match = await this.findMatchingEntity(name, type);
3122
- if (match && match !== normalized) {
3123
- log.debug(`fuzzy match: "${normalized}" \u2192 existing "${match}"`);
3124
- normalized = match;
3125
- }
3126
- const filePath = path.join(this.entitiesDir, `${normalized}.md`);
3127
- let entity = {
3601
+ return this.entityStore.writeEntity(
3128
3602
  name,
3129
3603
  type,
3130
- created: "",
3131
- updated: (/* @__PURE__ */ new Date()).toISOString(),
3132
- facts: [],
3133
- summary: void 0,
3134
- synthesis: void 0,
3135
- synthesisUpdatedAt: void 0,
3136
- synthesisVersion: void 0,
3137
- synthesisStructuredFactCount: void 0,
3138
- synthesisStructuredFactDigest: void 0,
3139
- timeline: [],
3140
- relationships: [],
3141
- activity: [],
3142
- aliases: []
3143
- };
3144
- try {
3145
- const existing = await this.readStorageSecureFile(filePath);
3146
- entity = parseEntityFile(existing, this.entitySchemas);
3147
- } catch (err) {
3148
- if (err instanceof SecureStoreLockedError) throw err;
3149
- if (!isErrnoCode(err, "ENOENT")) throw err;
3150
- }
3151
- const timestamp = options.timestamp?.trim() || (/* @__PURE__ */ new Date()).toISOString();
3152
- const source = options.source?.trim() || void 0;
3153
- const sessionKey = options.sessionKey?.trim() || void 0;
3154
- const principal = options.principal?.trim() || void 0;
3155
- const structuredSectionMap = new Map(
3156
- (entity.structuredSections ?? []).map((section) => [section.key, {
3157
- ...section,
3158
- facts: [...section.facts]
3159
- }])
3160
- );
3161
- for (const section of options.structuredSections ?? []) {
3162
- const normalizedSection = normalizeEntityStructuredSection(type, section, this.entitySchemas);
3163
- const normalizedFacts = normalizeStructuredSectionFacts(section.facts);
3164
- if (normalizedFacts.length === 0) continue;
3165
- const existingSection = structuredSectionMap.get(normalizedSection.key);
3166
- if (!existingSection) {
3167
- structuredSectionMap.set(normalizedSection.key, {
3168
- key: normalizedSection.key,
3169
- title: normalizedSection.title,
3170
- facts: normalizedFacts
3171
- });
3172
- continue;
3173
- }
3174
- existingSection.facts = normalizeStructuredSectionFacts([...existingSection.facts, ...normalizedFacts]);
3175
- if (!existingSection.title.trim() && normalizedSection.title.trim()) {
3176
- existingSection.title = normalizedSection.title;
3177
- }
3178
- }
3179
- for (const fact of safeFacts) {
3180
- const nextEntry = {
3181
- timestamp,
3182
- text: fact,
3183
- ...source ? { source } : {},
3184
- ...sessionKey ? { sessionKey } : {},
3185
- ...principal ? { principal } : {}
3186
- };
3187
- const alreadyPresent = entity.timeline.some(
3188
- (entry) => entry.timestamp === nextEntry.timestamp && entry.text === nextEntry.text && entry.source === nextEntry.source && entry.sessionKey === nextEntry.sessionKey && entry.principal === nextEntry.principal
3189
- );
3190
- if (alreadyPresent) continue;
3191
- entity.timeline.push(nextEntry);
3192
- }
3193
- entity.structuredSections = sortStructuredSectionsBySchema(
3194
- type,
3195
- Array.from(structuredSectionMap.values()).filter((section) => section.facts.length > 0),
3196
- this.entitySchemas
3604
+ facts,
3605
+ options
3197
3606
  );
3198
- entity.facts = compileEntityFacts(entity.timeline, entity.structuredSections);
3199
- entity.summary = entity.synthesis || entity.summary;
3200
- entity.name = name;
3201
- entity.type = type;
3202
- entity.created = entity.created || timestamp;
3203
- entity.updated = (/* @__PURE__ */ new Date()).toISOString();
3204
- await this.snapshotBeforeWrite(filePath, "write");
3205
- await this.writeStorageSecureFile(filePath, serializeEntityFile(entity, this.entitySchemas));
3206
- this.invalidateKnowledgeIndexCache();
3207
- this.bumpMemoryStatusVersion();
3208
- log.debug(`wrote entity ${normalized}`);
3209
- return normalized;
3210
3607
  }
3211
3608
  async readProfile() {
3212
3609
  try {
@@ -3364,7 +3761,7 @@ ${sanitized.text}
3364
3761
  * per-process in-memory cache safe across process boundaries.
3365
3762
  */
3366
3763
  invalidateColdMemoriesCache() {
3367
- const coldRoot = path.join(this.baseDir, "cold");
3764
+ const coldRoot = path2.join(this.baseDir, "cold");
3368
3765
  _StorageManager.coldMemoriesCache.delete(coldRoot);
3369
3766
  this.bumpColdWriteVersion();
3370
3767
  invalidateAllForDir(this.baseDir);
@@ -3400,14 +3797,14 @@ ${sanitized.text}
3400
3797
  const dirStat = await lstat(dir);
3401
3798
  if (dirStat.isSymbolicLink() || !dirStat.isDirectory()) return;
3402
3799
  assertPathInsideRoot(memoryRootReal, await realpath(dir), dir);
3403
- entries = await readdir(dir, { withFileTypes: true });
3800
+ entries = await readdir2(dir, { withFileTypes: true });
3404
3801
  } catch {
3405
3802
  return;
3406
3803
  }
3407
3804
  const subdirs = [];
3408
3805
  for (const entry of entries) {
3409
3806
  if (entry.isSymbolicLink()) continue;
3410
- const fullPath = path.join(dir, entry.name);
3807
+ const fullPath = path2.join(dir, entry.name);
3411
3808
  if (entry.isDirectory()) {
3412
3809
  subdirs.push(fullPath);
3413
3810
  } else if (entry.name.endsWith(".md")) {
@@ -3423,7 +3820,7 @@ ${sanitized.text}
3423
3820
  }
3424
3821
  };
3425
3822
  for (const dir of RECALL_FALLBACK_DIRS) {
3426
- await collectPaths(path.join(this.baseDir, dir));
3823
+ await collectPaths(path2.join(this.baseDir, dir));
3427
3824
  }
3428
3825
  return filePaths;
3429
3826
  }
@@ -3492,7 +3889,7 @@ ${sanitized.text}
3492
3889
  const correctionPaths = [];
3493
3890
  const factPaths = [];
3494
3891
  for (const filePath of filePaths) {
3495
- if (filePath === this.correctionsDir || filePath.startsWith(`${this.correctionsDir}${path.sep}`)) {
3892
+ if (filePath === this.correctionsDir || filePath.startsWith(`${this.correctionsDir}${path2.sep}`)) {
3496
3893
  correctionPaths.push(filePath);
3497
3894
  } else {
3498
3895
  factPaths.push(filePath);
@@ -3610,10 +4007,10 @@ ${sanitized.text}
3610
4007
  const filePaths = [];
3611
4008
  const collectPaths = async (dir) => {
3612
4009
  try {
3613
- const entries = await readdir(dir, { withFileTypes: true });
4010
+ const entries = await readdir2(dir, { withFileTypes: true });
3614
4011
  const subdirs = [];
3615
4012
  for (const entry of entries) {
3616
- const fullPath = path.join(dir, entry.name);
4013
+ const fullPath = path2.join(dir, entry.name);
3617
4014
  if (entry.isDirectory()) {
3618
4015
  subdirs.push(fullPath);
3619
4016
  } else if (entry.name.endsWith(".md")) {
@@ -3640,9 +4037,9 @@ ${sanitized.text}
3640
4037
  const root = this.archiveDir;
3641
4038
  const readDir = async (dir) => {
3642
4039
  try {
3643
- const entries = await readdir(dir, { withFileTypes: true });
4040
+ const entries = await readdir2(dir, { withFileTypes: true });
3644
4041
  for (const entry of entries) {
3645
- const fullPath = path.join(dir, entry.name);
4042
+ const fullPath = path2.join(dir, entry.name);
3646
4043
  if (entry.isDirectory()) {
3647
4044
  await readDir(fullPath);
3648
4045
  } else if (entry.name.endsWith(".md")) {
@@ -3687,11 +4084,11 @@ ${sanitized.text}
3687
4084
  content: parsed.content
3688
4085
  };
3689
4086
  }
3690
- const normalizedPath = filePath.split(path.sep).join("/");
4087
+ const normalizedPath = filePath.split(path2.sep).join("/");
3691
4088
  if (normalizedPath.includes("/entities/") && filePath.endsWith(".md")) {
3692
4089
  const entity = parseEntityFile(raw, this.entitySchemas);
3693
4090
  if (!entity.name) return null;
3694
- const nameWithoutExt = path.basename(filePath, ".md");
4091
+ const nameWithoutExt = path2.basename(filePath, ".md");
3695
4092
  const fileMtime = entity.updated || await stat(filePath).then((s) => s.mtime.toISOString()).catch(() => (/* @__PURE__ */ new Date(0)).toISOString());
3696
4093
  return {
3697
4094
  path: filePath,
@@ -3715,7 +4112,7 @@ ${sanitized.text}
3715
4112
  }
3716
4113
  }
3717
4114
  resolveTierRootDir(tier) {
3718
- return tier === "cold" ? path.join(this.baseDir, "cold") : this.baseDir;
4115
+ return tier === "cold" ? path2.join(this.baseDir, "cold") : this.baseDir;
3719
4116
  }
3720
4117
  resolveMemoryDateDir(memory) {
3721
4118
  const preferred = memory.frontmatter.created || memory.frontmatter.updated;
@@ -3730,13 +4127,13 @@ ${sanitized.text}
3730
4127
  buildTierMemoryPath(memory, tier) {
3731
4128
  const root = this.resolveTierRootDir(tier);
3732
4129
  if (this.isArtifactMemory(memory)) {
3733
- return path.join(root, "artifacts", this.resolveMemoryDateDir(memory), `${memory.frontmatter.id}.md`);
4130
+ return path2.join(root, "artifacts", this.resolveMemoryDateDir(memory), `${memory.frontmatter.id}.md`);
3734
4131
  }
3735
4132
  if (memory.frontmatter.category === "correction") {
3736
- return path.join(root, "corrections", `${memory.frontmatter.id}.md`);
4133
+ return path2.join(root, "corrections", `${memory.frontmatter.id}.md`);
3737
4134
  }
3738
4135
  const dir = categoryDirName(memory.frontmatter.category);
3739
- return path.join(root, dir, this.resolveMemoryDateDir(memory), `${memory.frontmatter.id}.md`);
4136
+ return path2.join(root, dir, this.resolveMemoryDateDir(memory), `${memory.frontmatter.id}.md`);
3740
4137
  }
3741
4138
  async writeMemoryFileAtomic(targetPath, memory) {
3742
4139
  const fileContent = `${serializeFrontmatter(memory.frontmatter)}
@@ -3749,11 +4146,11 @@ ${memory.content}
3749
4146
  }
3750
4147
  async moveMemoryToPath(memory, targetPath) {
3751
4148
  await this.writeMemoryFileAtomic(targetPath, memory);
3752
- const sourcePath = path.resolve(memory.path);
3753
- const destPath = path.resolve(targetPath);
4149
+ const sourcePath = path2.resolve(memory.path);
4150
+ const destPath = path2.resolve(targetPath);
3754
4151
  if (sourcePath !== destPath) {
3755
4152
  try {
3756
- await unlink(memory.path);
4153
+ await unlink2(memory.path);
3757
4154
  } catch (err) {
3758
4155
  const message = err instanceof Error ? err.message : String(err);
3759
4156
  if (!message.includes("ENOENT")) {
@@ -3765,15 +4162,15 @@ ${memory.content}
3765
4162
  }
3766
4163
  async migrateMemoryToTier(memory, targetTier) {
3767
4164
  const targetPath = this.buildTierMemoryPath(memory, targetTier);
3768
- const sourcePath = path.resolve(memory.path);
3769
- const destPath = path.resolve(targetPath);
4165
+ const sourcePath = path2.resolve(memory.path);
4166
+ const destPath = path2.resolve(targetPath);
3770
4167
  if (sourcePath === destPath) {
3771
4168
  return { changed: false, targetPath };
3772
4169
  }
3773
4170
  const existing = await this.readMemoryByPath(targetPath);
3774
4171
  if (existing?.frontmatter.id === memory.frontmatter.id) {
3775
4172
  try {
3776
- await unlink(memory.path);
4173
+ await unlink2(memory.path);
3777
4174
  } catch (err) {
3778
4175
  const message = err instanceof Error ? err.message : String(err);
3779
4176
  if (!message.includes("ENOENT")) {
@@ -3792,7 +4189,7 @@ ${memory.content}
3792
4189
  return { changed: true, targetPath };
3793
4190
  }
3794
4191
  get archiveDir() {
3795
- return path.join(this.baseDir, "archive");
4192
+ return path2.join(this.baseDir, "archive");
3796
4193
  }
3797
4194
  /**
3798
4195
  * Archive a memory by moving it from facts/ to archive/YYYY-MM-DD/.
@@ -3803,7 +4200,7 @@ ${memory.content}
3803
4200
  try {
3804
4201
  const now = lifecycle?.at ?? /* @__PURE__ */ new Date();
3805
4202
  const today = now.toISOString().slice(0, 10);
3806
- const destDir = path.join(this.archiveDir, today);
4203
+ const destDir = path2.join(this.archiveDir, today);
3807
4204
  await mkdir(destDir, { recursive: true });
3808
4205
  const updatedFm = {
3809
4206
  ...memory.frontmatter,
@@ -3815,9 +4212,9 @@ ${memory.content}
3815
4212
 
3816
4213
  ${memory.content}
3817
4214
  `;
3818
- const destPath = path.join(destDir, path.basename(memory.path));
4215
+ const destPath = path2.join(destDir, path2.basename(memory.path));
3819
4216
  await this.writeStorageSecureFile(destPath, fileContent);
3820
- await unlink(memory.path);
4217
+ await unlink2(memory.path);
3821
4218
  this.invalidateAllMemoriesCache();
3822
4219
  await this.appendGeneratedMemoryLifecycleEventFailOpen(
3823
4220
  "storage.archiveMemory",
@@ -3844,33 +4241,19 @@ ${memory.content}
3844
4241
  }
3845
4242
  async readEntities() {
3846
4243
  try {
3847
- const entries = await readdir(this.entitiesDir);
4244
+ const entries = await readdir2(this.entitiesDir);
3848
4245
  return entries.filter((e) => e.endsWith(".md")).map((e) => e.replace(".md", ""));
3849
4246
  } catch {
3850
4247
  return [];
3851
4248
  }
3852
4249
  }
3853
4250
  async readEntity(name) {
3854
- const filePath = this.resolveEntityFilePath(name);
3855
- if (filePath === null) {
3856
- return "";
3857
- }
3858
- try {
3859
- return await this.readStorageSecureFile(filePath);
3860
- } catch (err) {
3861
- if (err instanceof SecureStoreLockedError) throw err;
3862
- if (!isErrnoCode(err, "ENOENT")) throw err;
3863
- return "";
3864
- }
4251
+ return this.entityStore.readEntity(
4252
+ name
4253
+ );
3865
4254
  }
3866
- /** Return sorted list of entity filenames (without .md extension) */
3867
4255
  async listEntityNames() {
3868
- try {
3869
- const entries = await readdir(this.entitiesDir);
3870
- return entries.filter((e) => e.endsWith(".md")).map((e) => e.replace(".md", "")).sort();
3871
- } catch {
3872
- return [];
3873
- }
4256
+ return this.entityStore.listEntityNames();
3874
4257
  }
3875
4258
  /**
3876
4259
  * Find an existing entity that fuzzy-matches the proposed name.
@@ -3912,7 +4295,7 @@ ${memory.content}
3912
4295
  const memory = memories.find((m) => m.frontmatter.id === id);
3913
4296
  if (!memory) return false;
3914
4297
  try {
3915
- await unlink(memory.path);
4298
+ await unlink2(memory.path);
3916
4299
  this.invalidateAllMemoriesCache();
3917
4300
  this.bumpMemoryStatusVersion();
3918
4301
  log.debug(`invalidated memory ${id}`);
@@ -3977,7 +4360,7 @@ ${memory.content}
3977
4360
  `;
3978
4361
  await this.writeStorageSecureFile(memory.path, fileContent);
3979
4362
  this.invalidateAllMemoriesCache();
3980
- if (memory.path.includes(`${path.sep}cold${path.sep}`)) {
4363
+ if (memory.path.includes(`${path2.sep}cold${path2.sep}`)) {
3981
4364
  this.invalidateColdMemoriesCache();
3982
4365
  }
3983
4366
  try {
@@ -4035,7 +4418,7 @@ ${memory.content}
4035
4418
  const expiresAt = new Date(m.frontmatter.expiresAt).getTime();
4036
4419
  if (expiresAt < now) {
4037
4420
  try {
4038
- await unlink(m.path);
4421
+ await unlink2(m.path);
4039
4422
  deleted.push(m);
4040
4423
  log.debug(`cleaned expired memory ${m.frontmatter.id} (TTL expired)`);
4041
4424
  } catch {
@@ -4049,7 +4432,7 @@ ${memory.content}
4049
4432
  return deleted;
4050
4433
  }
4051
4434
  async loadBuffer() {
4052
- const bufferPath = path.join(this.stateDir, "buffer.json");
4435
+ const bufferPath = path2.join(this.stateDir, "buffer.json");
4053
4436
  try {
4054
4437
  const raw = await this.readStorageSecureFile(bufferPath);
4055
4438
  return JSON.parse(raw);
@@ -4061,11 +4444,11 @@ ${memory.content}
4061
4444
  }
4062
4445
  async saveBuffer(state) {
4063
4446
  await this.ensureDirectories();
4064
- const bufferPath = path.join(this.stateDir, "buffer.json");
4447
+ const bufferPath = path2.join(this.stateDir, "buffer.json");
4065
4448
  await this.writeStorageSecureFile(bufferPath, JSON.stringify(state, null, 2));
4066
4449
  }
4067
4450
  async loadMeta() {
4068
- const metaPath = path.join(this.stateDir, "meta.json");
4451
+ const metaPath = path2.join(this.stateDir, "meta.json");
4069
4452
  try {
4070
4453
  const raw = await this.readStorageSecureFile(metaPath);
4071
4454
  const parsed = JSON.parse(raw);
@@ -4099,7 +4482,7 @@ ${memory.content}
4099
4482
  }
4100
4483
  async saveMeta(state) {
4101
4484
  await this.ensureDirectories();
4102
- const metaPath = path.join(this.stateDir, "meta.json");
4485
+ const metaPath = path2.join(this.stateDir, "meta.json");
4103
4486
  await this.writeStorageSecureFile(metaPath, JSON.stringify(state, null, 2));
4104
4487
  }
4105
4488
  async appendMemoryActionEvents(events) {
@@ -4269,7 +4652,7 @@ ${memory.content}
4269
4652
  async appendReextractJobs(events) {
4270
4653
  if (events.length === 0) return 0;
4271
4654
  await this.ensureDirectories();
4272
- const filePath = path.join(this.stateDir, "reextract-jobs.jsonl");
4655
+ const filePath = path2.join(this.stateDir, "reextract-jobs.jsonl");
4273
4656
  const lines = events.map((event) => JSON.stringify(event)).join("\n") + "\n";
4274
4657
  try {
4275
4658
  await this.appendStorageSecureFile(filePath, lines);
@@ -4282,7 +4665,7 @@ ${memory.content}
4282
4665
  }
4283
4666
  async readReextractJobs(limit = 200) {
4284
4667
  const safeLimit = Number.isFinite(limit) ? Math.max(1, Math.min(1e3, Math.floor(limit))) : 200;
4285
- const filePath = path.join(this.stateDir, "reextract-jobs.jsonl");
4668
+ const filePath = path2.join(this.stateDir, "reextract-jobs.jsonl");
4286
4669
  try {
4287
4670
  const raw = await this.readStorageSecureFile(filePath);
4288
4671
  const lines = raw.split("\n").filter((line) => line.trim().length > 0);
@@ -4463,8 +4846,8 @@ ${memory.content}
4463
4846
  activationState: "active"
4464
4847
  });
4465
4848
  await Promise.all([
4466
- unlink(this.compressionGuidelineDraftPath).catch(() => void 0),
4467
- unlink(this.compressionGuidelineDraftStatePath).catch(() => void 0)
4849
+ unlink2(this.compressionGuidelineDraftPath).catch(() => void 0),
4850
+ unlink2(this.compressionGuidelineDraftStatePath).catch(() => void 0)
4468
4851
  ]);
4469
4852
  return true;
4470
4853
  }
@@ -4536,7 +4919,7 @@ ${memory.content}
4536
4919
  const date = nowIso.slice(0, 10);
4537
4920
  const id = this.generateId("incident");
4538
4921
  const incident = createContinuityIncidentRecord(id, input, nowIso);
4539
- const filePath = path.join(this.identityIncidentsDir, `${date}-${id}.md`);
4922
+ const filePath = path2.join(this.identityIncidentsDir, `${date}-${id}.md`);
4540
4923
  await this.writeStorageSecureFile(filePath, serializeContinuityIncident(incident));
4541
4924
  return { ...incident, filePath };
4542
4925
  }
@@ -4549,7 +4932,7 @@ ${memory.content}
4549
4932
  const incidents = [];
4550
4933
  for (const file of candidates) {
4551
4934
  if (incidents.length >= cappedLimit) break;
4552
- const filePath = path.join(this.identityIncidentsDir, file);
4935
+ const filePath = path2.join(this.identityIncidentsDir, file);
4553
4936
  try {
4554
4937
  const raw = await this.readStorageSecureFile(filePath);
4555
4938
  const parsed = parseContinuityIncident(raw);
@@ -4580,7 +4963,7 @@ ${memory.content}
4580
4963
  await this.ensureDirectories();
4581
4964
  const safeKey = this.sanitizeIdentityAuditKey(key);
4582
4965
  const dir = period === "weekly" ? this.identityAuditsWeeklyDir : this.identityAuditsMonthlyDir;
4583
- const filePath = path.join(dir, `${safeKey}.md`);
4966
+ const filePath = path2.join(dir, `${safeKey}.md`);
4584
4967
  await this.writeStorageSecureFile(filePath, content);
4585
4968
  return filePath;
4586
4969
  }
@@ -4588,7 +4971,7 @@ ${memory.content}
4588
4971
  try {
4589
4972
  const safeKey = this.sanitizeIdentityAuditKey(key);
4590
4973
  const dir = period === "weekly" ? this.identityAuditsWeeklyDir : this.identityAuditsMonthlyDir;
4591
- return await this.readStorageSecureFile(path.join(dir, `${safeKey}.md`));
4974
+ return await this.readStorageSecureFile(path2.join(dir, `${safeKey}.md`));
4592
4975
  } catch (err) {
4593
4976
  if (err instanceof Error && err.message === "Invalid identity audit key") return null;
4594
4977
  if (!isErrnoCode(err, "ENOENT")) throw err;
@@ -4635,7 +5018,7 @@ ${memory.content}
4635
5018
  return `${prefix}-${ts}-${rand}`;
4636
5019
  }
4637
5020
  async readContinuityIncidentFileNames() {
4638
- const files = await readdir(this.identityIncidentsDir);
5021
+ const files = await readdir2(this.identityIncidentsDir);
4639
5022
  return files.filter((file) => file.endsWith(".md")).sort().reverse();
4640
5023
  }
4641
5024
  async readContinuityIncidentFile(filePath) {
@@ -4652,12 +5035,12 @@ ${memory.content}
4652
5035
  const fileNames = await this.readContinuityIncidentFileNames();
4653
5036
  const directMatch = fileNames.find((name) => name.endsWith(`-${id}.md`));
4654
5037
  if (directMatch) {
4655
- const directPath = path.join(this.identityIncidentsDir, directMatch);
5038
+ const directPath = path2.join(this.identityIncidentsDir, directMatch);
4656
5039
  const parsed = await this.readContinuityIncidentFile(directPath);
4657
5040
  if (parsed?.id === id) return directPath;
4658
5041
  }
4659
5042
  for (const fileName of fileNames) {
4660
- const filePath = path.join(this.identityIncidentsDir, fileName);
5043
+ const filePath = path2.join(this.identityIncidentsDir, fileName);
4661
5044
  const parsed = await this.readContinuityIncidentFile(filePath);
4662
5045
  if (parsed?.id === id) return filePath;
4663
5046
  }
@@ -4687,7 +5070,7 @@ ${question}
4687
5070
 
4688
5071
  **Context:** ${context}
4689
5072
  `;
4690
- const filePath = path.join(this.questionsDir, `${id}.md`);
5073
+ const filePath = path2.join(this.questionsDir, `${id}.md`);
4691
5074
  await this.writeStorageSecureFile(filePath, content);
4692
5075
  log.debug(`wrote question ${id} to ${filePath}`);
4693
5076
  this.invalidateQuestionsCache();
@@ -4707,11 +5090,11 @@ ${question}
4707
5090
  }
4708
5091
  }
4709
5092
  try {
4710
- const files = await readdir(this.questionsDir);
5093
+ const files = await readdir2(this.questionsDir);
4711
5094
  const questions = [];
4712
5095
  for (const file of files) {
4713
5096
  if (!file.endsWith(".md")) continue;
4714
- const filePath = path.join(this.questionsDir, file);
5097
+ const filePath = path2.join(this.questionsDir, file);
4715
5098
  const raw = await readMaybeEncryptedFile(filePath, this._secureStoreKey, this.baseDir);
4716
5099
  const parsed = this.parseQuestionFile(raw, filePath);
4717
5100
  if (parsed) {
@@ -4734,7 +5117,7 @@ ${question}
4734
5117
  if (!match) return null;
4735
5118
  const frontmatterStr = match[1];
4736
5119
  const body = match[2].trim();
4737
- const id = this.extractFrontmatterValue(frontmatterStr, "id") ?? path.basename(filePath, ".md");
5120
+ const id = this.extractFrontmatterValue(frontmatterStr, "id") ?? path2.basename(filePath, ".md");
4738
5121
  const created = this.extractFrontmatterValue(frontmatterStr, "created") ?? "";
4739
5122
  const priority = parseFloat(
4740
5123
  this.extractFrontmatterValue(frontmatterStr, "priority") ?? "0.5"
@@ -4796,11 +5179,11 @@ ${question}
4796
5179
  } catch {
4797
5180
  }
4798
5181
  const hygiene = opts?.hygiene;
4799
- const rotateEnabled = hygiene?.enabled === true && hygiene.rotateEnabled === true && Array.isArray(hygiene.rotatePaths) && hygiene.rotatePaths.includes(path.basename(identityPath));
5182
+ const rotateEnabled = hygiene?.enabled === true && hygiene.rotateEnabled === true && Array.isArray(hygiene.rotatePaths) && hygiene.rotatePaths.includes(path2.basename(identityPath));
4800
5183
  if (rotateEnabled) {
4801
5184
  const maxBytes = hygiene.rotateMaxBytes;
4802
5185
  if (existing.length > maxBytes) {
4803
- const archiveDir = path.join(workspaceDir, hygiene.archiveDir);
5186
+ const archiveDir = path2.join(workspaceDir, hygiene.archiveDir);
4804
5187
  const { newContent } = await rotateMarkdownFileToArchive({
4805
5188
  filePath: identityPath,
4806
5189
  archiveDir,
@@ -4894,7 +5277,7 @@ ${reflection}
4894
5277
  * Deduplicates by target+label.
4895
5278
  */
4896
5279
  async addEntityRelationship(name, rel) {
4897
- const filePath = path.join(this.entitiesDir, `${name}.md`);
5280
+ const filePath = path2.join(this.entitiesDir, `${name}.md`);
4898
5281
  let entity;
4899
5282
  try {
4900
5283
  const content = await this.readStorageSecureFile(filePath);
@@ -4919,7 +5302,7 @@ ${reflection}
4919
5302
  * Prepends to the beginning, prunes oldest entries beyond maxEntries.
4920
5303
  */
4921
5304
  async addEntityActivity(name, entry, maxEntries) {
4922
- const filePath = path.join(this.entitiesDir, `${name}.md`);
5305
+ const filePath = path2.join(this.entitiesDir, `${name}.md`);
4923
5306
  let entity;
4924
5307
  try {
4925
5308
  const content = await this.readStorageSecureFile(filePath);
@@ -4942,7 +5325,7 @@ ${reflection}
4942
5325
  * Add an alias to an entity file. Deduplicates.
4943
5326
  */
4944
5327
  async addEntityAlias(name, alias) {
4945
- const filePath = path.join(this.entitiesDir, `${name}.md`);
5328
+ const filePath = path2.join(this.entitiesDir, `${name}.md`);
4946
5329
  let entity;
4947
5330
  try {
4948
5331
  const content = await this.readStorageSecureFile(filePath);
@@ -4959,40 +5342,12 @@ ${reflection}
4959
5342
  await this.writeStorageSecureFile(filePath, serializeEntityFile(entity, this.entitySchemas));
4960
5343
  this.invalidateKnowledgeIndexCache();
4961
5344
  }
4962
- /**
4963
- * Set or rewrite the synthesis layer of an entity file.
4964
- */
4965
5345
  async updateEntitySynthesis(name, synthesis, options = {}) {
4966
- const filePath = path.join(this.entitiesDir, `${name}.md`);
4967
- let entity;
4968
- try {
4969
- const content = await this.readStorageSecureFile(filePath);
4970
- entity = parseEntityFile(content, this.entitySchemas);
4971
- } catch (err) {
4972
- if (err instanceof SecureStoreLockedError) throw err;
4973
- if (!isErrnoCode(err, "ENOENT")) throw err;
4974
- log.debug(`updateEntitySynthesis: entity file ${name}.md not found`);
4975
- return;
4976
- }
4977
- const updatedAt = options.updatedAt?.trim() || entity.synthesisUpdatedAt?.trim() || void 0;
4978
- const entityUpdatedAt = options.entityUpdatedAt?.trim() || updatedAt || entity.updated || (/* @__PURE__ */ new Date()).toISOString();
4979
- const synthesisTimelineCount = Number.isInteger(options.synthesisTimelineCount) && (options.synthesisTimelineCount ?? 0) >= 0 ? options.synthesisTimelineCount : void 0;
4980
- const synthesisStructuredFactCount = Number.isInteger(options.synthesisStructuredFactCount) && (options.synthesisStructuredFactCount ?? 0) >= 0 ? options.synthesisStructuredFactCount : countEntityStructuredFacts(entity);
4981
- const synthesisStructuredFactDigest = options.synthesisStructuredFactDigest?.trim() || fingerprintEntityStructuredFacts(entity);
4982
- entity.synthesis = synthesis.trim();
4983
- entity.summary = entity.synthesis;
4984
- entity.synthesisUpdatedAt = updatedAt;
4985
- entity.synthesisTimelineCount = synthesisTimelineCount;
4986
- entity.synthesisStructuredFactCount = synthesisStructuredFactCount;
4987
- entity.synthesisStructuredFactDigest = synthesisStructuredFactDigest;
4988
- entity.synthesisVersion = Math.max(0, entity.synthesisVersion ?? 0) + (options.incrementVersion === false ? 0 : 1);
4989
- entity.updated = entityUpdatedAt;
4990
- await this.writeStorageSecureFile(filePath, serializeEntityFile(entity, this.entitySchemas));
4991
- await this.removeEntitySynthesisQueueEntries([
4992
- .../* @__PURE__ */ new Set([name, this.normalizeEntityName(entity.name, entity.type)])
4993
- ]);
4994
- this.invalidateKnowledgeIndexCache();
4995
- this.bumpMemoryStatusVersion();
5346
+ return this.entityStore.updateEntitySynthesis(
5347
+ name,
5348
+ synthesis,
5349
+ options
5350
+ );
4996
5351
  }
4997
5352
  /**
4998
5353
  * Backward-compatible alias for legacy callers/tests.
@@ -5001,7 +5356,7 @@ ${reflection}
5001
5356
  const updatedAt = (/* @__PURE__ */ new Date()).toISOString();
5002
5357
  let synthesisTimelineCount;
5003
5358
  try {
5004
- const filePath = path.join(this.entitiesDir, `${name}.md`);
5359
+ const filePath = path2.join(this.entitiesDir, `${name}.md`);
5005
5360
  const content = await this.readStorageSecureFile(filePath);
5006
5361
  synthesisTimelineCount = parseEntityFile(content, this.entitySchemas).timeline.length;
5007
5362
  } catch (err) {
@@ -5084,7 +5439,7 @@ ${reflection}
5084
5439
  if (!raw) continue;
5085
5440
  const serialized = serializeEntityFile(parseEntityFile(raw, this.entitySchemas), this.entitySchemas);
5086
5441
  if (raw.trimEnd() === serialized.trimEnd()) continue;
5087
- await this.writeStorageSecureFile(path.join(this.entitiesDir, `${entityName}.md`), serialized);
5442
+ await this.writeStorageSecureFile(path2.join(this.entitiesDir, `${entityName}.md`), serialized);
5088
5443
  migrated += 1;
5089
5444
  }
5090
5445
  if (migrated > 0) {
@@ -5099,45 +5454,8 @@ ${reflection}
5099
5454
  // ---------------------------------------------------------------------------
5100
5455
  // Scoring + Knowledge Index (Knowledge Graph v7.0)
5101
5456
  // ---------------------------------------------------------------------------
5102
- /**
5103
- * Read all entity files and return lightweight EntityFile objects.
5104
- * Parsing is fast (~50-100ms for ~1,800 files) since entity files are small.
5105
- */
5106
5457
  async readAllEntityFiles() {
5107
- const currentVersion = this.getMemoryStatusVersion();
5108
- const schemaCacheKey = buildEntitySchemaCacheKey(this.entitySchemas);
5109
- const cacheKey = `${this.getEntityCacheSecureStoreKey()}\0${schemaCacheKey}`;
5110
- const cached = getCachedEntities(this.baseDir, currentVersion, cacheKey);
5111
- if (cached) return cached;
5112
- try {
5113
- const entries = await readdir(this.entitiesDir);
5114
- const mdFiles = entries.filter((e) => e.endsWith(".md"));
5115
- if (mdFiles.length === 0) return [];
5116
- const BATCH_SIZE = 100;
5117
- const entities = [];
5118
- for (let i = 0; i < mdFiles.length; i += BATCH_SIZE) {
5119
- const batch = mdFiles.slice(i, i + BATCH_SIZE);
5120
- const results = await Promise.all(
5121
- batch.map(async (entry) => {
5122
- try {
5123
- return await this.readStorageSecureFile(path.join(this.entitiesDir, entry));
5124
- } catch (err) {
5125
- if (err instanceof SecureStoreLockedError) throw err;
5126
- if (!isErrnoCode(err, "ENOENT")) throw err;
5127
- return null;
5128
- }
5129
- })
5130
- );
5131
- for (const content of results) {
5132
- if (content !== null) entities.push(parseEntityFile(content, this.entitySchemas));
5133
- }
5134
- }
5135
- setCachedEntities(this.baseDir, entities, currentVersion, cacheKey);
5136
- return entities;
5137
- } catch (err) {
5138
- if (err instanceof SecureStoreLockedError || !isErrnoCode(err, "ENOENT")) throw err;
5139
- return [];
5140
- }
5458
+ return this.entityStore.readAllEntityFiles();
5141
5459
  }
5142
5460
  /**
5143
5461
  * Score an entity based on recency, frequency, activity, type priority,
@@ -5163,53 +5481,11 @@ ${reflection}
5163
5481
  const relDensity = Math.min(entity.relationships.length / 8, 1);
5164
5482
  return recency * 0.4 + frequency * 0.25 + activityScore * 0.15 + typePriority * 0.1 + relDensity * 0.1;
5165
5483
  }
5166
- /**
5167
- * Build the Knowledge Index: a compact markdown table of top-scored entities.
5168
- * Respects maxEntities and maxChars limits from config.
5169
- */
5170
5484
  async buildKnowledgeIndex(config, overrides) {
5171
- const useDefaultLimits = overrides?.maxEntities === void 0 && overrides?.maxChars === void 0;
5172
- if (useDefaultLimits && this.knowledgeIndexCache && Date.now() - this.knowledgeIndexCache.builtAt < _StorageManager.KNOWLEDGE_INDEX_CACHE_TTL_MS) {
5173
- return { result: this.knowledgeIndexCache.result, cached: true };
5174
- }
5175
- const entities = await this.readAllEntityFiles();
5176
- if (entities.length === 0) {
5177
- if (useDefaultLimits) this.knowledgeIndexCache = { result: "", builtAt: Date.now() };
5178
- return { result: "", cached: false };
5179
- }
5180
- const now = /* @__PURE__ */ new Date();
5181
- const scored = entities.map((e) => ({
5182
- name: e.name,
5183
- type: e.type,
5184
- score: _StorageManager.scoreEntity(e, now),
5185
- factCount: e.facts.length,
5186
- summary: e.synthesis ?? e.summary,
5187
- topRelationships: e.relationships.slice(0, 3).map((r) => r.target)
5188
- }));
5189
- scored.sort((a, b) => b.score - a.score);
5190
- const maxEntities = typeof overrides?.maxEntities === "number" ? Math.max(0, Math.floor(overrides.maxEntities)) : config.knowledgeIndexMaxEntities;
5191
- const topN = scored.slice(0, maxEntities);
5192
- if (topN.length === 0) {
5193
- if (useDefaultLimits) this.knowledgeIndexCache = { result: "", builtAt: Date.now() };
5194
- return { result: "", cached: false };
5195
- }
5196
- const header = "## Knowledge Index\n\n| Entity | Type | Summary | Connected to |\n|--------|------|---------|-------------|";
5197
- const rows = [];
5198
- let totalChars = header.length;
5199
- const maxChars = typeof overrides?.maxChars === "number" ? Math.max(0, Math.floor(overrides.maxChars)) : config.knowledgeIndexMaxChars;
5200
- for (const entity of topN) {
5201
- const summary = entity.summary || `${entity.factCount} facts`;
5202
- const connected = entity.topRelationships.length > 0 ? entity.topRelationships.join(", ") : "\u2014";
5203
- const row = `| ${entity.name} | ${entity.type} | ${summary} | ${connected} |`;
5204
- if (totalChars + row.length + 1 > maxChars) break;
5205
- rows.push(row);
5206
- totalChars += row.length + 1;
5207
- }
5208
- const result = rows.length === 0 ? "" : `${header}
5209
- ${rows.join("\n")}
5210
- `;
5211
- if (useDefaultLimits) this.knowledgeIndexCache = { result, builtAt: Date.now() };
5212
- return { result, cached: false };
5485
+ return this.entityStore.buildKnowledgeIndex(
5486
+ config,
5487
+ overrides
5488
+ );
5213
5489
  }
5214
5490
  /** Invalidate the Knowledge Index cache (call after entity mutations). */
5215
5491
  invalidateKnowledgeIndexCache() {
@@ -5220,201 +5496,8 @@ ${rows.join("\n")}
5220
5496
  // ---------------------------------------------------------------------------
5221
5497
  /** Max lines for profile.md before LLM consolidation triggers */
5222
5498
  static PROFILE_MAX_LINES = 300;
5223
- /**
5224
- * Merge fragmented entity files that resolve to the same canonical name.
5225
- * Preserves relationships, activity, aliases, and summary from all fragments.
5226
- * Returns count of files merged.
5227
- */
5228
5499
  async mergeFragmentedEntities() {
5229
- let merged = 0;
5230
- try {
5231
- const entries = await readdir(this.entitiesDir);
5232
- const mdFiles = entries.filter((e) => e.endsWith(".md"));
5233
- const groups = /* @__PURE__ */ new Map();
5234
- for (const file of mdFiles) {
5235
- const baseName = file.replace(".md", "");
5236
- const dashIdx = baseName.indexOf("-");
5237
- if (dashIdx === -1) continue;
5238
- const type = baseName.slice(0, dashIdx);
5239
- const restOfName = baseName.slice(dashIdx + 1);
5240
- const canonical = this.normalizeEntityName(restOfName, type);
5241
- if (!groups.has(canonical)) groups.set(canonical, []);
5242
- groups.get(canonical).push(file);
5243
- }
5244
- for (const [canonical, files] of groups) {
5245
- if (files.length <= 1) continue;
5246
- const mergedEntity = {
5247
- name: "",
5248
- type: "other",
5249
- created: "",
5250
- updated: "",
5251
- extraFrontmatterLines: [],
5252
- preSectionLines: [],
5253
- facts: [],
5254
- summary: void 0,
5255
- synthesis: void 0,
5256
- synthesisUpdatedAt: void 0,
5257
- synthesisTimelineCount: void 0,
5258
- synthesisStructuredFactCount: void 0,
5259
- synthesisStructuredFactDigest: void 0,
5260
- synthesisVersion: void 0,
5261
- timeline: [],
5262
- relationships: [],
5263
- activity: [],
5264
- aliases: [],
5265
- structuredSections: [],
5266
- extraSections: []
5267
- };
5268
- for (const file of files) {
5269
- const filePath = path.join(this.entitiesDir, file);
5270
- try {
5271
- const content = await this.readStorageSecureFile(filePath);
5272
- const parsed = parseEntityFile(content, this.entitySchemas);
5273
- if (!mergedEntity.type || mergedEntity.type === "other") {
5274
- mergedEntity.type = parsed.type;
5275
- }
5276
- if (!mergedEntity.updated || compareEntityTimestamps(parsed.updated, mergedEntity.updated) > 0) {
5277
- mergedEntity.updated = parsed.updated;
5278
- }
5279
- const parsedCreated = parsed.created || parsed.updated;
5280
- const mergedCreated = mergedEntity.created?.trim() || "";
5281
- const parsedCreatedMs = parsedCreated ? Date.parse(parsedCreated) : Number.NaN;
5282
- const mergedCreatedMs = mergedCreated ? Date.parse(mergedCreated) : Number.NaN;
5283
- const parsedCreatedIsValid = Number.isFinite(parsedCreatedMs);
5284
- const mergedCreatedIsValid = Number.isFinite(mergedCreatedMs);
5285
- if (parsedCreated && (!mergedCreated || parsedCreatedIsValid && !mergedCreatedIsValid || parsedCreatedIsValid && mergedCreatedIsValid && parsedCreatedMs < mergedCreatedMs || !parsedCreatedIsValid && !mergedCreatedIsValid && compareEntityTimestamps(parsedCreated, mergedCreated) < 0)) {
5286
- mergedEntity.created = parsedCreated;
5287
- }
5288
- if (parsed.name.length > mergedEntity.name.length) {
5289
- mergedEntity.name = parsed.name;
5290
- }
5291
- const parsedSynthesisUpdatedAt = parsed.synthesisUpdatedAt?.trim() || void 0;
5292
- const mergedSynthesisUpdatedAt = mergedEntity.synthesisUpdatedAt?.trim() || void 0;
5293
- if (parsed.synthesis && (!mergedEntity.synthesis || !mergedSynthesisUpdatedAt && Boolean(parsedSynthesisUpdatedAt) || Boolean(mergedSynthesisUpdatedAt) && Boolean(parsedSynthesisUpdatedAt) && compareEntityTimestamps(parsedSynthesisUpdatedAt, mergedSynthesisUpdatedAt) > 0)) {
5294
- mergedEntity.synthesis = parsed.synthesis;
5295
- mergedEntity.summary = parsed.synthesis;
5296
- mergedEntity.synthesisUpdatedAt = parsedSynthesisUpdatedAt;
5297
- mergedEntity.synthesisTimelineCount = parsed.synthesisTimelineCount;
5298
- mergedEntity.synthesisStructuredFactCount = parsed.synthesisStructuredFactCount;
5299
- mergedEntity.synthesisStructuredFactDigest = parsed.synthesisStructuredFactDigest;
5300
- mergedEntity.synthesisVersion = parsed.synthesisVersion;
5301
- } else if (!mergedEntity.summary && parsed.summary) {
5302
- mergedEntity.summary = parsed.summary;
5303
- mergedEntity.synthesis = parsed.summary;
5304
- mergedEntity.synthesisUpdatedAt = parsedSynthesisUpdatedAt;
5305
- mergedEntity.synthesisTimelineCount = parsed.synthesisTimelineCount;
5306
- mergedEntity.synthesisStructuredFactCount = parsed.synthesisStructuredFactCount;
5307
- mergedEntity.synthesisStructuredFactDigest = parsed.synthesisStructuredFactDigest;
5308
- mergedEntity.synthesisVersion = parsed.synthesisVersion;
5309
- }
5310
- mergedEntity.timeline.push(...parsed.timeline);
5311
- mergedEntity.relationships.push(...parsed.relationships);
5312
- mergedEntity.activity.push(...parsed.activity);
5313
- mergedEntity.aliases.push(...parsed.aliases);
5314
- const mergedStructuredSectionMap = new Map(
5315
- (mergedEntity.structuredSections ?? []).map((section) => [section.key, {
5316
- ...section,
5317
- facts: [...section.facts]
5318
- }])
5319
- );
5320
- for (const section of parsed.structuredSections ?? []) {
5321
- const existingSection = mergedStructuredSectionMap.get(section.key);
5322
- if (!existingSection) {
5323
- mergedStructuredSectionMap.set(section.key, {
5324
- key: section.key,
5325
- title: section.title,
5326
- facts: [...new Set(section.facts.map((fact) => fact.trim()).filter((fact) => fact.length > 0))]
5327
- });
5328
- continue;
5329
- }
5330
- const mergedFacts = new Set(existingSection.facts.map((fact) => fact.trim()));
5331
- for (const fact of section.facts) {
5332
- const trimmed = fact.trim();
5333
- if (!trimmed) continue;
5334
- mergedFacts.add(trimmed);
5335
- }
5336
- existingSection.facts = Array.from(mergedFacts);
5337
- if (!existingSection.title.trim() && section.title.trim()) {
5338
- existingSection.title = section.title;
5339
- }
5340
- }
5341
- mergedEntity.structuredSections = Array.from(mergedStructuredSectionMap.values());
5342
- mergedEntity.extraFrontmatterLines.push(...parsed.extraFrontmatterLines ?? []);
5343
- mergedEntity.preSectionLines.push(...parsed.preSectionLines ?? []);
5344
- mergedEntity.extraSections.push(...(parsed.extraSections ?? []).map((section) => ({
5345
- title: section.title,
5346
- lines: [...section.lines]
5347
- })));
5348
- } catch (err) {
5349
- if (err instanceof SecureStoreLockedError) throw err;
5350
- if (!isErrnoCode(err, "ENOENT")) throw err;
5351
- }
5352
- }
5353
- const timelineKeys = /* @__PURE__ */ new Set();
5354
- mergedEntity.timeline = mergedEntity.timeline.filter((entry) => {
5355
- const key = JSON.stringify([
5356
- entry.timestamp,
5357
- entry.source ?? "",
5358
- entry.sessionKey ?? "",
5359
- entry.principal ?? "",
5360
- entry.text
5361
- ]);
5362
- if (timelineKeys.has(key)) return false;
5363
- timelineKeys.add(key);
5364
- return true;
5365
- });
5366
- const relKeys = /* @__PURE__ */ new Set();
5367
- mergedEntity.relationships = mergedEntity.relationships.filter((r) => {
5368
- const key = `${r.target}::${r.label}`;
5369
- if (relKeys.has(key)) return false;
5370
- relKeys.add(key);
5371
- return true;
5372
- });
5373
- const actKeys = /* @__PURE__ */ new Set();
5374
- mergedEntity.activity = mergedEntity.activity.filter((a) => {
5375
- const key = `${a.date}::${a.note}`;
5376
- if (actKeys.has(key)) return false;
5377
- actKeys.add(key);
5378
- return true;
5379
- }).sort((a, b) => b.date.localeCompare(a.date));
5380
- mergedEntity.aliases = [...new Set(mergedEntity.aliases)];
5381
- mergedEntity.structuredSections = sortStructuredSectionsBySchema(
5382
- mergedEntity.type,
5383
- mergedEntity.structuredSections ?? [],
5384
- this.entitySchemas
5385
- );
5386
- mergedEntity.facts = compileEntityFacts(mergedEntity.timeline, mergedEntity.structuredSections);
5387
- const extraSectionKeys = /* @__PURE__ */ new Set();
5388
- mergedEntity.extraSections = (mergedEntity.extraSections ?? []).filter((section) => {
5389
- const key = `${section.title}::${section.lines.join("\n")}`;
5390
- if (extraSectionKeys.has(key)) return false;
5391
- extraSectionKeys.add(key);
5392
- return true;
5393
- });
5394
- if (!mergedEntity.name) {
5395
- const dashIdx = canonical.indexOf("-");
5396
- mergedEntity.name = dashIdx !== -1 ? canonical.slice(dashIdx + 1) : canonical;
5397
- }
5398
- mergedEntity.created = mergedEntity.created || mergedEntity.updated || (/* @__PURE__ */ new Date()).toISOString();
5399
- mergedEntity.updated = mergedEntity.updated || (/* @__PURE__ */ new Date()).toISOString();
5400
- const canonicalPath = path.join(this.entitiesDir, `${canonical}.md`);
5401
- await this.writeStorageSecureFile(canonicalPath, serializeEntityFile(mergedEntity, this.entitySchemas));
5402
- for (const file of files) {
5403
- const filePath = path.join(this.entitiesDir, file);
5404
- if (filePath !== canonicalPath) {
5405
- try {
5406
- await unlink(filePath);
5407
- merged++;
5408
- log.debug(`merged entity ${file} \u2192 ${canonical}.md`);
5409
- } catch {
5410
- }
5411
- }
5412
- }
5413
- }
5414
- } catch (err) {
5415
- if (err instanceof SecureStoreLockedError || !isErrnoCode(err, "ENOENT")) throw err;
5416
- }
5417
- return merged;
5500
+ return this.entityStore.mergeFragmentedEntities();
5418
5501
  }
5419
5502
  async cleanExpiredCommitments(decayDays) {
5420
5503
  const memories = await this.readAllMemories();
@@ -5429,7 +5512,7 @@ ${rows.join("\n")}
5429
5512
  const updatedAt = new Date(m.frontmatter.updated).getTime();
5430
5513
  if (updatedAt < cutoff) {
5431
5514
  try {
5432
- await unlink(m.path);
5515
+ await unlink2(m.path);
5433
5516
  deleted.push(m);
5434
5517
  log.debug(`cleaned expired commitment ${m.frontmatter.id}`);
5435
5518
  } catch {
@@ -5499,7 +5582,7 @@ ${memory.content}
5499
5582
  const filePaths = await this.collectActiveMemoryPaths();
5500
5583
  const foundIds = /* @__PURE__ */ new Set();
5501
5584
  for (const filePath of filePaths) {
5502
- const basename = path.basename(filePath, ".md");
5585
+ const basename = path2.basename(filePath, ".md");
5503
5586
  if (wantedIds.has(basename)) {
5504
5587
  foundIds.add(basename);
5505
5588
  if (foundIds.size === wantedIds.size) break;
@@ -5689,14 +5772,14 @@ Reason: ${reason}`, {
5689
5772
  // Memory Summarization (Phase 4A)
5690
5773
  // ---------------------------------------------------------------------------
5691
5774
  get summariesDir() {
5692
- return path.join(this.baseDir, "summaries");
5775
+ return path2.join(this.baseDir, "summaries");
5693
5776
  }
5694
5777
  /**
5695
5778
  * Write a memory summary.
5696
5779
  */
5697
5780
  async writeSummary(summary) {
5698
5781
  await mkdir(this.summariesDir, { recursive: true });
5699
- const filePath = path.join(this.summariesDir, `${summary.id}.json`);
5782
+ const filePath = path2.join(this.summariesDir, `${summary.id}.json`);
5700
5783
  await this.writeStorageSecureFile(filePath, JSON.stringify(summary, null, 2));
5701
5784
  log.debug(`wrote summary ${summary.id}`);
5702
5785
  }
@@ -5705,11 +5788,11 @@ Reason: ${reason}`, {
5705
5788
  */
5706
5789
  async readSummaries() {
5707
5790
  try {
5708
- const files = await readdir(this.summariesDir);
5791
+ const files = await readdir2(this.summariesDir);
5709
5792
  const summaries = [];
5710
5793
  for (const file of files) {
5711
5794
  if (!file.endsWith(".json")) continue;
5712
- const filePath = path.join(this.summariesDir, file);
5795
+ const filePath = path2.join(this.summariesDir, file);
5713
5796
  const raw = await this.readStorageSecureFile(filePath);
5714
5797
  summaries.push(JSON.parse(raw));
5715
5798
  }
@@ -5770,7 +5853,7 @@ ${memory.content}
5770
5853
  * Save topic scores to meta.json.
5771
5854
  */
5772
5855
  async saveTopics(topics) {
5773
- const metaPath = path.join(this.stateDir, "topics.json");
5856
+ const metaPath = path2.join(this.stateDir, "topics.json");
5774
5857
  await mkdir(this.stateDir, { recursive: true });
5775
5858
  await this.writeStorageSecureFile(metaPath, JSON.stringify({ topics, updatedAt: (/* @__PURE__ */ new Date()).toISOString() }, null, 2));
5776
5859
  log.debug(`saved ${topics.length} topic scores`);
@@ -5779,7 +5862,7 @@ ${memory.content}
5779
5862
  * Load topic scores from meta.json.
5780
5863
  */
5781
5864
  async loadTopics() {
5782
- const metaPath = path.join(this.stateDir, "topics.json");
5865
+ const metaPath = path2.join(this.stateDir, "topics.json");
5783
5866
  try {
5784
5867
  const raw = await this.readStorageSecureFile(metaPath);
5785
5868
  return JSON.parse(raw);
@@ -5857,14 +5940,19 @@ ${memory.content}
5857
5940
  };
5858
5941
 
5859
5942
  export {
5943
+ selfDeps,
5860
5944
  normalizeEntityName,
5861
5945
  ContentHashIndex,
5862
5946
  normalizeAttributePairs,
5947
+ normalizeStructuredSectionFacts,
5948
+ compileEntityFacts,
5863
5949
  compareEntityTimestamps,
5950
+ countEntityStructuredFacts,
5864
5951
  fingerprintEntityStructuredFacts,
5865
5952
  isEntitySynthesisStale,
5866
5953
  parseEntityFile,
5867
5954
  serializeEntityFile,
5955
+ buildEntitySchemaCacheKey,
5868
5956
  StorageManager
5869
5957
  };
5870
- //# sourceMappingURL=chunk-34THARMH.js.map
5958
+ //# sourceMappingURL=chunk-XBM5DG4O.js.map