@snoai/memory 0.0.0-stage → 1.0.1

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 +33 -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-BbEvEocb.d.ts +110 -0
  64. package/dist/adapter-B7Jox9-6.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-C5rmogoY.js +3605 -0
  74. package/dist/atomic-memory-extraction-d9EG-4ti.d.ts +327 -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-CxbHPkMX.d.ts +53 -0
  80. package/dist/capture-policy-detector-DaMfy9CZ.js +357 -0
  81. package/dist/classifier-DnbbtwTS.d.ts +272 -0
  82. package/dist/client.d.ts +34 -0
  83. package/dist/client.js +306 -0
  84. package/dist/coding-skin.d.ts +51 -0
  85. package/dist/coding-skin.js +55 -0
  86. package/dist/config-CL90qYva.js +2576 -0
  87. package/dist/connection-3IVXpuPE.d.ts +391 -0
  88. package/dist/connection-C9YD5sgm.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-Bl3lthzE.d.ts +30 -0
  93. package/dist/data-bootstrap-P8sie9WA.js +172 -0
  94. package/dist/data-paths-C7sNdqvP.d.ts +22 -0
  95. package/dist/derived-suppression-cache-CI0durYx.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-0aqS8pVF.d.ts +351 -0
  108. package/dist/index-BO4RU_mc.d.ts +650 -0
  109. package/dist/index-DL8AVj0Z.d.ts +571 -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 +62 -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 +36 -0
  168. package/dist/internal/engine/bindings/sno-station-mem-runtime-mode.js +104 -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-BSYUAcUb.js +1374 -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-BMKWj-Nx.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-BiuRjSJc.d.ts +23 -0
  331. package/dist/memory-metadata-codec-DL1sbJiN.js +577 -0
  332. package/dist/memory-metadata-codec-DUvsYe_X.d.ts +68 -0
  333. package/dist/memory-runtime-DqUS4cWi.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-CqY1BUUA.d.ts +16 -0
  337. package/dist/memory-source-order-YMRoeDLd.js +134 -0
  338. package/dist/memory-store-base-CQ_bHlYA.d.ts +1094 -0
  339. package/dist/memory-store-shared-DqpWJXZZ.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-BUjXG5o7.js +184 -0
  348. package/dist/memory-temporality-classifier-Brht5jyK.d.ts +43 -0
  349. package/dist/memory-tier-promoter-CqGxCkue.d.ts +43 -0
  350. package/dist/memory-tool-dependencies-CatGzI9R.d.ts +14 -0
  351. package/dist/memory-tool-dependencies-DjUoelnm.js +19 -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-CNNe9gkg.d.ts +17 -0
  355. package/dist/observable-llm-client-CRuKlefQ.d.ts +21 -0
  356. package/dist/observable-memory-store-CnGDpOY5.d.ts +73 -0
  357. package/dist/observable-retriever-Cooc62Qw.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-BhGKPBjw.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-ClUl-iv6.js +644 -0
  369. package/dist/reflection-command-hooks-G1-dI2Av.d.ts +32 -0
  370. package/dist/reflection-deps-Ccm2Jf5W.d.ts +19 -0
  371. package/dist/reflection-embedded-generator-BRvqV5N-.js +130 -0
  372. package/dist/reflection-embedded-generator-kfQfKEYV.d.ts +14 -0
  373. package/dist/reflection-injection-hooks-CS_uhjoD.d.ts +43 -0
  374. package/dist/reflection-lifecycle-hooks-CRSpUdLi.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-Dg2HgROM.js +2 -0
  380. package/dist/rem-batch-executor-DuC4nYyf.js +31640 -0
  381. package/dist/rem-consumer-retrieval-CR0dtcHR.js +246 -0
  382. package/dist/rem-trigger-Hn6od8IV.js +730 -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-Dxss5fRv.d.ts +469 -0
  387. package/dist/retriever-ZoLvPRHq.js +1757 -0
  388. package/dist/rolldown-runtime-D7D4PA-g.js +13 -0
  389. package/dist/routes-DLHT__Ay.js +60 -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-CSvxchqg.js +1412 -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-CoWqUMbK.js +30 -0
  401. package/dist/sno-station-mem-runtime-dependencies-DHESIuPn.d.ts +31 -0
  402. package/dist/sqlite-runtime-L_ywirTm.d.ts +58 -0
  403. package/dist/store-C8sUTssE.d.ts +27 -0
  404. package/dist/store-nPql26YM.js +5830 -0
  405. package/dist/strategy-hook-runner-Bxy851Xx.d.ts +16 -0
  406. package/dist/strategy-hook-runner-Djify5Rw.js +110 -0
  407. package/dist/token-counter-BD1f48Km.js +73 -0
  408. package/dist/trace-C1JxMfs-.d.ts +86 -0
  409. package/dist/types-CWdhXLxr.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,1412 @@
1
+ import { $ as appendAuditEntryStrict, Ct as ModelCallRefusedError, H as parseRemOperationType, V as REM_BUILT_OPERATION_TYPES, at as readJsonlLines, tt as getAuditPath } from "./rem-batch-executor-DuC4nYyf.js";
2
+ import { a as MEMORY_ROUTES, c as memoryMethod, n as MEMORY_DEFAULT_SKIN_ID, o as MEMORY_SKIN_HEADER, r as MEMORY_ERROR_STATUS } from "./routes-DLHT__Ay.js";
3
+ import { C as getSnoStationMemStateDir, S as getSidecarSocketPath, _ as readRemTestHoldMs, c as REM_SIDECAR_ORIGIN, d as getRemDiscoveryPath, f as getRemJobJournalPath, g as readRemOperationalConfig, i as REM_JOBS_PATH_PREFIX, l as REM_SOURCE, nr as MEMORY_SHUTDOWN_TIMEOUT_MS, r as REM_CORRELATION_ID_HEADER, s as REM_SIDECAR_HOST, u as getRemChassisJournalPath, v as SettingsUnavailableError, y as getDiscoveryPath } from "./config-CL90qYva.js";
4
+ import { n as remNeedsHost, r as ContractError } from "./rem-trigger-Hn6od8IV.js";
5
+ import { setImmediate } from "node:timers/promises";
6
+ import { createLogger, currentLogContext, effectiveLogLevel, emitDiagnostic } from "@snoai/utils/logger";
7
+ import path from "node:path";
8
+ import { existsSync, readFileSync, rmSync } from "node:fs";
9
+ import { z } from "zod";
10
+ import { randomBytes, randomUUID } from "node:crypto";
11
+ import { mkdir, open, readFile, rename, rm } from "node:fs/promises";
12
+ import { withLogContext as withLogContext$1 } from "@snoai/utils/log-context";
13
+ import { createServer } from "node:http";
14
+ import { createConnection, createServer as createServer$1 } from "node:net";
15
+ import locking from "fs-ext";
16
+ //#region src/contract/discovery.ts
17
+ const discoverySchema = z.strictObject({
18
+ pid: z.number().int().positive(),
19
+ port: z.number().int().min(1).max(65535),
20
+ token: z.string().regex(/^[a-f0-9]{64}$/)
21
+ });
22
+ async function readDiscovery() {
23
+ let text;
24
+ try {
25
+ text = await readFile(getDiscoveryPath(), "utf8");
26
+ } catch (error) {
27
+ if (error instanceof Error && "code" in error && error.code === "ENOENT") return void 0;
28
+ throw new ContractError("sidecar-unreachable");
29
+ }
30
+ try {
31
+ return discoverySchema.parse(JSON.parse(text));
32
+ } catch {
33
+ throw new ContractError("sidecar-unreachable");
34
+ }
35
+ }
36
+ //#endregion
37
+ //#region src/sidecar/request-body.ts
38
+ var PayloadTooLargeError = class extends Error {
39
+ constructor() {
40
+ super("payload_too_large");
41
+ }
42
+ };
43
+ function readRequestBody(request, signal) {
44
+ return new Promise((resolve, reject) => {
45
+ const chunks = [];
46
+ let bytes = 0;
47
+ const cleanup = () => {
48
+ request.off("data", onData);
49
+ request.off("end", onEnd);
50
+ request.off("error", onError);
51
+ request.off("aborted", onAborted);
52
+ signal?.removeEventListener("abort", onAbort);
53
+ };
54
+ const onError = (error) => {
55
+ cleanup();
56
+ request.resume();
57
+ reject(error);
58
+ };
59
+ const onAbort = () => onError(signal?.reason);
60
+ const onAborted = () => onError(/* @__PURE__ */ new Error("request_aborted"));
61
+ const onEnd = () => {
62
+ cleanup();
63
+ resolve(Buffer.concat(chunks).toString("utf8"));
64
+ };
65
+ const onData = (chunk) => {
66
+ const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
67
+ bytes += buffer.length;
68
+ if (bytes > 8388608) {
69
+ onError(new PayloadTooLargeError());
70
+ return;
71
+ }
72
+ chunks.push(buffer);
73
+ };
74
+ request.on("data", onData);
75
+ request.once("end", onEnd);
76
+ request.once("error", onError);
77
+ request.once("aborted", onAborted);
78
+ signal?.addEventListener("abort", onAbort, { once: true });
79
+ if (signal?.aborted) onAbort();
80
+ });
81
+ }
82
+ //#endregion
83
+ //#region src/sidecar/memory-routes.ts
84
+ const log$2 = createLogger("sno-station-mem:memory-routes");
85
+ async function serveMemoryRoute(request, response, pathname, openPool, activeTasks) {
86
+ const method = memoryMethod(pathname);
87
+ if (!method || request.method !== "POST") return false;
88
+ const skinId = request.headers[MEMORY_SKIN_HEADER];
89
+ let timer;
90
+ const controller = new AbortController();
91
+ const abort = () => controller.abort(new ContractError("timeout"));
92
+ let rejectDeadline;
93
+ if (method !== "capture") response.once("close", abort);
94
+ try {
95
+ const deadline = new Promise((_, reject) => {
96
+ rejectDeadline = () => reject(controller.signal.reason);
97
+ controller.signal.addEventListener("abort", rejectDeadline, { once: true });
98
+ timer = setTimeout(abort, MEMORY_ROUTES[method].timeoutMs);
99
+ });
100
+ const task = (async () => {
101
+ const body = await readBody(request, controller.signal);
102
+ controller.signal.throwIfAborted();
103
+ const pool = await openPool();
104
+ controller.signal.throwIfAborted();
105
+ return pool.invoke(method, body, typeof skinId === "string" && skinId.trim() ? skinId : MEMORY_DEFAULT_SKIN_ID, controller.signal);
106
+ })();
107
+ const boundedTask = Promise.race([task, deadline]);
108
+ const completion = Object.assign(task.then(() => void 0, () => void 0), {
109
+ label: currentLogContext().operation_id ?? method,
110
+ method
111
+ });
112
+ activeTasks.add(completion);
113
+ completion.finally(() => activeTasks.delete(completion));
114
+ const result = await boundedTask;
115
+ response.writeHead(200, { "content-type": "application/json" });
116
+ response.end(JSON.stringify(result));
117
+ } catch (error) {
118
+ if (error instanceof SettingsUnavailableError) {
119
+ response.writeHead(503, { "content-type": "application/json" });
120
+ response.end(JSON.stringify({
121
+ degraded: true,
122
+ error: error.message,
123
+ reason: error.message
124
+ }));
125
+ return true;
126
+ }
127
+ log$2.error("Memory engine request failed", {
128
+ method,
129
+ skinId,
130
+ error,
131
+ error_message: error instanceof Error ? error.message : String(error),
132
+ error_stack: error instanceof Error ? error.stack : void 0
133
+ }, {
134
+ event_name: "memory.sidecar.request.failed",
135
+ file: "packages/memory/src/sidecar/memory-routes.ts",
136
+ function: "serveMemoryRoute",
137
+ site_id: "memory.sidecar.request.failed"
138
+ });
139
+ if (error instanceof PayloadTooLargeError) {
140
+ response.writeHead(413, { "content-type": "application/json" });
141
+ response.end(JSON.stringify({ error: "payload_too_large" }));
142
+ return true;
143
+ }
144
+ const reason = error instanceof ContractError ? error.reason : "engine-failed";
145
+ const status = MEMORY_ERROR_STATUS[reason];
146
+ if (!response.headersSent) response.writeHead(status, { "content-type": "application/json" });
147
+ response.end(JSON.stringify({
148
+ degraded: true,
149
+ reason
150
+ }));
151
+ } finally {
152
+ clearTimeout(timer);
153
+ response.off("close", abort);
154
+ if (rejectDeadline) controller.signal.removeEventListener("abort", rejectDeadline);
155
+ }
156
+ return true;
157
+ }
158
+ async function readBody(request, signal) {
159
+ const body = await readRequestBody(request, signal);
160
+ try {
161
+ return JSON.parse(body);
162
+ } catch {
163
+ throw new ContractError("invalid-input");
164
+ }
165
+ }
166
+ //#endregion
167
+ //#region src/sidecar/rem-chassis-journal.ts
168
+ /** @file rem-chassis-journal.ts
169
+ * @purpose Persists reason-bearing REM chassis stage outcomes as append-only JSONL.
170
+ * @boundary Sidecar runner journal only; job-state transitions remain in RemJobStore.
171
+ */
172
+ var RemChassisJournal = class {
173
+ journalPath;
174
+ operationQueue = Promise.resolve();
175
+ constructor(journalPath) {
176
+ this.journalPath = journalPath;
177
+ }
178
+ appendJournal(jobId, jobType, entry) {
179
+ return this.queueAppend(jobId, jobType, entry);
180
+ }
181
+ appendJournalWithCorrelation(jobId, jobType, correlationId, entry) {
182
+ return this.queueAppend(jobId, jobType, entry, correlationId);
183
+ }
184
+ queueAppend(jobId, jobType, entry, correlationId) {
185
+ const result = this.operationQueue.then(() => this.append(jobId, jobType, entry, correlationId));
186
+ this.operationQueue = result.then(() => void 0, () => void 0);
187
+ return result;
188
+ }
189
+ async append(jobId, jobType, entry, correlationId) {
190
+ const parent = path.dirname(this.journalPath);
191
+ await mkdir(parent, { recursive: true });
192
+ const journalAlreadyExisted = existsSync(this.journalPath);
193
+ const handle = await open(this.journalPath, "a");
194
+ try {
195
+ const record = {
196
+ job_id: jobId,
197
+ job_type: jobType,
198
+ ...correlationId === void 0 ? {} : { correlation_id: correlationId },
199
+ stage: entry.stage,
200
+ outcome: entry.outcome,
201
+ pairs_scanned: entry.pairsScanned,
202
+ verdicts: entry.verdicts,
203
+ actions_applied: entry.actionsApplied,
204
+ ...entry.reason === void 0 ? {} : { reason: entry.reason },
205
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
206
+ };
207
+ await handle.writeFile(`${JSON.stringify(record)}\n`, "utf8");
208
+ await handle.sync();
209
+ } finally {
210
+ await handle.close();
211
+ }
212
+ if (!journalAlreadyExisted) await syncDirectory$2(parent);
213
+ }
214
+ };
215
+ async function syncDirectory$2(directory) {
216
+ if (process.platform === "win32") return;
217
+ const handle = await open(directory, "r");
218
+ try {
219
+ await handle.sync();
220
+ } finally {
221
+ await handle.close();
222
+ }
223
+ }
224
+ //#endregion
225
+ //#region src/sidecar/rem-job-store.ts
226
+ /** @file rem-job-store.ts
227
+ * @purpose Persists append-only REM job state transitions.
228
+ * @boundary Durable local JSONL journal used by the standalone REM sidecar.
229
+ */
230
+ const log$1 = createLogger("sno-station-mem:rem-jobs");
231
+ const remJobStateSchema = z.enum([
232
+ "queued",
233
+ "running",
234
+ "done",
235
+ "failed",
236
+ "skipped"
237
+ ]);
238
+ const remJobMeasurementsSchema = z.object({
239
+ rows_considered: z.number().int().nonnegative(),
240
+ pairs_built: z.number().int().nonnegative().optional(),
241
+ pair_cap_binding: z.boolean().optional(),
242
+ model_calls: z.number().int().nonnegative(),
243
+ model_tokens: z.number().int().nonnegative(),
244
+ wall_ms: z.number().int().nonnegative()
245
+ }).strict();
246
+ const remJobStatsSchema = z.object({
247
+ operations: z.number().int().nonnegative(),
248
+ applied_count: z.number().int().nonnegative().optional(),
249
+ actionable_candidate_count: z.number().int().nonnegative().optional(),
250
+ applied_fraction: z.number().min(0).max(1).nullable().optional(),
251
+ scan: z.object({
252
+ scope: z.string().min(1),
253
+ candidate_count: z.number().int().nonnegative(),
254
+ stamped_skipped_count: z.number().int().nonnegative().optional(),
255
+ actionable_candidate_count: z.number().int().nonnegative().optional()
256
+ }).strict().optional(),
257
+ parse_failure_count: z.number().int().nonnegative().optional(),
258
+ top_refusal_reasons: z.array(z.string().min(1)).max(2).optional(),
259
+ measured: remJobMeasurementsSchema.optional(),
260
+ by_operation: z.array(z.object({
261
+ operation: z.string().min(1),
262
+ applied_count: z.number().int().nonnegative(),
263
+ actionable_candidate_count: z.number().int().nonnegative(),
264
+ candidate_count: z.number().int().nonnegative(),
265
+ parse_failure_count: z.number().int().nonnegative(),
266
+ top_refusal_reasons: z.array(z.string().min(1)).max(2),
267
+ measured: remJobMeasurementsSchema
268
+ }).strict()).min(1).optional()
269
+ }).strict();
270
+ function parseRemJobStats(value) {
271
+ const parsed = remJobStatsSchema.safeParse(value);
272
+ return parsed.success ? parsed.data : void 0;
273
+ }
274
+ const remWaveJobSchema = z.object({
275
+ payloadVersion: z.literal(1),
276
+ waveId: z.string().min(1),
277
+ correlationId: z.string().min(1),
278
+ scope: z.string().min(1),
279
+ requestedOperations: z.array(z.string().min(1)).min(1),
280
+ state: remJobStateSchema,
281
+ startedAt: z.string().datetime().nullable(),
282
+ finishedAt: z.string().datetime().nullable(),
283
+ stats: remJobStatsSchema,
284
+ error: z.string().min(1).optional()
285
+ }).strict();
286
+ const legacyJobSchema = z.object({
287
+ job_id: z.string().min(1),
288
+ state: remJobStateSchema,
289
+ type: z.string().min(1),
290
+ scope: z.string().min(1),
291
+ started_at: z.string().datetime().nullable(),
292
+ finished_at: z.string().datetime().nullable(),
293
+ stats: remJobStatsSchema,
294
+ error: z.string().min(1).optional(),
295
+ correlation_id: z.string().min(1)
296
+ }).strict();
297
+ const OPERATION_ORDER = [
298
+ "rem-replace",
299
+ "rem-update",
300
+ "rem-distill",
301
+ "rem-retire"
302
+ ];
303
+ var RemJobStore = class RemJobStore {
304
+ journalPath;
305
+ onDurableTransition;
306
+ jobs = /* @__PURE__ */ new Map();
307
+ persistedJobs = /* @__PURE__ */ new Set();
308
+ mergeKeys = /* @__PURE__ */ new Map();
309
+ operationQueue = Promise.resolve();
310
+ constructor(journalPath, onDurableTransition) {
311
+ this.journalPath = journalPath;
312
+ this.onDurableTransition = onDurableTransition;
313
+ }
314
+ static async open(journalPath, onDurableTransition = () => void 0) {
315
+ const store = new RemJobStore(journalPath, onDurableTransition);
316
+ await store.migrateLegacyJournal().catch((error) => store.reportFailure(error));
317
+ await store.load();
318
+ return store;
319
+ }
320
+ isPersisted(jobId) {
321
+ return this.persistedJobs.has(jobId);
322
+ }
323
+ get(jobId) {
324
+ const job = this.jobs.get(jobId);
325
+ return job === void 0 ? void 0 : toRemJob(job);
326
+ }
327
+ nonTerminalJobs() {
328
+ return Array.from(this.jobs.values()).filter((job) => job.state === "queued" || job.state === "running").map(toRemJob);
329
+ }
330
+ async createQueued(type, scope, correlationId) {
331
+ return this.enqueue(async () => {
332
+ const requestedOperations = canonicalOperations(typeof type === "string" ? [type] : type);
333
+ if (requestedOperations.length === 0) throw new Error("REM wave requires at least one supported operation");
334
+ const mergeKey = `${correlationId}\0${scope}`;
335
+ const existingId = this.mergeKeys.get(mergeKey);
336
+ const existing = existingId === void 0 ? void 0 : this.jobs.get(existingId);
337
+ if (existing !== void 0 && existing.state === "queued") {
338
+ const mergedOperations = canonicalOperations([...existing.requestedOperations, ...requestedOperations]);
339
+ if (mergedOperations.length === existing.requestedOperations.length) return {
340
+ created: false,
341
+ job: toRemJob(existing)
342
+ };
343
+ const updated = remWaveJobSchema.parse({
344
+ ...existing,
345
+ requestedOperations: mergedOperations
346
+ });
347
+ const durable = await this.persist(updated);
348
+ this.jobs.set(updated.waveId, updated);
349
+ if (durable) this.onDurableTransition(toRemJob(updated));
350
+ return {
351
+ created: false,
352
+ job: toRemJob(updated)
353
+ };
354
+ }
355
+ if (existing !== void 0 && existing.state !== "skipped" && requestedOperations.every((operation) => existing.requestedOperations.includes(operation))) return {
356
+ created: false,
357
+ job: toRemJob(existing)
358
+ };
359
+ const job = remWaveJobSchema.parse({
360
+ payloadVersion: 1,
361
+ waveId: `rem-wave-${randomUUID()}`,
362
+ correlationId,
363
+ scope,
364
+ requestedOperations,
365
+ state: "queued",
366
+ startedAt: null,
367
+ finishedAt: null,
368
+ stats: { operations: 0 }
369
+ });
370
+ const durable = await this.persist(job);
371
+ this.jobs.set(job.waveId, job);
372
+ this.mergeKeys.set(mergeKey, job.waveId);
373
+ const outward = toRemJob(job);
374
+ if (durable) this.onDurableTransition(outward);
375
+ return {
376
+ created: true,
377
+ job: outward
378
+ };
379
+ });
380
+ }
381
+ async transition(jobId, transition) {
382
+ return this.enqueue(async () => {
383
+ const current = this.jobs.get(jobId);
384
+ if (!current) throw new Error(`REM job not found: ${jobId}`);
385
+ const next = remWaveJobSchema.parse({
386
+ ...current,
387
+ state: transition.state,
388
+ ...transition.started_at === void 0 ? {} : { startedAt: transition.started_at },
389
+ ...transition.finished_at === void 0 ? {} : { finishedAt: transition.finished_at },
390
+ ...transition.stats === void 0 ? {} : { stats: transition.stats },
391
+ ...transition.error === void 0 ? {} : { error: transition.error }
392
+ });
393
+ const durable = await this.persist(next);
394
+ this.jobs.set(jobId, next);
395
+ const outward = toRemJob(next);
396
+ if (durable) this.onDurableTransition(outward);
397
+ return outward;
398
+ });
399
+ }
400
+ async load() {
401
+ if (!existsSync(this.journalPath)) return;
402
+ const bytes = await readFile(this.journalPath);
403
+ const lines = bytes.toString("utf8").split("\n");
404
+ const endsWithNewline = bytes.length === 0 || bytes[bytes.length - 1] === 10;
405
+ for (const [index, line] of lines.entries()) {
406
+ if (!line) continue;
407
+ if (!endsWithNewline && index === lines.length - 1) {
408
+ const lastNewline = bytes.lastIndexOf(10);
409
+ await this.truncateJournal(lastNewline < 0 ? 0 : lastNewline + 1);
410
+ return;
411
+ }
412
+ try {
413
+ const parsed = JSON.parse(line);
414
+ const job = remWaveJobSchema.parse(parsed);
415
+ this.jobs.set(job.waveId, job);
416
+ this.mergeKeys.set(`${job.correlationId}\0${job.scope}`, job.waveId);
417
+ } catch (error) {
418
+ log$1.error("rem.journal.failed", {
419
+ path: this.journalPath,
420
+ line: index + 1,
421
+ error
422
+ }, {
423
+ event_name: "rem.journal.failed",
424
+ file: "packages/memory/src/sidecar/rem-job-store.ts",
425
+ function: "load",
426
+ site_id: "rem-job-store.load.invalid-line"
427
+ });
428
+ }
429
+ }
430
+ }
431
+ async migrateLegacyJournal() {
432
+ const legacyPath = path.join(path.dirname(this.journalPath), "rem-jobs.jsonl");
433
+ if (!existsSync(legacyPath)) return;
434
+ const latest = /* @__PURE__ */ new Map();
435
+ for await (const line of readJsonlLines(legacyPath)) try {
436
+ const parsed = JSON.parse(line);
437
+ const job = legacyJobSchema.parse(parsed);
438
+ latest.set(job.job_id, job);
439
+ } catch (error) {
440
+ const reason = error instanceof Error ? error.message : String(error);
441
+ this.reportFailure(reason);
442
+ }
443
+ const interrupted = [...latest.values()].filter((job) => job.state === "queued" || job.state === "running");
444
+ if (interrupted.length > 0) {
445
+ const finishedAt = (/* @__PURE__ */ new Date()).toISOString();
446
+ const handle = await open(legacyPath, "a");
447
+ try {
448
+ for (const job of interrupted) await handle.writeFile(`${JSON.stringify({
449
+ ...job,
450
+ state: "failed",
451
+ finished_at: finishedAt,
452
+ error: "sidecar_upgrade_interrupted"
453
+ })}\n`, "utf8");
454
+ await handle.sync();
455
+ } finally {
456
+ await handle.close();
457
+ }
458
+ }
459
+ await rename(legacyPath, path.join(path.dirname(legacyPath), "rem-jobs.v0.jsonl"));
460
+ }
461
+ reportFailure(error) {
462
+ log$1.error("rem.journal.failed", {
463
+ error,
464
+ path: this.journalPath
465
+ }, {
466
+ event_name: "rem.journal.failed",
467
+ file: "packages/memory/src/sidecar/rem-job-store.ts",
468
+ function: "reportFailure",
469
+ site_id: "rem.journal.failed"
470
+ });
471
+ }
472
+ async persist(job) {
473
+ this.persistedJobs.delete(job.waveId);
474
+ await this.append(job);
475
+ this.persistedJobs.add(job.waveId);
476
+ return true;
477
+ }
478
+ async truncateJournal(length) {
479
+ const handle = await open(this.journalPath, "r+");
480
+ try {
481
+ await handle.truncate(length);
482
+ await handle.sync();
483
+ } finally {
484
+ await handle.close();
485
+ }
486
+ }
487
+ async append(job) {
488
+ const parent = path.dirname(this.journalPath);
489
+ await mkdir(parent, { recursive: true });
490
+ const journalAlreadyExisted = existsSync(this.journalPath);
491
+ const handle = await open(this.journalPath, "a");
492
+ try {
493
+ await handle.writeFile(`${JSON.stringify(job)}\n`, "utf8");
494
+ await handle.sync();
495
+ } finally {
496
+ await handle.close();
497
+ }
498
+ if (!journalAlreadyExisted) await syncDirectory$1(parent);
499
+ }
500
+ enqueue(operation) {
501
+ const result = this.operationQueue.then(operation);
502
+ this.operationQueue = result.then(() => void 0, () => void 0);
503
+ return result;
504
+ }
505
+ };
506
+ function canonicalOperations(operations) {
507
+ const unique = new Set(operations);
508
+ return OPERATION_ORDER.filter((operation) => unique.has(operation));
509
+ }
510
+ function toRemJob(job) {
511
+ return {
512
+ job_id: job.waveId,
513
+ state: job.state,
514
+ type: job.requestedOperations[0] ?? "rem-replace",
515
+ scope: job.scope,
516
+ started_at: job.startedAt,
517
+ finished_at: job.finishedAt,
518
+ stats: job.stats,
519
+ ...job.error === void 0 ? {} : { error: job.error },
520
+ correlation_id: job.correlationId,
521
+ requested_operations: [...job.requestedOperations]
522
+ };
523
+ }
524
+ async function syncDirectory$1(directory) {
525
+ if (process.platform === "win32") return;
526
+ const handle = await open(directory, "r");
527
+ try {
528
+ await handle.sync();
529
+ } finally {
530
+ await handle.close();
531
+ }
532
+ }
533
+ //#endregion
534
+ //#region src/sidecar/server.ts
535
+ /** @file server.ts
536
+ * @purpose Runs the loopback HTTP surface and empty asynchronous REM executor.
537
+ * @boundary Sno CLI requests, durable REM job state, and the existing local audit writer.
538
+ */
539
+ const log = createLogger("sno-station-mem:rem-sidecar");
540
+ const runRequestSchema = z.union([z.object({
541
+ type: z.string().min(1),
542
+ scope: z.string().trim().min(1)
543
+ }).strict(), z.object({
544
+ types: z.array(z.string().min(1)).min(1),
545
+ scope: z.string().trim().min(1)
546
+ }).strict()]);
547
+ var HttpError = class extends Error {
548
+ status;
549
+ code;
550
+ constructor(status, code) {
551
+ super(code);
552
+ this.status = status;
553
+ this.code = code;
554
+ }
555
+ };
556
+ var DuplicateSidecarError = class extends Error {};
557
+ async function socketIsLive(socketPath) {
558
+ return new Promise((resolve, reject) => {
559
+ const socket = createConnection(socketPath);
560
+ socket.once("connect", () => {
561
+ socket.destroy();
562
+ resolve(true);
563
+ });
564
+ socket.once("error", (error) => {
565
+ socket.destroy();
566
+ if ("code" in error && (error.code === "ECONNREFUSED" || error.code === "ENOENT")) resolve(false);
567
+ else reject(error);
568
+ });
569
+ });
570
+ }
571
+ async function bindSidecarSocket() {
572
+ const socketPath = getSidecarSocketPath();
573
+ await mkdir(path.dirname(socketPath), {
574
+ recursive: true,
575
+ mode: 448
576
+ });
577
+ const directory = await open(path.dirname(socketPath), "r");
578
+ try {
579
+ for (;;) try {
580
+ locking.flockSync(directory.fd, "exnb");
581
+ break;
582
+ } catch (error) {
583
+ if (!(error instanceof Error && "code" in error && error.code === "EAGAIN")) throw error;
584
+ await setImmediate();
585
+ }
586
+ const guard = createServer$1((socket) => socket.destroy());
587
+ for (;;) try {
588
+ await new Promise((resolve, reject) => {
589
+ guard.once("error", reject);
590
+ guard.listen(socketPath, () => {
591
+ guard.removeListener("error", reject);
592
+ resolve();
593
+ });
594
+ });
595
+ return guard;
596
+ } catch (error) {
597
+ if (!(error instanceof Error && "code" in error && error.code === "EADDRINUSE")) throw error;
598
+ if (await socketIsLive(socketPath)) {
599
+ const discovery = await readDiscovery().catch(() => void 0);
600
+ emitDiagnostic("info", "sidecar.duplicate.exit", { pid: discovery?.pid }, {
601
+ event_name: "sidecar.duplicate.exit",
602
+ file: "packages/memory/src/sidecar/server.ts",
603
+ function: "bindSidecarSocket",
604
+ site_id: "sidecar.duplicate.exit"
605
+ });
606
+ throw new DuplicateSidecarError();
607
+ }
608
+ await rm(socketPath, { force: true });
609
+ }
610
+ } finally {
611
+ await directory.close();
612
+ }
613
+ }
614
+ async function startRemSidecar() {
615
+ const guard = await bindSidecarSocket();
616
+ const exitCleanup = () => {
617
+ guard.close();
618
+ };
619
+ process.once("exit", exitCleanup);
620
+ const releaseGuard = async () => {
621
+ await new Promise((resolve) => guard.close(() => resolve()));
622
+ process.removeListener("exit", exitCleanup);
623
+ };
624
+ try {
625
+ const sidecar = await startOwnedRemSidecar();
626
+ return {
627
+ port: sidecar.port,
628
+ async stop() {
629
+ let drained;
630
+ try {
631
+ ({drained} = await sidecar.stop());
632
+ } finally {
633
+ if (drained) drained.then(releaseGuard);
634
+ else await releaseGuard();
635
+ }
636
+ }
637
+ };
638
+ } catch (error) {
639
+ await releaseGuard();
640
+ throw error;
641
+ }
642
+ }
643
+ async function startOwnedRemSidecar() {
644
+ let stopping = false;
645
+ let currentMemory;
646
+ let openingMemory;
647
+ let settingsError;
648
+ const memory = {
649
+ current: () => currentMemory,
650
+ async open() {
651
+ if (currentMemory) return currentMemory;
652
+ if (settingsError) throw settingsError;
653
+ openingMemory ??= import("./memory-runtime-DqUS4cWi.js").then((module) => module.MemoryRuntimePool.open()).then((pool) => {
654
+ currentMemory = pool;
655
+ if (stopping) pool.stopTimers();
656
+ return pool;
657
+ }).catch((error) => {
658
+ if (error instanceof SettingsUnavailableError) settingsError = error;
659
+ throw error;
660
+ }).finally(() => {
661
+ openingMemory = void 0;
662
+ });
663
+ return openingMemory;
664
+ }
665
+ };
666
+ const token = randomBytes(32).toString("hex");
667
+ const holdMs = readRemTestHoldMs();
668
+ const chassisJournal = new RemChassisJournal(getRemChassisJournalPath());
669
+ const onDurableTransition = (job) => {
670
+ log.info("job_transition_durable", {
671
+ event: "job_transition_durable",
672
+ job_id: job.job_id,
673
+ state: job.state,
674
+ correlation_id: job.correlation_id,
675
+ durable: true
676
+ }, {
677
+ event_name: "sno_station_mem.server.job.transition.durable",
678
+ file: "packages/memory/src/sidecar/server.ts",
679
+ function: "<anonymous callback>",
680
+ site_id: "server.<anonymous callback>.5eb5a60e6b"
681
+ });
682
+ };
683
+ const store = RemJobStore.open(getRemJobJournalPath(), onDurableTransition);
684
+ const pendingTimers = /* @__PURE__ */ new Map();
685
+ const startPendingStarts = () => {
686
+ for (const start of pendingTimers.values()) start();
687
+ };
688
+ const activeTasks = /* @__PURE__ */ new Set();
689
+ const pendingRequests = /* @__PURE__ */ new Set();
690
+ const server = createServer((request, response) => {
691
+ const started = performance.now();
692
+ const operationId = `rem-http-${randomUUID()}`;
693
+ const context = {};
694
+ const requestLabel = `${operationId} ${request.method} ${requestPath(request)}`;
695
+ pendingRequests.add(requestLabel);
696
+ let requestLogged = false;
697
+ const recordRequest = (cancelled = false) => {
698
+ if (requestLogged) return;
699
+ requestLogged = true;
700
+ pendingRequests.delete(requestLabel);
701
+ let outcome = "success";
702
+ if (cancelled) outcome = "cancelled";
703
+ else if (response.statusCode >= 500) outcome = "failed";
704
+ else if (response.statusCode >= 400) outcome = "refused";
705
+ withLogContext$1({
706
+ operation_id: operationId,
707
+ job_id: context.job_id,
708
+ external_reference: context.correlation_id
709
+ }, () => {
710
+ log[outcome === "failed" ? "error" : "info"]("http_request", {
711
+ outcome,
712
+ method: request.method ?? "UNKNOWN",
713
+ path: requestPath(request),
714
+ status: response.statusCode,
715
+ duration_ms: Math.max(0, Math.round(performance.now() - started)),
716
+ ...context
717
+ }, {
718
+ event_name: "sno_station_mem.server.http.request",
719
+ file: "packages/memory/src/sidecar/server.ts",
720
+ function: "recordRequest",
721
+ site_id: "server.<anonymous callback>.47c4662916"
722
+ });
723
+ });
724
+ };
725
+ response.once("finish", () => recordRequest());
726
+ response.once("close", () => recordRequest(!response.writableFinished));
727
+ withLogContext$1({ operation_id: operationId }, () => routeRequest(request, response, store, chassisJournal, holdMs, pendingTimers, activeTasks, context, memory, () => stopping, token).catch((error) => {
728
+ if (error instanceof SettingsUnavailableError) {
729
+ context.error_code = error.message;
730
+ if (!response.headersSent) sendJson(response, 503, { error: error.message });
731
+ else response.end();
732
+ return;
733
+ }
734
+ let httpError = new HttpError(500, "internal_error");
735
+ if (error instanceof HttpError) httpError = error;
736
+ else if (error instanceof PayloadTooLargeError) httpError = new HttpError(413, "payload_too_large");
737
+ context.error_code = httpError.code;
738
+ log.error("request_failed", { error }, {
739
+ event_name: "sno_station_mem.server.request.failed",
740
+ file: "packages/memory/src/sidecar/server.ts",
741
+ function: "<anonymous callback>",
742
+ site_id: "server.<anonymous callback>.a7a2656a08"
743
+ });
744
+ if (!response.headersSent) sendJson(response, httpError.status, { error: httpError.code });
745
+ else response.end();
746
+ }));
747
+ });
748
+ const jobs = await store;
749
+ const recoveryJobs = jobs.nonTerminalJobs();
750
+ await listen(server);
751
+ const address = server.address();
752
+ if (!address || typeof address === "string") {
753
+ server.close();
754
+ throw new Error("REM sidecar did not bind a TCP address");
755
+ }
756
+ const discoveryPath = getRemDiscoveryPath();
757
+ const discovery = {
758
+ port: address.port,
759
+ token,
760
+ pid: process.pid
761
+ };
762
+ let discoveryTimer;
763
+ let discoveryAttempt = 0;
764
+ const publishDiscovery = async () => {
765
+ discoveryAttempt++;
766
+ try {
767
+ await writeDiscovery(discoveryPath, discovery);
768
+ if (discoveryAttempt > 1) log.info("sidecar.discovery.published", { attempt: discoveryAttempt }, {
769
+ event_name: "sidecar.discovery.published",
770
+ file: "packages/memory/src/sidecar/server.ts",
771
+ function: "publishDiscovery",
772
+ site_id: "sidecar.discovery.published"
773
+ });
774
+ } catch (error) {
775
+ log.error("sidecar.discovery.failed", {
776
+ attempt: discoveryAttempt,
777
+ error
778
+ }, {
779
+ event_name: "sidecar.discovery.failed",
780
+ file: "packages/memory/src/sidecar/server.ts",
781
+ function: "publishDiscovery",
782
+ site_id: "sidecar.discovery.failed"
783
+ });
784
+ if (!stopping) discoveryTimer = setTimeout(() => {
785
+ discoveryPublication = publishDiscovery();
786
+ }, 5e3);
787
+ }
788
+ };
789
+ let discoveryPublication = publishDiscovery();
790
+ await discoveryPublication;
791
+ memory.open().catch((error) => {
792
+ if (!(error instanceof SettingsUnavailableError)) reportSidecarFailure("memory startup", error);
793
+ });
794
+ const recovery = (async () => {
795
+ const jobIds = await recoverInterruptedJobs(jobs, await readCompletedJobStats(new Set(recoveryJobs.map((job) => job.job_id))), recoveryJobs);
796
+ for (const jobId of jobIds) await runChassisJob(jobs, chassisJournal, jobId, 0, await memory.open());
797
+ })().catch((error) => reportSidecarFailure("recovery", error));
798
+ activeTasks.add(Object.assign(recovery, { label: "rem-recovery" }));
799
+ recovery.finally(() => activeTasks.delete(recovery));
800
+ const exitCleanup = () => {
801
+ removeOwnedDiscoverySync(discoveryPath, token);
802
+ };
803
+ process.once("exit", exitCleanup);
804
+ log.info("started", {
805
+ host: REM_SIDECAR_HOST,
806
+ port: address.port,
807
+ pid: process.pid
808
+ }, {
809
+ event_name: "sno_station_mem.server.started",
810
+ file: "packages/memory/src/sidecar/server.ts",
811
+ function: "startLockedRemSidecar",
812
+ site_id: "server.startLockedRemSidecar.96a92b085b"
813
+ });
814
+ return {
815
+ port: address.port,
816
+ async stop() {
817
+ const started = performance.now();
818
+ let cleanedUp = false;
819
+ let phase = "http_requests";
820
+ let timer;
821
+ stopping = true;
822
+ clearTimeout(discoveryTimer);
823
+ process.removeListener("exit", exitCleanup);
824
+ try {
825
+ startPendingStarts();
826
+ currentMemory?.stopTimers();
827
+ const cleanup = (async () => {
828
+ await closeServer(server);
829
+ startPendingStarts();
830
+ phase = "active_tasks";
831
+ await Promise.allSettled(activeTasks);
832
+ phase = "runtime_open";
833
+ await openingMemory?.catch(() => void 0);
834
+ phase = "runtime_close";
835
+ await currentMemory?.close();
836
+ phase = "discovery";
837
+ await discoveryPublication;
838
+ return true;
839
+ })();
840
+ cleanedUp = await Promise.race([cleanup, new Promise((resolve) => {
841
+ timer = setTimeout(() => {
842
+ log.error("sidecar.shutdown.timeout", {
843
+ phase,
844
+ active_tasks: activeTasks.size,
845
+ pending_requests: [...pendingRequests],
846
+ running_tasks: [...activeTasks].map((task) => task.label ?? "rem")
847
+ }, {
848
+ event_name: "sidecar.shutdown.timeout",
849
+ file: "packages/memory/src/sidecar/server.ts",
850
+ function: "startRemSidecar.stop",
851
+ site_id: "sidecar.shutdown.timeout"
852
+ });
853
+ for (const task of activeTasks) withLogContext$1({ operation_id: task.label }, () => {
854
+ log.error("sidecar.shutdown.task.running", { method: task.method ?? "rem" }, {
855
+ event_name: "sidecar.shutdown.task.running",
856
+ file: "packages/memory/src/sidecar/server.ts",
857
+ function: "startRemSidecar.stop",
858
+ site_id: "sidecar.shutdown.task.running"
859
+ });
860
+ });
861
+ server.closeAllConnections();
862
+ currentMemory?.stopTimers();
863
+ resolve(false);
864
+ }, MEMORY_SHUTDOWN_TIMEOUT_MS);
865
+ })]);
866
+ } finally {
867
+ clearTimeout(timer);
868
+ await discoveryPublication;
869
+ await removeOwnedDiscovery(discoveryPath, token);
870
+ log[cleanedUp ? "info" : "error"]("REM sidecar cleanup completed", {
871
+ outcome: cleanedUp ? "success" : "failed",
872
+ duration_ms: performance.now() - started,
873
+ active_tasks: activeTasks.size
874
+ }, {
875
+ event_name: "sidecar.shutdown.completed",
876
+ file: "packages/memory/src/sidecar/server.ts",
877
+ function: "startRemSidecar.stop",
878
+ site_id: "sidecar.shutdown.completed"
879
+ });
880
+ }
881
+ return cleanedUp ? {} : { drained: Promise.allSettled(activeTasks).then(() => void 0) };
882
+ }
883
+ };
884
+ }
885
+ async function routeRequest(request, response, pendingStore, chassisJournal, holdMs, pendingTimers, activeTasks, context, memory, isStopping, token) {
886
+ const url = new URL(request.url ?? "/healthz", REM_SIDECAR_ORIGIN);
887
+ if (request.method === "GET" && url.pathname === "/healthz") {
888
+ try {
889
+ const runtime = await memory.open();
890
+ sendJson(response, 200, {
891
+ status: runtime.modelPreparationError ? "degraded" : "ok",
892
+ ...runtime.modelPreparationError && { error: runtime.modelPreparationError },
893
+ log_level: effectiveLogLevel(),
894
+ accessCounters: runtime.counters
895
+ });
896
+ } catch (error) {
897
+ if (!(error instanceof SettingsUnavailableError)) throw error;
898
+ sendJson(response, 503, {
899
+ status: "error",
900
+ error: error.message
901
+ });
902
+ }
903
+ return;
904
+ }
905
+ if (request.headers["x-sidecar-token"] !== token) {
906
+ sendJson(response, 401, {});
907
+ return;
908
+ }
909
+ if (url.pathname.startsWith("/v1/")) {
910
+ if (await serveMemoryRoute(request, response, url.pathname, () => memory.open(), activeTasks)) return;
911
+ }
912
+ if (request.method === "POST" && url.pathname === "/rem/run") {
913
+ const correlationId = readCorrelationId(request) ?? `rem-corr-${randomUUID()}`;
914
+ context.correlation_id = correlationId;
915
+ const raw = await readJsonBody(request);
916
+ const parsedInput = runRequestSchema.safeParse(raw);
917
+ if (!parsedInput.success) throw new HttpError(400, "invalid_request");
918
+ const input = parsedInput.data;
919
+ const types = "types" in input ? input.types : [input.type];
920
+ const requestedTypes = types.filter((type) => REM_BUILT_OPERATION_TYPES.some((operation) => operation === type));
921
+ const unknownTypes = types.filter((type) => !requestedTypes.includes(type));
922
+ if (unknownTypes.length) {
923
+ reportSidecarFailure("unsupported_rem_type", new Error(unknownTypes.join(",")));
924
+ context.error_code = "unsupported_rem_type";
925
+ sendJson(response, 400, {
926
+ error: "unsupported_rem_type",
927
+ unknownTypes
928
+ });
929
+ return;
930
+ }
931
+ const store = await pendingStore;
932
+ const runtime = await memory.open();
933
+ if (remNeedsHost(runtime.config.mode, runtime.settings.modelCalls) && !runtime.connectedRemPort()) {
934
+ context.error_code = "no host model connected";
935
+ sendJson(response, 503, { error: "no host model connected" });
936
+ return;
937
+ }
938
+ let allocation;
939
+ try {
940
+ allocation = await store.createQueued(requestedTypes, input.scope, correlationId);
941
+ } catch (error) {
942
+ if (errorMessage(error) === "wave_closed") {
943
+ context.error_code = "wave_closed";
944
+ sendJson(response, 409, { error: "wave_closed" });
945
+ return;
946
+ }
947
+ throw error;
948
+ }
949
+ const { created, job } = allocation;
950
+ context.job_id = job.job_id;
951
+ log.info("job_allocated", {
952
+ created,
953
+ event: "job_allocated",
954
+ job_id: job.job_id,
955
+ type: job.type,
956
+ scope: job.scope,
957
+ correlation_id: job.correlation_id
958
+ }, {
959
+ event_name: "sno_station_mem.server.job.allocated",
960
+ file: "packages/memory/src/sidecar/server.ts",
961
+ function: "routeRequest",
962
+ site_id: "server.routeRequest.0ea180a77c"
963
+ });
964
+ if (created) {
965
+ const delayMs = "types" in input ? 0 : 100;
966
+ const { promise: task, resolve, reject } = Promise.withResolvers();
967
+ activeTasks.add(Object.assign(task, { label: job.job_id }));
968
+ task.catch((error) => reportSidecarFailure("rem_run", error)).finally(() => activeTasks.delete(task));
969
+ const start = () => {
970
+ clearTimeout(timer);
971
+ pendingTimers.delete(timer);
972
+ runChassisJob(store, chassisJournal, job.job_id, holdMs, runtime).then(resolve, reject);
973
+ };
974
+ const timer = setTimeout(start, delayMs);
975
+ pendingTimers.set(timer, start);
976
+ if (isStopping()) start();
977
+ }
978
+ sendJson(response, 202, {
979
+ job_id: job.job_id,
980
+ waveId: job.job_id
981
+ });
982
+ return;
983
+ }
984
+ if (request.method === "GET" && url.pathname.startsWith("/rem/jobs/")) {
985
+ const store = await pendingStore;
986
+ const jobId = url.pathname.slice(REM_JOBS_PATH_PREFIX.length);
987
+ const job = store.get(jobId);
988
+ context.job_id = jobId;
989
+ context.correlation_id = readCorrelationId(request) ?? job?.correlation_id;
990
+ if (!job) {
991
+ context.error_code = "job_not_found";
992
+ sendJson(response, 404, { error: "job_not_found" });
993
+ return;
994
+ }
995
+ sendJson(response, 200, job);
996
+ return;
997
+ }
998
+ context.error_code = "not_found";
999
+ sendJson(response, 404, { error: "not_found" });
1000
+ }
1001
+ async function runChassisJob(store, journal, waveId, holdMs, runtime) {
1002
+ const queued = store.get(waveId);
1003
+ if (queued === void 0) throw new Error(`REM wave not found: ${waveId}`);
1004
+ const resuming = queued.state === "running";
1005
+ return withLogContext$1({
1006
+ operation_id: queued.job_id,
1007
+ job_id: queued.job_id,
1008
+ session_reference: queued.scope,
1009
+ external_reference: queued.correlation_id
1010
+ }, async () => {
1011
+ const started = performance.now();
1012
+ let persistence = "unavailable";
1013
+ let completion;
1014
+ let failed = false;
1015
+ let failure;
1016
+ const requestedOperations = queued.requested_operations.flatMap((operation) => {
1017
+ const parsed = parseRemOperationType(operation);
1018
+ return parsed === void 0 ? [] : [parsed];
1019
+ });
1020
+ let writesApplied = false;
1021
+ try {
1022
+ if (remNeedsHost(runtime.config.mode, runtime.settings.modelCalls) && !runtime.connectedRemPort()) {
1023
+ await skipNonTerminalJob(store, queued.job_id, "no host model connected");
1024
+ return;
1025
+ }
1026
+ const running = resuming ? queued : await store.transition(queued.job_id, {
1027
+ state: "running",
1028
+ started_at: (/* @__PURE__ */ new Date()).toISOString()
1029
+ });
1030
+ if (!resuming) await auditRem("rem_triggered", running);
1031
+ if (holdMs > 0) await new Promise((resolvePromise) => setTimeout(resolvePromise, holdMs));
1032
+ const configuration = readRemOperationalConfig();
1033
+ const enabledBySettings = runtime.settings.rem.operations;
1034
+ const enabledOperations = [];
1035
+ const cleanRefusalReasons = [];
1036
+ for (const operation of requestedOperations) {
1037
+ let reason;
1038
+ if (!isBuiltOperation(operation)) reason = `not-built:${operation}`;
1039
+ else if (configuration.operations[operation] && enabledBySettings.includes(operation)) {
1040
+ enabledOperations.push(operation);
1041
+ continue;
1042
+ } else reason = `switched-off:${operation}`;
1043
+ cleanRefusalReasons.push(reason);
1044
+ await appendChassisRefusal(journal, queued, operation, "refused", reason);
1045
+ }
1046
+ const { runRemProductionOrderedWave } = await import("./rem-batch-executor-Dg2HgROM.js");
1047
+ const result = enabledOperations.length === 0 ? {
1048
+ decision: "allow",
1049
+ reasonCode: null,
1050
+ waveId: queued.job_id,
1051
+ actionsApplied: 0,
1052
+ actionableCandidateCount: 0,
1053
+ appliedFraction: null,
1054
+ candidateCount: 0,
1055
+ stampedSkippedCount: 0,
1056
+ parseFailureCount: 0,
1057
+ topRefusalReasons: [],
1058
+ measurements: {
1059
+ rowsConsidered: 0,
1060
+ pairsBuilt: 0,
1061
+ pairCapBinding: false,
1062
+ modelCalls: 0,
1063
+ modelTokens: 0,
1064
+ wallMs: 0
1065
+ },
1066
+ perOperation: []
1067
+ } : await runRemProductionOrderedWave({
1068
+ mode: runtime.config.mode,
1069
+ settings: runtime.settings,
1070
+ agentPort: runtime.connectedRemPort(),
1071
+ scope: queued.scope,
1072
+ waveId: queued.job_id,
1073
+ requestedOperations: enabledOperations
1074
+ });
1075
+ if (result.decision === "refuse") {
1076
+ const operation = enabledOperations[0] ?? "rem-replace";
1077
+ const reason = result.reasonCode;
1078
+ await appendChassisRefusal(journal, queued, operation, "failed", reason);
1079
+ throw new Error(reason);
1080
+ }
1081
+ writesApplied = true;
1082
+ const completionStats = {
1083
+ operations: result.actionsApplied,
1084
+ applied_count: result.actionsApplied,
1085
+ actionable_candidate_count: result.actionableCandidateCount,
1086
+ applied_fraction: result.appliedFraction,
1087
+ scan: {
1088
+ scope: queued.scope,
1089
+ candidate_count: result.candidateCount,
1090
+ stamped_skipped_count: result.stampedSkippedCount,
1091
+ actionable_candidate_count: result.actionableCandidateCount
1092
+ },
1093
+ parse_failure_count: result.parseFailureCount,
1094
+ top_refusal_reasons: [...cleanRefusalReasons, ...result.topRefusalReasons].slice(0, 2),
1095
+ measured: {
1096
+ rows_considered: result.measurements.rowsConsidered,
1097
+ pairs_built: result.measurements.pairsBuilt,
1098
+ pair_cap_binding: result.measurements.pairCapBinding,
1099
+ model_calls: result.measurements.modelCalls,
1100
+ model_tokens: result.measurements.modelTokens,
1101
+ wall_ms: result.measurements.wallMs
1102
+ },
1103
+ ...result.perOperation.length === 0 ? {} : { by_operation: result.perOperation.map(({ operation, ...operationResult }) => ({
1104
+ operation,
1105
+ applied_count: operationResult.actionsApplied,
1106
+ actionable_candidate_count: operationResult.actionableCandidateCount,
1107
+ candidate_count: operationResult.candidateCount,
1108
+ parse_failure_count: operationResult.parseFailureCount,
1109
+ top_refusal_reasons: operationResult.topRefusalReasons,
1110
+ measured: {
1111
+ rows_considered: operationResult.measurements.rowsConsidered,
1112
+ pairs_built: operationResult.measurements.pairsBuilt,
1113
+ pair_cap_binding: operationResult.measurements.pairCapBinding,
1114
+ model_calls: operationResult.measurements.modelCalls,
1115
+ model_tokens: operationResult.measurements.modelTokens,
1116
+ wall_ms: operationResult.measurements.wallMs
1117
+ }
1118
+ })) }
1119
+ };
1120
+ completion = completionStats;
1121
+ persistence = await persistCompletedJob(store, running, completionStats);
1122
+ for (const operationResult of result.perOperation) try {
1123
+ await journal.appendJournalWithCorrelation(running.job_id, operationResult.operation, running.correlation_id, {
1124
+ stage: operationResult.operation,
1125
+ outcome: operationResult.actionsApplied > 0 ? "done" : "no-action",
1126
+ pairsScanned: operationResult.measurements.pairsBuilt,
1127
+ verdicts: operationResult.actionableCandidateCount,
1128
+ actionsApplied: operationResult.actionsApplied
1129
+ });
1130
+ } catch (error) {
1131
+ log.error("job_completion_journal_failed", {
1132
+ error,
1133
+ job_id: running.job_id,
1134
+ job_type: operationResult.operation,
1135
+ correlation_id: running.correlation_id
1136
+ }, {
1137
+ event_name: "sno_station_mem.server.job.completion.journal.failed",
1138
+ file: "packages/memory/src/sidecar/server.ts",
1139
+ function: "runChassisJob",
1140
+ site_id: "server.runChassisJob.e7639bd8fc"
1141
+ });
1142
+ }
1143
+ } catch (error) {
1144
+ failed = true;
1145
+ failure = error;
1146
+ if (!writesApplied) {
1147
+ if (error instanceof ModelCallRefusedError) await skipNonTerminalJob(store, queued.job_id, error.reason, error.callId, error.destination);
1148
+ else await failNonTerminalJob(store, queued.job_id, errorMessage(error));
1149
+ }
1150
+ } finally {
1151
+ let outcome = "empty-success";
1152
+ if (failed) outcome = writesApplied ? "partial" : "failed";
1153
+ else if (persistence === "unavailable") outcome = "partial";
1154
+ else if ((completion?.applied_count ?? 0) > 0) outcome = "success";
1155
+ log[failed || persistence === "unavailable" ? "error" : "info"]("REM job completed", {
1156
+ outcome,
1157
+ job_id: queued.job_id,
1158
+ basis: persistence,
1159
+ applied_count: completion?.applied_count ?? (writesApplied ? null : 0),
1160
+ candidate_count: completion?.scan?.candidate_count ?? null,
1161
+ parse_failure_count: completion?.parse_failure_count ?? null,
1162
+ duration_ms: performance.now() - started,
1163
+ ...failure === void 0 ? {} : { error: failure }
1164
+ }, {
1165
+ event_name: "sidecar.job.completed",
1166
+ file: "packages/memory/src/sidecar/server.ts",
1167
+ function: "runChassisJob",
1168
+ site_id: "sidecar.job.completed"
1169
+ });
1170
+ }
1171
+ });
1172
+ }
1173
+ async function persistCompletedJob(store, job, stats) {
1174
+ const auditPersisted = await auditRem("rem_completed", job, { stats });
1175
+ await store.transition(job.job_id, {
1176
+ state: "done",
1177
+ finished_at: (/* @__PURE__ */ new Date()).toISOString(),
1178
+ stats
1179
+ });
1180
+ if (store.isPersisted(job.job_id)) return "job_journal";
1181
+ if (auditPersisted) return "completed_audit";
1182
+ reportSidecarFailure("completion-persistence", /* @__PURE__ */ new Error("completed work has no durable completion receipt"));
1183
+ return "unavailable";
1184
+ }
1185
+ async function appendChassisRefusal(journal, job, jobType, outcome, reason) {
1186
+ await journal.appendJournalWithCorrelation(job.job_id, jobType, job.correlation_id, {
1187
+ stage: jobType,
1188
+ outcome,
1189
+ pairsScanned: 0,
1190
+ verdicts: 0,
1191
+ actionsApplied: 0,
1192
+ reason
1193
+ });
1194
+ }
1195
+ function isBuiltOperation(jobType) {
1196
+ return REM_BUILT_OPERATION_TYPES.some((operation) => operation === jobType);
1197
+ }
1198
+ function errorMessage(error) {
1199
+ return error instanceof Error ? error.message : String(error);
1200
+ }
1201
+ async function failNonTerminalJob(store, jobId, reason) {
1202
+ const current = store.get(jobId);
1203
+ if (!current || current.state !== "queued" && current.state !== "running") return;
1204
+ try {
1205
+ await auditRem("rem_failed", current, { error: reason });
1206
+ await store.transition(jobId, {
1207
+ state: "failed",
1208
+ finished_at: (/* @__PURE__ */ new Date()).toISOString(),
1209
+ error: reason
1210
+ });
1211
+ } catch (error) {
1212
+ log.error("job_failure_audit_failed", {
1213
+ error,
1214
+ job_id: jobId
1215
+ }, {
1216
+ event_name: "sno_station_mem.server.job.failure.audit.failed",
1217
+ file: "packages/memory/src/sidecar/server.ts",
1218
+ function: "failNonTerminalJob",
1219
+ site_id: "server.failNonTerminalJob.cf84e07c6d"
1220
+ });
1221
+ }
1222
+ }
1223
+ async function skipNonTerminalJob(store, jobId, reason, callId, destination) {
1224
+ const current = store.get(jobId);
1225
+ if (!current || current.state !== "queued" && current.state !== "running") return;
1226
+ await auditRem("rem_skipped", current, {
1227
+ reason,
1228
+ call_id: callId,
1229
+ destination
1230
+ });
1231
+ await store.transition(jobId, {
1232
+ state: "skipped",
1233
+ finished_at: (/* @__PURE__ */ new Date()).toISOString(),
1234
+ error: reason
1235
+ });
1236
+ }
1237
+ async function recoverInterruptedJobs(store, completedJobStats, jobs) {
1238
+ const resumableJobIds = [];
1239
+ for (const job of jobs) try {
1240
+ const stats = completedJobStats.get(job.job_id);
1241
+ if (stats !== void 0) {
1242
+ await store.transition(job.job_id, {
1243
+ state: "done",
1244
+ finished_at: (/* @__PURE__ */ new Date()).toISOString(),
1245
+ stats
1246
+ });
1247
+ continue;
1248
+ }
1249
+ if (job.state === "running") {
1250
+ log.warn("job_recovery_resuming", {
1251
+ job_id: job.job_id,
1252
+ correlation_id: job.correlation_id,
1253
+ reason: "completion_receipt_missing_replay_same_wave"
1254
+ }, {
1255
+ event_name: "sno_station_mem.server.job.recovery.resuming",
1256
+ file: "packages/memory/src/sidecar/server.ts",
1257
+ function: "recoverInterruptedJobs",
1258
+ site_id: "server.recoverInterruptedJobs.15309ea841"
1259
+ });
1260
+ resumableJobIds.push(job.job_id);
1261
+ continue;
1262
+ }
1263
+ await auditRem("rem_failed", job, { error: "sidecar_restart" });
1264
+ await store.transition(job.job_id, {
1265
+ state: "failed",
1266
+ finished_at: (/* @__PURE__ */ new Date()).toISOString(),
1267
+ error: "sidecar_restart"
1268
+ });
1269
+ } catch (error) {
1270
+ reportSidecarFailure("job-recovery", error);
1271
+ }
1272
+ return resumableJobIds;
1273
+ }
1274
+ async function readCompletedJobStats(wantedJobs) {
1275
+ const completed = /* @__PURE__ */ new Map();
1276
+ for await (const line of readJsonlLines(getAuditPath(getSnoStationMemStateDir()))) {
1277
+ if (line.length === 0) continue;
1278
+ try {
1279
+ const entry = JSON.parse(line);
1280
+ if (!isRecord(entry) || entry["event"] !== "rem_completed") continue;
1281
+ const details = entry["details"];
1282
+ if (!isRecord(details) || typeof details["job_id"] !== "string" || !wantedJobs.has(details["job_id"])) continue;
1283
+ const type = details["type"];
1284
+ if (typeof type !== "string" || parseRemOperationType(type) === void 0) continue;
1285
+ const stats = parseRemJobStats(details["stats"]);
1286
+ if (stats === void 0) continue;
1287
+ completed.set(details["job_id"], stats);
1288
+ } catch {}
1289
+ }
1290
+ return completed;
1291
+ }
1292
+ async function auditRem(event, job, extra = {}) {
1293
+ return appendAuditEntryStrict(getSnoStationMemStateDir(), {
1294
+ event,
1295
+ scope: job.scope,
1296
+ resultStatus: event === "rem_skipped" ? "skipped" : event === "rem_failed" ? "error" : "ok",
1297
+ details: {
1298
+ type: job.type,
1299
+ scope: job.scope,
1300
+ job_id: job.job_id,
1301
+ correlation_id: job.correlation_id,
1302
+ source: REM_SOURCE,
1303
+ stats: { operations: 0 },
1304
+ ...extra
1305
+ }
1306
+ });
1307
+ }
1308
+ function readCorrelationId(request) {
1309
+ const value = request.headers[REM_CORRELATION_ID_HEADER];
1310
+ if (typeof value !== "string") return void 0;
1311
+ const trimmed = value.trim();
1312
+ return trimmed.length > 0 ? trimmed : void 0;
1313
+ }
1314
+ async function readJsonBody(request) {
1315
+ const body = await readRequestBody(request);
1316
+ try {
1317
+ return JSON.parse(body);
1318
+ } catch {
1319
+ throw new HttpError(400, "invalid_request");
1320
+ }
1321
+ }
1322
+ function sendJson(response, status, body) {
1323
+ const payload = JSON.stringify(body);
1324
+ response.writeHead(status, {
1325
+ "Content-Type": "application/json",
1326
+ "Content-Length": Buffer.byteLength(payload)
1327
+ });
1328
+ response.end(payload);
1329
+ }
1330
+ function requestPath(request) {
1331
+ try {
1332
+ return new URL(request.url ?? "/healthz", REM_SIDECAR_ORIGIN).pathname;
1333
+ } catch {
1334
+ return request.url ?? "/healthz";
1335
+ }
1336
+ }
1337
+ async function listen(server) {
1338
+ await new Promise((resolvePromise, reject) => {
1339
+ server.once("error", reject);
1340
+ server.listen(0, REM_SIDECAR_HOST, () => {
1341
+ server.removeListener("error", reject);
1342
+ resolvePromise();
1343
+ });
1344
+ });
1345
+ }
1346
+ async function closeServer(server) {
1347
+ if (!server.listening) return;
1348
+ await new Promise((resolvePromise, reject) => {
1349
+ server.close((error) => error ? reject(error) : resolvePromise());
1350
+ });
1351
+ }
1352
+ async function writeDiscovery(discoveryPath, discovery) {
1353
+ const parent = path.dirname(discoveryPath);
1354
+ await mkdir(parent, { recursive: true });
1355
+ const temporaryPath = `${discoveryPath}.${randomUUID()}.tmp`;
1356
+ const handle = await open(temporaryPath, "wx", 384);
1357
+ try {
1358
+ try {
1359
+ await handle.writeFile(JSON.stringify(discovery), "utf8");
1360
+ await handle.sync();
1361
+ } finally {
1362
+ await handle.close();
1363
+ }
1364
+ await rename(temporaryPath, discoveryPath);
1365
+ await syncDirectory(parent);
1366
+ } finally {
1367
+ await rm(temporaryPath, { force: true });
1368
+ }
1369
+ }
1370
+ async function removeOwnedDiscovery(discoveryPath, token) {
1371
+ if (!await discoveryBelongsTo(discoveryPath, token)) return;
1372
+ await rm(discoveryPath, { force: true });
1373
+ await syncDirectory(path.dirname(discoveryPath));
1374
+ }
1375
+ function removeOwnedDiscoverySync(discoveryPath, token) {
1376
+ try {
1377
+ if (JSON.parse(readFileSync(discoveryPath, "utf8")).token === token) rmSync(discoveryPath, { force: true });
1378
+ } catch {}
1379
+ }
1380
+ async function discoveryBelongsTo(discoveryPath, token) {
1381
+ if (!existsSync(discoveryPath)) return false;
1382
+ try {
1383
+ return JSON.parse(await readFile(discoveryPath, "utf8")).token === token;
1384
+ } catch {
1385
+ return false;
1386
+ }
1387
+ }
1388
+ async function syncDirectory(directory) {
1389
+ if (process.platform === "win32") return;
1390
+ const handle = await open(directory, "r");
1391
+ try {
1392
+ await handle.sync();
1393
+ } finally {
1394
+ await handle.close();
1395
+ }
1396
+ }
1397
+ function isRecord(value) {
1398
+ return typeof value === "object" && value !== null;
1399
+ }
1400
+ function reportSidecarFailure(step, error) {
1401
+ log.error("sidecar.operation.failed", {
1402
+ step,
1403
+ error
1404
+ }, {
1405
+ event_name: "sidecar.operation.failed",
1406
+ file: "packages/memory/src/sidecar/server.ts",
1407
+ function: "reportSidecarFailure",
1408
+ site_id: "sidecar.operation.failed"
1409
+ });
1410
+ }
1411
+ //#endregion
1412
+ export { DuplicateSidecarError, startRemSidecar };