@remnic/core 9.4.2 → 9.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (379) hide show
  1. package/dist/access-admin-ops-surface.d.ts +6 -6
  2. package/dist/access-admin-ops-surface.js +28 -28
  3. package/dist/access-boundary.d.ts +27 -8
  4. package/dist/access-boundary.js +33 -29
  5. package/dist/access-cli.js +83 -81
  6. package/dist/access-cli.js.map +1 -1
  7. package/dist/access-http.d.ts +52 -6
  8. package/dist/access-http.js +40 -38
  9. package/dist/access-identity-continuity-surface.d.ts +5 -5
  10. package/dist/access-identity-continuity-surface.js +28 -28
  11. package/dist/access-lcm-surface.d.ts +6 -6
  12. package/dist/access-lcm-surface.js +28 -28
  13. package/dist/access-mcp.d.ts +16 -6
  14. package/dist/access-mcp.js +37 -35
  15. package/dist/access-observe-write-surface.d.ts +6 -6
  16. package/dist/access-observe-write-surface.js +28 -28
  17. package/dist/access-operations-batch.js +33 -32
  18. package/dist/access-operations.d.ts +9 -9
  19. package/dist/access-operations.js +35 -34
  20. package/dist/access-recall-surface.d.ts +6 -6
  21. package/dist/access-recall-surface.js +28 -28
  22. package/dist/access-schema.d.ts +4 -4
  23. package/dist/access-schema.js +4 -4
  24. package/dist/{access-service-m-2VO_Ig.d.ts → access-service-CXJaql3A.d.ts} +4 -4
  25. package/dist/access-service.d.ts +6 -6
  26. package/dist/access-service.js +28 -28
  27. package/dist/access-surface-catalog.d.ts +6 -6
  28. package/dist/access-surface-catalog.js +1 -0
  29. package/dist/access-surface-catalog.js.map +1 -1
  30. package/dist/access-token-capabilities.d.ts +174 -0
  31. package/dist/access-token-capabilities.js +33 -0
  32. package/dist/action-confidence.d.ts +1 -1
  33. package/dist/active-memory-bridge.d.ts +1 -1
  34. package/dist/active-recall.d.ts +1 -1
  35. package/dist/active-recall.js +2 -2
  36. package/dist/adapters/index.js +4 -4
  37. package/dist/adapters/registry.js +2 -2
  38. package/dist/{auto-sync-HMHQHUAG.js → auto-sync-4A5YBWYO.js} +4 -4
  39. package/dist/behavior-learner.d.ts +1 -1
  40. package/dist/behavior-signals.d.ts +1 -1
  41. package/dist/bootstrap.d.ts +5 -5
  42. package/dist/briefing.d.ts +2 -2
  43. package/dist/briefing.js +9 -9
  44. package/dist/buffer-surprise-report.d.ts +1 -1
  45. package/dist/buffer.d.ts +2 -2
  46. package/dist/calibration.d.ts +1 -1
  47. package/dist/capabilities.d.ts +1 -1
  48. package/dist/{capsule-crypto-CZJSLEFG.js → capsule-crypto-RAARDY3M.js} +2 -2
  49. package/dist/capsule-crypto-RAARDY3M.js.map +1 -0
  50. package/dist/{catalog-BxWokdC2.d.ts → catalog-C9cu67Ig.d.ts} +1 -1
  51. package/dist/causal-behavior.d.ts +1 -1
  52. package/dist/causal-behavior.js +5 -5
  53. package/dist/causal-chain.js +3 -3
  54. package/dist/causal-consolidation.d.ts +1 -1
  55. package/dist/causal-consolidation.js +13 -13
  56. package/dist/causal-retrieval.js +3 -3
  57. package/dist/causal-trajectory-graph.d.ts +1 -1
  58. package/dist/causal-trajectory.js +1 -1
  59. package/dist/{chunk-6ZIETXZ2.js → chunk-23JFRB73.js} +2 -2
  60. package/dist/{chunk-IC6QX5TC.js → chunk-3XIY7MDQ.js} +6 -6
  61. package/dist/{chunk-FZGGZAAU.js → chunk-4GNEDXDI.js} +146 -2
  62. package/dist/chunk-4GNEDXDI.js.map +1 -0
  63. package/dist/{chunk-LOR6ZM5R.js → chunk-4LV23CHK.js} +2 -2
  64. package/dist/{chunk-E2SPGGUI.js → chunk-4OKLXWDZ.js} +13 -6
  65. package/dist/chunk-4OKLXWDZ.js.map +1 -0
  66. package/dist/{chunk-AER6MT24.js → chunk-6SXVCD7W.js} +2 -2
  67. package/dist/{chunk-OHDJ34CC.js → chunk-72WG5QKN.js} +2 -2
  68. package/dist/{chunk-CZAZX7JP.js → chunk-7MW3CVLD.js} +4 -4
  69. package/dist/{chunk-CXLNZXG5.js → chunk-7XGSIUP5.js} +1 -1
  70. package/dist/{chunk-CZAA5N5S.js → chunk-AYZJID4S.js} +2 -2
  71. package/dist/{chunk-M7XQSUBB.js → chunk-B3ABVQ36.js} +116 -9
  72. package/dist/chunk-B3ABVQ36.js.map +1 -0
  73. package/dist/{chunk-6BISDEN6.js → chunk-BEM4D2QG.js} +14 -14
  74. package/dist/{chunk-ZPOROUTX.js → chunk-CYWA2CXR.js} +5 -5
  75. package/dist/{chunk-M5QKGHCR.js → chunk-CYWCKFCL.js} +5 -5
  76. package/dist/chunk-D7FOKIY5.js +173 -0
  77. package/dist/chunk-D7FOKIY5.js.map +1 -0
  78. package/dist/{chunk-4BFRBP45.js → chunk-DEG5ULFJ.js} +2 -2
  79. package/dist/{chunk-JLR3JSTL.js → chunk-DS7MM2ES.js} +3 -3
  80. package/dist/{chunk-2BFLDH5F.js → chunk-EEIROWEG.js} +2 -2
  81. package/dist/{chunk-5QZDMSSN.js → chunk-FKCRGLRD.js} +237 -82
  82. package/dist/{chunk-5QZDMSSN.js.map → chunk-FKCRGLRD.js.map} +1 -1
  83. package/dist/{chunk-X4A62ET7.js → chunk-H2DXDQCQ.js} +17 -17
  84. package/dist/{chunk-27FLVMDC.js → chunk-HLN7RROI.js} +7 -7
  85. package/dist/chunk-IC2TCZJ2.js +54 -0
  86. package/dist/chunk-IC2TCZJ2.js.map +1 -0
  87. package/dist/{chunk-2U2A5HF4.js → chunk-J3XHPFEU.js} +6 -6
  88. package/dist/{chunk-AKUCU7CI.js → chunk-JI5AVXYO.js} +5 -5
  89. package/dist/{chunk-KCJ5H6XQ.js → chunk-JSNVWNGX.js} +2 -2
  90. package/dist/{chunk-7Z2DZNWN.js → chunk-KL4UAXUY.js} +43 -2
  91. package/dist/{chunk-7Z2DZNWN.js.map → chunk-KL4UAXUY.js.map} +1 -1
  92. package/dist/{chunk-FLVL4L3L.js → chunk-KTULX4YO.js} +4 -4
  93. package/dist/{chunk-ILFJ7AVS.js → chunk-LADFWYHY.js} +35 -21
  94. package/dist/chunk-LADFWYHY.js.map +1 -0
  95. package/dist/{chunk-437S3G37.js → chunk-LNQUAJNC.js} +1 -1
  96. package/dist/{chunk-EPGWWCZF.js → chunk-LR5DZ56F.js} +6 -6
  97. package/dist/{chunk-YDSWRD33.js → chunk-N3JDIRBW.js} +4 -4
  98. package/dist/{chunk-OUMTBFSQ.js → chunk-NKCPUHCI.js} +5 -5
  99. package/dist/{chunk-7QWMTOIF.js → chunk-P454KXD6.js} +112 -34
  100. package/dist/chunk-P454KXD6.js.map +1 -0
  101. package/dist/{chunk-DR6PEJU3.js → chunk-PCLIWBGD.js} +44 -59
  102. package/dist/chunk-PCLIWBGD.js.map +1 -0
  103. package/dist/{chunk-BGTAL46Y.js → chunk-PNLFN2PZ.js} +2 -2
  104. package/dist/{chunk-P6SYWE4G.js → chunk-PVUJ6WVV.js} +10 -10
  105. package/dist/{chunk-YPEMNNNY.js → chunk-RGK27ELN.js} +6 -6
  106. package/dist/{chunk-2QSZNTDO.js → chunk-RKNJBZ55.js} +4 -4
  107. package/dist/{chunk-66FLU5BT.js → chunk-SIRPLF54.js} +6 -6
  108. package/dist/{chunk-M7GGMGMZ.js → chunk-SVOHGUMI.js} +1202 -126
  109. package/dist/chunk-SVOHGUMI.js.map +1 -0
  110. package/dist/{chunk-HRCACVHL.js → chunk-TLUDFPZL.js} +2 -2
  111. package/dist/{chunk-2FOD2YY3.js → chunk-UFUKHGZD.js} +236 -103
  112. package/dist/chunk-UFUKHGZD.js.map +1 -0
  113. package/dist/{chunk-2MR3MFQB.js → chunk-UPSAT4PY.js} +2 -2
  114. package/dist/{chunk-4P4626RY.js → chunk-UTRJFDP2.js} +4 -4
  115. package/dist/{chunk-CGS7UKWM.js → chunk-VCW74PNH.js} +2 -2
  116. package/dist/{chunk-5GPPACXK.js → chunk-VSMRDBFT.js} +2 -1
  117. package/dist/{chunk-NG7YBCJO.js → chunk-XCL57M6Q.js} +4 -4
  118. package/dist/{chunk-CLX5VDNY.js → chunk-Y4RKAQZ7.js} +4 -4
  119. package/dist/{chunk-DGYCWCQ7.js → chunk-Y7UNNAZD.js} +2 -2
  120. package/dist/{chunk-EZ25VE3G.js → chunk-YNDLCWXS.js} +4 -4
  121. package/dist/{chunk-XN3TUUX2.js → chunk-YQB32INI.js} +2 -2
  122. package/dist/{cli-EiBBOt3r.d.ts → cli-CqdPA6z9.d.ts} +3 -3
  123. package/dist/cli.d.ts +7 -7
  124. package/dist/cli.js +61 -59
  125. package/dist/compounding/engine.d.ts +2 -2
  126. package/dist/compounding/engine.js +9 -9
  127. package/dist/compounding/preference-consolidator.d.ts +1 -1
  128. package/dist/compression-optimizer.d.ts +1 -1
  129. package/dist/config.d.ts +1 -1
  130. package/dist/config.js +2 -2
  131. package/dist/connectors/codex-materialize-runner.d.ts +1 -1
  132. package/dist/connectors/codex-materialize-runner.js +9 -9
  133. package/dist/connectors/codex-materialize.d.ts +1 -1
  134. package/dist/connectors/index.d.ts +1 -1
  135. package/dist/connectors/index.js +13 -11
  136. package/dist/consolidation-provenance-check.d.ts +2 -2
  137. package/dist/consolidation-undo.d.ts +2 -2
  138. package/dist/contradiction/index.d.ts +2 -2
  139. package/dist/contradiction/index.js +4 -4
  140. package/dist/conversation-index/backend.d.ts +1 -1
  141. package/dist/conversation-index/backend.js +2 -2
  142. package/dist/conversation-index/chunker.d.ts +1 -1
  143. package/dist/conversation-index/faiss-adapter.d.ts +1 -1
  144. package/dist/conversation-index/indexer.d.ts +1 -1
  145. package/dist/conversation-index/search.d.ts +1 -1
  146. package/dist/dashboard-runtime.js +2 -2
  147. package/dist/day-summary.d.ts +1 -1
  148. package/dist/delinearize.d.ts +1 -1
  149. package/dist/direct-answer-wiring.d.ts +1 -1
  150. package/dist/direct-answer.d.ts +1 -1
  151. package/dist/embedding-fallback.d.ts +1 -1
  152. package/dist/enrichment/index.d.ts +1 -1
  153. package/dist/entity-retrieval.d.ts +2 -2
  154. package/dist/entity-retrieval.js +9 -9
  155. package/dist/entity-schema.d.ts +1 -1
  156. package/dist/explicit-capture.d.ts +5 -5
  157. package/dist/extraction-faithfulness.d.ts +1 -1
  158. package/dist/extraction-judge-telemetry.d.ts +1 -1
  159. package/dist/extraction-judge-training.d.ts +1 -1
  160. package/dist/extraction-judge.d.ts +1 -1
  161. package/dist/extraction.d.ts +1 -1
  162. package/dist/fallback-llm.d.ts +1 -1
  163. package/dist/{first-start-migration-DY6YCRC2.js → first-start-migration-VBJQL6OI.js} +5 -5
  164. package/dist/graph-dashboard-diff.d.ts +1 -1
  165. package/dist/graph-dashboard-key.d.ts +1 -1
  166. package/dist/graph-dashboard-parser.d.ts +1 -1
  167. package/dist/graph-edge-reinforcement.d.ts +1 -1
  168. package/dist/graph-snapshot.d.ts +1 -1
  169. package/dist/graph.d.ts +1 -1
  170. package/dist/identity-continuity.d.ts +1 -1
  171. package/dist/importance.d.ts +1 -1
  172. package/dist/index.d.ts +271 -17
  173. package/dist/index.js +163 -99
  174. package/dist/intent.d.ts +1 -1
  175. package/dist/lcm/engine.d.ts +1 -1
  176. package/dist/lcm/engine.js +2 -2
  177. package/dist/lcm/index.d.ts +1 -1
  178. package/dist/lcm/index.js +2 -2
  179. package/dist/lcm/tools.d.ts +1 -1
  180. package/dist/lifecycle.d.ts +1 -1
  181. package/dist/live-connectors-runner.d.ts +1 -1
  182. package/dist/local-llm.d.ts +1 -1
  183. package/dist/local-model-endpoint.d.ts +1 -1
  184. package/dist/maintenance/memory-governance.d.ts +1 -1
  185. package/dist/maintenance/memory-governance.js +10 -10
  186. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +9 -9
  187. package/dist/maintenance/rebuild-memory-projection.js +11 -11
  188. package/dist/mcp-memory-inspector-app.d.ts +6 -6
  189. package/dist/mcp-read-only-tools.d.ts +16 -0
  190. package/dist/mcp-read-only-tools.js +8 -0
  191. package/dist/mcp-read-only-tools.js.map +1 -0
  192. package/dist/memory-action-policy.d.ts +1 -1
  193. package/dist/memory-cache.d.ts +1 -1
  194. package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
  195. package/dist/memory-projection-store.d.ts +1 -1
  196. package/dist/memory-provenance.d.ts +1 -1
  197. package/dist/memory-worth-outcomes.d.ts +2 -2
  198. package/dist/models-json.d.ts +1 -1
  199. package/dist/namespaces/migrate.d.ts +3 -3
  200. package/dist/namespaces/migrate.js +19 -19
  201. package/dist/namespaces/principal.d.ts +1 -1
  202. package/dist/namespaces/search.d.ts +1 -1
  203. package/dist/namespaces/search.js +10 -10
  204. package/dist/namespaces/storage.d.ts +3 -3
  205. package/dist/namespaces/storage.js +9 -9
  206. package/dist/native-knowledge.d.ts +1 -1
  207. package/dist/operator-toolkit.d.ts +2 -2
  208. package/dist/operator-toolkit.js +25 -25
  209. package/dist/orchestration/compression-guideline-coordinator.d.ts +2 -2
  210. package/dist/orchestration/maintenance.d.ts +2 -2
  211. package/dist/orchestration/maintenance.js +11 -11
  212. package/dist/{orchestrator-B2Y28Z9t.d.ts → orchestrator-CWFrT8AF.d.ts} +91 -60
  213. package/dist/orchestrator.d.ts +5 -5
  214. package/dist/orchestrator.js +85 -83
  215. package/dist/patterns-cli.d.ts +1 -1
  216. package/dist/policy-runtime.d.ts +1 -1
  217. package/dist/provenance.d.ts +1 -1
  218. package/dist/{qmd-Db9mOkzB.d.ts → qmd--fnPMK60.d.ts} +1 -1
  219. package/dist/qmd-preflight.d.ts +2 -2
  220. package/dist/qmd-recall-cache.d.ts +1 -1
  221. package/dist/qmd.d.ts +2 -2
  222. package/dist/recall-disclosure-escalation.d.ts +1 -1
  223. package/dist/recall-explain-renderer.d.ts +1 -1
  224. package/dist/recall-planner-llm.d.ts +1 -1
  225. package/dist/recall-state.d.ts +1 -1
  226. package/dist/recall-tag-filter.d.ts +1 -1
  227. package/dist/recall-timings.d.ts +1 -1
  228. package/dist/recall-xray-cli.d.ts +1 -1
  229. package/dist/recall-xray-renderer.d.ts +1 -1
  230. package/dist/recall-xray.d.ts +1 -1
  231. package/dist/resolve-auth-token.d.ts +1 -1
  232. package/dist/resume-bundles.js +4 -4
  233. package/dist/retrieval-agents.d.ts +2 -2
  234. package/dist/retrieval-tiers.d.ts +1 -1
  235. package/dist/routing/engine.d.ts +1 -1
  236. package/dist/routing/store.d.ts +1 -1
  237. package/dist/schemas.d.ts +22 -22
  238. package/dist/search/document-scanner.js +2 -2
  239. package/dist/search/embed-helper.d.ts +1 -1
  240. package/dist/search/factory.d.ts +1 -1
  241. package/dist/search/factory.js +9 -9
  242. package/dist/search/index.d.ts +1 -1
  243. package/dist/search/index.js +13 -13
  244. package/dist/search/lancedb-backend.d.ts +1 -1
  245. package/dist/search/lancedb-backend.js +3 -3
  246. package/dist/search/meilisearch-backend.d.ts +1 -1
  247. package/dist/search/meilisearch-backend.js +3 -3
  248. package/dist/search/noop-backend.d.ts +1 -1
  249. package/dist/search/orama-backend.d.ts +1 -1
  250. package/dist/search/orama-backend.js +3 -3
  251. package/dist/search/port.d.ts +1 -1
  252. package/dist/search/remote-backend.d.ts +1 -1
  253. package/dist/{semantic-consolidation-BDVIbLRw.d.ts → semantic-consolidation-O5lMZ4LG.d.ts} +1 -1
  254. package/dist/semantic-consolidation.d.ts +2 -2
  255. package/dist/semantic-consolidation.js +11 -11
  256. package/dist/semantic-rule-promotion.js +9 -9
  257. package/dist/semantic-rule-verifier.d.ts +1 -1
  258. package/dist/semantic-rule-verifier.js +10 -10
  259. package/dist/session-observer-bands.d.ts +1 -1
  260. package/dist/session-observer-state.d.ts +1 -1
  261. package/dist/shared-context/manager.d.ts +1 -1
  262. package/dist/signal.d.ts +1 -1
  263. package/dist/storage-C1maCNbc.d.ts +1591 -0
  264. package/dist/storage.d.ts +5 -1239
  265. package/dist/storage.js +8 -8
  266. package/dist/summarizer.d.ts +1 -1
  267. package/dist/summary-snapshot.d.ts +1 -1
  268. package/dist/temporal-supersession.d.ts +2 -2
  269. package/dist/temporal-validity.d.ts +1 -1
  270. package/dist/threading.d.ts +1 -1
  271. package/dist/tier-migration.d.ts +2 -2
  272. package/dist/tier-routing.d.ts +1 -1
  273. package/dist/{tier-stats-TG6GUZ6N.js → tier-stats-5XF4UBRQ.js} +4 -4
  274. package/dist/tokens.d.ts +17 -2
  275. package/dist/tokens.js +3 -1
  276. package/dist/topics.d.ts +1 -1
  277. package/dist/transcript.d.ts +1 -1
  278. package/dist/transfer/backup.js +2 -2
  279. package/dist/transfer/capsule-export.js +3 -3
  280. package/dist/transfer/capsule-import.js +3 -3
  281. package/dist/transfer/types.d.ts +12 -12
  282. package/dist/trust-score-stage.d.ts +1 -1
  283. package/dist/trust-score.d.ts +1 -1
  284. package/dist/{types-ljkd82rn.d.ts → types-CGgcNWCG.d.ts} +31 -1
  285. package/dist/types.d.ts +1 -1
  286. package/dist/utility-runtime.d.ts +1 -1
  287. package/dist/verified-recall.js +10 -10
  288. package/package.json +2 -2
  289. package/src/access-boundary.test.ts +62 -0
  290. package/src/access-boundary.ts +165 -126
  291. package/src/access-http.test.ts +781 -0
  292. package/src/access-http.ts +334 -108
  293. package/src/access-mcp.test.ts +264 -0
  294. package/src/access-mcp.ts +45 -70
  295. package/src/access-operations-batch.ts +35 -12
  296. package/src/access-surface-catalog.test.ts +22 -14
  297. package/src/access-surface-catalog.ts +6 -3
  298. package/src/access-token-capabilities.test.ts +844 -0
  299. package/src/access-token-capabilities.ts +391 -0
  300. package/src/chat/chat-mcp.test.ts +232 -0
  301. package/src/chat/chat-session.ts +34 -0
  302. package/src/cli-wearables-fuse.test.ts +197 -0
  303. package/src/cli.ts +25 -0
  304. package/src/index.ts +14 -0
  305. package/src/mcp-read-only-tools.ts +61 -0
  306. package/src/storage.ts +16 -0
  307. package/src/tokens.ts +32 -3
  308. package/src/wearables/cli.test.ts +102 -0
  309. package/src/wearables/cli.ts +65 -0
  310. package/src/wearables/config.test.ts +32 -0
  311. package/src/wearables/config.ts +52 -0
  312. package/src/wearables/day-store.test.ts +246 -0
  313. package/src/wearables/day-store.ts +272 -3
  314. package/src/wearables/fusion/cluster.ts +230 -0
  315. package/src/wearables/fusion/fuse.ts +218 -0
  316. package/src/wearables/fusion/fusion.test.ts +2575 -0
  317. package/src/wearables/fusion/index.ts +50 -0
  318. package/src/wearables/fusion/reconcile.ts +831 -0
  319. package/src/wearables/fusion/reconstruct.ts +251 -0
  320. package/src/wearables/fusion/store.ts +480 -0
  321. package/src/wearables/fusion/types.ts +228 -0
  322. package/src/wearables/index.ts +41 -0
  323. package/src/wearables/service.test.ts +1030 -2
  324. package/src/wearables/service.ts +258 -16
  325. package/src/wearables/speakers.test.ts +128 -0
  326. package/src/wearables/speakers.ts +58 -4
  327. package/src/wearables/storage-io.test.ts +146 -0
  328. package/src/wearables/types.ts +31 -0
  329. package/dist/chunk-2FOD2YY3.js.map +0 -1
  330. package/dist/chunk-7QWMTOIF.js.map +0 -1
  331. package/dist/chunk-DR6PEJU3.js.map +0 -1
  332. package/dist/chunk-E2SPGGUI.js.map +0 -1
  333. package/dist/chunk-FZGGZAAU.js.map +0 -1
  334. package/dist/chunk-ILFJ7AVS.js.map +0 -1
  335. package/dist/chunk-M7GGMGMZ.js.map +0 -1
  336. package/dist/chunk-M7XQSUBB.js.map +0 -1
  337. /package/dist/{capsule-crypto-CZJSLEFG.js.map → access-token-capabilities.js.map} +0 -0
  338. /package/dist/{auto-sync-HMHQHUAG.js.map → auto-sync-4A5YBWYO.js.map} +0 -0
  339. /package/dist/{chunk-6ZIETXZ2.js.map → chunk-23JFRB73.js.map} +0 -0
  340. /package/dist/{chunk-IC6QX5TC.js.map → chunk-3XIY7MDQ.js.map} +0 -0
  341. /package/dist/{chunk-LOR6ZM5R.js.map → chunk-4LV23CHK.js.map} +0 -0
  342. /package/dist/{chunk-AER6MT24.js.map → chunk-6SXVCD7W.js.map} +0 -0
  343. /package/dist/{chunk-OHDJ34CC.js.map → chunk-72WG5QKN.js.map} +0 -0
  344. /package/dist/{chunk-CZAZX7JP.js.map → chunk-7MW3CVLD.js.map} +0 -0
  345. /package/dist/{chunk-CXLNZXG5.js.map → chunk-7XGSIUP5.js.map} +0 -0
  346. /package/dist/{chunk-CZAA5N5S.js.map → chunk-AYZJID4S.js.map} +0 -0
  347. /package/dist/{chunk-6BISDEN6.js.map → chunk-BEM4D2QG.js.map} +0 -0
  348. /package/dist/{chunk-ZPOROUTX.js.map → chunk-CYWA2CXR.js.map} +0 -0
  349. /package/dist/{chunk-M5QKGHCR.js.map → chunk-CYWCKFCL.js.map} +0 -0
  350. /package/dist/{chunk-4BFRBP45.js.map → chunk-DEG5ULFJ.js.map} +0 -0
  351. /package/dist/{chunk-JLR3JSTL.js.map → chunk-DS7MM2ES.js.map} +0 -0
  352. /package/dist/{chunk-2BFLDH5F.js.map → chunk-EEIROWEG.js.map} +0 -0
  353. /package/dist/{chunk-X4A62ET7.js.map → chunk-H2DXDQCQ.js.map} +0 -0
  354. /package/dist/{chunk-27FLVMDC.js.map → chunk-HLN7RROI.js.map} +0 -0
  355. /package/dist/{chunk-2U2A5HF4.js.map → chunk-J3XHPFEU.js.map} +0 -0
  356. /package/dist/{chunk-AKUCU7CI.js.map → chunk-JI5AVXYO.js.map} +0 -0
  357. /package/dist/{chunk-KCJ5H6XQ.js.map → chunk-JSNVWNGX.js.map} +0 -0
  358. /package/dist/{chunk-FLVL4L3L.js.map → chunk-KTULX4YO.js.map} +0 -0
  359. /package/dist/{chunk-437S3G37.js.map → chunk-LNQUAJNC.js.map} +0 -0
  360. /package/dist/{chunk-EPGWWCZF.js.map → chunk-LR5DZ56F.js.map} +0 -0
  361. /package/dist/{chunk-YDSWRD33.js.map → chunk-N3JDIRBW.js.map} +0 -0
  362. /package/dist/{chunk-OUMTBFSQ.js.map → chunk-NKCPUHCI.js.map} +0 -0
  363. /package/dist/{chunk-BGTAL46Y.js.map → chunk-PNLFN2PZ.js.map} +0 -0
  364. /package/dist/{chunk-P6SYWE4G.js.map → chunk-PVUJ6WVV.js.map} +0 -0
  365. /package/dist/{chunk-YPEMNNNY.js.map → chunk-RGK27ELN.js.map} +0 -0
  366. /package/dist/{chunk-2QSZNTDO.js.map → chunk-RKNJBZ55.js.map} +0 -0
  367. /package/dist/{chunk-66FLU5BT.js.map → chunk-SIRPLF54.js.map} +0 -0
  368. /package/dist/{chunk-HRCACVHL.js.map → chunk-TLUDFPZL.js.map} +0 -0
  369. /package/dist/{chunk-2MR3MFQB.js.map → chunk-UPSAT4PY.js.map} +0 -0
  370. /package/dist/{chunk-4P4626RY.js.map → chunk-UTRJFDP2.js.map} +0 -0
  371. /package/dist/{chunk-CGS7UKWM.js.map → chunk-VCW74PNH.js.map} +0 -0
  372. /package/dist/{chunk-5GPPACXK.js.map → chunk-VSMRDBFT.js.map} +0 -0
  373. /package/dist/{chunk-NG7YBCJO.js.map → chunk-XCL57M6Q.js.map} +0 -0
  374. /package/dist/{chunk-CLX5VDNY.js.map → chunk-Y4RKAQZ7.js.map} +0 -0
  375. /package/dist/{chunk-DGYCWCQ7.js.map → chunk-Y7UNNAZD.js.map} +0 -0
  376. /package/dist/{chunk-EZ25VE3G.js.map → chunk-YNDLCWXS.js.map} +0 -0
  377. /package/dist/{chunk-XN3TUUX2.js.map → chunk-YQB32INI.js.map} +0 -0
  378. /package/dist/{first-start-migration-DY6YCRC2.js.map → first-start-migration-VBJQL6OI.js.map} +0 -0
  379. /package/dist/{tier-stats-TG6GUZ6N.js.map → tier-stats-5XF4UBRQ.js.map} +0 -0
@@ -1,7 +1,12 @@
1
1
  import {
2
2
  WEARABLES_DIR_NAME,
3
- isValidTranscriptDate
4
- } from "./chunk-M7XQSUBB.js";
3
+ hasSelfMarker,
4
+ isValidTranscriptDate,
5
+ parseTranscriptSegmentLine,
6
+ resolveSpeaker,
7
+ unescapeSegmentText,
8
+ unescapeSpeakerLabel
9
+ } from "./chunk-B3ABVQ36.js";
5
10
  import {
6
11
  TombstoneStore,
7
12
  buildRetiredFactTombstoneInputs,
@@ -11,14 +16,12 @@ import {
11
16
  isErrnoCode
12
17
  } from "./chunk-5UZXUTVO.js";
13
18
  import {
14
- assertPathInsideRoot
15
- } from "./chunk-5GPPACXK.js";
19
+ assertPathInsideRoot,
20
+ pathIsInside
21
+ } from "./chunk-VSMRDBFT.js";
16
22
  import {
17
23
  supersessionKeysForFact
18
24
  } from "./chunk-EHK6KZHK.js";
19
- import {
20
- stripAttributesSuffix
21
- } from "./chunk-SVOZFLIQ.js";
22
25
  import {
23
26
  DEFAULT_CITATION_FORMAT,
24
27
  hasCitation,
@@ -28,10 +31,21 @@ import {
28
31
  assertMemoryFrontmatterId,
29
32
  warnProjectionFallback
30
33
  } from "./chunk-4KJLYTLS.js";
34
+ import {
35
+ stripAttributesSuffix
36
+ } from "./chunk-SVOZFLIQ.js";
31
37
  import {
32
38
  SPECULATIVE_TTL_DAYS,
33
39
  confidenceTier
34
40
  } from "./chunk-JS2HKKOK.js";
41
+ import {
42
+ markProjectedMemoryPathInvalid,
43
+ readProjectedGovernanceRecord,
44
+ readProjectedMemoryBrowse,
45
+ readProjectedMemoryState,
46
+ readProjectedMemoryTimeline,
47
+ updateProjectedMemoryPath
48
+ } from "./chunk-RHOZ5LLO.js";
35
49
  import {
36
50
  getCachedEntities,
37
51
  invalidateAllForDir,
@@ -47,14 +61,6 @@ import {
47
61
  normalizeProjectionPreview,
48
62
  normalizeProjectionTags
49
63
  } from "./chunk-SCU65EZI.js";
50
- import {
51
- markProjectedMemoryPathInvalid,
52
- readProjectedGovernanceRecord,
53
- readProjectedMemoryBrowse,
54
- readProjectedMemoryState,
55
- readProjectedMemoryTimeline,
56
- updateProjectedMemoryPath
57
- } from "./chunk-RHOZ5LLO.js";
58
64
  import {
59
65
  rotateMarkdownFileToArchive
60
66
  } from "./chunk-DM2T26WE.js";
@@ -88,14 +94,14 @@ import {
88
94
  reconcileProvenanceRead,
89
95
  serializeProvenanceFields
90
96
  } from "./chunk-OEHCMALU.js";
91
- import {
92
- sanitizeMemoryContent
93
- } from "./chunk-5GKPFL3S.js";
94
97
  import {
95
98
  matchEntitySchemaSection,
96
99
  normalizeEntityStructuredSection,
97
100
  sortStructuredSectionsBySchema
98
101
  } from "./chunk-4DJQYKMN.js";
102
+ import {
103
+ sanitizeMemoryContent
104
+ } from "./chunk-5GKPFL3S.js";
99
105
  import {
100
106
  log
101
107
  } from "./chunk-37CTGERM.js";
@@ -118,10 +124,10 @@ import {
118
124
  } from "./chunk-VS2IYZRU.js";
119
125
 
120
126
  // src/storage.ts
121
- import { access, readdir as readdir4, readFile, stat as stat2, writeFile, mkdir, unlink as unlink2, appendFile, open as open2 } from "fs/promises";
127
+ import { access, lstat as lstat2, readdir as readdir4, readFile, realpath as realpath2, stat as stat2, writeFile, mkdir, unlink as unlink2, appendFile, open as open2 } from "fs/promises";
122
128
  import { appendFileSync, createReadStream as createReadStream2, mkdirSync, readFileSync, statSync } from "fs";
123
- import { createHash } from "crypto";
124
- import path4 from "path";
129
+ import { createHash as createHash3 } from "crypto";
130
+ import path5 from "path";
125
131
 
126
132
  // src/storage/memory-read-store.ts
127
133
  import { lstat, readdir, realpath, stat } from "fs/promises";
@@ -1259,6 +1265,1050 @@ var IdentityContinuityStore = class {
1259
1265
  }
1260
1266
  };
1261
1267
 
1268
+ // src/wearables/fusion/cluster.ts
1269
+ var DEFAULT_PROXIMITY_GAP_MS = 5 * 6e4;
1270
+ function maxSegmentExtent(segments) {
1271
+ let best;
1272
+ for (const seg of segments) {
1273
+ const iso = seg.endIso ?? seg.startIso;
1274
+ if (iso === void 0) continue;
1275
+ const ms = Date.parse(iso);
1276
+ if (!Number.isFinite(ms)) continue;
1277
+ if (best === void 0 || ms > best.ms) {
1278
+ best = { ms, iso };
1279
+ }
1280
+ }
1281
+ return best;
1282
+ }
1283
+ function effectiveInterval(conversation) {
1284
+ const start = Date.parse(conversation.startIso);
1285
+ const endRaw = conversation.endIso !== void 0 ? Date.parse(conversation.endIso) : NaN;
1286
+ const end = Number.isFinite(endRaw) ? endRaw : maxSegmentExtent(conversation.segments)?.ms ?? start;
1287
+ return { start, end: Math.max(end, start) };
1288
+ }
1289
+ function compareConversation(a, b) {
1290
+ if (a.source !== b.source) return a.source < b.source ? -1 : 1;
1291
+ if (a.conversationId !== b.conversationId) {
1292
+ return a.conversationId < b.conversationId ? -1 : 1;
1293
+ }
1294
+ return 0;
1295
+ }
1296
+ function clusterConversations(inputs, proximityGapMs = DEFAULT_PROXIMITY_GAP_MS) {
1297
+ const finite = [];
1298
+ const noStart = [];
1299
+ for (const conv of inputs) {
1300
+ const interval = effectiveInterval(conv);
1301
+ if (Number.isFinite(interval.start)) {
1302
+ finite.push({ conv, interval });
1303
+ } else {
1304
+ noStart.push(conv);
1305
+ }
1306
+ }
1307
+ finite.sort((a, b) => {
1308
+ if (a.interval.start !== b.interval.start) {
1309
+ return a.interval.start - b.interval.start;
1310
+ }
1311
+ return compareConversation(a.conv, b.conv);
1312
+ });
1313
+ const n = finite.length;
1314
+ const parent = new Array(n);
1315
+ for (let i = 0; i < n; i++) parent[i] = i;
1316
+ const find = (x) => {
1317
+ let root = x;
1318
+ while (parent[root] !== root) root = parent[root];
1319
+ let cur = x;
1320
+ while (parent[cur] !== root) {
1321
+ const next = parent[cur];
1322
+ parent[cur] = root;
1323
+ cur = next;
1324
+ }
1325
+ return root;
1326
+ };
1327
+ const union = (a, b) => {
1328
+ const ra = find(a);
1329
+ const rb = find(b);
1330
+ if (ra !== rb) parent[ra] = rb;
1331
+ };
1332
+ for (let i = 0; i < n; i++) {
1333
+ const endGap = finite[i].interval.end + proximityGapMs;
1334
+ for (let j = i + 1; j < n; j++) {
1335
+ if (finite[j].interval.start > endGap) break;
1336
+ if (finite[i].conv.source === finite[j].conv.source) continue;
1337
+ union(i, j);
1338
+ }
1339
+ }
1340
+ const clusters = [];
1341
+ const rootToCluster = /* @__PURE__ */ new Map();
1342
+ for (let i = 0; i < n; i++) {
1343
+ const root = find(i);
1344
+ let idx = rootToCluster.get(root);
1345
+ if (idx === void 0) {
1346
+ idx = clusters.length;
1347
+ rootToCluster.set(root, idx);
1348
+ clusters.push([]);
1349
+ }
1350
+ clusters[idx].push(finite[i].conv);
1351
+ }
1352
+ noStart.sort(compareConversation);
1353
+ for (const conv of noStart) {
1354
+ clusters.push([conv]);
1355
+ }
1356
+ return clusters;
1357
+ }
1358
+
1359
+ // src/wearables/fusion/reconcile.ts
1360
+ var DEFAULT_WINDOW_TOLERANCE_MS = 3e4;
1361
+ var DEFAULT_SOURCE_TRUST = 0.8;
1362
+ var TRUST_DECISION_EPSILON = 1e-9;
1363
+ var GENERIC_LABEL_PATTERN = /^(Speaker \d+|Unknown speaker|SPEAKER_\d+)$/i;
1364
+ function speakerKey(label, isSelf) {
1365
+ return isSelf ? "self" : label;
1366
+ }
1367
+ function resolveTrust(source, trustMap) {
1368
+ const value = trustMap?.[source];
1369
+ if (typeof value === "number" && Number.isFinite(value)) {
1370
+ return Math.min(1, Math.max(0, value));
1371
+ }
1372
+ return DEFAULT_SOURCE_TRUST;
1373
+ }
1374
+ function normalizeWords(text) {
1375
+ return text.toLowerCase().replace(/[^\p{L}\p{N}\s]/gu, " ").split(/\s+/).filter((word) => word.length > 0);
1376
+ }
1377
+ function wordsEqual(a, b) {
1378
+ if (a.length !== b.length) return false;
1379
+ for (let i = 0; i < a.length; i++) {
1380
+ if (a[i] !== b[i]) return false;
1381
+ }
1382
+ return true;
1383
+ }
1384
+ function isWordPrefix(short, long) {
1385
+ if (short.length === 0 || short.length > long.length) return false;
1386
+ for (let i = 0; i < short.length; i++) {
1387
+ if (short[i] !== long[i]) return false;
1388
+ }
1389
+ return true;
1390
+ }
1391
+ function wordsCorroborate(a, b, allowPrefix) {
1392
+ if (wordsEqual(a, b)) return true;
1393
+ if (!allowPrefix) return false;
1394
+ return isWordPrefix(a, b) || isWordPrefix(b, a);
1395
+ }
1396
+ function clamp01(value) {
1397
+ if (!Number.isFinite(value)) return 0;
1398
+ return Math.min(1, Math.max(0, value));
1399
+ }
1400
+ function fusionInputsFromConversations(sourceId, conversations, registry) {
1401
+ return conversations.map((conversation) => {
1402
+ const segments = conversation.segments.map((raw) => {
1403
+ const resolved = resolveSpeaker(sourceId, raw, registry);
1404
+ return {
1405
+ speaker: resolved.label,
1406
+ isSelf: resolved.isSelf,
1407
+ text: raw.text,
1408
+ ...raw.startIso !== void 0 ? { startIso: raw.startIso } : {},
1409
+ ...raw.endIso !== void 0 ? { endIso: raw.endIso } : {}
1410
+ };
1411
+ });
1412
+ return {
1413
+ source: sourceId,
1414
+ conversationId: conversation.id,
1415
+ startIso: conversation.startIso,
1416
+ ...conversation.endIso !== void 0 ? { endIso: conversation.endIso } : {},
1417
+ ...conversation.title !== void 0 ? { title: conversation.title } : {},
1418
+ ...conversation.summary !== void 0 ? { summary: conversation.summary } : {},
1419
+ segments
1420
+ };
1421
+ });
1422
+ }
1423
+ function fuseCluster(cluster, options = {}) {
1424
+ const trustMap = options.sourceTrust;
1425
+ const toleranceMs = options.windowToleranceMs ?? DEFAULT_WINDOW_TOLERANCE_MS;
1426
+ const sources = [];
1427
+ const sourcesSeen = /* @__PURE__ */ new Set();
1428
+ for (const conv of cluster) {
1429
+ if (!sourcesSeen.has(conv.source)) {
1430
+ sourcesSeen.add(conv.source);
1431
+ sources.push(conv.source);
1432
+ }
1433
+ }
1434
+ let startMs = Number.POSITIVE_INFINITY;
1435
+ let endMs = Number.NEGATIVE_INFINITY;
1436
+ let startIso;
1437
+ let endIso;
1438
+ for (const conv of cluster) {
1439
+ const ms = Date.parse(conv.startIso);
1440
+ if (Number.isFinite(ms) && ms < startMs) {
1441
+ startMs = ms;
1442
+ startIso = conv.startIso;
1443
+ }
1444
+ if (conv.endIso !== void 0) {
1445
+ const endM = Date.parse(conv.endIso);
1446
+ if (Number.isFinite(endM) && endM > endMs) {
1447
+ endMs = endM;
1448
+ endIso = conv.endIso;
1449
+ }
1450
+ }
1451
+ }
1452
+ const segmentExtent = maxSegmentExtent(
1453
+ cluster.flatMap((conv) => conv.segments)
1454
+ );
1455
+ if (segmentExtent !== void 0 && segmentExtent.ms > endMs) {
1456
+ endMs = segmentExtent.ms;
1457
+ endIso = segmentExtent.iso;
1458
+ }
1459
+ if (endIso !== void 0 && Number.isFinite(startMs) && endMs < startMs) {
1460
+ endIso = startIso;
1461
+ endMs = startMs;
1462
+ }
1463
+ if (startIso === void 0) {
1464
+ startIso = cluster[0]?.startIso ?? (/* @__PURE__ */ new Date(0)).toISOString();
1465
+ }
1466
+ let title;
1467
+ let summary;
1468
+ for (const conv of cluster) {
1469
+ if (title === void 0 && conv.title !== void 0 && conv.title.trim().length > 0) {
1470
+ title = conv.title.trim();
1471
+ }
1472
+ if (summary === void 0 && conv.summary !== void 0 && conv.summary.trim().length > 0) {
1473
+ summary = conv.summary.trim();
1474
+ }
1475
+ if (title !== void 0 && summary !== void 0) break;
1476
+ }
1477
+ const tagged = [];
1478
+ for (const conv of cluster) {
1479
+ const sourceTrust = resolveTrust(conv.source, trustMap);
1480
+ for (const segment of conv.segments) {
1481
+ const startMsValue = segment.startIso !== void 0 ? Date.parse(segment.startIso) : NaN;
1482
+ tagged.push({
1483
+ source: conv.source,
1484
+ conversationId: conv.conversationId,
1485
+ speakerLabel: segment.speaker,
1486
+ isSelf: segment.isSelf,
1487
+ text: segment.text,
1488
+ startMs: Number.isFinite(startMsValue) ? startMsValue : Number.POSITIVE_INFINITY,
1489
+ ...segment.startIso !== void 0 ? { startIso: segment.startIso } : {},
1490
+ ...segment.endIso !== void 0 ? { endIso: segment.endIso } : {},
1491
+ sourceTrust,
1492
+ originalIndex: tagged.length
1493
+ });
1494
+ }
1495
+ }
1496
+ tagged.sort((a, b) => {
1497
+ const aFinite = Number.isFinite(a.startMs);
1498
+ const bFinite = Number.isFinite(b.startMs);
1499
+ if (aFinite && bFinite && a.startMs !== b.startMs) return a.startMs - b.startMs;
1500
+ if (aFinite !== bFinite) return aFinite ? -1 : 1;
1501
+ return a.originalIndex - b.originalIndex;
1502
+ });
1503
+ const groups = [];
1504
+ for (const seg of tagged) {
1505
+ const key = speakerKey(seg.speakerLabel, seg.isSelf);
1506
+ const segMissing = !Number.isFinite(seg.startMs);
1507
+ const segWords = normalizeWords(seg.text);
1508
+ const corroborates = (group) => {
1509
+ if (group.members.some((member) => member.source === seg.source)) {
1510
+ return false;
1511
+ }
1512
+ const groupMissing = !Number.isFinite(group.anchorMs);
1513
+ if (groupMissing !== segMissing) return false;
1514
+ if (!groupMissing && Math.abs(seg.startMs - group.anchorMs) > toleranceMs) {
1515
+ return false;
1516
+ }
1517
+ return group.members.some(
1518
+ (member) => wordsCorroborate(normalizeWords(member.text), segWords, !groupMissing)
1519
+ );
1520
+ };
1521
+ const closestCorroborating = (wantSameSpeaker) => {
1522
+ let best;
1523
+ let bestDelta = Infinity;
1524
+ for (const group of groups) {
1525
+ if (group.key === key !== wantSameSpeaker || !corroborates(group)) {
1526
+ continue;
1527
+ }
1528
+ const delta = !segMissing && Number.isFinite(group.anchorMs) ? Math.abs(seg.startMs - group.anchorMs) : 0;
1529
+ if (best === void 0 || delta < bestDelta || delta === bestDelta && group.anchorMs < best.anchorMs) {
1530
+ best = group;
1531
+ bestDelta = delta;
1532
+ }
1533
+ }
1534
+ return best;
1535
+ };
1536
+ let chosen = closestCorroborating(true);
1537
+ if (chosen === void 0) {
1538
+ chosen = closestCorroborating(false);
1539
+ }
1540
+ if (chosen !== void 0) {
1541
+ chosen.members.push(seg);
1542
+ if (seg.originalIndex < chosen.originalIndex) {
1543
+ chosen.originalIndex = seg.originalIndex;
1544
+ }
1545
+ } else {
1546
+ groups.push({
1547
+ key,
1548
+ speakerLabel: seg.speakerLabel,
1549
+ isSelf: seg.isSelf,
1550
+ members: [seg],
1551
+ anchorMs: seg.startMs,
1552
+ // The creating segment is the EARLIEST member (tagged is
1553
+ // time-sorted), so its clock IS the group anchor that groups are
1554
+ // sorted by and that the fused segment must be emitted at.
1555
+ anchorStartIso: seg.startIso,
1556
+ anchorEndIso: seg.endIso,
1557
+ originalIndex: seg.originalIndex
1558
+ });
1559
+ }
1560
+ }
1561
+ groups.sort((a, b) => {
1562
+ const aMissing = !Number.isFinite(a.anchorMs);
1563
+ const bMissing = !Number.isFinite(b.anchorMs);
1564
+ if (aMissing !== bMissing) return aMissing ? 1 : -1;
1565
+ if (!aMissing && a.anchorMs !== b.anchorMs) return a.anchorMs - b.anchorMs;
1566
+ return a.originalIndex - b.originalIndex;
1567
+ });
1568
+ const segments = [];
1569
+ const disagreements = [];
1570
+ for (const group of groups) {
1571
+ const reconciled = reconcileGroup(group);
1572
+ segments.push(reconciled.segment);
1573
+ disagreements.push(...reconciled.disagreements);
1574
+ }
1575
+ const preSortOrder = new Map(segments.map((seg, i) => [seg, i]));
1576
+ segments.sort((a, b) => {
1577
+ const aMs = a.startIso !== void 0 ? Date.parse(a.startIso) : Number.NaN;
1578
+ const bMs = b.startIso !== void 0 ? Date.parse(b.startIso) : Number.NaN;
1579
+ const aFinite = Number.isFinite(aMs);
1580
+ const bFinite = Number.isFinite(bMs);
1581
+ if (aFinite && bFinite) {
1582
+ if (aMs !== bMs) return aMs - bMs;
1583
+ } else if (aFinite !== bFinite) {
1584
+ return aFinite ? -1 : 1;
1585
+ }
1586
+ return (preSortOrder.get(a) ?? 0) - (preSortOrder.get(b) ?? 0);
1587
+ });
1588
+ detectCrossSegmentDisagreements(segments, toleranceMs, disagreements);
1589
+ const result = {
1590
+ sources,
1591
+ speakers: collectSpeakers(tagged),
1592
+ startIso,
1593
+ segments,
1594
+ disagreements
1595
+ };
1596
+ if (endIso !== void 0) result.endIso = endIso;
1597
+ if (title !== void 0) result.title = title;
1598
+ if (summary !== void 0) result.summary = summary;
1599
+ return result;
1600
+ }
1601
+ function reconcileGroup(group) {
1602
+ const members = group.members;
1603
+ const ranked = [...members].sort((a, b) => {
1604
+ if (Math.abs(b.sourceTrust - a.sourceTrust) > TRUST_DECISION_EPSILON) {
1605
+ return b.sourceTrust - a.sourceTrust;
1606
+ }
1607
+ if (b.text.length !== a.text.length) return b.text.length - a.text.length;
1608
+ if (a.source !== b.source) return a.source < b.source ? -1 : 1;
1609
+ if (a.conversationId !== b.conversationId) {
1610
+ return a.conversationId < b.conversationId ? -1 : 1;
1611
+ }
1612
+ return a.originalIndex - b.originalIndex;
1613
+ });
1614
+ const top = ranked[0];
1615
+ const topWords = normalizeWords(top.text);
1616
+ let chosen = top;
1617
+ if (topWords.length > 0) {
1618
+ let bestLen = -1;
1619
+ for (const candidate of ranked) {
1620
+ if (candidate === top) continue;
1621
+ const candidateWords = normalizeWords(candidate.text);
1622
+ if (isWordPrefix(topWords, candidateWords) && candidateWords.length > topWords.length && candidateWords.length > bestLen) {
1623
+ chosen = candidate;
1624
+ bestLen = candidateWords.length;
1625
+ }
1626
+ }
1627
+ }
1628
+ const truncatedOverride = chosen !== top;
1629
+ const others = ranked.filter((member) => member !== chosen);
1630
+ const chosenWords = normalizeWords(chosen.text);
1631
+ const reason = members.length === 1 ? "only-source" : truncatedOverride ? "more-complete" : others.some(
1632
+ (r) => chosen.sourceTrust - r.sourceTrust > TRUST_DECISION_EPSILON
1633
+ ) ? "higher-trust" : others.some((r) => chosen.text.length - r.text.length > 0) ? "more-complete" : "tie-break";
1634
+ const disagree = [];
1635
+ let conflict = false;
1636
+ for (const candidate of others) {
1637
+ const candidateWords = normalizeWords(candidate.text);
1638
+ if (chosenWords.length === 0 && candidateWords.length === 0) continue;
1639
+ if (wordsEqual(chosenWords, candidateWords)) continue;
1640
+ if (isWordPrefix(candidateWords, chosenWords) || isWordPrefix(chosenWords, candidateWords)) {
1641
+ continue;
1642
+ }
1643
+ conflict = true;
1644
+ disagree.push({ source: candidate.source, value: candidate.text });
1645
+ }
1646
+ const distinctSpeakerKeys = new Set(
1647
+ members.map((m) => speakerKey(m.speakerLabel, m.isSelf))
1648
+ );
1649
+ const speakerConflict = distinctSpeakerKeys.size > 1;
1650
+ const alternatives = others.map((candidate) => ({
1651
+ source: candidate.source,
1652
+ text: candidate.text
1653
+ }));
1654
+ const confidence = conflict || speakerConflict ? clamp01(chosen.sourceTrust * 0.7) : members.length > 1 ? clamp01(chosen.sourceTrust + 0.1 * (members.length - 1)) : clamp01(chosen.sourceTrust);
1655
+ const segment = {
1656
+ speaker: chosen.speakerLabel,
1657
+ isSelf: chosen.isSelf,
1658
+ text: chosen.text,
1659
+ confidence,
1660
+ provenance: {
1661
+ source: chosen.source,
1662
+ conversationId: chosen.conversationId,
1663
+ sourceTrust: chosen.sourceTrust,
1664
+ reason,
1665
+ alternatives,
1666
+ ...chosen.startIso !== void 0 ? { sourceStartIso: chosen.startIso } : {},
1667
+ ...chosen.endIso !== void 0 ? { sourceEndIso: chosen.endIso } : {}
1668
+ },
1669
+ ...group.anchorStartIso !== void 0 ? { startIso: group.anchorStartIso } : {},
1670
+ ...group.anchorEndIso !== void 0 ? { endIso: group.anchorEndIso } : {}
1671
+ };
1672
+ const disagreements = [];
1673
+ const anchorIso = group.anchorStartIso ?? (Number.isFinite(group.anchorMs) ? new Date(group.anchorMs).toISOString() : void 0);
1674
+ if (conflict) {
1675
+ disagreements.push({
1676
+ kind: "asr-text",
1677
+ subject: anchorIso ?? "(no timestamp)",
1678
+ candidates: [{ source: chosen.source, value: chosen.text }, ...disagree],
1679
+ provisional: { source: chosen.source, value: chosen.text }
1680
+ });
1681
+ }
1682
+ if (speakerConflict) {
1683
+ const speakerCandidates = members.map((m) => ({ source: m.source, value: m.speakerLabel })).sort(
1684
+ (a, b) => a.source < b.source ? -1 : a.source > b.source ? 1 : 0
1685
+ );
1686
+ disagreements.push({
1687
+ kind: "speaker",
1688
+ subject: anchorIso ?? "(no timestamp)",
1689
+ candidates: speakerCandidates,
1690
+ provisional: { source: chosen.source, value: chosen.speakerLabel }
1691
+ });
1692
+ }
1693
+ return { segment, disagreements };
1694
+ }
1695
+ function detectCrossSegmentDisagreements(segments, toleranceMs, out) {
1696
+ const n = segments.length;
1697
+ if (n < 2) return;
1698
+ const claimed = new Array(n).fill(false);
1699
+ for (let i = 0; i < n; i++) {
1700
+ if (claimed[i]) continue;
1701
+ const seed = segments[i];
1702
+ const seedMs = seed.startIso !== void 0 ? Date.parse(seed.startIso) : NaN;
1703
+ if (!Number.isFinite(seedMs)) continue;
1704
+ const seedWords = normalizeWords(seed.text);
1705
+ const clusterIdx = [];
1706
+ for (let j = i + 1; j < n; j++) {
1707
+ if (claimed[j]) continue;
1708
+ const cand = segments[j];
1709
+ if (speakerKey(cand.speaker, cand.isSelf) !== speakerKey(seed.speaker, seed.isSelf)) {
1710
+ continue;
1711
+ }
1712
+ if (cand.provenance.source === seed.provenance.source) continue;
1713
+ const candMs = cand.startIso !== void 0 ? Date.parse(cand.startIso) : NaN;
1714
+ if (!Number.isFinite(candMs)) continue;
1715
+ if (Math.abs(candMs - seedMs) > toleranceMs) continue;
1716
+ if (wordsCorroborate(seedWords, normalizeWords(cand.text), true)) {
1717
+ continue;
1718
+ }
1719
+ clusterIdx.push(j);
1720
+ }
1721
+ if (clusterIdx.length === 0) continue;
1722
+ clusterIdx.unshift(i);
1723
+ for (const idx of clusterIdx) claimed[idx] = true;
1724
+ const involved = clusterIdx.map((idx) => segments[idx]);
1725
+ const involvedOrder = new Map(involved.map((seg, i2) => [seg, i2]));
1726
+ involved.sort((a, b) => {
1727
+ if (Math.abs(b.provenance.sourceTrust - a.provenance.sourceTrust) > TRUST_DECISION_EPSILON) {
1728
+ return b.provenance.sourceTrust - a.provenance.sourceTrust;
1729
+ }
1730
+ if (b.text.length !== a.text.length) return b.text.length - a.text.length;
1731
+ if (a.provenance.source !== b.provenance.source) {
1732
+ return a.provenance.source < b.provenance.source ? -1 : 1;
1733
+ }
1734
+ return involvedOrder.get(a) - involvedOrder.get(b);
1735
+ });
1736
+ const provisional = involved[0];
1737
+ const anchorIso = involved.map((s) => s.startIso).filter((v) => v !== void 0).sort()[0];
1738
+ for (const seg of involved) {
1739
+ seg.confidence = clamp01(seg.provenance.sourceTrust * 0.7);
1740
+ }
1741
+ out.push({
1742
+ kind: "asr-text",
1743
+ subject: anchorIso ?? "(no timestamp)",
1744
+ candidates: involved.map((s) => ({
1745
+ source: s.provenance.source,
1746
+ value: s.text
1747
+ })),
1748
+ provisional: {
1749
+ source: provisional.provenance.source,
1750
+ value: provisional.text
1751
+ }
1752
+ });
1753
+ }
1754
+ }
1755
+ function collectSpeakers(tagged) {
1756
+ const order = [];
1757
+ const acc = /* @__PURE__ */ new Map();
1758
+ for (const seg of tagged) {
1759
+ const key = speakerKey(seg.speakerLabel, seg.isSelf);
1760
+ let entry = acc.get(key);
1761
+ if (entry === void 0) {
1762
+ entry = {
1763
+ label: seg.speakerLabel,
1764
+ isSelf: seg.isSelf,
1765
+ sources: /* @__PURE__ */ new Set(),
1766
+ generic: GENERIC_LABEL_PATTERN.test(seg.speakerLabel)
1767
+ };
1768
+ acc.set(key, entry);
1769
+ order.push(key);
1770
+ }
1771
+ entry.sources.add(seg.source);
1772
+ }
1773
+ return order.map((key) => {
1774
+ const entry = acc.get(key);
1775
+ if (entry === void 0) throw new Error("fusion speaker accumulator miss");
1776
+ const sourceCount = entry.sources.size;
1777
+ const confidence = entry.isSelf ? sourceCount > 1 ? 0.95 : 0.85 : entry.generic ? sourceCount > 1 ? 0.7 : 0.5 : sourceCount > 1 ? 0.9 : 0.7;
1778
+ return {
1779
+ label: entry.label,
1780
+ isSelf: entry.isSelf,
1781
+ confidence,
1782
+ sources: [...entry.sources].sort()
1783
+ };
1784
+ });
1785
+ }
1786
+
1787
+ // src/wearables/fusion/fuse.ts
1788
+ import { createHash } from "crypto";
1789
+ var FUSION_ID_PREFIX = "fusion";
1790
+ var FUSION_ALGO_VERSION = "2026-07-12-1";
1791
+ function canonicalInputsKey(date, inputs) {
1792
+ const sorted = [...inputs].sort((a, b) => {
1793
+ if (a.source !== b.source) return a.source < b.source ? -1 : 1;
1794
+ if (a.conversationId !== b.conversationId) {
1795
+ return a.conversationId < b.conversationId ? -1 : 1;
1796
+ }
1797
+ return 0;
1798
+ });
1799
+ const record = [
1800
+ date,
1801
+ sorted.map((conv) => [
1802
+ conv.source,
1803
+ conv.conversationId,
1804
+ conv.startIso,
1805
+ conv.endIso ?? "",
1806
+ conv.title ?? "",
1807
+ conv.summary ?? "",
1808
+ conv.segments.map((segment) => [
1809
+ segment.speaker,
1810
+ segment.isSelf ? "self" : "other",
1811
+ segment.startIso ?? "",
1812
+ segment.endIso ?? "",
1813
+ segment.text
1814
+ ])
1815
+ ])
1816
+ ];
1817
+ return createHash("sha256").update(JSON.stringify(record), "utf-8").digest("hex");
1818
+ }
1819
+ function configFingerprint(options, sources) {
1820
+ const proximityGapMs = options.proximityGapMs ?? DEFAULT_PROXIMITY_GAP_MS;
1821
+ const windowToleranceMs = options.windowToleranceMs ?? DEFAULT_WINDOW_TOLERANCE_MS;
1822
+ const trustMap = options.sourceTrust ?? {};
1823
+ const trustEntries = [...new Set(sources)].sort().map((source) => [source, trustMap[source] ?? DEFAULT_SOURCE_TRUST]);
1824
+ return JSON.stringify([proximityGapMs, windowToleranceMs, trustEntries]);
1825
+ }
1826
+ function canonicalDayKey(date, inputs, options, algoVersion = FUSION_ALGO_VERSION) {
1827
+ const inputsKey = canonicalInputsKey(date, inputs);
1828
+ const fingerprint = configFingerprint(
1829
+ options,
1830
+ inputs.map((conv) => conv.source)
1831
+ );
1832
+ return createHash("sha256").update(inputsKey).update("\n").update(fingerprint).update("\n").update(algoVersion).digest("hex");
1833
+ }
1834
+ function buildProvenance(cluster, proximityGapMs, windowToleranceMs) {
1835
+ return {
1836
+ contributions: cluster.map((conv) => ({
1837
+ source: conv.source,
1838
+ conversationId: conv.conversationId,
1839
+ startIso: conv.startIso,
1840
+ ...conv.endIso !== void 0 ? { endIso: conv.endIso } : {},
1841
+ segmentCount: conv.segments.length
1842
+ })),
1843
+ proximityGapMs,
1844
+ windowToleranceMs,
1845
+ method: "time-proximity"
1846
+ };
1847
+ }
1848
+ function fuseDay(date, inputs, options = {}) {
1849
+ const proximityGapMs = options.proximityGapMs ?? DEFAULT_PROXIMITY_GAP_MS;
1850
+ const windowToleranceMs = options.windowToleranceMs ?? DEFAULT_WINDOW_TOLERANCE_MS;
1851
+ const clusters = clusterConversations(inputs, proximityGapMs);
1852
+ const conversations = clusters.map((cluster) => {
1853
+ const fused = fuseCluster(cluster, {
1854
+ ...options,
1855
+ windowToleranceMs
1856
+ });
1857
+ const id = `${FUSION_ID_PREFIX}-${canonicalInputsKey(date, cluster).slice(0, 24)}`;
1858
+ const result = {
1859
+ id,
1860
+ date,
1861
+ startIso: fused.startIso,
1862
+ sources: fused.sources,
1863
+ speakers: fused.speakers,
1864
+ segments: fused.segments,
1865
+ disagreements: fused.disagreements,
1866
+ provenance: buildProvenance(cluster, proximityGapMs, windowToleranceMs)
1867
+ };
1868
+ if (fused.endIso !== void 0) result.endIso = fused.endIso;
1869
+ if (fused.title !== void 0) result.title = fused.title;
1870
+ if (fused.summary !== void 0) result.summary = fused.summary;
1871
+ return result;
1872
+ });
1873
+ const sourcesSeen = /* @__PURE__ */ new Set();
1874
+ const sources = [];
1875
+ for (const conv of conversations) {
1876
+ for (const source of conv.sources) {
1877
+ if (!sourcesSeen.has(source)) {
1878
+ sourcesSeen.add(source);
1879
+ sources.push(source);
1880
+ }
1881
+ }
1882
+ }
1883
+ return {
1884
+ date,
1885
+ conversations,
1886
+ sources,
1887
+ contentHash: canonicalDayKey(date, inputs, options)
1888
+ };
1889
+ }
1890
+
1891
+ // src/wearables/fusion/store.ts
1892
+ import { createHash as createHash2 } from "crypto";
1893
+ import * as path4 from "path";
1894
+ var FUSION_KIND = "wearable-fusion";
1895
+ function hashFusionBody(conversations) {
1896
+ return createHash2("sha256").update(JSON.stringify(conversations), "utf-8").digest("hex");
1897
+ }
1898
+ function composeFusionDayMeta(date, conversations, sources, contentHash, fusedAt) {
1899
+ return {
1900
+ kind: FUSION_KIND,
1901
+ date,
1902
+ sourceCount: sources.length,
1903
+ conversationCount: conversations.length,
1904
+ contentHash,
1905
+ bodyHash: hashFusionBody(conversations),
1906
+ fusedAt
1907
+ };
1908
+ }
1909
+ function serializeFusionDay(meta, conversations) {
1910
+ const lines = ["---"];
1911
+ lines.push(`kind: ${meta.kind}`);
1912
+ lines.push(`date: ${JSON.stringify(meta.date)}`);
1913
+ lines.push(`sourceCount: ${meta.sourceCount}`);
1914
+ lines.push(`conversationCount: ${meta.conversationCount}`);
1915
+ lines.push(`contentHash: ${JSON.stringify(meta.contentHash)}`);
1916
+ lines.push(`bodyHash: ${JSON.stringify(meta.bodyHash)}`);
1917
+ lines.push(`fusedAt: ${JSON.stringify(meta.fusedAt)}`);
1918
+ lines.push("---");
1919
+ lines.push("");
1920
+ return `${lines.join("\n")}
1921
+ ${JSON.stringify(conversations, null, 2)}
1922
+ `;
1923
+ }
1924
+ function parseScalar(value) {
1925
+ const trimmed = value.trim();
1926
+ if (trimmed.startsWith('"') && trimmed.endsWith('"') && trimmed.length >= 2) {
1927
+ try {
1928
+ const parsed = JSON.parse(trimmed);
1929
+ if (typeof parsed === "string") return parsed;
1930
+ } catch {
1931
+ }
1932
+ }
1933
+ return trimmed;
1934
+ }
1935
+ function parseNonNegativeInt(value) {
1936
+ if (value === void 0) return 0;
1937
+ const parsed = Number(value);
1938
+ if (!Number.isFinite(parsed) || parsed < 0) return 0;
1939
+ return Math.floor(parsed);
1940
+ }
1941
+ var FUSED_SEGMENT_PICK_REASONS = {
1942
+ "only-source": true,
1943
+ "higher-trust": true,
1944
+ "more-complete": true,
1945
+ "tie-break": true
1946
+ };
1947
+ var FUSED_DISAGREEMENT_KINDS = {
1948
+ "asr-text": true,
1949
+ speaker: true,
1950
+ timestamp: true
1951
+ };
1952
+ function isPlainObject(value) {
1953
+ return typeof value === "object" && value !== null && !Array.isArray(value);
1954
+ }
1955
+ function isStringArray(value) {
1956
+ return Array.isArray(value) && value.every((item) => typeof item === "string");
1957
+ }
1958
+ function isFusedSegmentProvenance(value) {
1959
+ if (!isPlainObject(value)) return false;
1960
+ if (typeof value.source !== "string") return false;
1961
+ if (typeof value.conversationId !== "string") return false;
1962
+ if (typeof value.sourceTrust !== "number") return false;
1963
+ if (typeof value.reason !== "string") return false;
1964
+ if (!(value.reason in FUSED_SEGMENT_PICK_REASONS)) return false;
1965
+ return Array.isArray(value.alternatives) && value.alternatives.every(
1966
+ (alt) => isPlainObject(alt) && typeof alt.source === "string" && typeof alt.text === "string"
1967
+ );
1968
+ }
1969
+ function isFusedSegment(value) {
1970
+ if (!isPlainObject(value)) return false;
1971
+ if (typeof value.speaker !== "string") return false;
1972
+ if (typeof value.isSelf !== "boolean") return false;
1973
+ if (typeof value.text !== "string") return false;
1974
+ if (typeof value.confidence !== "number") return false;
1975
+ return isFusedSegmentProvenance(value.provenance);
1976
+ }
1977
+ function isFusedSpeaker(value) {
1978
+ if (!isPlainObject(value)) return false;
1979
+ if (typeof value.label !== "string") return false;
1980
+ if (typeof value.isSelf !== "boolean") return false;
1981
+ if (typeof value.confidence !== "number") return false;
1982
+ return isStringArray(value.sources);
1983
+ }
1984
+ function isFusedDisagreement(value) {
1985
+ if (!isPlainObject(value)) return false;
1986
+ if (typeof value.kind !== "string") return false;
1987
+ if (!(value.kind in FUSED_DISAGREEMENT_KINDS)) return false;
1988
+ if (typeof value.subject !== "string") return false;
1989
+ return Array.isArray(value.candidates) && value.candidates.every(
1990
+ (cand) => isPlainObject(cand) && typeof cand.source === "string" && typeof cand.value === "string"
1991
+ );
1992
+ }
1993
+ function isFusedContribution(value) {
1994
+ if (!isPlainObject(value)) return false;
1995
+ if (typeof value.source !== "string") return false;
1996
+ if (typeof value.conversationId !== "string") return false;
1997
+ if (typeof value.startIso !== "string") return false;
1998
+ return typeof value.segmentCount === "number";
1999
+ }
2000
+ function isFusedConversationProvenance(value) {
2001
+ if (!isPlainObject(value)) return false;
2002
+ if (!Array.isArray(value.contributions) || !value.contributions.every(isFusedContribution)) {
2003
+ return false;
2004
+ }
2005
+ if (typeof value.proximityGapMs !== "number") return false;
2006
+ if (typeof value.windowToleranceMs !== "number") return false;
2007
+ return value.method === "time-proximity";
2008
+ }
2009
+ function isFusedWearableConversation(value) {
2010
+ if (!isPlainObject(value)) return false;
2011
+ if (typeof value.id !== "string") return false;
2012
+ if (typeof value.date !== "string") return false;
2013
+ if (typeof value.startIso !== "string") return false;
2014
+ if (!isStringArray(value.sources)) return false;
2015
+ if (!Array.isArray(value.speakers) || !value.speakers.every(isFusedSpeaker)) return false;
2016
+ if (!Array.isArray(value.segments) || !value.segments.every(isFusedSegment)) return false;
2017
+ if (!Array.isArray(value.disagreements) || !value.disagreements.every(isFusedDisagreement)) {
2018
+ return false;
2019
+ }
2020
+ return isFusedConversationProvenance(value.provenance);
2021
+ }
2022
+ function parseFusionDay(raw) {
2023
+ if (!raw.startsWith("---\n")) return null;
2024
+ const closeIndex = raw.indexOf("\n---\n", 4);
2025
+ if (closeIndex === -1) return null;
2026
+ const header = raw.slice(4, closeIndex);
2027
+ const body = raw.slice(closeIndex + 5).replace(/^\n/, "");
2028
+ const scalars = /* @__PURE__ */ new Map();
2029
+ for (const line of header.split("\n")) {
2030
+ const match = line.match(/^([A-Za-z][A-Za-z0-9]*): (.*)$/);
2031
+ if (match) scalars.set(match[1], parseScalar(match[2]));
2032
+ }
2033
+ if (scalars.get("kind") !== FUSION_KIND) return null;
2034
+ const date = scalars.get("date");
2035
+ if (date === void 0) return null;
2036
+ let conversations = [];
2037
+ let parseOk = true;
2038
+ const bodyTrimmed = body.trim();
2039
+ if (bodyTrimmed.length === 0) {
2040
+ parseOk = false;
2041
+ } else {
2042
+ try {
2043
+ const parsed = JSON.parse(bodyTrimmed);
2044
+ if (Array.isArray(parsed) && parsed.every(isFusedWearableConversation)) {
2045
+ conversations = parsed;
2046
+ } else {
2047
+ parseOk = false;
2048
+ }
2049
+ } catch {
2050
+ parseOk = false;
2051
+ }
2052
+ }
2053
+ const meta = {
2054
+ kind: FUSION_KIND,
2055
+ date,
2056
+ sourceCount: parseNonNegativeInt(scalars.get("sourceCount")),
2057
+ conversationCount: parseNonNegativeInt(scalars.get("conversationCount")),
2058
+ contentHash: scalars.get("contentHash") ?? "",
2059
+ bodyHash: scalars.get("bodyHash") ?? "",
2060
+ fusedAt: scalars.get("fusedAt") ?? ""
2061
+ };
2062
+ return { meta, conversations, parseOk };
2063
+ }
2064
+ var FUSION_DIR_NAME = "_fusion";
2065
+ var FusionArtifactStore = class {
2066
+ constructor(wearablesDir, memoryDir, io) {
2067
+ this.wearablesDir = wearablesDir;
2068
+ this.memoryDir = memoryDir;
2069
+ this.io = io;
2070
+ }
2071
+ wearablesDir;
2072
+ memoryDir;
2073
+ io;
2074
+ fusedDayPath(date) {
2075
+ if (!isValidTranscriptDate(date)) {
2076
+ throw new Error(
2077
+ `invalid wearable fusion date '${String(date)}' \u2014 expected YYYY-MM-DD`
2078
+ );
2079
+ }
2080
+ return path4.join(this.wearablesDir, FUSION_DIR_NAME, `${date}.md`);
2081
+ }
2082
+ async writeFusedDay(date, serialized) {
2083
+ const filePath = this.fusedDayPath(date);
2084
+ await this.assertPathContained(filePath);
2085
+ await this.io.writeFile(filePath, serialized);
2086
+ }
2087
+ /** Read a stored fused-day artifact; null when absent. */
2088
+ async readFusedDay(date) {
2089
+ const filePath = this.fusedDayPath(date);
2090
+ await this.assertPathContained(filePath);
2091
+ try {
2092
+ return await this.io.readFile(filePath);
2093
+ } catch (err) {
2094
+ if (err.code === "ENOENT") return null;
2095
+ throw err;
2096
+ }
2097
+ }
2098
+ /**
2099
+ * Remove a stored fused-day artifact. Idempotent: a no-op when the
2100
+ * artifact is already absent. Used to clear a now-stale derived file
2101
+ * before a fusion run that deliberately refuses to fuse (e.g. a day
2102
+ * whose sources later conflict on timezone) so fusedConversations()
2103
+ * does not keep serving a stale view (issue #1849).
2104
+ */
2105
+ async deleteFusedDay(date) {
2106
+ const filePath = this.fusedDayPath(date);
2107
+ await this.assertPathContained(filePath);
2108
+ try {
2109
+ await this.io.deleteFile(filePath);
2110
+ } catch (err) {
2111
+ if (err.code === "ENOENT") return;
2112
+ throw err;
2113
+ }
2114
+ }
2115
+ /** List dates with stored fused artifacts, newest first. */
2116
+ async listFusedDays() {
2117
+ const fusionDir = path4.join(this.wearablesDir, FUSION_DIR_NAME);
2118
+ await this.assertPathContained(fusionDir);
2119
+ let entries;
2120
+ try {
2121
+ entries = await this.io.readDir(fusionDir);
2122
+ } catch (err) {
2123
+ if (err.code === "ENOENT") return [];
2124
+ throw err;
2125
+ }
2126
+ const days = [];
2127
+ for (const entry of entries) {
2128
+ if (!entry.endsWith(".md")) continue;
2129
+ const date = entry.slice(0, -3);
2130
+ if (!isValidTranscriptDate(date)) continue;
2131
+ days.push(date);
2132
+ }
2133
+ days.sort((a, b) => a > b ? -1 : a < b ? 1 : 0);
2134
+ return days;
2135
+ }
2136
+ /**
2137
+ * Reject a symlinked/traversing fusion artifact path before any IO. The
2138
+ * fusion dir (`<wearablesDir>/_fusion`) and its parents are followed
2139
+ * directly by the secure IO; a symlink placed there (attacker-writable
2140
+ * or a malformed memory dir) would otherwise be followed and
2141
+ * read/write/delete outside the allowed root (AGENTS.md pattern #3).
2142
+ *
2143
+ * Containment is anchored to the real MEMORY-DIR root, not the
2144
+ * wearables dir, AND the wearables root is checked explicitly: if
2145
+ * `wearablesDir` itself is a symlink that resolves outside memoryDir, a
2146
+ * leaf candidate like `<wearablesDir>/_fusion/<date>.md` may not yet
2147
+ * exist (so its realpath ENOENT-skips) and the write would silently
2148
+ * create the file inside the symlinked escape target. Checking
2149
+ * `wearablesDir` itself — which resolves through the symlink when it
2150
+ * exists — closes that gap, while the per-leaf checks catch a nested
2151
+ * `_fusion` or per-file symlink. Absent paths are allowed (a fresh
2152
+ * write creates them lexically under the root; only a path that
2153
+ * resolves to an existing target can redirect IO). Mirrors
2154
+ * `assertPathInsideRoot` in the storage walkers.
2155
+ */
2156
+ async assertPathContained(targetPath) {
2157
+ let rootReal;
2158
+ try {
2159
+ rootReal = await this.io.realpath(this.memoryDir);
2160
+ } catch {
2161
+ rootReal = path4.resolve(this.memoryDir);
2162
+ }
2163
+ await this.assertNoEscape(rootReal, this.wearablesDir);
2164
+ await this.assertNoEscape(rootReal, path4.dirname(targetPath));
2165
+ await this.assertNoEscape(rootReal, targetPath);
2166
+ await this.assertFusionDirNotSymlinked();
2167
+ }
2168
+ /**
2169
+ * Refuse a pre-existing symbolic link at the `<wearablesDir>/_fusion`
2170
+ * directory. Unlike `assertNoEscape` (which follows the link and only
2171
+ * rejects when the target lands outside the memory dir), this catches a
2172
+ * fusion root that aliases an in-bounds path — e.g. a `_fusion` link
2173
+ * pointed at a raw source transcript — so fusion IO never writes
2174
+ * through it and overwrites the aliased file. Absent dirs are allowed
2175
+ * (a fresh write creates a real directory lexically under the root).
2176
+ */
2177
+ async assertFusionDirNotSymlinked() {
2178
+ const fusionDir = path4.join(this.wearablesDir, FUSION_DIR_NAME);
2179
+ let stat3;
2180
+ try {
2181
+ stat3 = await this.io.lstat(fusionDir);
2182
+ } catch (err) {
2183
+ if (err.code === "ENOENT") return;
2184
+ throw err;
2185
+ }
2186
+ if (stat3.isSymbolicLink) {
2187
+ throw new Error(
2188
+ "wearable fusion dir '_fusion' is a symbolic link \u2014 refusing to follow it even when it resolves inside the memory dir (AGENTS.md pattern #3)"
2189
+ );
2190
+ }
2191
+ }
2192
+ /**
2193
+ * Refuse a candidate whose realpath escapes the memory root. Absent
2194
+ * candidates are allowed: a missing path cannot yet redirect IO, and
2195
+ * the secure write creates it lexically under the root.
2196
+ */
2197
+ async assertNoEscape(rootReal, candidate) {
2198
+ let candidateReal;
2199
+ try {
2200
+ candidateReal = await this.io.realpath(candidate);
2201
+ } catch {
2202
+ return;
2203
+ }
2204
+ if (!pathIsInside(rootReal, candidateReal)) {
2205
+ throw new Error(
2206
+ "wearable fusion artifact path resolves outside the memory dir \u2014 refusing to follow a symlink/traversal (AGENTS.md pattern #3)"
2207
+ );
2208
+ }
2209
+ }
2210
+ };
2211
+
2212
+ // src/wearables/fusion/reconstruct.ts
2213
+ var CONVERSATION_HEADING = /^## (.+?)\u2013(.+?)(?:\s\u00b7\s(.*))?\s\(conversation (.+)\)$/;
2214
+ var LOCATION_LINE = /^\*Location: (.+)\*$/;
2215
+ var CLOCK_PATTERN = /^(\d{2}):(\d{2})$/;
2216
+ var MINUTES_PER_DAY = 24 * 60;
2217
+ var MAX_PLAUSIBLE_WRAP_MINUTES = 12 * 60;
2218
+ function clockToIso(clock, date) {
2219
+ const match = CLOCK_PATTERN.exec(clock.trim());
2220
+ if (match === null) return void 0;
2221
+ const hour = match[1] === "24" ? "00" : match[1];
2222
+ return `${date}T${hour}:${match[2]}:00.000Z`;
2223
+ }
2224
+ function clockMinutesOfDay(clock) {
2225
+ const match = CLOCK_PATTERN.exec(clock.trim());
2226
+ if (match === null) return void 0;
2227
+ const hour = match[1] === "24" ? 0 : Number.parseInt(match[1], 10);
2228
+ return hour * 60 + Number.parseInt(match[2], 10);
2229
+ }
2230
+ function nextCalendarDay(date) {
2231
+ const [y, m, d] = date.split("-").map((part) => Number.parseInt(part, 10));
2232
+ const dt = new Date(Date.UTC(y, m - 1, d));
2233
+ dt.setUTCDate(dt.getUTCDate() + 1);
2234
+ const yy = dt.getUTCFullYear();
2235
+ const mm = String(dt.getUTCMonth() + 1).padStart(2, "0");
2236
+ const dd = String(dt.getUTCDate()).padStart(2, "0");
2237
+ return `${yy}-${mm}-${dd}`;
2238
+ }
2239
+ function reconstructFusionInputs(date, dayTranscripts) {
2240
+ if (!isValidTranscriptDate(date)) return [];
2241
+ const inputs = [];
2242
+ for (const { source, body, escaped } of dayTranscripts) {
2243
+ let current = null;
2244
+ const flushCurrent = () => {
2245
+ if (current === null) return;
2246
+ const startIso = current.startIso ?? current.segments.find((segment) => segment.startIso !== void 0)?.startIso ?? `${date}T00:00:00.000Z`;
2247
+ const input = {
2248
+ source,
2249
+ conversationId: current.conversationId,
2250
+ startIso,
2251
+ segments: current.segments
2252
+ };
2253
+ if (current.endIso !== void 0) input.endIso = current.endIso;
2254
+ if (current.title !== void 0) input.title = current.title;
2255
+ inputs.push(input);
2256
+ current = null;
2257
+ };
2258
+ for (const rawLine of body.split("\n")) {
2259
+ const line = rawLine.trimEnd();
2260
+ if (line.length === 0) continue;
2261
+ const heading = CONVERSATION_HEADING.exec(line);
2262
+ if (heading !== null) {
2263
+ flushCurrent();
2264
+ const [, startClock, endClock, title, id] = heading;
2265
+ const startMin = clockMinutesOfDay(startClock);
2266
+ const endMin = clockMinutesOfDay(endClock);
2267
+ const wrapped = startMin !== void 0 && endMin !== void 0 && endMin < startMin;
2268
+ const wrapDuration = startMin !== void 0 && endMin !== void 0 ? MINUTES_PER_DAY - startMin + endMin : void 0;
2269
+ const plausibleWrap = wrapped && wrapDuration !== void 0 && wrapDuration <= MAX_PLAUSIBLE_WRAP_MINUTES;
2270
+ const startIso = clockToIso(startClock, date);
2271
+ const endIso = plausibleWrap ? clockToIso(endClock, nextCalendarDay(date)) : clockToIso(endClock, date);
2272
+ current = {
2273
+ conversationId: id,
2274
+ segments: [],
2275
+ wrapped,
2276
+ ...startMin !== void 0 ? { wrapStartMin: startMin } : {},
2277
+ ...startIso !== void 0 ? { startIso } : {},
2278
+ ...endIso !== void 0 ? { endIso } : {},
2279
+ ...title !== void 0 && title.length > 0 ? { title } : {}
2280
+ };
2281
+ continue;
2282
+ }
2283
+ if (LOCATION_LINE.exec(line) !== null) continue;
2284
+ const segmentMatch = parseTranscriptSegmentLine(line);
2285
+ if (segmentMatch !== null) {
2286
+ if (current === null) continue;
2287
+ const { label, clock, text: rawText } = segmentMatch;
2288
+ const text = escaped ? unescapeSegmentText(rawText) : rawText;
2289
+ const segMin = clockMinutesOfDay(clock);
2290
+ const segWrapDuration = current.wrapStartMin !== void 0 && segMin !== void 0 ? MINUTES_PER_DAY - current.wrapStartMin + segMin : void 0;
2291
+ const plausibleSegWrap = current.wrapStartMin !== void 0 && segMin !== void 0 && segMin < current.wrapStartMin && segWrapDuration !== void 0 && segWrapDuration <= MAX_PLAUSIBLE_WRAP_MINUTES;
2292
+ const segDate = plausibleSegWrap ? nextCalendarDay(date) : date;
2293
+ const startIso = clockToIso(clock, segDate);
2294
+ const speaker = escaped ? unescapeSpeakerLabel(label.trim()) : label.trim();
2295
+ const segment = {
2296
+ speaker,
2297
+ // Self status is read from the RESERVED `(you)` marker, which the
2298
+ // renderer guarantees can only appear on the wearer's label -
2299
+ // never on a non-self display name (issue #1849).
2300
+ isSelf: hasSelfMarker(speaker),
2301
+ text,
2302
+ ...startIso !== void 0 ? { startIso } : {}
2303
+ };
2304
+ current.segments.push(segment);
2305
+ }
2306
+ }
2307
+ flushCurrent();
2308
+ }
2309
+ return inputs;
2310
+ }
2311
+
1262
2312
  // src/storage.ts
1263
2313
  var ARTIFACT_SEARCH_STOPWORDS = /* @__PURE__ */ new Set([
1264
2314
  "a",
@@ -1865,17 +2915,17 @@ var KNOWN_ENTITY_FILENAME_PREFIXES = /* @__PURE__ */ new Set([
1865
2915
  "topic"
1866
2916
  ]);
1867
2917
  function inferEntityTypeFromFilename(pathRel) {
1868
- const basename = path4.basename(pathRel, ".md").toLowerCase();
2918
+ const basename = path5.basename(pathRel, ".md").toLowerCase();
1869
2919
  const separator = basename.indexOf("-");
1870
2920
  if (separator <= 0) return void 0;
1871
2921
  const candidate = basename.slice(0, separator);
1872
2922
  return KNOWN_ENTITY_FILENAME_PREFIXES.has(candidate) ? candidate : void 0;
1873
2923
  }
1874
2924
  function normalizeFrontmatterForPath(frontmatter, pathRel, content = "") {
1875
- const normalizedPath = pathRel.split(path4.sep).join("/");
2925
+ const normalizedPath = pathRel.split(path5.sep).join("/");
1876
2926
  let normalizedFrontmatter = frontmatter;
1877
2927
  if (normalizedPath === "entities" || normalizedPath.startsWith("entities/") || normalizedPath.includes("/entities/")) {
1878
- const basename = path4.basename(pathRel, ".md");
2928
+ const basename = path5.basename(pathRel, ".md");
1879
2929
  const inferredType = inferEntityTypeFromContent(content) || inferEntityTypeFromFilename(pathRel) || "entity";
1880
2930
  const existingTags = Array.isArray(frontmatter.tags) ? frontmatter.tags : [];
1881
2931
  normalizedFrontmatter = {
@@ -1942,8 +2992,8 @@ var ContentHashIndex = class _ContentHashIndex {
1942
2992
  secureStoreKeyProvider;
1943
2993
  secureStoreWriteKeyProvider;
1944
2994
  memoryDir;
1945
- constructor(stateDir, secureStoreKeyProvider = () => null, secureStoreWriteKeyProvider = secureStoreKeyProvider, memoryDir = path4.dirname(stateDir)) {
1946
- this.filePath = path4.join(stateDir, "fact-hashes.txt");
2995
+ constructor(stateDir, secureStoreKeyProvider = () => null, secureStoreWriteKeyProvider = secureStoreKeyProvider, memoryDir = path5.dirname(stateDir)) {
2996
+ this.filePath = path5.join(stateDir, "fact-hashes.txt");
1947
2997
  this.secureStoreKeyProvider = secureStoreKeyProvider;
1948
2998
  this.secureStoreWriteKeyProvider = secureStoreWriteKeyProvider;
1949
2999
  this.memoryDir = memoryDir;
@@ -1990,7 +3040,7 @@ var ContentHashIndex = class _ContentHashIndex {
1990
3040
  /** Persist index to disk if changed. */
1991
3041
  async save() {
1992
3042
  if (!this.dirty) return;
1993
- await mkdir(path4.dirname(this.filePath), { recursive: true });
3043
+ await mkdir(path5.dirname(this.filePath), { recursive: true });
1994
3044
  await writeMaybeEncryptedFile(
1995
3045
  this.filePath,
1996
3046
  [...this.hashes].join("\n") + "\n",
@@ -2532,7 +3582,7 @@ function fingerprintEntityStructuredFacts(entity) {
2532
3582
  facts: normalizeStructuredSectionFacts(section.facts).slice().sort((left, right) => left.localeCompare(right))
2533
3583
  })).filter((section) => section.facts.length > 0).sort((left, right) => left.key.localeCompare(right.key) || left.title.localeCompare(right.title) || left.facts.join("\n").localeCompare(right.facts.join("\n")));
2534
3584
  if (normalizedSections.length === 0) return void 0;
2535
- return createHash("sha256").update(JSON.stringify(normalizedSections)).digest("hex");
3585
+ return createHash3("sha256").update(JSON.stringify(normalizedSections)).digest("hex");
2536
3586
  }
2537
3587
  function isEntitySynthesisStale(entity) {
2538
3588
  const structuredFactCount = countEntityStructuredFacts(entity);
@@ -3056,7 +4106,7 @@ var StorageManager3 = class _StorageManager {
3056
4106
  void 0,
3057
4107
  this.baseDir
3058
4108
  );
3059
- const rel = path4.relative(this.baseDir, filePath).split(path4.sep).join("/");
4109
+ const rel = path5.relative(this.baseDir, filePath).split(path5.sep).join("/");
3060
4110
  return `${rel}:${version.versionId}`;
3061
4111
  } catch (err) {
3062
4112
  log.warn(
@@ -3113,13 +4163,13 @@ var StorageManager3 = class _StorageManager {
3113
4163
  }
3114
4164
  identityFilePath(workspaceDir, namespace) {
3115
4165
  const rawNamespace = typeof namespace === "string" ? namespace.trim() : "";
3116
- if (!rawNamespace) return path4.join(workspaceDir, "IDENTITY.md");
4166
+ if (!rawNamespace) return path5.join(workspaceDir, "IDENTITY.md");
3117
4167
  const safeNamespace = rawNamespace.replace(/[^a-zA-Z0-9._-]/g, "-");
3118
- return path4.join(workspaceDir, `IDENTITY.${safeNamespace}.md`);
4168
+ return path5.join(workspaceDir, `IDENTITY.${safeNamespace}.md`);
3119
4169
  }
3120
4170
  versionFilePath(kind) {
3121
4171
  const fileName = kind === "memory-status" ? ".memory-status-version.log" : kind === "artifact-write" ? ".artifact-write-version.log" : ".cold-write-version.log";
3122
- return path4.join(this.stateDir, fileName);
4172
+ return path5.join(this.stateDir, fileName);
3123
4173
  }
3124
4174
  bumpSharedVersion(kind, fallbackMap) {
3125
4175
  const filePath = this.versionFilePath(kind);
@@ -3166,7 +4216,7 @@ var StorageManager3 = class _StorageManager {
3166
4216
  // memories.
3167
4217
  // -------------------------------------------------------------------------
3168
4218
  get wearablesDir() {
3169
- return path4.join(this.baseDir, WEARABLES_DIR_NAME);
4219
+ return path5.join(this.baseDir, WEARABLES_DIR_NAME);
3170
4220
  }
3171
4221
  /**
3172
4222
  * Resolve the on-disk path for a source/day transcript. Throws on
@@ -3184,7 +4234,7 @@ var StorageManager3 = class _StorageManager {
3184
4234
  `invalid wearable transcript date '${String(date)}' \u2014 expected YYYY-MM-DD`
3185
4235
  );
3186
4236
  }
3187
- return path4.join(this.wearablesDir, sourceId, `${date}.md`);
4237
+ return path5.join(this.wearablesDir, sourceId, `${date}.md`);
3188
4238
  }
3189
4239
  async writeWearableDayTranscript(sourceId, date, serialized) {
3190
4240
  const targetPath = this.wearableTranscriptPath(sourceId, date);
@@ -3205,6 +4255,19 @@ var StorageManager3 = class _StorageManager {
3205
4255
  sourceId
3206
4256
  );
3207
4257
  }
4258
+ _fusionStore;
4259
+ /** Derived fusion-day IO; file IO lives in wearables/fusion (#1810). */
4260
+ fusionArtifactStore() {
4261
+ if (this._fusionStore) return this._fusionStore;
4262
+ return this._fusionStore = new FusionArtifactStore(this.wearablesDir, this.baseDir, {
4263
+ writeFile: (p, c) => this.writeStorageSecureFile(p, c),
4264
+ readFile: (p) => readMaybeEncryptedFile(p, this._secureStoreKey, this.baseDir),
4265
+ readDir: (d) => readdir4(d),
4266
+ deleteFile: (p) => unlink2(p),
4267
+ realpath: (p) => realpath2(p),
4268
+ lstat: (p) => lstat2(p).then((st) => ({ isSymbolicLink: st.isSymbolicLink() }))
4269
+ });
4270
+ }
3208
4271
  /**
3209
4272
  * Locate a wearable-sourced memory by exact (trimmed) content,
3210
4273
  * ignoring the "[Attributes: ...]" suffix writeMemory appends for
@@ -3271,25 +4334,25 @@ var StorageManager3 = class _StorageManager {
3271
4334
  });
3272
4335
  }
3273
4336
  get factsDir() {
3274
- return path4.join(this.baseDir, "facts");
4337
+ return path5.join(this.baseDir, "facts");
3275
4338
  }
3276
4339
  get correctionsDir() {
3277
- return path4.join(this.baseDir, "corrections");
4340
+ return path5.join(this.baseDir, "corrections");
3278
4341
  }
3279
4342
  get proceduresDir() {
3280
- return path4.join(this.baseDir, "procedures");
4343
+ return path5.join(this.baseDir, "procedures");
3281
4344
  }
3282
4345
  get reasoningTracesDir() {
3283
- return path4.join(this.baseDir, "reasoning-traces");
4346
+ return path5.join(this.baseDir, "reasoning-traces");
3284
4347
  }
3285
4348
  get entitiesDir() {
3286
- return path4.join(this.baseDir, "entities");
4349
+ return path5.join(this.baseDir, "entities");
3287
4350
  }
3288
4351
  resolveEntityFilePath(name) {
3289
4352
  if (typeof name !== "string") return null;
3290
- const filePath = path4.resolve(this.entitiesDir, `${name}.md`);
3291
- const relative = path4.relative(this.entitiesDir, filePath);
3292
- if (relative === "" || relative.startsWith("..") || path4.isAbsolute(relative)) {
4353
+ const filePath = path5.resolve(this.entitiesDir, `${name}.md`);
4354
+ const relative = path5.relative(this.entitiesDir, filePath);
4355
+ if (relative === "" || relative.startsWith("..") || path5.isAbsolute(relative)) {
3293
4356
  return null;
3294
4357
  }
3295
4358
  return filePath;
@@ -3304,10 +4367,10 @@ var StorageManager3 = class _StorageManager {
3304
4367
  return writeMaybeEncryptedFileFromChunks(filePath, chunks, this.resolveWriteKey(), {}, this.baseDir).then(() => this.notifyCatalogWrite());
3305
4368
  }
3306
4369
  assertManagedStoragePath(filePath, method) {
3307
- const resolved = path4.resolve(filePath);
3308
- const base = path4.resolve(this.baseDir);
3309
- const rel = path4.relative(base, resolved);
3310
- if (rel === "" || rel === ".." || rel.startsWith(`..${path4.sep}`) || path4.isAbsolute(rel)) {
4370
+ const resolved = path5.resolve(filePath);
4371
+ const base = path5.resolve(this.baseDir);
4372
+ const rel = path5.relative(base, resolved);
4373
+ if (rel === "" || rel === ".." || rel.startsWith(`..${path5.sep}`) || path5.isAbsolute(rel)) {
3311
4374
  throw new Error(`${method}: file path escapes memory dir`);
3312
4375
  }
3313
4376
  return resolved;
@@ -3319,7 +4382,7 @@ var StorageManager3 = class _StorageManager {
3319
4382
  async digestOfflineSyncFile(filePath) {
3320
4383
  const target = this.assertManagedStoragePath(filePath, "storage.digestOfflineSyncFile");
3321
4384
  const st = await stat2(target);
3322
- const relPath = path4.relative(this.baseDir, target).split(path4.sep).join("/");
4385
+ const relPath = path5.relative(this.baseDir, target).split(path5.sep).join("/");
3323
4386
  const cache = await this.loadOfflineSyncDigestCache();
3324
4387
  const cached = cache.get(relPath);
3325
4388
  if (cached && cached.statBytes === st.size && cached.mtimeMs === st.mtimeMs && cached.ctimeMs === st.ctimeMs && !cached.encrypted) {
@@ -3333,11 +4396,11 @@ var StorageManager3 = class _StorageManager {
3333
4396
  if (encrypted) {
3334
4397
  const content = await readMaybeEncryptedFileBuffer(target, this._secureStoreKey, this.baseDir);
3335
4398
  digest = {
3336
- sha256: createHash("sha256").update(content).digest("hex"),
4399
+ sha256: createHash3("sha256").update(content).digest("hex"),
3337
4400
  bytes: content.byteLength
3338
4401
  };
3339
4402
  } else {
3340
- const hash = createHash("sha256");
4403
+ const hash = createHash3("sha256");
3341
4404
  let bytes = 0;
3342
4405
  for await (const rawChunk of createReadStream2(target)) {
3343
4406
  const chunk = Buffer.isBuffer(rawChunk) ? rawChunk : Buffer.from(rawChunk);
@@ -3380,7 +4443,7 @@ var StorageManager3 = class _StorageManager {
3380
4443
  const bytes = typeof record.bytes === "number" ? record.bytes : NaN;
3381
4444
  const sha256 = typeof record.sha256 === "string" ? record.sha256 : "";
3382
4445
  const encrypted = record.encrypted === true;
3383
- if (cachePath.length === 0 || cachePath === ".." || cachePath.startsWith("../") || path4.isAbsolute(cachePath) || !Number.isFinite(statBytes) || !Number.isFinite(mtimeMs) || !Number.isFinite(ctimeMs) || !Number.isFinite(bytes) || !/^[a-f0-9]{64}$/i.test(sha256)) {
4446
+ if (cachePath.length === 0 || cachePath === ".." || cachePath.startsWith("../") || path5.isAbsolute(cachePath) || !Number.isFinite(statBytes) || !Number.isFinite(mtimeMs) || !Number.isFinite(ctimeMs) || !Number.isFinite(bytes) || !/^[a-f0-9]{64}$/i.test(sha256)) {
3384
4447
  continue;
3385
4448
  }
3386
4449
  cache.set(cachePath, { statBytes, mtimeMs, ctimeMs, encrypted, sha256, bytes });
@@ -3422,7 +4485,7 @@ var StorageManager3 = class _StorageManager {
3422
4485
  const cache = this.offlineSyncDigestCache;
3423
4486
  if (!cache) return;
3424
4487
  const entries = [...cache.entries()].sort(([a], [b]) => a.localeCompare(b)).map(([entryPath, entry]) => ({ path: entryPath, ...entry }));
3425
- await mkdir(path4.dirname(this.offlineSyncDigestCachePath), { recursive: true });
4488
+ await mkdir(path5.dirname(this.offlineSyncDigestCachePath), { recursive: true });
3426
4489
  await writeFile(
3427
4490
  this.offlineSyncDigestCachePath,
3428
4491
  `${JSON.stringify({ version: 1, entries })}
@@ -3475,10 +4538,10 @@ var StorageManager3 = class _StorageManager {
3475
4538
  if (isErrnoCode(error, "ENOENT")) return;
3476
4539
  throw error;
3477
4540
  });
3478
- if (filePath.includes(`${path4.sep}cold${path4.sep}`)) {
4541
+ if (filePath.includes(`${path5.sep}cold${path5.sep}`)) {
3479
4542
  this.invalidateColdMemoriesCache();
3480
4543
  }
3481
- if (filePath.includes(`${path4.sep}artifacts${path4.sep}`)) {
4544
+ if (filePath.includes(`${path5.sep}artifacts${path5.sep}`)) {
3482
4545
  this.bumpArtifactWriteVersion();
3483
4546
  }
3484
4547
  this.bumpMemoryStatusVersion();
@@ -3506,7 +4569,7 @@ var StorageManager3 = class _StorageManager {
3506
4569
  }
3507
4570
  async appendStorageSecureFileUnlocked(filePath, content) {
3508
4571
  const writeKey = this.resolveWriteKey();
3509
- await mkdir(path4.dirname(filePath), { recursive: true });
4572
+ await mkdir(path5.dirname(filePath), { recursive: true });
3510
4573
  if (writeKey === null) {
3511
4574
  try {
3512
4575
  if (isEncryptedFile(await readFile(filePath))) {
@@ -3532,16 +4595,16 @@ var StorageManager3 = class _StorageManager {
3532
4595
  this.notifyCatalogWrite();
3533
4596
  }
3534
4597
  get stateDir() {
3535
- return path4.join(this.baseDir, "state");
4598
+ return path5.join(this.baseDir, "state");
3536
4599
  }
3537
4600
  get offlineSyncDigestCachePath() {
3538
- return path4.join(this.baseDir, ".offline-sync", "digest-cache.v1.json");
4601
+ return path5.join(this.baseDir, ".offline-sync", "digest-cache.v1.json");
3539
4602
  }
3540
4603
  get entitySynthesisQueuePath() {
3541
- return path4.join(this.stateDir, "entity-synthesis-queue.json");
4604
+ return path5.join(this.stateDir, "entity-synthesis-queue.json");
3542
4605
  }
3543
4606
  get factHashIndexReadyPath() {
3544
- return path4.join(this.stateDir, "fact-hashes.ready");
4607
+ return path5.join(this.stateDir, "fact-hashes.ready");
3545
4608
  }
3546
4609
  // ── Tombstone store access (issue #1579) ─────────────────────────────────
3547
4610
  /**
@@ -3551,7 +4614,7 @@ var StorageManager3 = class _StorageManager {
3551
4614
  * helpers are injected into the store).
3552
4615
  */
3553
4616
  get tombstonesPath() {
3554
- return path4.join(this.stateDir, "tombstones.jsonl");
4617
+ return path5.join(this.stateDir, "tombstones.jsonl");
3555
4618
  }
3556
4619
  /**
3557
4620
  * Configure the tombstone invariant for this storage instance. Installed
@@ -3750,7 +4813,7 @@ var StorageManager3 = class _StorageManager {
3750
4813
  );
3751
4814
  }
3752
4815
  await factHashIndex.save();
3753
- await mkdir(path4.dirname(this.factHashIndexReadyPath), { recursive: true });
4816
+ await mkdir(path5.dirname(this.factHashIndexReadyPath), { recursive: true });
3754
4817
  await writeFile(this.factHashIndexReadyPath, "v1\n", "utf-8");
3755
4818
  this.factHashIndexAuthoritative = true;
3756
4819
  })().finally(() => {
@@ -3759,55 +4822,55 @@ var StorageManager3 = class _StorageManager {
3759
4822
  await this.factHashIndexAuthoritativePromise;
3760
4823
  }
3761
4824
  get questionsDir() {
3762
- return path4.join(this.baseDir, "questions");
4825
+ return path5.join(this.baseDir, "questions");
3763
4826
  }
3764
4827
  get artifactsDir() {
3765
- return path4.join(this.baseDir, "artifacts");
4828
+ return path5.join(this.baseDir, "artifacts");
3766
4829
  }
3767
4830
  get identityDir() {
3768
- return path4.join(this.baseDir, "identity");
4831
+ return path5.join(this.baseDir, "identity");
3769
4832
  }
3770
4833
  get identityAnchorPath() {
3771
- return path4.join(this.identityDir, "identity-anchor.md");
4834
+ return path5.join(this.identityDir, "identity-anchor.md");
3772
4835
  }
3773
4836
  get identityIncidentsDir() {
3774
- return path4.join(this.identityDir, "incidents");
4837
+ return path5.join(this.identityDir, "incidents");
3775
4838
  }
3776
4839
  get identityAuditsWeeklyDir() {
3777
- return path4.join(this.identityDir, "audits", "weekly");
4840
+ return path5.join(this.identityDir, "audits", "weekly");
3778
4841
  }
3779
4842
  get identityAuditsMonthlyDir() {
3780
- return path4.join(this.identityDir, "audits", "monthly");
4843
+ return path5.join(this.identityDir, "audits", "monthly");
3781
4844
  }
3782
4845
  get identityImprovementLoopsPath() {
3783
- return path4.join(this.identityDir, "improvement-loops.md");
4846
+ return path5.join(this.identityDir, "improvement-loops.md");
3784
4847
  }
3785
4848
  get identityReflectionsPath() {
3786
- return path4.join(this.identityDir, "reflections.md");
4849
+ return path5.join(this.identityDir, "reflections.md");
3787
4850
  }
3788
4851
  get profilePath() {
3789
- return path4.join(this.baseDir, "profile.md");
4852
+ return path5.join(this.baseDir, "profile.md");
3790
4853
  }
3791
4854
  get memoryActionsPath() {
3792
- return path4.join(this.stateDir, "memory-actions.jsonl");
4855
+ return path5.join(this.stateDir, "memory-actions.jsonl");
3793
4856
  }
3794
4857
  get memoryLifecycleLedgerPath() {
3795
- return path4.join(this.stateDir, "memory-lifecycle-ledger.jsonl");
4858
+ return path5.join(this.stateDir, "memory-lifecycle-ledger.jsonl");
3796
4859
  }
3797
4860
  get compressionGuidelinesPath() {
3798
- return path4.join(this.stateDir, "compression-guidelines.md");
4861
+ return path5.join(this.stateDir, "compression-guidelines.md");
3799
4862
  }
3800
4863
  get compressionGuidelineDraftPath() {
3801
- return path4.join(this.stateDir, "compression-guidelines.draft.md");
4864
+ return path5.join(this.stateDir, "compression-guidelines.draft.md");
3802
4865
  }
3803
4866
  get compressionGuidelineStatePath() {
3804
- return path4.join(this.stateDir, "compression-guideline-state.json");
4867
+ return path5.join(this.stateDir, "compression-guideline-state.json");
3805
4868
  }
3806
4869
  get compressionGuidelineDraftStatePath() {
3807
- return path4.join(this.stateDir, "compression-guideline-draft-state.json");
4870
+ return path5.join(this.stateDir, "compression-guideline-draft-state.json");
3808
4871
  }
3809
4872
  get behaviorSignalsPath() {
3810
- return path4.join(this.stateDir, "behavior-signals.jsonl");
4873
+ return path5.join(this.stateDir, "behavior-signals.jsonl");
3811
4874
  }
3812
4875
  /**
3813
4876
  * Buffer surprise telemetry ledger (issue #563 PR 3).
@@ -3820,7 +4883,7 @@ var StorageManager3 = class _StorageManager {
3820
4883
  * governance sweeps can treat it uniformly.
3821
4884
  */
3822
4885
  get bufferSurpriseLedgerPath() {
3823
- return path4.join(this.stateDir, "buffer-surprise-ledger.jsonl");
4886
+ return path5.join(this.stateDir, "buffer-surprise-ledger.jsonl");
3824
4887
  }
3825
4888
  /**
3826
4889
  * Entity alias table loaded from THIS store's config/aliases.json.
@@ -3854,7 +4917,7 @@ var StorageManager3 = class _StorageManager {
3854
4917
  this.loadAliasesSync();
3855
4918
  }
3856
4919
  loadAliasesSync() {
3857
- const aliasPath = path4.join(this.baseDir, "config", "aliases.json");
4920
+ const aliasPath = path5.join(this.baseDir, "config", "aliases.json");
3858
4921
  this.userAliases = {};
3859
4922
  try {
3860
4923
  const raw = readFileSync(aliasPath, "utf-8");
@@ -3879,9 +4942,9 @@ var StorageManager3 = class _StorageManager {
3879
4942
  }
3880
4943
  async ensureDirectories() {
3881
4944
  const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
3882
- await mkdir(path4.join(this.factsDir, today), { recursive: true });
3883
- await mkdir(path4.join(this.proceduresDir, today), { recursive: true });
3884
- await mkdir(path4.join(this.reasoningTracesDir, today), { recursive: true });
4945
+ await mkdir(path5.join(this.factsDir, today), { recursive: true });
4946
+ await mkdir(path5.join(this.proceduresDir, today), { recursive: true });
4947
+ await mkdir(path5.join(this.reasoningTracesDir, today), { recursive: true });
3885
4948
  await mkdir(this.correctionsDir, { recursive: true });
3886
4949
  await mkdir(this.entitiesDir, { recursive: true });
3887
4950
  await mkdir(this.stateDir, { recursive: true });
@@ -3891,7 +4954,7 @@ var StorageManager3 = class _StorageManager {
3891
4954
  await mkdir(this.identityIncidentsDir, { recursive: true });
3892
4955
  await mkdir(this.identityAuditsWeeklyDir, { recursive: true });
3893
4956
  await mkdir(this.identityAuditsMonthlyDir, { recursive: true });
3894
- await mkdir(path4.join(this.baseDir, "config"), { recursive: true });
4957
+ await mkdir(path5.join(this.baseDir, "config"), { recursive: true });
3895
4958
  }
3896
4959
  /**
3897
4960
  * Resolve the on-disk write path for a memory of the given category, creating
@@ -3908,11 +4971,11 @@ var StorageManager3 = class _StorageManager {
3908
4971
  async resolveCategoryWritePath(category, id, today) {
3909
4972
  if (category === "correction") {
3910
4973
  await mkdir(this.correctionsDir, { recursive: true });
3911
- return path4.join(this.correctionsDir, `${id}.md`);
4974
+ return path5.join(this.correctionsDir, `${id}.md`);
3912
4975
  }
3913
- const datedDir = path4.join(getCategoryDir(this.baseDir, category), today);
4976
+ const datedDir = path5.join(getCategoryDir(this.baseDir, category), today);
3914
4977
  await mkdir(datedDir, { recursive: true });
3915
- return path4.join(datedDir, `${id}.md`);
4978
+ return path5.join(datedDir, `${id}.md`);
3916
4979
  }
3917
4980
  async writeMemory(category, content, options = {}) {
3918
4981
  await this.ensureDirectories();
@@ -4162,7 +5225,7 @@ ${sanitized.text}
4162
5225
  await this.ensureDirectories();
4163
5226
  const now = /* @__PURE__ */ new Date();
4164
5227
  const day = now.toISOString().slice(0, 10);
4165
- const dir = path4.join(this.artifactsDir, day);
5228
+ const dir = path5.join(this.artifactsDir, day);
4166
5229
  await mkdir(dir, { recursive: true });
4167
5230
  const id = `artifact-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`;
4168
5231
  const fm = {
@@ -4186,7 +5249,7 @@ ${sanitized.text}
4186
5249
  log.warn(`artifact content rejected for ${id}; violations=${sanitized.violations.join(", ")}`);
4187
5250
  return "";
4188
5251
  }
4189
- const filePath = path4.join(dir, `${id}.md`);
5252
+ const filePath = path5.join(dir, `${id}.md`);
4190
5253
  await this.writeStorageSecureFile(filePath, `${serializeFrontmatter(fm)}
4191
5254
 
4192
5255
  ${sanitized.text}
@@ -4388,7 +5451,7 @@ ${sanitized.text}
4388
5451
  * per-process in-memory cache safe across process boundaries.
4389
5452
  */
4390
5453
  invalidateColdMemoriesCache() {
4391
- const coldRoot = path4.join(this.baseDir, "cold");
5454
+ const coldRoot = path5.join(this.baseDir, "cold");
4392
5455
  _StorageManager.coldMemoriesCache.delete(coldRoot);
4393
5456
  this.bumpColdWriteVersion();
4394
5457
  invalidateAllForDir(this.baseDir);
@@ -4478,7 +5541,7 @@ ${sanitized.text}
4478
5541
  const correctionPaths = [];
4479
5542
  const factPaths = [];
4480
5543
  for (const filePath of filePaths) {
4481
- if (filePath === this.correctionsDir || filePath.startsWith(`${this.correctionsDir}${path4.sep}`)) {
5544
+ if (filePath === this.correctionsDir || filePath.startsWith(`${this.correctionsDir}${path5.sep}`)) {
4482
5545
  correctionPaths.push(filePath);
4483
5546
  } else {
4484
5547
  factPaths.push(filePath);
@@ -4543,7 +5606,7 @@ ${sanitized.text}
4543
5606
  try {
4544
5607
  const entries = await readdir4(dir, { withFileTypes: true });
4545
5608
  for (const entry of entries) {
4546
- const fullPath = path4.join(dir, entry.name);
5609
+ const fullPath = path5.join(dir, entry.name);
4547
5610
  if (entry.isDirectory()) {
4548
5611
  await readDir(fullPath);
4549
5612
  } else if (entry.name.endsWith(".md")) {
@@ -4578,7 +5641,7 @@ ${sanitized.text}
4578
5641
  );
4579
5642
  }
4580
5643
  resolveTierRootDir(tier) {
4581
- return tier === "cold" ? path4.join(this.baseDir, "cold") : this.baseDir;
5644
+ return tier === "cold" ? path5.join(this.baseDir, "cold") : this.baseDir;
4582
5645
  }
4583
5646
  resolveMemoryDateDir(memory) {
4584
5647
  const preferred = memory.frontmatter.created || memory.frontmatter.updated;
@@ -4593,13 +5656,13 @@ ${sanitized.text}
4593
5656
  buildTierMemoryPath(memory, tier) {
4594
5657
  const root = this.resolveTierRootDir(tier);
4595
5658
  if (this.isArtifactMemory(memory)) {
4596
- return path4.join(root, "artifacts", this.resolveMemoryDateDir(memory), `${memory.frontmatter.id}.md`);
5659
+ return path5.join(root, "artifacts", this.resolveMemoryDateDir(memory), `${memory.frontmatter.id}.md`);
4597
5660
  }
4598
5661
  if (memory.frontmatter.category === "correction") {
4599
- return path4.join(root, "corrections", `${memory.frontmatter.id}.md`);
5662
+ return path5.join(root, "corrections", `${memory.frontmatter.id}.md`);
4600
5663
  }
4601
5664
  const dir = categoryDirName(memory.frontmatter.category);
4602
- return path4.join(root, dir, this.resolveMemoryDateDir(memory), `${memory.frontmatter.id}.md`);
5665
+ return path5.join(root, dir, this.resolveMemoryDateDir(memory), `${memory.frontmatter.id}.md`);
4603
5666
  }
4604
5667
  async writeMemoryFileAtomic(targetPath, memory) {
4605
5668
  const fileContent = `${serializeFrontmatter(memory.frontmatter)}
@@ -4612,8 +5675,8 @@ ${memory.content}
4612
5675
  }
4613
5676
  async moveMemoryToPath(memory, targetPath) {
4614
5677
  await this.writeMemoryFileAtomic(targetPath, memory);
4615
- const sourcePath = path4.resolve(memory.path);
4616
- const destPath = path4.resolve(targetPath);
5678
+ const sourcePath = path5.resolve(memory.path);
5679
+ const destPath = path5.resolve(targetPath);
4617
5680
  if (sourcePath !== destPath) {
4618
5681
  try {
4619
5682
  await unlink2(memory.path);
@@ -4629,8 +5692,8 @@ ${memory.content}
4629
5692
  }
4630
5693
  async migrateMemoryToTier(memory, targetTier) {
4631
5694
  const targetPath = this.buildTierMemoryPath(memory, targetTier);
4632
- const sourcePath = path4.resolve(memory.path);
4633
- const destPath = path4.resolve(targetPath);
5695
+ const sourcePath = path5.resolve(memory.path);
5696
+ const destPath = path5.resolve(targetPath);
4634
5697
  if (sourcePath === destPath) {
4635
5698
  return { changed: false, targetPath };
4636
5699
  }
@@ -4657,7 +5720,7 @@ ${memory.content}
4657
5720
  return { changed: true, targetPath };
4658
5721
  }
4659
5722
  get archiveDir() {
4660
- return path4.join(this.baseDir, "archive");
5723
+ return path5.join(this.baseDir, "archive");
4661
5724
  }
4662
5725
  /**
4663
5726
  * Archive a memory by moving it from facts/ to archive/YYYY-MM-DD/.
@@ -4668,7 +5731,7 @@ ${memory.content}
4668
5731
  try {
4669
5732
  const now = lifecycle?.at ?? /* @__PURE__ */ new Date();
4670
5733
  const today = now.toISOString().slice(0, 10);
4671
- const destDir = path4.join(this.archiveDir, today);
5734
+ const destDir = path5.join(this.archiveDir, today);
4672
5735
  await mkdir(destDir, { recursive: true });
4673
5736
  const updatedFm = {
4674
5737
  ...memory.frontmatter,
@@ -4680,7 +5743,7 @@ ${memory.content}
4680
5743
 
4681
5744
  ${memory.content}
4682
5745
  `;
4683
- const destPath = path4.join(destDir, path4.basename(memory.path));
5746
+ const destPath = path5.join(destDir, path5.basename(memory.path));
4684
5747
  await this.writeStorageSecureFile(destPath, fileContent);
4685
5748
  await unlink2(memory.path);
4686
5749
  markProjectedMemoryPathInvalid(this.baseDir, memory.frontmatter.id);
@@ -4830,7 +5893,7 @@ ${memory.content}
4830
5893
  `;
4831
5894
  await this.writeStorageSecureFile(memory.path, fileContent);
4832
5895
  this.invalidateAllMemoriesCache();
4833
- if (memory.path.includes(`${path4.sep}cold${path4.sep}`)) {
5896
+ if (memory.path.includes(`${path5.sep}cold${path5.sep}`)) {
4834
5897
  this.invalidateColdMemoriesCache();
4835
5898
  }
4836
5899
  try {
@@ -4903,7 +5966,7 @@ ${memory.content}
4903
5966
  return deleted;
4904
5967
  }
4905
5968
  async loadBuffer() {
4906
- const bufferPath = path4.join(this.stateDir, "buffer.json");
5969
+ const bufferPath = path5.join(this.stateDir, "buffer.json");
4907
5970
  try {
4908
5971
  const raw = await this.readStorageSecureFile(bufferPath);
4909
5972
  return JSON.parse(raw);
@@ -4915,11 +5978,11 @@ ${memory.content}
4915
5978
  }
4916
5979
  async saveBuffer(state) {
4917
5980
  await this.ensureDirectories();
4918
- const bufferPath = path4.join(this.stateDir, "buffer.json");
5981
+ const bufferPath = path5.join(this.stateDir, "buffer.json");
4919
5982
  await this.writeStorageSecureFile(bufferPath, JSON.stringify(state, null, 2));
4920
5983
  }
4921
5984
  async loadMeta() {
4922
- const metaPath = path4.join(this.stateDir, "meta.json");
5985
+ const metaPath = path5.join(this.stateDir, "meta.json");
4923
5986
  try {
4924
5987
  const raw = await this.readStorageSecureFile(metaPath);
4925
5988
  const parsed = JSON.parse(raw);
@@ -4953,7 +6016,7 @@ ${memory.content}
4953
6016
  }
4954
6017
  async saveMeta(state) {
4955
6018
  await this.ensureDirectories();
4956
- const metaPath = path4.join(this.stateDir, "meta.json");
6019
+ const metaPath = path5.join(this.stateDir, "meta.json");
4957
6020
  await this.writeStorageSecureFile(metaPath, JSON.stringify(state, null, 2));
4958
6021
  }
4959
6022
  async appendMemoryActionEvents(events) {
@@ -5039,7 +6102,7 @@ ${memory.content}
5039
6102
  async appendReextractJobs(events) {
5040
6103
  if (events.length === 0) return 0;
5041
6104
  await this.ensureDirectories();
5042
- const filePath = path4.join(this.stateDir, "reextract-jobs.jsonl");
6105
+ const filePath = path5.join(this.stateDir, "reextract-jobs.jsonl");
5043
6106
  const lines = events.map((event) => JSON.stringify(event)).join("\n") + "\n";
5044
6107
  try {
5045
6108
  await this.appendStorageSecureFile(filePath, lines);
@@ -5052,7 +6115,7 @@ ${memory.content}
5052
6115
  }
5053
6116
  async readReextractJobs(limit = 200) {
5054
6117
  const safeLimit = Number.isFinite(limit) ? Math.max(1, Math.min(1e3, Math.floor(limit))) : 200;
5055
- const filePath = path4.join(this.stateDir, "reextract-jobs.jsonl");
6118
+ const filePath = path5.join(this.stateDir, "reextract-jobs.jsonl");
5056
6119
  try {
5057
6120
  const raw = await this.readStorageSecureFile(filePath);
5058
6121
  const lines = raw.split("\n").filter((line) => line.trim().length > 0);
@@ -5210,7 +6273,7 @@ ${memory.content}
5210
6273
  return false;
5211
6274
  }
5212
6275
  if (draftState.contentHash) {
5213
- const contentHash = createHash("sha256").update(draftContent).digest("hex");
6276
+ const contentHash = createHash3("sha256").update(draftContent).digest("hex");
5214
6277
  if (contentHash !== draftState.contentHash) return false;
5215
6278
  }
5216
6279
  await this.writeCompressionGuidelines(draftContent);
@@ -5290,7 +6353,7 @@ ${question}
5290
6353
 
5291
6354
  **Context:** ${context}
5292
6355
  `;
5293
- const filePath = path4.join(this.questionsDir, `${id}.md`);
6356
+ const filePath = path5.join(this.questionsDir, `${id}.md`);
5294
6357
  await this.writeStorageSecureFile(filePath, content);
5295
6358
  log.debug(`wrote question ${id} to ${filePath}`);
5296
6359
  this.invalidateQuestionsCache();
@@ -5308,7 +6371,7 @@ ${question}
5308
6371
  if (!match) return null;
5309
6372
  const frontmatterStr = match[1];
5310
6373
  const body = match[2].trim();
5311
- const id = this.extractFrontmatterValue(frontmatterStr, "id") ?? path4.basename(filePath, ".md");
6374
+ const id = this.extractFrontmatterValue(frontmatterStr, "id") ?? path5.basename(filePath, ".md");
5312
6375
  const created = this.extractFrontmatterValue(frontmatterStr, "created") ?? "";
5313
6376
  const priority = parseFloat(
5314
6377
  this.extractFrontmatterValue(frontmatterStr, "priority") ?? "0.5"
@@ -5371,11 +6434,11 @@ ${question}
5371
6434
  } catch {
5372
6435
  }
5373
6436
  const hygiene = opts?.hygiene;
5374
- const rotateEnabled = hygiene?.enabled === true && hygiene.rotateEnabled === true && Array.isArray(hygiene.rotatePaths) && hygiene.rotatePaths.includes(path4.basename(identityPath));
6437
+ const rotateEnabled = hygiene?.enabled === true && hygiene.rotateEnabled === true && Array.isArray(hygiene.rotatePaths) && hygiene.rotatePaths.includes(path5.basename(identityPath));
5375
6438
  if (rotateEnabled) {
5376
6439
  const maxBytes = hygiene.rotateMaxBytes;
5377
6440
  if (existing.length > maxBytes) {
5378
- const archiveDir = path4.join(workspaceDir, hygiene.archiveDir);
6441
+ const archiveDir = path5.join(workspaceDir, hygiene.archiveDir);
5379
6442
  const { newContent } = await rotateMarkdownFileToArchive({
5380
6443
  filePath: identityPath,
5381
6444
  archiveDir,
@@ -5469,7 +6532,7 @@ ${reflection}
5469
6532
  * Deduplicates by target+label.
5470
6533
  */
5471
6534
  async addEntityRelationship(name, rel) {
5472
- const filePath = path4.join(this.entitiesDir, `${name}.md`);
6535
+ const filePath = path5.join(this.entitiesDir, `${name}.md`);
5473
6536
  let entity;
5474
6537
  try {
5475
6538
  const content = await this.readStorageSecureFile(filePath);
@@ -5494,7 +6557,7 @@ ${reflection}
5494
6557
  * Prepends to the beginning, prunes oldest entries beyond maxEntries.
5495
6558
  */
5496
6559
  async addEntityActivity(name, entry, maxEntries) {
5497
- const filePath = path4.join(this.entitiesDir, `${name}.md`);
6560
+ const filePath = path5.join(this.entitiesDir, `${name}.md`);
5498
6561
  let entity;
5499
6562
  try {
5500
6563
  const content = await this.readStorageSecureFile(filePath);
@@ -5517,7 +6580,7 @@ ${reflection}
5517
6580
  * Add an alias to an entity file. Deduplicates.
5518
6581
  */
5519
6582
  async addEntityAlias(name, alias) {
5520
- const filePath = path4.join(this.entitiesDir, `${name}.md`);
6583
+ const filePath = path5.join(this.entitiesDir, `${name}.md`);
5521
6584
  let entity;
5522
6585
  try {
5523
6586
  const content = await this.readStorageSecureFile(filePath);
@@ -5548,7 +6611,7 @@ ${reflection}
5548
6611
  const updatedAt = (/* @__PURE__ */ new Date()).toISOString();
5549
6612
  let synthesisTimelineCount;
5550
6613
  try {
5551
- const filePath = path4.join(this.entitiesDir, `${name}.md`);
6614
+ const filePath = path5.join(this.entitiesDir, `${name}.md`);
5552
6615
  const content = await this.readStorageSecureFile(filePath);
5553
6616
  synthesisTimelineCount = parseEntityFile(content, this.entitySchemas).timeline.length;
5554
6617
  } catch (err) {
@@ -5631,7 +6694,7 @@ ${reflection}
5631
6694
  if (!raw) continue;
5632
6695
  const serialized = serializeEntityFile(parseEntityFile(raw, this.entitySchemas), this.entitySchemas);
5633
6696
  if (raw.trimEnd() === serialized.trimEnd()) continue;
5634
- await this.writeStorageSecureFile(path4.join(this.entitiesDir, `${entityName}.md`), serialized);
6697
+ await this.writeStorageSecureFile(path5.join(this.entitiesDir, `${entityName}.md`), serialized);
5635
6698
  migrated += 1;
5636
6699
  }
5637
6700
  if (migrated > 0) {
@@ -5775,7 +6838,7 @@ ${memory.content}
5775
6838
  const filePaths = await this.collectActiveMemoryPaths();
5776
6839
  const foundIds = /* @__PURE__ */ new Set();
5777
6840
  for (const filePath of filePaths) {
5778
- const basename = path4.basename(filePath, ".md");
6841
+ const basename = path5.basename(filePath, ".md");
5779
6842
  if (wantedIds.has(basename)) {
5780
6843
  foundIds.add(basename);
5781
6844
  if (foundIds.size === wantedIds.size) break;
@@ -5967,14 +7030,14 @@ Reason: ${reason}`, {
5967
7030
  // Memory Summarization (Phase 4A)
5968
7031
  // ---------------------------------------------------------------------------
5969
7032
  get summariesDir() {
5970
- return path4.join(this.baseDir, "summaries");
7033
+ return path5.join(this.baseDir, "summaries");
5971
7034
  }
5972
7035
  /**
5973
7036
  * Write a memory summary.
5974
7037
  */
5975
7038
  async writeSummary(summary) {
5976
7039
  await mkdir(this.summariesDir, { recursive: true });
5977
- const filePath = path4.join(this.summariesDir, `${summary.id}.json`);
7040
+ const filePath = path5.join(this.summariesDir, `${summary.id}.json`);
5978
7041
  await this.writeStorageSecureFile(filePath, JSON.stringify(summary, null, 2));
5979
7042
  log.debug(`wrote summary ${summary.id}`);
5980
7043
  }
@@ -5987,7 +7050,7 @@ Reason: ${reason}`, {
5987
7050
  const summaries = [];
5988
7051
  for (const file of files) {
5989
7052
  if (!file.endsWith(".json")) continue;
5990
- const filePath = path4.join(this.summariesDir, file);
7053
+ const filePath = path5.join(this.summariesDir, file);
5991
7054
  const raw = await this.readStorageSecureFile(filePath);
5992
7055
  summaries.push(JSON.parse(raw));
5993
7056
  }
@@ -6048,7 +7111,7 @@ ${memory.content}
6048
7111
  * Save topic scores to meta.json.
6049
7112
  */
6050
7113
  async saveTopics(topics) {
6051
- const metaPath = path4.join(this.stateDir, "topics.json");
7114
+ const metaPath = path5.join(this.stateDir, "topics.json");
6052
7115
  await mkdir(this.stateDir, { recursive: true });
6053
7116
  await this.writeStorageSecureFile(metaPath, JSON.stringify({ topics, updatedAt: (/* @__PURE__ */ new Date()).toISOString() }, null, 2));
6054
7117
  log.debug(`saved ${topics.length} topic scores`);
@@ -6057,7 +7120,7 @@ ${memory.content}
6057
7120
  * Load topic scores from meta.json.
6058
7121
  */
6059
7122
  async loadTopics() {
6060
- const metaPath = path4.join(this.stateDir, "topics.json");
7123
+ const metaPath = path5.join(this.stateDir, "topics.json");
6061
7124
  try {
6062
7125
  const raw = await this.readStorageSecureFile(metaPath);
6063
7126
  return JSON.parse(raw);
@@ -6136,6 +7199,19 @@ ${memory.content}
6136
7199
 
6137
7200
  export {
6138
7201
  selfDeps,
7202
+ DEFAULT_PROXIMITY_GAP_MS,
7203
+ clusterConversations,
7204
+ DEFAULT_WINDOW_TOLERANCE_MS,
7205
+ DEFAULT_SOURCE_TRUST,
7206
+ fusionInputsFromConversations,
7207
+ fuseCluster,
7208
+ fuseDay,
7209
+ FUSION_KIND,
7210
+ hashFusionBody,
7211
+ composeFusionDayMeta,
7212
+ serializeFusionDay,
7213
+ parseFusionDay,
7214
+ reconstructFusionInputs,
6139
7215
  parseFrontmatterStringValue,
6140
7216
  parseFrontmatter,
6141
7217
  normalizeFrontmatterForPath,
@@ -6154,4 +7230,4 @@ export {
6154
7230
  isValidBufferSurpriseEvent,
6155
7231
  StorageManager3 as StorageManager
6156
7232
  };
6157
- //# sourceMappingURL=chunk-M7GGMGMZ.js.map
7233
+ //# sourceMappingURL=chunk-SVOHGUMI.js.map