@snoai/memory 0.0.0-stage → 1.0.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 (478) hide show
  1. package/LICENSE +176 -0
  2. package/README.md +7 -2
  3. package/config/b-profile-section-registry.json +118 -0
  4. package/config/llm/compiled/2026-05-19T230932Z/manifest.json +25 -0
  5. package/config/llm/compiled/2026-05-19T230932Z/registry-root.json +67 -0
  6. package/config/llm/compiled/2026-05-19T230932Z/resolved/mem_claw/openai_gpt_5_nano.json +5 -0
  7. package/config/llm/compiled/2026-05-19T230932Z/resolved/mem_claw/openrouter_auto.json +5 -0
  8. package/config/llm/compiled/2026-05-19T230932Z/resolved/mem_claw/sno_ai_extract.json +5 -0
  9. package/config/llm/compiled/2026-05-19T230932Z/source/mem_claw/openai_gpt_5_nano.mda +24 -0
  10. package/config/llm/compiled/2026-05-19T230932Z/source/mem_claw/openrouter_auto.mda +24 -0
  11. package/config/llm/compiled/2026-05-19T230932Z/source/mem_claw/sno_ai_extract.mda +24 -0
  12. package/config/llm/compiled/2026-07-21T001311Z/manifest.json +43 -0
  13. package/config/llm/compiled/2026-07-21T001311Z/registry-root.json +97 -0
  14. package/config/llm/compiled/2026-07-21T001311Z/resolved/mem_claw/openai_gpt_5_nano.json +5 -0
  15. package/config/llm/compiled/2026-07-21T001311Z/resolved/mem_claw/openrouter_auto.json +5 -0
  16. package/config/llm/compiled/2026-07-21T001311Z/resolved/mem_claw/sno_ai_extract.json +5 -0
  17. package/config/llm/compiled/2026-07-21T001311Z/resolved/mem_claw/sno_conflict_verdict.json +10 -0
  18. package/config/llm/compiled/2026-07-21T001311Z/resolved/mem_claw/sno_extract_chat.json +10 -0
  19. package/config/llm/compiled/2026-07-21T001311Z/resolved/mem_claw/sno_extract_profile.json +10 -0
  20. package/config/llm/compiled/2026-07-21T001311Z/source/mem_claw/openai_gpt_5_nano.mda +24 -0
  21. package/config/llm/compiled/2026-07-21T001311Z/source/mem_claw/openrouter_auto.mda +24 -0
  22. package/config/llm/compiled/2026-07-21T001311Z/source/mem_claw/sno_ai_extract.mda +24 -0
  23. package/config/llm/compiled/2026-07-21T001311Z/source/mem_claw/sno_conflict_verdict.mda +27 -0
  24. package/config/llm/compiled/2026-07-21T001311Z/source/mem_claw/sno_extract_chat.mda +27 -0
  25. package/config/llm/compiled/2026-07-21T001311Z/source/mem_claw/sno_extract_profile.mda +27 -0
  26. package/config/llm/compiled/2026-08-29T060335Z/manifest.json +43 -0
  27. package/config/llm/compiled/2026-08-29T060335Z/registry-root.json +97 -0
  28. package/config/llm/compiled/2026-08-29T060335Z/resolved/mem_claw/openai_gpt_5_nano.json +5 -0
  29. package/config/llm/compiled/2026-08-29T060335Z/resolved/mem_claw/openrouter_auto.json +5 -0
  30. package/config/llm/compiled/2026-08-29T060335Z/resolved/mem_claw/sno_ai_extract.json +5 -0
  31. package/config/llm/compiled/2026-08-29T060335Z/resolved/mem_claw/sno_conflict_verdict.json +10 -0
  32. package/config/llm/compiled/2026-08-29T060335Z/resolved/mem_claw/sno_extract_chat.json +10 -0
  33. package/config/llm/compiled/2026-08-29T060335Z/resolved/mem_claw/sno_extract_profile.json +10 -0
  34. package/config/llm/compiled/2026-08-29T060335Z/source/mem_claw/openai_gpt_5_nano.mda +24 -0
  35. package/config/llm/compiled/2026-08-29T060335Z/source/mem_claw/openrouter_auto.mda +24 -0
  36. package/config/llm/compiled/2026-08-29T060335Z/source/mem_claw/sno_ai_extract.mda +24 -0
  37. package/config/llm/compiled/2026-08-29T060335Z/source/mem_claw/sno_conflict_verdict.mda +27 -0
  38. package/config/llm/compiled/2026-08-29T060335Z/source/mem_claw/sno_extract_chat.mda +27 -0
  39. package/config/llm/compiled/2026-08-29T060335Z/source/mem_claw/sno_extract_profile.mda +27 -0
  40. package/config/llm/compiled/2026-09-04T004828Z/manifest.json +43 -0
  41. package/config/llm/compiled/2026-09-04T004828Z/registry-root.json +97 -0
  42. package/config/llm/compiled/2026-09-04T004828Z/resolved/mem_claw/openai_gpt_5_nano.json +5 -0
  43. package/config/llm/compiled/2026-09-04T004828Z/resolved/mem_claw/openrouter_auto.json +5 -0
  44. package/config/llm/compiled/2026-09-04T004828Z/resolved/mem_claw/sno_ai_extract.json +5 -0
  45. package/config/llm/compiled/2026-09-04T004828Z/resolved/mem_claw/sno_conflict_verdict.json +10 -0
  46. package/config/llm/compiled/2026-09-04T004828Z/resolved/mem_claw/sno_extract_chat.json +10 -0
  47. package/config/llm/compiled/2026-09-04T004828Z/resolved/mem_claw/sno_extract_profile.json +10 -0
  48. package/config/llm/compiled/2026-09-04T004828Z/source/mem_claw/openai_gpt_5_nano.mda +24 -0
  49. package/config/llm/compiled/2026-09-04T004828Z/source/mem_claw/openrouter_auto.mda +24 -0
  50. package/config/llm/compiled/2026-09-04T004828Z/source/mem_claw/sno_ai_extract.mda +24 -0
  51. package/config/llm/compiled/2026-09-04T004828Z/source/mem_claw/sno_conflict_verdict.mda +27 -0
  52. package/config/llm/compiled/2026-09-04T004828Z/source/mem_claw/sno_extract_chat.mda +27 -0
  53. package/config/llm/compiled/2026-09-04T004828Z/source/mem_claw/sno_extract_profile.mda +27 -0
  54. package/config/llm/current.json +4 -0
  55. package/config/llm/source/mem_claw/openai_gpt_5_nano.mda +24 -0
  56. package/config/llm/source/mem_claw/openrouter_auto.mda +24 -0
  57. package/config/llm/source/mem_claw/sno_ai_extract.mda +24 -0
  58. package/config/llm/source/mem_claw/sno_conflict_verdict.mda +27 -0
  59. package/config/llm/source/mem_claw/sno_extract_chat.mda +27 -0
  60. package/config/llm/source/mem_claw/sno_extract_profile.mda +27 -0
  61. package/config/llm.trust.json +37 -0
  62. package/dist/_types-CUKHSRkS.d.ts +103 -0
  63. package/dist/access-tracker-CSc21GtV.d.ts +110 -0
  64. package/dist/adapter-DMEmCTKo.d.ts +69 -0
  65. package/dist/adapter-XaRHZWZ2.js +333 -0
  66. package/dist/agent-llm-port-5oXgBpzJ.d.ts +53 -0
  67. package/dist/all-resources-BQK2ugjB.js +6379 -0
  68. package/dist/all-resources-Dij6l5h0.d.ts +18 -0
  69. package/dist/ambient-learning-text-normalizer-CxjATmMp.js +170 -0
  70. package/dist/ambient-learning-text-normalizer-_fH3LeuK.d.ts +10 -0
  71. package/dist/atomic-extraction-reply-BJ9XV_9s.js +863 -0
  72. package/dist/atomic-extraction-skill-CcXmuCqL.js +56 -0
  73. package/dist/atomic-memory-extraction-BpOUWPJM.d.ts +327 -0
  74. package/dist/atomic-memory-extraction-sdNf1-B1.js +3605 -0
  75. package/dist/b-profile-section-dictionary-provider-BHkoNqgk.js +1812 -0
  76. package/dist/b-profile-section-dictionary-provider-BxbksLj3.d.ts +62 -0
  77. package/dist/best-effort-BPZSzKk0.d.ts +9 -0
  78. package/dist/calendar-instruction-CzqZbAPG.js +194 -0
  79. package/dist/capture-policy-detector-CHz5GOPA.d.ts +53 -0
  80. package/dist/capture-policy-detector-DaMfy9CZ.js +357 -0
  81. package/dist/classifier-C96uH9OF.d.ts +272 -0
  82. package/dist/client.d.ts +34 -0
  83. package/dist/client.js +305 -0
  84. package/dist/coding-skin.d.ts +51 -0
  85. package/dist/coding-skin.js +55 -0
  86. package/dist/config-tSrvLXgV.js +2577 -0
  87. package/dist/connection-DAbzki8K.d.ts +391 -0
  88. package/dist/connection-DliCOBB2.js +297 -0
  89. package/dist/daily-log-generator-CH_KuWHs.js +469 -0
  90. package/dist/daily-log-generator-CsQPHl4A.d.ts +73 -0
  91. package/dist/daily-spend-estimator-DiwzBlo1.d.ts +8 -0
  92. package/dist/data-bootstrap-CYniFp8b.js +172 -0
  93. package/dist/data-bootstrap-CcJUwkqf.d.ts +30 -0
  94. package/dist/data-paths-C7sNdqvP.d.ts +22 -0
  95. package/dist/derived-suppression-cache-C7bGARc0.d.ts +36 -0
  96. package/dist/diagnostic-encoder.d.ts +6 -0
  97. package/dist/diagnostic-encoder.js +29 -0
  98. package/dist/embedding-provider-client-Q_hJonK9.js +294 -0
  99. package/dist/embedding-provider-client-vynZMuit.d.ts +94 -0
  100. package/dist/entry-metadata-parser-BIVSMCIk.js +20 -0
  101. package/dist/error-D-wb-rZw.js +23 -0
  102. package/dist/error-signals-D8_3vYu4.d.ts +28 -0
  103. package/dist/error-signals-lMH2uAdV.js +134 -0
  104. package/dist/errors-CeVRxf9V.d.ts +49 -0
  105. package/dist/extraction-text-sanitizer-B_AhIecT.d.ts +32 -0
  106. package/dist/i18n-text-DbD6Qify.d.ts +13 -0
  107. package/dist/index-BsMap4It.d.ts +650 -0
  108. package/dist/index-DL8AVj0Z.d.ts +571 -0
  109. package/dist/index-DQ7VL6d3.d.ts +350 -0
  110. package/dist/index.d.ts +65 -0
  111. package/dist/index.js +1201 -0
  112. package/dist/intent-analyzer-B5XVrWwe.d.ts +28 -0
  113. package/dist/internal/config/index.d.ts +2 -0
  114. package/dist/internal/config/index.js +581 -0
  115. package/dist/internal/config/plugin-config-schema.d.ts +2 -0
  116. package/dist/internal/config/plugin-config-schema.js +2 -0
  117. package/dist/internal/config/product-mode.d.ts +2 -0
  118. package/dist/internal/config/product-mode.js +36 -0
  119. package/dist/internal/config/settings.d.ts +2 -0
  120. package/dist/internal/config/settings.js +265 -0
  121. package/dist/internal/config/skill-categories.d.ts +4 -0
  122. package/dist/internal/config/skill-categories.js +68 -0
  123. package/dist/internal/config/skin-defaults.d.ts +6 -0
  124. package/dist/internal/config/skin-defaults.js +6 -0
  125. package/dist/internal/contract/discovery.d.ts +10 -0
  126. package/dist/internal/contract/discovery.js +53 -0
  127. package/dist/internal/contract/profile.d.ts +2 -0
  128. package/dist/internal/contract/profile.js +44 -0
  129. package/dist/internal/contract/routes.d.ts +2 -0
  130. package/dist/internal/contract/routes.js +61 -0
  131. package/dist/internal/engine/bindings/memory-cli-shared.d.ts +47 -0
  132. package/dist/internal/engine/bindings/memory-cli-shared.js +84 -0
  133. package/dist/internal/engine/bindings/memory-forget-tool.d.ts +5 -0
  134. package/dist/internal/engine/bindings/memory-forget-tool.js +66 -0
  135. package/dist/internal/engine/bindings/memory-list-tool.d.ts +5 -0
  136. package/dist/internal/engine/bindings/memory-list-tool.js +57 -0
  137. package/dist/internal/engine/bindings/memory-recall-tool.d.ts +10 -0
  138. package/dist/internal/engine/bindings/memory-recall-tool.js +283 -0
  139. package/dist/internal/engine/bindings/memory-reflection-resolve-tool.d.ts +5 -0
  140. package/dist/internal/engine/bindings/memory-reflection-resolve-tool.js +150 -0
  141. package/dist/internal/engine/bindings/memory-stats-tool.d.ts +5 -0
  142. package/dist/internal/engine/bindings/memory-stats-tool.js +43 -0
  143. package/dist/internal/engine/bindings/memory-store-tool.d.ts +5 -0
  144. package/dist/internal/engine/bindings/memory-store-tool.js +165 -0
  145. package/dist/internal/engine/bindings/memory-tool-access.d.ts +16 -0
  146. package/dist/internal/engine/bindings/memory-tool-access.js +46 -0
  147. package/dist/internal/engine/bindings/memory-tool-formatting.d.ts +62 -0
  148. package/dist/internal/engine/bindings/memory-tool-formatting.js +106 -0
  149. package/dist/internal/engine/bindings/memory-tool-results.d.ts +8 -0
  150. package/dist/internal/engine/bindings/memory-tool-results.js +41 -0
  151. package/dist/internal/engine/bindings/memory-tool-schemas.d.ts +109 -0
  152. package/dist/internal/engine/bindings/memory-tool-schemas.js +75 -0
  153. package/dist/internal/engine/bindings/memory-update-tool.d.ts +5 -0
  154. package/dist/internal/engine/bindings/memory-update-tool.js +127 -0
  155. package/dist/internal/engine/bindings/sno-station-mem-ambient-learning-hook.d.ts +14 -0
  156. package/dist/internal/engine/bindings/sno-station-mem-ambient-learning-hook.js +248 -0
  157. package/dist/internal/engine/bindings/sno-station-mem-auto-recall-hook.d.ts +12 -0
  158. package/dist/internal/engine/bindings/sno-station-mem-auto-recall-hook.js +324 -0
  159. package/dist/internal/engine/bindings/sno-station-mem-hook-types.d.ts +56 -0
  160. package/dist/internal/engine/bindings/sno-station-mem-hook-types.js +1 -0
  161. package/dist/internal/engine/bindings/sno-station-mem-insight-distill-factory.d.ts +14 -0
  162. package/dist/internal/engine/bindings/sno-station-mem-insight-distill-factory.js +119 -0
  163. package/dist/internal/engine/bindings/sno-station-mem-message-transcript.d.ts +52 -0
  164. package/dist/internal/engine/bindings/sno-station-mem-message-transcript.js +145 -0
  165. package/dist/internal/engine/bindings/sno-station-mem-reset-hook.d.ts +10 -0
  166. package/dist/internal/engine/bindings/sno-station-mem-reset-hook.js +9 -0
  167. package/dist/internal/engine/bindings/sno-station-mem-runtime-mode.d.ts +37 -0
  168. package/dist/internal/engine/bindings/sno-station-mem-runtime-mode.js +105 -0
  169. package/dist/internal/engine/bindings/sno-station-mem-session-state.d.ts +10 -0
  170. package/dist/internal/engine/bindings/sno-station-mem-session-state.js +27 -0
  171. package/dist/internal/engine/eval/trace.d.ts +2 -0
  172. package/dist/internal/engine/eval/trace.js +151 -0
  173. package/dist/internal/engine/extraction/ambient-learning-text-normalizer.d.ts +2 -0
  174. package/dist/internal/engine/extraction/ambient-learning-text-normalizer.js +2 -0
  175. package/dist/internal/engine/extraction/atomic-memory-extraction.d.ts +2 -0
  176. package/dist/internal/engine/extraction/atomic-memory-extraction.js +2 -0
  177. package/dist/internal/engine/extraction/b-profile-section-dictionary-provider.d.ts +2 -0
  178. package/dist/internal/engine/extraction/b-profile-section-dictionary-provider.js +2 -0
  179. package/dist/internal/engine/extraction/b-profile-section-rekey.d.ts +49 -0
  180. package/dist/internal/engine/extraction/b-profile-section-rekey.js +730 -0
  181. package/dist/internal/engine/extraction/capture-policy-detector.d.ts +2 -0
  182. package/dist/internal/engine/extraction/capture-policy-detector.js +2 -0
  183. package/dist/internal/engine/extraction/embedding-provider-client.d.ts +2 -0
  184. package/dist/internal/engine/extraction/embedding-provider-client.js +2 -0
  185. package/dist/internal/engine/extraction/extraction-text-sanitizer.d.ts +2 -0
  186. package/dist/internal/engine/extraction/extraction-text-sanitizer.js +114 -0
  187. package/dist/internal/engine/extraction/memory-metadata-codec.d.ts +3 -0
  188. package/dist/internal/engine/extraction/memory-metadata-codec.js +2 -0
  189. package/dist/internal/engine/extraction/memory-temporality-classifier.d.ts +2 -0
  190. package/dist/internal/engine/extraction/memory-temporality-classifier.js +2 -0
  191. package/dist/internal/engine/i18n/all-resources.d.ts +2 -0
  192. package/dist/internal/engine/i18n/all-resources.js +2 -0
  193. package/dist/internal/engine/i18n/locales.d.ts +2 -0
  194. package/dist/internal/engine/i18n/locales.js +19 -0
  195. package/dist/internal/engine/i18n/res/_types.d.ts +2 -0
  196. package/dist/internal/engine/i18n/res/_types.js +11 -0
  197. package/dist/internal/engine/observability/adapter.d.ts +2 -0
  198. package/dist/internal/engine/observability/adapter.js +2 -0
  199. package/dist/internal/engine/observability/best-effort.d.ts +2 -0
  200. package/dist/internal/engine/observability/best-effort.js +41 -0
  201. package/dist/internal/engine/observability/early-diagnostics.js +2 -0
  202. package/dist/internal/engine/observability/memory-snapshot.d.ts +2 -0
  203. package/dist/internal/engine/observability/memory-snapshot.js +44 -0
  204. package/dist/internal/engine/observability/observable-embedder.d.ts +2 -0
  205. package/dist/internal/engine/observability/observable-embedder.js +43 -0
  206. package/dist/internal/engine/observability/observable-llm-client.d.ts +2 -0
  207. package/dist/internal/engine/observability/observable-llm-client.js +98 -0
  208. package/dist/internal/engine/observability/observable-memory-store.d.ts +2 -0
  209. package/dist/internal/engine/observability/observable-memory-store.js +701 -0
  210. package/dist/internal/engine/observability/observable-retriever.d.ts +2 -0
  211. package/dist/internal/engine/observability/observable-retriever.js +95 -0
  212. package/dist/internal/engine/observability/runtime-diagnostics.d.ts +13 -0
  213. package/dist/internal/engine/observability/runtime-diagnostics.js +96 -0
  214. package/dist/internal/engine/observability/session-registry.d.ts +2 -0
  215. package/dist/internal/engine/observability/session-registry.js +58 -0
  216. package/dist/internal/engine/observability/version-metadata.d.ts +7 -0
  217. package/dist/internal/engine/observability/version-metadata.js +59 -0
  218. package/dist/internal/engine/operations/daily-spend-estimator.d.ts +2 -0
  219. package/dist/internal/engine/operations/daily-spend-estimator.js +97 -0
  220. package/dist/internal/engine/operations/learning-file-maintenance.d.ts +2 -0
  221. package/dist/internal/engine/operations/learning-file-maintenance.js +255 -0
  222. package/dist/internal/engine/operations/memory-tier-promoter.d.ts +2 -0
  223. package/dist/internal/engine/operations/memory-tier-promoter.js +95 -0
  224. package/dist/internal/engine/operations/runtime-audit-log.d.ts +3 -0
  225. package/dist/internal/engine/operations/runtime-audit-log.js +3 -0
  226. package/dist/internal/engine/provider/canonical-memory-corpus.d.ts +38 -0
  227. package/dist/internal/engine/provider/canonical-memory-corpus.js +253 -0
  228. package/dist/internal/engine/provider/provider-registration.d.ts +39 -0
  229. package/dist/internal/engine/provider/provider-registration.js +2 -0
  230. package/dist/internal/engine/provider/provider-row-renderer.d.ts +7 -0
  231. package/dist/internal/engine/provider/provider-row-renderer.js +53 -0
  232. package/dist/internal/engine/provider/provider-types.d.ts +2 -0
  233. package/dist/internal/engine/provider/provider-types.js +1 -0
  234. package/dist/internal/engine/reflection/daily-log-generator.d.ts +2 -0
  235. package/dist/internal/engine/reflection/daily-log-generator.js +2 -0
  236. package/dist/internal/engine/reflection/reflection-command-hooks.d.ts +2 -0
  237. package/dist/internal/engine/reflection/reflection-command-hooks.js +2 -0
  238. package/dist/internal/engine/reflection/reflection-deps.d.ts +2 -0
  239. package/dist/internal/engine/reflection/reflection-deps.js +1 -0
  240. package/dist/internal/engine/reflection/reflection-embedded-generator.d.ts +2 -0
  241. package/dist/internal/engine/reflection/reflection-embedded-generator.js +2 -0
  242. package/dist/internal/engine/reflection/reflection-injection-hooks.d.ts +2 -0
  243. package/dist/internal/engine/reflection/reflection-injection-hooks.js +219 -0
  244. package/dist/internal/engine/reflection/reflection-lifecycle-hooks.d.ts +2 -0
  245. package/dist/internal/engine/reflection/reflection-lifecycle-hooks.js +63 -0
  246. package/dist/internal/engine/reflection/strategy-hook-runner.d.ts +4 -0
  247. package/dist/internal/engine/reflection/strategy-hook-runner.js +3 -0
  248. package/dist/internal/engine/rem/classifier.d.ts +2 -0
  249. package/dist/internal/engine/rem/classifier.js +180 -0
  250. package/dist/internal/engine/rem/index.d.ts +4 -0
  251. package/dist/internal/engine/rem/index.js +2551 -0
  252. package/dist/internal/engine/rem/types.d.ts +2 -0
  253. package/dist/internal/engine/rem/types.js +40 -0
  254. package/dist/internal/engine/retrieval/access-tracker.d.ts +2 -0
  255. package/dist/internal/engine/retrieval/access-tracker.js +314 -0
  256. package/dist/internal/engine/retrieval/intent-analyzer.d.ts +2 -0
  257. package/dist/internal/engine/retrieval/intent-analyzer.js +27 -0
  258. package/dist/internal/engine/retrieval/retrieval-gate.d.ts +2 -0
  259. package/dist/internal/engine/retrieval/retrieval-gate.js +47 -0
  260. package/dist/internal/engine/retrieval/retriever.d.ts +2 -0
  261. package/dist/internal/engine/retrieval/retriever.js +2 -0
  262. package/dist/internal/engine/security/memory-scope-policy.d.ts +2 -0
  263. package/dist/internal/engine/security/memory-scope-policy.js +2 -0
  264. package/dist/internal/engine/security/redact.d.ts +2 -0
  265. package/dist/internal/engine/security/redact.js +34 -0
  266. package/dist/internal/engine/security/scopes.d.ts +3 -0
  267. package/dist/internal/engine/security/scopes.js +3 -0
  268. package/dist/internal/engine/shared/errors.d.ts +2 -0
  269. package/dist/internal/engine/shared/errors.js +66 -0
  270. package/dist/internal/engine/shared/i18n-text.d.ts +2 -0
  271. package/dist/internal/engine/shared/i18n-text.js +58 -0
  272. package/dist/internal/engine/shared/iso-date-time.d.ts +16 -0
  273. package/dist/internal/engine/shared/iso-date-time.js +40 -0
  274. package/dist/internal/engine/shared/lru.d.ts +2 -0
  275. package/dist/internal/engine/shared/lru.js +30 -0
  276. package/dist/internal/engine/shared/memory-kind-policy.d.ts +2 -0
  277. package/dist/internal/engine/shared/memory-kind-policy.js +64 -0
  278. package/dist/internal/engine/shared/paths.d.ts +3 -0
  279. package/dist/internal/engine/shared/paths.js +2 -0
  280. package/dist/internal/engine/shared/types.d.ts +3 -0
  281. package/dist/internal/engine/shared/types.js +25 -0
  282. package/dist/internal/engine/shared/utils.d.ts +2 -0
  283. package/dist/internal/engine/shared/utils.js +175 -0
  284. package/dist/internal/engine/telemetry/memory-telemetry-api.d.ts +134 -0
  285. package/dist/internal/engine/telemetry/memory-telemetry-api.js +730 -0
  286. package/dist/internal/engine/telemetry/memory-telemetry-observability.d.ts +24 -0
  287. package/dist/internal/engine/telemetry/memory-telemetry-observability.js +133 -0
  288. package/dist/internal/engine/telemetry/memory-telemetry-outbox.d.ts +2 -0
  289. package/dist/internal/engine/telemetry/memory-telemetry-outbox.js +443 -0
  290. package/dist/internal/engine/telemetry/memory-telemetry-types.d.ts +2 -0
  291. package/dist/internal/engine/telemetry/memory-telemetry-types.js +21 -0
  292. package/dist/internal/engine/telemetry/observe-ledger.d.ts +30 -0
  293. package/dist/internal/engine/telemetry/observe-ledger.js +111 -0
  294. package/dist/internal/model/agent-llm-port.d.ts +2 -0
  295. package/dist/internal/model/agent-llm-port.js +1 -0
  296. package/dist/internal/model/llm-client.d.ts +3 -0
  297. package/dist/internal/model/llm-client.js +3 -0
  298. package/dist/internal/model/llm-failure.d.ts +26 -0
  299. package/dist/internal/model/llm-failure.js +63 -0
  300. package/dist/internal/model/llm-mode-routing.d.ts +22 -0
  301. package/dist/internal/model/llm-mode-routing.js +37 -0
  302. package/dist/internal/store/atomic-memory-cutover-sql.d.ts +13 -0
  303. package/dist/internal/store/atomic-memory-cutover-sql.js +237 -0
  304. package/dist/internal/store/connection.d.ts +2 -0
  305. package/dist/internal/store/connection.js +2 -0
  306. package/dist/internal/store/data-bootstrap.d.ts +2 -0
  307. package/dist/internal/store/data-bootstrap.js +2 -0
  308. package/dist/internal/store/data-paths.d.ts +2 -0
  309. package/dist/internal/store/data-paths.js +65 -0
  310. package/dist/internal/store/maintenance.d.ts +75 -0
  311. package/dist/internal/store/maintenance.js +1401 -0
  312. package/dist/internal/store/memory-kinds-cutover-migrator.d.ts +28 -0
  313. package/dist/internal/store/memory-kinds-cutover-migrator.js +415 -0
  314. package/dist/internal/store/migrations.d.ts +27 -0
  315. package/dist/internal/store/migrations.js +201 -0
  316. package/dist/internal/store/sqlite-runtime.d.ts +2 -0
  317. package/dist/internal/store/sqlite-runtime.js +109 -0
  318. package/dist/internal/store/store.d.ts +3 -0
  319. package/dist/internal/store/store.js +2 -0
  320. package/dist/learning-file-maintenance-9b-Ut6Kv.d.ts +30 -0
  321. package/dist/llm-client-B7Xoxqou.js +1378 -0
  322. package/dist/llm-client-DOTSGzhe.d.ts +51 -0
  323. package/dist/locales-JxGmkG6t.d.ts +7 -0
  324. package/dist/log-site-catalog.generated-B9WYdnAM.js +2321 -0
  325. package/dist/log-site-catalog.json +1 -0
  326. package/dist/lru-DyoaTyIs.d.ts +14 -0
  327. package/dist/memdump.d.ts +52 -0
  328. package/dist/memdump.js +163 -0
  329. package/dist/memory-entry-projector-DHo8jH10.js +1015 -0
  330. package/dist/memory-kind-policy-LKt0u3gy.d.ts +23 -0
  331. package/dist/memory-metadata-codec-C3oQd47V.d.ts +68 -0
  332. package/dist/memory-metadata-codec-DL1sbJiN.js +577 -0
  333. package/dist/memory-runtime-BZtREuwW.js +19459 -0
  334. package/dist/memory-scope-policy-1gg5QlWZ.d.ts +67 -0
  335. package/dist/memory-scope-policy-DICSCURA.js +283 -0
  336. package/dist/memory-snapshot-3e44ND2i.d.ts +16 -0
  337. package/dist/memory-source-order-BtrIxaIt.js +134 -0
  338. package/dist/memory-store-base-XRA4S9Xl.d.ts +1095 -0
  339. package/dist/memory-store-shared-DeIDkhLj.js +158 -0
  340. package/dist/memory-store-write-validation-B_hDG2zf.js +243 -0
  341. package/dist/memory-telemetry-incidents-BWA9kcZx.js +8 -0
  342. package/dist/memory-telemetry-metadata-CA7W8tK6.js +77 -0
  343. package/dist/memory-telemetry-outbox-ddTdImt7.d.ts +74 -0
  344. package/dist/memory-telemetry-receipts-MAJecvXQ.d.ts +34 -0
  345. package/dist/memory-telemetry-receipts-YsxbwOAf.js +91 -0
  346. package/dist/memory-telemetry-types-CufVmrCs.d.ts +14 -0
  347. package/dist/memory-temporality-classifier-CEdRTN5J.d.ts +43 -0
  348. package/dist/memory-temporality-classifier-CKiTAHXe.js +184 -0
  349. package/dist/memory-tier-promoter-DbTpahkP.d.ts +43 -0
  350. package/dist/memory-tool-dependencies-CLODycUw.js +19 -0
  351. package/dist/memory-tool-dependencies-N69chrQc.d.ts +14 -0
  352. package/dist/model-call-table-CspopkBg.js +563 -0
  353. package/dist/model-reply-text-CKopStP2.js +334 -0
  354. package/dist/observable-embedder-DQnNgf9O.d.ts +17 -0
  355. package/dist/observable-llm-client-uwqPADpN.d.ts +21 -0
  356. package/dist/observable-memory-store-BaZKbhgq.d.ts +73 -0
  357. package/dist/observable-retriever-Dt_NUxAA.d.ts +23 -0
  358. package/dist/operation-cancellation-CTKWwNHk.js +81 -0
  359. package/dist/paths-qVF-5uBq.d.ts +1 -0
  360. package/dist/plugin-config-schema-C0UUbOmG.d.ts +413 -0
  361. package/dist/plugin-config-schema-YJLyIIcJ.js +361 -0
  362. package/dist/profile-TWPJ_myr.d.ts +13 -0
  363. package/dist/profile-section-writer-hIphqpUY.js +2149 -0
  364. package/dist/provider-registration-CF1tg8Xy.js +721 -0
  365. package/dist/provider-runtime-types-DFhtdA6d.d.ts +134 -0
  366. package/dist/provider-types-CZGm6v88.d.ts +23 -0
  367. package/dist/redact-BTIZcHQL.d.ts +5 -0
  368. package/dist/reflection-command-hooks-BeQiJI9-.js +644 -0
  369. package/dist/reflection-command-hooks-C1Vxgb-O.d.ts +32 -0
  370. package/dist/reflection-deps-RpLPFrSc.d.ts +19 -0
  371. package/dist/reflection-embedded-generator-CDUhgV96.js +130 -0
  372. package/dist/reflection-embedded-generator-CxOex5xK.d.ts +14 -0
  373. package/dist/reflection-injection-hooks-DfUgqu8f.d.ts +43 -0
  374. package/dist/reflection-lifecycle-hooks-Ct5HBdSG.d.ts +27 -0
  375. package/dist/relation-dictionary-Cev1kyLe.js +4248 -0
  376. package/dist/release-download.d.ts +8 -0
  377. package/dist/release-download.js +32 -0
  378. package/dist/relevant-memories-context-m8nuFZcM.js +23 -0
  379. package/dist/rem-batch-executor-Cbm5gfSe.js +31644 -0
  380. package/dist/rem-batch-executor-bc0IFlp2.js +2 -0
  381. package/dist/rem-consumer-retrieval-CRpvG8KS.js +246 -0
  382. package/dist/rem-trigger-BTxkcjgT.js +729 -0
  383. package/dist/resolver-Dy-hnjCR.js +103 -0
  384. package/dist/results-C3ZLroMb.js +140 -0
  385. package/dist/retrieval-gate-Bx2Zg7jD.d.ts +31 -0
  386. package/dist/retriever-CygHBazG.js +1757 -0
  387. package/dist/retriever-Ruk3zp7_.d.ts +469 -0
  388. package/dist/rolldown-runtime-D7D4PA-g.js +13 -0
  389. package/dist/routes-Ce7SQKec.js +59 -0
  390. package/dist/runtime-audit-log-BCeujlEp.js +430 -0
  391. package/dist/runtime-audit-log-zpQiR9HT.d.ts +149 -0
  392. package/dist/scopes-CSOn6zdd.js +71 -0
  393. package/dist/scopes-CtrY-YQ3.d.ts +23 -0
  394. package/dist/server-BPAY4NTG.js +1410 -0
  395. package/dist/session-registry-DBoE7AvZ.d.ts +14 -0
  396. package/dist/sidecar/main.d.ts +1 -0
  397. package/dist/sidecar/main.js +56 -0
  398. package/dist/signed-registry-constants-Bv0fgZ8Q.d.ts +12 -0
  399. package/dist/signed-registry-constants-yq3DlG3B.js +82 -0
  400. package/dist/sno-station-mem-runtime-dependencies-Bu-MiqPX.d.ts +31 -0
  401. package/dist/sno-station-mem-runtime-dependencies-DjLOhB45.js +30 -0
  402. package/dist/sqlite-runtime-L_ywirTm.d.ts +58 -0
  403. package/dist/store-2pM0-dZg.d.ts +27 -0
  404. package/dist/store-DzpZBMEm.js +5830 -0
  405. package/dist/strategy-hook-runner-gBtU47tX.d.ts +16 -0
  406. package/dist/strategy-hook-runner-zmdIYOmQ.js +110 -0
  407. package/dist/token-counter-BD1f48Km.js +73 -0
  408. package/dist/trace-1t1n_wUm.d.ts +86 -0
  409. package/dist/types-DxKqU60b.d.ts +477 -0
  410. package/dist/types-pVomjzqR.d.ts +132 -0
  411. package/dist/unplaced-candidate-migration-CbQHzcEM.js +940 -0
  412. package/dist/utils-Ctb9aevJ.d.ts +34 -0
  413. package/drizzle/0000_initial.sql +10 -0
  414. package/drizzle/0001_virtual_tables.sql +34 -0
  415. package/drizzle/0002_add_indexes.sql +11 -0
  416. package/drizzle/0003_content_hash_lookup_index.sql +2 -0
  417. package/drizzle/0004_chunk_swap.sql +60 -0
  418. package/drizzle/0005_drop_legacy_vec_fts.sql +10 -0
  419. package/drizzle/0006_fts_simple.sql +45 -0
  420. package/drizzle/0007_restore_simple_fts.sql +40 -0
  421. package/drizzle/0008_widen_memory_hash_unique_index.sql +4 -0
  422. package/drizzle/0009_memory_telemetry.sql +109 -0
  423. package/drizzle/0010_provider_mappings.sql +27 -0
  424. package/drizzle/0011_db_optimization.sql +82 -0
  425. package/drizzle/0012_b_profile_lanes.sql +9 -0
  426. package/drizzle/0013_extraction_timestamps.sql +6 -0
  427. package/drizzle/0014_extraction_timestamp_source.sql +3 -0
  428. package/drizzle/0015_task_lifecycle_state.sql +101 -0
  429. package/drizzle/0016_task_lifecycle_legacy_migration.sql +144 -0
  430. package/drizzle/0017_unplaced_candidates.sql +15 -0
  431. package/drizzle/0018_rem_batch_chassis.sql +71 -0
  432. package/drizzle/0019_profile_recovery_entries.sql +17 -0
  433. package/drizzle/0020_rem_scan_retry_progress.down.sql +14 -0
  434. package/drizzle/0020_rem_scan_retry_progress.sql +24 -0
  435. package/drizzle/0021_rem_two_facet_storage.down.sql +14 -0
  436. package/drizzle/0021_rem_two_facet_storage.sql +42 -0
  437. package/drizzle/0022_rem_facet_chunk_versions.down.sql +4 -0
  438. package/drizzle/0022_rem_facet_chunk_versions.sql +4 -0
  439. package/drizzle/0023_rem_defect_ledger.sql +40 -0
  440. package/drizzle/0024_rem_unbuilt_foundations.down.sql +13 -0
  441. package/drizzle/0024_rem_unbuilt_foundations.sql +65 -0
  442. package/drizzle/0025_rem_journal_operation_constraint.sql +28 -0
  443. package/drizzle/0026_rem_journal_detail.sql +1 -0
  444. package/drizzle/0027_legacy_nodix_namespace.sql +3 -0
  445. package/drizzle/0028_memory_timezone.sql +23 -0
  446. package/drizzle/0029_rem_write_hash_symmetry.sql +17 -0
  447. package/drizzle/0030_atomic_memory_additive.sql +105 -0
  448. package/drizzle/0031_atomic_extraction_ledger.sql +23 -0
  449. package/drizzle/0032_atomic_memory_entities.sql +12 -0
  450. package/drizzle/0033_todo_own_store.sql +99 -0
  451. package/drizzle/meta/0000_snapshot.json +87 -0
  452. package/drizzle/meta/_journal.json +244 -0
  453. package/generated/rem-operations.json +1 -0
  454. package/package.json +126 -4
  455. package/scripts/download-simple-tokenizer.mjs +254 -0
  456. package/settings.default.json +243 -0
  457. package/skills/extract-atomic-memory/SKILL.md +298 -0
  458. package/skills/extract-atomic-memory/references/account-for-turns.md +9 -0
  459. package/skills/extract-atomic-memory/references/calendar-meaning.md +64 -0
  460. package/skills/extract-atomic-memory/references/capture.md +120 -0
  461. package/skills/extract-atomic-memory/references/enrichment.md +92 -0
  462. package/skills/extract-atomic-memory/references/missing-durable-half.md +6 -0
  463. package/skills/extract-atomic-memory/references/progress-classification.md +21 -0
  464. package/skills/extract-atomic-memory/references/resolve-subject.md +19 -0
  465. package/skills/extract-atomic-memory/references/surrounding-context.md +10 -0
  466. package/skills/extract-atomic-memory/references/user-subject-guard.md +29 -0
  467. package/skills/judge-group-closure/SKILL.md +25 -0
  468. package/skills/judge-rem-memory-updates/SKILL.md +56 -0
  469. package/skills/judge-rem-memory-updates/agents/openai.yaml +4 -0
  470. package/skills/judge-retired-position/SKILL.md +25 -0
  471. package/skills/judge-task-lifecycle/SKILL.md +45 -0
  472. package/skills/key-state-attribute/SKILL.md +16 -0
  473. package/skills/resolve-entity-identity/SKILL.md +24 -0
  474. package/skills/resolve-relative-time/SKILL.md +22 -0
  475. package/sqlite-extensions/LICENSE-simple-tokenizer +28 -0
  476. package/sqlite-extensions/LICENSE-sqlite-vec +21 -0
  477. package/sqlite-extensions/linux-arm64/vec0.so +0 -0
  478. package/sqlite-extensions/linux-x64/vec0.so +0 -0
@@ -0,0 +1,730 @@
1
+ import { MAX_LIST_LIMIT } from "../../config/index.js";
2
+ import { a as buildInsightMetadata, c as stringifyInsightMetadata, h as deriveFactKey, s as parseInsightMetadata } from "../../../memory-metadata-codec-DL1sbJiN.js";
3
+ import { boundSectionContent, buildIndexedText } from "./extraction-text-sanitizer.js";
4
+ import { i as getActiveSectionRegistry, o as normalizeTopicToSectionName, s as restoreCachedSectionDictionary } from "../../../b-profile-section-dictionary-provider-BHkoNqgk.js";
5
+ import { o as canonicalizeProfileSectionName, r as recordTokenCounter } from "../../../memory-store-write-validation-B_hDG2zf.js";
6
+ import { createLogger } from "@snoai/utils/logger";
7
+ //#region src/engine/extraction/b-profile-section-rekey.ts
8
+ /** @file b-profile-section-rekey.ts
9
+ * @purpose Re-keys fall-through B-profile rows after a section dictionary upgrade.
10
+ * @boundary Deterministic store mutations only; no LLM or network calls.
11
+ */
12
+ const log = createLogger("sno-station-mem:b-profile-section-rekey");
13
+ const GENERAL_SECTION = "preferences.general";
14
+ const MISSING_TOPIC_FLAG = "profile.preference.missing_topic";
15
+ const B_PROFILE_CANONICAL_FORM_REPAIR_VERSION = 1;
16
+ async function runBProfileSectionRekey(args) {
17
+ const registry = getActiveSectionRegistry();
18
+ let cached;
19
+ try {
20
+ cached = await args.cache.read();
21
+ } catch (error) {
22
+ log.warn("section dictionary cache rejected during re-key; treating it as absent", { error }, {
23
+ event_name: "sno_station_mem.b-profile-section-rekey.section.dictionary.cache.rejected.during.re.key.treating.it.as.absent",
24
+ file: "packages/memory/src/engine/extraction/b-profile-section-rekey.ts",
25
+ function: "runBProfileSectionRekey",
26
+ site_id: "b-profile-section-rekey.runBProfileSectionRekey.b452a7657e"
27
+ });
28
+ cached = void 0;
29
+ }
30
+ const registryRepairPending = cached?.appliedSchemaVersion !== registry.schema_version;
31
+ const canonicalRepairPending = cached?.canonicalFormRepairVersion !== 1;
32
+ if (!registryRepairPending && !canonicalRepairPending) {
33
+ const empty = emptyReport();
34
+ return {
35
+ dryRun: empty,
36
+ applied: empty,
37
+ skippedByVersion: true
38
+ };
39
+ }
40
+ let dryRun = emptyReport();
41
+ let applied = emptyReport();
42
+ if (canonicalRepairPending) {
43
+ const plan = await buildCanonicalRepairPlan(args.store, args.projectIdFilter);
44
+ log.info("B-profile canonical-form repair dry run", plan.report, {
45
+ event_name: "sno_station_mem.b-profile-section-rekey.b.profile.canonical.form.repair.dry.run",
46
+ file: "packages/memory/src/engine/extraction/b-profile-section-rekey.ts",
47
+ function: "runBProfileSectionRekey",
48
+ site_id: "b-profile-section-rekey.runBProfileSectionRekey.4494531e35"
49
+ });
50
+ assertCanonicalPlanReconciles(plan);
51
+ const canonicalApplied = await applyCanonicalRepairPlan(args.store, plan);
52
+ if (!reportsEqual(plan.report, canonicalApplied)) {
53
+ log.error("B-profile canonical-form repair reconciliation failed", {
54
+ dryRun: plan.report,
55
+ applied: canonicalApplied
56
+ }, {
57
+ event_name: "sno_station_mem.b-profile-section-rekey.b.profile.canonical.form.repair.reconciliation.failed",
58
+ file: "packages/memory/src/engine/extraction/b-profile-section-rekey.ts",
59
+ function: "runBProfileSectionRekey",
60
+ site_id: "b-profile-section-rekey.runBProfileSectionRekey.5276d7dfea"
61
+ });
62
+ throw new Error("B-profile canonical-form repair applied counts diverged from dry run");
63
+ }
64
+ dryRun = combineReports(dryRun, plan.report);
65
+ applied = combineReports(applied, canonicalApplied);
66
+ }
67
+ if (registryRepairPending || canonicalRepairPending) {
68
+ const plan = await buildRekeyPlan(args.store, args.projectIdFilter);
69
+ log.info("B-profile section re-key dry run", plan.report, {
70
+ event_name: "sno_station_mem.b-profile-section-rekey.b.profile.section.re.key.dry.run",
71
+ file: "packages/memory/src/engine/extraction/b-profile-section-rekey.ts",
72
+ function: "runBProfileSectionRekey",
73
+ site_id: "b-profile-section-rekey.runBProfileSectionRekey.1acb6c65f8"
74
+ });
75
+ assertPlanReconciles(plan.report);
76
+ const registryApplied = await applyRekeyPlan(args.store, plan);
77
+ if (!reportsEqual(plan.report, registryApplied)) {
78
+ log.error("B-profile section re-key reconciliation failed", {
79
+ dryRun: plan.report,
80
+ applied: registryApplied
81
+ }, {
82
+ event_name: "sno_station_mem.b-profile-section-rekey.b.profile.section.re.key.reconciliation.failed",
83
+ file: "packages/memory/src/engine/extraction/b-profile-section-rekey.ts",
84
+ function: "runBProfileSectionRekey",
85
+ site_id: "b-profile-section-rekey.runBProfileSectionRekey.d8bb76de51"
86
+ });
87
+ throw new Error("B-profile section re-key applied counts diverged from dry run");
88
+ }
89
+ dryRun = combineReports(dryRun, plan.report);
90
+ applied = combineReports(applied, registryApplied);
91
+ }
92
+ if (args.projectIdFilter === void 0) await args.cache.write({
93
+ activeRegistry: registry,
94
+ ...cached?.fetchedForPluginVersion === void 0 ? {} : { fetchedForPluginVersion: cached.fetchedForPluginVersion },
95
+ appliedSchemaVersion: registry.schema_version,
96
+ canonicalFormRepairVersion: 1
97
+ });
98
+ log.info("B-profile section re-key applied", applied, {
99
+ event_name: "sno_station_mem.b-profile-section-rekey.b.profile.section.re.key.applied",
100
+ file: "packages/memory/src/engine/extraction/b-profile-section-rekey.ts",
101
+ function: "runBProfileSectionRekey",
102
+ site_id: "b-profile-section-rekey.runBProfileSectionRekey.ce06a215a3"
103
+ });
104
+ return {
105
+ dryRun,
106
+ applied,
107
+ skippedByVersion: false
108
+ };
109
+ }
110
+ function scheduleBProfileSectionRekey(args) {
111
+ (async () => {
112
+ await restoreCachedSectionDictionary({
113
+ mode: args.mode,
114
+ cache: args.cache
115
+ });
116
+ await runBProfileSectionRekey({
117
+ store: args.store,
118
+ cache: args.cache
119
+ });
120
+ })().catch((error) => {
121
+ log.error("detached B-profile section re-key failed", { error }, {
122
+ event_name: "sno_station_mem.b-profile-section-rekey.detached.b.profile.section.re.key.failed",
123
+ file: "packages/memory/src/engine/extraction/b-profile-section-rekey.ts",
124
+ function: "<anonymous callback>",
125
+ site_id: "b-profile-section-rekey.<anonymous callback>.9cc8218e54"
126
+ });
127
+ });
128
+ }
129
+ async function buildCanonicalRepairPlan(store, projectIdFilter) {
130
+ const activeRows = (await listAllProfileRows(store, projectIdFilter)).map((row) => parseRow(row)).filter((row) => row !== void 0).sort(compareRows).filter((row) => row.metadata.invalidated_at === void 0 && isCanonicalRepairEligible(row.metadata));
131
+ const report = emptyReport();
132
+ report.sourceRows = activeRows.length;
133
+ const groups = /* @__PURE__ */ new Map();
134
+ for (const row of activeRows) {
135
+ const sectionName = canonicalRepairTargetSection(row);
136
+ const groupKey = `${row.entry.projectId}\u0000${sectionName}`;
137
+ const group = groups.get(groupKey);
138
+ if (group) group.rows.push(row);
139
+ else groups.set(groupKey, {
140
+ sectionName,
141
+ rows: [row]
142
+ });
143
+ }
144
+ Object.assign(report, measureSplitGroups(activeRows));
145
+ const actions = [];
146
+ let finalCount = activeRows.length;
147
+ for (const group of groups.values()) {
148
+ const actionRows = group.rows.length === 1 ? group.rows : group.rows.filter((row) => {
149
+ if (canonicalizeProfileSectionName(row.sectionName) === GENERAL_SECTION && group.sectionName !== GENERAL_SECTION && !hasMergeablePreferenceClause(row.metadata.l2_content)) {
150
+ report.unchanged += 1;
151
+ return false;
152
+ }
153
+ return true;
154
+ });
155
+ if (actionRows.length === 1) {
156
+ const source = actionRows[0];
157
+ if (!source) continue;
158
+ if (source.sectionName === group.sectionName) {
159
+ report.unchanged += 1;
160
+ continue;
161
+ }
162
+ actions.push({
163
+ kind: "migrate",
164
+ sources: [source.entry],
165
+ newSection: group.sectionName
166
+ });
167
+ report.migrated += 1;
168
+ report.targetKeys += 1;
169
+ continue;
170
+ }
171
+ if (actionRows.length === 0) continue;
172
+ actions.push({
173
+ kind: "merge",
174
+ sources: actionRows.map((row) => row.entry),
175
+ newSection: group.sectionName
176
+ });
177
+ report.collisions += 1;
178
+ report.merged += 1;
179
+ report.targetKeys += 1;
180
+ finalCount -= actionRows.length - 1;
181
+ }
182
+ report.finalCount = finalCount;
183
+ return {
184
+ report,
185
+ actions,
186
+ projectIdFilter
187
+ };
188
+ }
189
+ async function applyCanonicalRepairPlan(store, plan) {
190
+ if (plan.actions.length === 0) return plan.report;
191
+ for (const action of plan.actions) {
192
+ const sources = action.sources.map((planned) => {
193
+ const current = store.getById(planned.id);
194
+ if (!current || current.contentHash !== planned.contentHash || current.metadata !== planned.metadata) throw new Error("B-profile canonical-form repair source changed after dry run");
195
+ const metadata = parseInsightMetadata(current.metadata, current);
196
+ if (typeof metadata.section_name !== "string" || metadata.invalidated_at !== void 0 || !isCanonicalRepairEligible(metadata) || canonicalRepairTargetSection({
197
+ metadata,
198
+ sectionName: metadata.section_name
199
+ }) !== action.newSection) throw new Error("B-profile canonical-form repair source no longer matches its plan");
200
+ return current;
201
+ });
202
+ if (action.kind === "migrate") {
203
+ const source = sources[0];
204
+ if (!source) throw new Error("B-profile canonical-form repair migration source missing");
205
+ await rekeyInPlace(store, source, action.newSection, action.newSection !== GENERAL_SECTION);
206
+ } else await mergeCanonicalCollision(store, sources, action.newSection);
207
+ }
208
+ const finalCount = (await listAllProfileRows(store, plan.projectIdFilter)).filter((row) => {
209
+ const parsed = parseRow(row);
210
+ if (!parsed) return false;
211
+ return parsed.metadata.invalidated_at === void 0 && isCanonicalRepairEligible(parsed.metadata);
212
+ }).length;
213
+ return {
214
+ ...plan.report,
215
+ finalCount
216
+ };
217
+ }
218
+ function canonicalRepairTargetSection(row) {
219
+ const canonicalSection = canonicalizeProfileSectionName(row.sectionName);
220
+ if (canonicalSection !== GENERAL_SECTION) return canonicalSection;
221
+ const rawTopicPhrase = row.metadata.rawTopicPhrase;
222
+ if (typeof rawTopicPhrase !== "string" || rawTopicPhrase.trim().length === 0) return canonicalSection;
223
+ return normalizeTopicToSectionName(rawTopicPhrase);
224
+ }
225
+ function isCanonicalRepairEligible(metadata) {
226
+ return metadata.active_task_kind !== "task" && metadata.active_task_kind !== "projection";
227
+ }
228
+ function measureSplitGroups(laneActiveRows) {
229
+ const rawSections = new Set(laneActiveRows.map((row) => row.sectionName));
230
+ const sectionsByForm = /* @__PURE__ */ new Map();
231
+ const sectionsByTopic = /* @__PURE__ */ new Map();
232
+ for (const section of rawSections) {
233
+ const form = normalizeSplitMeasurementKey(section);
234
+ const matchingForms = sectionsByForm.get(form) ?? /* @__PURE__ */ new Set();
235
+ matchingForms.add(section);
236
+ sectionsByForm.set(form, matchingForms);
237
+ const separator = section.indexOf(".");
238
+ if (separator < 0) continue;
239
+ const topic = normalizeSplitMeasurementKey(section.slice(separator + 1));
240
+ const matchingTopics = sectionsByTopic.get(topic) ?? /* @__PURE__ */ new Set();
241
+ matchingTopics.add(section);
242
+ sectionsByTopic.set(topic, matchingTopics);
243
+ }
244
+ const separatorSplitGroups = Array.from(sectionsByForm.values()).filter((sections) => sections.size > 1).length;
245
+ const domainPrefixSplitGroups = Array.from(sectionsByTopic.values()).filter((sections) => {
246
+ return new Set(Array.from(sections, (section) => section.slice(0, section.indexOf(".")))).size > 1;
247
+ }).length;
248
+ const canonicalSections = new Set(laneActiveRows.map((row) => canonicalizeProfileSectionName(row.sectionName)));
249
+ const crossPathPairs = /* @__PURE__ */ new Set();
250
+ for (const row of laneActiveRows) {
251
+ const section = canonicalizeProfileSectionName(row.sectionName);
252
+ if (!section.startsWith("preferences.")) continue;
253
+ const candidates = [section.slice(12), ...typeof row.metadata.rawTopicPhrase === "string" ? [row.metadata.rawTopicPhrase] : []];
254
+ for (const candidate of candidates) {
255
+ const registrySection = normalizeTopicToSectionName(candidate);
256
+ if (registrySection === GENERAL_SECTION || registrySection === section || !canonicalSections.has(registrySection)) continue;
257
+ crossPathPairs.add([section, registrySection].sort().join("\0"));
258
+ }
259
+ }
260
+ return {
261
+ separatorSplitGroups,
262
+ domainPrefixSplitGroups,
263
+ crossPathSplitGroups: crossPathPairs.size
264
+ };
265
+ }
266
+ function normalizeSplitMeasurementKey(value) {
267
+ return value.normalize("NFKC").toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
268
+ }
269
+ async function mergeCanonicalCollision(store, sources, newSection) {
270
+ const sourceMetadata = sources.map((source) => parseInsightMetadata(source.metadata, source));
271
+ const targetFactKey = deriveFactKey({
272
+ kind: "profile",
273
+ section_name: newSection
274
+ });
275
+ if (!targetFactKey) throw new Error(`B-profile canonical-form repair target '${newSection}' is invalid`);
276
+ const activeFactGuard = {
277
+ factKey: targetFactKey,
278
+ expectedIds: sources.filter((_, index) => sourceMetadata[index]?.fact_key === targetFactKey).map((source) => source.id)
279
+ };
280
+ const mergedContent = combineUniquePreferenceClauses(...sourceMetadata.map((metadata) => metadata.l2_content));
281
+ const at = Math.max(Date.now(), ...sources.map((source) => source.timestamp));
282
+ const mergedClauseKeys = new Set(splitPreferenceClauses(mergedContent).map(normalizeClause).filter(Boolean));
283
+ let exactTargetIndex = -1;
284
+ let exactAliasTargetIndex = -1;
285
+ for (let index = sourceMetadata.length - 1; index >= 0; index -= 1) {
286
+ const metadata = sourceMetadata[index];
287
+ if (!metadata) continue;
288
+ const targetClauseKeys = new Set(splitPreferenceClauses(metadata.l2_content).map(normalizeClause).filter(Boolean));
289
+ if (!(targetClauseKeys.size === mergedClauseKeys.size && Array.from(targetClauseKeys).every((clause) => mergedClauseKeys.has(clause)))) continue;
290
+ if (metadata.section_name === newSection) {
291
+ exactTargetIndex = index;
292
+ break;
293
+ }
294
+ if (exactAliasTargetIndex < 0) exactAliasTargetIndex = index;
295
+ }
296
+ if (exactTargetIndex < 0) exactTargetIndex = exactAliasTargetIndex;
297
+ if (exactTargetIndex >= 0) {
298
+ const target = sources[exactTargetIndex];
299
+ if (!target) throw new Error("B-profile canonical-form repair exact target disappeared");
300
+ const targetMetadata = sourceMetadata[exactTargetIndex];
301
+ if (!targetMetadata) throw new Error("B-profile canonical-form repair exact target metadata disappeared");
302
+ const finalTargetMetadata = targetMetadata.section_name === newSection ? target.metadata : metadataForSection(target, newSection);
303
+ if ((await store.supersede({
304
+ create: {
305
+ text: target.text,
306
+ category: target.category,
307
+ projectId: target.projectId,
308
+ importance: target.importance,
309
+ timestamp: target.timestamp,
310
+ metadata: finalTargetMetadata,
311
+ trusted: true
312
+ },
313
+ activeFactGuard,
314
+ preserveExisting: {
315
+ id: target.id,
316
+ expectedContentHash: target.contentHash,
317
+ expectedMetadata: target.metadata
318
+ },
319
+ closes: sources.filter((source) => source.id !== target.id).map((source) => ({
320
+ id: source.id,
321
+ expectedContentHash: source.contentHash,
322
+ expectedMetadata: source.metadata,
323
+ buildMetadata: (createdId) => closedMetadata(source, createdId, at, newSection, true)
324
+ }))
325
+ })).id !== target.id) throw new Error("B-profile canonical-form repair exact target was not preserved");
326
+ return;
327
+ }
328
+ const target = sources[0];
329
+ if (!target) throw new Error("B-profile canonical-form repair collision has no rows");
330
+ const targetMetadata = sourceMetadata[0];
331
+ if (!targetMetadata) throw new Error("B-profile canonical-form repair target metadata missing");
332
+ const abstract = firstSentence(mergedContent);
333
+ const boundedContent = boundSectionContent(mergedContent, abstract, await recordTokenCounter(store.embedder));
334
+ const replacementMetadata = buildInsightMetadata({
335
+ text: boundedContent,
336
+ category: "profile",
337
+ timestamp: at
338
+ }, {
339
+ ...metadataForMergeProduct(targetMetadata),
340
+ l0_abstract: abstract,
341
+ l1_overview: boundedContent,
342
+ l2_content: boundedContent,
343
+ section_name: newSection,
344
+ supersedes: target.id,
345
+ valid_from: at,
346
+ asserted_at: at
347
+ });
348
+ await store.supersede({
349
+ create: {
350
+ text: buildIndexedText(abstract, boundedContent),
351
+ category: "profile",
352
+ projectId: target.projectId,
353
+ importance: Math.max(...sources.map((source) => source.importance)),
354
+ timestamp: at,
355
+ metadata: stringifyInsightMetadata(replacementMetadata),
356
+ trusted: true
357
+ },
358
+ activeFactGuard,
359
+ closes: sources.map((source) => ({
360
+ id: source.id,
361
+ expectedContentHash: source.contentHash,
362
+ expectedMetadata: source.metadata,
363
+ buildMetadata: (createdId) => closedMetadata(source, createdId, at, newSection, true)
364
+ }))
365
+ });
366
+ }
367
+ async function buildRekeyPlan(store, projectIdFilter) {
368
+ const activeRows = (await listAllProfileRows(store, projectIdFilter)).map((row) => parseRow(row)).filter((row) => row !== void 0).filter((row) => row.metadata.invalidated_at === void 0);
369
+ const sources = activeRows.filter((row) => row.metadata.section_name === GENERAL_SECTION).sort(compareRows).map((row) => row.entry);
370
+ const report = emptyReport();
371
+ report.sourceRows = sources.length;
372
+ const actions = [];
373
+ const plannedTargets = /* @__PURE__ */ new Set();
374
+ const targetKeys = /* @__PURE__ */ new Set();
375
+ for (const source of sources) {
376
+ const metadata = parseInsightMetadata(source.metadata, source);
377
+ const rawTopicPhrase = metadata.rawTopicPhrase;
378
+ if (typeof rawTopicPhrase !== "string" || !rawTopicPhrase.trim()) {
379
+ report.missingRawPhrase += 1;
380
+ continue;
381
+ }
382
+ const newSection = normalizeTopicToSectionName(rawTopicPhrase);
383
+ if (newSection === GENERAL_SECTION || newSection === metadata.section_name) {
384
+ report.unchanged += 1;
385
+ continue;
386
+ }
387
+ const targetFactKey = deriveFactKey({
388
+ kind: "profile",
389
+ section_name: newSection
390
+ });
391
+ if (!targetFactKey) {
392
+ report.rejected += 1;
393
+ continue;
394
+ }
395
+ const planKey = `${source.projectId}\u0000${targetFactKey}`;
396
+ targetKeys.add(planKey);
397
+ const existingTarget = store.getByFactKey(source.projectId, targetFactKey);
398
+ if (existingTarget) try {
399
+ parseInsightMetadata(existingTarget.metadata, existingTarget);
400
+ } catch {
401
+ report.rejected += 1;
402
+ continue;
403
+ }
404
+ const kind = existingTarget || plannedTargets.has(planKey) ? "merge" : "migrate";
405
+ if (kind === "merge" && !hasMergeablePreferenceClause(metadata.l2_content)) {
406
+ report.rejected += 1;
407
+ continue;
408
+ }
409
+ actions.push({
410
+ kind,
411
+ source,
412
+ targetFactKey,
413
+ newSection
414
+ });
415
+ plannedTargets.add(planKey);
416
+ if (kind === "merge") {
417
+ report.collisions += 1;
418
+ report.merged += 1;
419
+ } else report.migrated += 1;
420
+ }
421
+ report.targetKeys = targetKeys.size;
422
+ report.finalCount = activeRows.length - report.merged;
423
+ return {
424
+ report,
425
+ actions,
426
+ projectIdFilter
427
+ };
428
+ }
429
+ async function applyRekeyPlan(store, plan) {
430
+ if (plan.actions.length === 0) return plan.report;
431
+ let migrated = 0;
432
+ let merged = 0;
433
+ for (const action of plan.actions) {
434
+ const source = store.getById(action.source.id);
435
+ if (!source || source.contentHash !== action.source.contentHash || source.metadata !== action.source.metadata || !sourceStillMatchesPlan(source, action.newSection)) throwReconciliationError("source row changed after dry run", action);
436
+ const target = store.getByFactKey(source.projectId, action.targetFactKey);
437
+ if (action.kind === "migrate") {
438
+ if (target) throwReconciliationError("unexpected target appeared after dry run", action);
439
+ await rekeyInPlace(store, source, action.newSection);
440
+ migrated += 1;
441
+ continue;
442
+ }
443
+ if (!target) throwReconciliationError("expected collision target disappeared", action);
444
+ await mergeCollision(store, source, target, action.newSection);
445
+ merged += 1;
446
+ }
447
+ const finalCount = (await listAllProfileRows(store, plan.projectIdFilter)).filter((row) => {
448
+ return parseRow(row)?.metadata.invalidated_at === void 0;
449
+ }).length;
450
+ return {
451
+ ...plan.report,
452
+ migrated,
453
+ merged,
454
+ collisions: merged,
455
+ finalCount
456
+ };
457
+ }
458
+ async function rekeyInPlace(store, source, newSection, expectTargetAbsent = true) {
459
+ const targetFactKey = deriveFactKey({
460
+ kind: "profile",
461
+ section_name: newSection
462
+ });
463
+ if (!targetFactKey) throw new Error(`B-profile section re-key target '${newSection}' is invalid`);
464
+ if (!await store.update(source.id, {
465
+ writerAuthority: "profile-writer",
466
+ metadata: metadataForSection(source, newSection),
467
+ expectedContentHash: source.contentHash,
468
+ expectedMetadata: source.metadata,
469
+ ...expectTargetAbsent ? { expectedAbsentFactKey: targetFactKey } : {}
470
+ })) throw new Error(`B-profile section re-key source '${source.id}' disappeared`);
471
+ }
472
+ function metadataForSection(source, newSection) {
473
+ const nextMetadata = { ...buildInsightMetadata(source, {
474
+ ...parseInsightMetadata(source.metadata, source),
475
+ section_name: newSection
476
+ }) };
477
+ delete nextMetadata[MISSING_TOPIC_FLAG];
478
+ return stringifyInsightMetadata(nextMetadata);
479
+ }
480
+ async function mergeCollision(store, source, target, newSection) {
481
+ const sourceMetadata = parseInsightMetadata(source.metadata, source);
482
+ const targetMetadata = parseInsightMetadata(target.metadata, target);
483
+ const sourceContent = sourceMetadata.l2_content;
484
+ const targetContent = targetMetadata.l2_content;
485
+ const normalizedTargetContent = combineUniquePreferenceClauses(targetContent);
486
+ const mergedContent = combineUniquePreferenceClauses(targetContent, sourceContent);
487
+ const at = Math.max(Date.now(), source.timestamp, target.timestamp);
488
+ if (mergedContent === normalizedTargetContent) {
489
+ const targetFactKey = deriveFactKey({
490
+ kind: "profile",
491
+ section_name: newSection
492
+ });
493
+ if (!targetFactKey) throw new Error(`B-profile section re-key target '${newSection}' is invalid`);
494
+ if ((await store.supersede({
495
+ create: {
496
+ text: target.text,
497
+ category: target.category,
498
+ projectId: target.projectId,
499
+ importance: target.importance,
500
+ timestamp: target.timestamp,
501
+ metadata: target.metadata,
502
+ trusted: true
503
+ },
504
+ closes: [closeSource(source, newSection, at)],
505
+ activeFactGuard: {
506
+ factKey: targetFactKey,
507
+ expectedId: target.id
508
+ },
509
+ preserveExisting: {
510
+ id: target.id,
511
+ expectedContentHash: target.contentHash,
512
+ expectedMetadata: target.metadata
513
+ }
514
+ })).id !== target.id) throw new Error("B-profile section re-key exact target was not preserved");
515
+ return;
516
+ }
517
+ const abstract = firstSentence(mergedContent);
518
+ const boundedContent = boundSectionContent(mergedContent, abstract, await recordTokenCounter(store.embedder));
519
+ const replacementMetadata = buildInsightMetadata({
520
+ text: boundedContent,
521
+ category: "profile",
522
+ timestamp: at
523
+ }, {
524
+ ...metadataForMergeProduct(targetMetadata),
525
+ l0_abstract: abstract,
526
+ l1_overview: boundedContent,
527
+ l2_content: boundedContent,
528
+ section_name: newSection,
529
+ supersedes: target.id,
530
+ valid_from: at,
531
+ asserted_at: at
532
+ });
533
+ await store.supersede({
534
+ create: {
535
+ text: buildIndexedText(abstract, boundedContent),
536
+ category: "profile",
537
+ projectId: target.projectId,
538
+ importance: Math.max(source.importance, target.importance),
539
+ timestamp: at,
540
+ metadata: stringifyInsightMetadata(replacementMetadata),
541
+ trusted: true
542
+ },
543
+ closes: [closeTarget(target, at), closeSource(source, newSection, at)]
544
+ });
545
+ }
546
+ function metadataForMergeProduct(metadata) {
547
+ const product = { ...metadata };
548
+ delete product.idempotency_key;
549
+ delete product.merge_lineage;
550
+ delete product.mappedKind;
551
+ if (product.source === "agent_end") for (const key of [
552
+ "source",
553
+ "role",
554
+ "session_key",
555
+ "session_id",
556
+ "chunk_index",
557
+ "chunk_count",
558
+ "chunking_version",
559
+ "content_type"
560
+ ]) delete product[key];
561
+ return product;
562
+ }
563
+ function closeSource(source, newSection, at) {
564
+ return {
565
+ id: source.id,
566
+ expectedContentHash: source.contentHash,
567
+ expectedMetadata: source.metadata,
568
+ buildMetadata: (createdId) => closedMetadata(source, createdId, at, newSection, true)
569
+ };
570
+ }
571
+ function closeTarget(target, at) {
572
+ return {
573
+ id: target.id,
574
+ expectedContentHash: target.contentHash,
575
+ expectedMetadata: target.metadata,
576
+ buildMetadata: (createdId) => closedMetadata(target, createdId, at, void 0, false)
577
+ };
578
+ }
579
+ function closedMetadata(row, createdId, at, sectionName, dropMissingTopicFlag) {
580
+ const current = parseInsightMetadata(row.metadata, row);
581
+ const nextMetadata = { ...buildInsightMetadata(row, {
582
+ ...current,
583
+ ...sectionName ? { section_name: sectionName } : {},
584
+ invalidated_at: current.valid_from === void 0 ? at : Math.max(at, current.valid_from),
585
+ superseded_by: createdId
586
+ }) };
587
+ if (dropMissingTopicFlag) delete nextMetadata[MISSING_TOPIC_FLAG];
588
+ return stringifyInsightMetadata(nextMetadata);
589
+ }
590
+ function parseRow(entry) {
591
+ try {
592
+ const metadata = parseInsightMetadata(entry.metadata, entry);
593
+ if (typeof metadata.section_name !== "string") return void 0;
594
+ return {
595
+ entry,
596
+ metadata,
597
+ sectionName: metadata.section_name
598
+ };
599
+ } catch {
600
+ return;
601
+ }
602
+ }
603
+ async function listAllProfileRows(store, projectIdFilter) {
604
+ const rows = [];
605
+ for (let offset = 0;; offset += MAX_LIST_LIMIT) {
606
+ const page = await store.list({
607
+ category: "profile",
608
+ limit: MAX_LIST_LIMIT,
609
+ offset,
610
+ ...projectIdFilter === void 0 ? {} : { projectIdFilter }
611
+ });
612
+ if (page.length === 0) return rows;
613
+ rows.push(...page);
614
+ }
615
+ }
616
+ function sourceStillMatchesPlan(source, newSection) {
617
+ const metadata = parseInsightMetadata(source.metadata, source);
618
+ const rawTopicPhrase = metadata.rawTopicPhrase;
619
+ return metadata.invalidated_at === void 0 && metadata.section_name === GENERAL_SECTION && typeof rawTopicPhrase === "string" && normalizeTopicToSectionName(rawTopicPhrase) === newSection;
620
+ }
621
+ function assertPlanReconciles(report) {
622
+ if (report.migrated + report.merged + report.rejected + report.missingRawPhrase + report.unchanged === report.sourceRows) return;
623
+ log.error("B-profile section re-key dry-run counts do not reconcile", report, {
624
+ event_name: "sno_station_mem.b-profile-section-rekey.b.profile.section.re.key.dry.run.counts.do.not.reconcile",
625
+ file: "packages/memory/src/engine/extraction/b-profile-section-rekey.ts",
626
+ function: "assertPlanReconciles",
627
+ site_id: "b-profile-section-rekey.assertPlanReconciles.03748b5c20"
628
+ });
629
+ throw new Error("B-profile section re-key dry-run counts do not reconcile");
630
+ }
631
+ function assertCanonicalPlanReconciles(plan) {
632
+ if (plan.actions.reduce((count, action) => count + action.sources.length, 0) + plan.report.unchanged === plan.report.sourceRows) return;
633
+ log.error("B-profile canonical-form repair dry-run counts do not reconcile", plan.report, {
634
+ event_name: "sno_station_mem.b-profile-section-rekey.b.profile.canonical.form.repair.dry.run.counts.do.not.reconcile",
635
+ file: "packages/memory/src/engine/extraction/b-profile-section-rekey.ts",
636
+ function: "assertCanonicalPlanReconciles",
637
+ site_id: "b-profile-section-rekey.assertCanonicalPlanReconciles.2ad72089d1"
638
+ });
639
+ throw new Error("B-profile canonical-form repair dry-run counts do not reconcile");
640
+ }
641
+ function throwReconciliationError(reason, action) {
642
+ log.error("B-profile section re-key aborted after dry-run divergence", {
643
+ reason_code: reason.replace(/[^a-z0-9]+/gi, "_").toLowerCase(),
644
+ memory_id: action.source.id,
645
+ projectId: action.source.projectId,
646
+ targetFactKey: action.targetFactKey
647
+ }, {
648
+ event_name: "sno_station_mem.b-profile-section-rekey.b.profile.section.re.key.aborted.after.dry.run.divergence",
649
+ file: "packages/memory/src/engine/extraction/b-profile-section-rekey.ts",
650
+ function: "throwReconciliationError",
651
+ site_id: "b-profile-section-rekey.throwReconciliationError.b59b599311"
652
+ });
653
+ throw new Error(`B-profile section re-key aborted: ${reason}`);
654
+ }
655
+ function reportsEqual(left, right) {
656
+ return JSON.stringify(left) === JSON.stringify(right);
657
+ }
658
+ function combineReports(left, right) {
659
+ return {
660
+ sourceRows: Math.max(left.sourceRows, right.sourceRows),
661
+ targetKeys: left.targetKeys + right.targetKeys,
662
+ collisions: left.collisions + right.collisions,
663
+ migrated: left.migrated + right.migrated,
664
+ merged: left.merged + right.merged,
665
+ rejected: left.rejected + right.rejected,
666
+ missingRawPhrase: left.missingRawPhrase + right.missingRawPhrase,
667
+ unchanged: left.unchanged + right.unchanged,
668
+ finalCount: right.finalCount,
669
+ separatorSplitGroups: left.separatorSplitGroups + right.separatorSplitGroups,
670
+ domainPrefixSplitGroups: left.domainPrefixSplitGroups + right.domainPrefixSplitGroups,
671
+ crossPathSplitGroups: left.crossPathSplitGroups + right.crossPathSplitGroups
672
+ };
673
+ }
674
+ function emptyReport() {
675
+ return {
676
+ sourceRows: 0,
677
+ targetKeys: 0,
678
+ collisions: 0,
679
+ migrated: 0,
680
+ merged: 0,
681
+ rejected: 0,
682
+ missingRawPhrase: 0,
683
+ unchanged: 0,
684
+ finalCount: 0,
685
+ separatorSplitGroups: 0,
686
+ domainPrefixSplitGroups: 0,
687
+ crossPathSplitGroups: 0
688
+ };
689
+ }
690
+ function compareRows(left, right) {
691
+ return left.entry.projectId.localeCompare(right.entry.projectId) || left.entry.timestamp - right.entry.timestamp || left.entry.id.localeCompare(right.entry.id);
692
+ }
693
+ function combineUniquePreferenceClauses(...texts) {
694
+ const seen = /* @__PURE__ */ new Set();
695
+ const clauses = [];
696
+ for (const text of texts) for (const clause of splitPreferenceClauses(text)) {
697
+ const key = normalizeClause(clause);
698
+ if (!key || seen.has(key)) continue;
699
+ seen.add(key);
700
+ clauses.push(clause);
701
+ }
702
+ return clauses.join("\n");
703
+ }
704
+ function hasMergeablePreferenceClause(text) {
705
+ return splitPreferenceClauses(text).some((clause) => normalizeClause(clause).length > 0);
706
+ }
707
+ function splitPreferenceClauses(text) {
708
+ return text.split(/\n+|(?<=[.!?])\s+/).map((item) => item.trim()).filter(Boolean);
709
+ }
710
+ /**
711
+ * Clause identity for dedup and for the exact-match check that decides which row survives a
712
+ * merge. Case, Unicode form and whitespace do not change what a clause says, so they are
713
+ * normalized away — and nothing else is.
714
+ *
715
+ * This used to delete every non-alphanumeric character, which merged clauses stating different
716
+ * facts: "I use C." and "I use C++." both became "i use c", so one of the two preferences was
717
+ * closed as a duplicate of the other and the count check still passed. Every symbol that
718
+ * distinguishes a name — `+`, `#`, `/`, `.` inside a word — is meaning, not formatting.
719
+ * A trailing sentence terminator is not, so the same clause with and without its full stop
720
+ * stays one clause.
721
+ */
722
+ function normalizeClause(text) {
723
+ const normalized = text.normalize("NFKC").toLowerCase().replace(/\s+/g, " ").trim().replace(/[.!?]+$/u, "").trim();
724
+ return /[\p{L}\p{N}]/u.test(normalized) ? normalized : "";
725
+ }
726
+ function firstSentence(text) {
727
+ return text.split(/(?<=[.!?])\s+/)[0]?.trim() || text;
728
+ }
729
+ //#endregion
730
+ export { B_PROFILE_CANONICAL_FORM_REPAIR_VERSION, applyRekeyPlan, runBProfileSectionRekey, scheduleBProfileSectionRekey };