@remnic/core 1.1.0 → 1.1.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 (287) hide show
  1. package/dist/access-audit.d.ts +56 -0
  2. package/dist/access-audit.js +9 -0
  3. package/dist/access-cli.js +62 -45
  4. package/dist/access-cli.js.map +1 -1
  5. package/dist/access-http.d.ts +16 -9
  6. package/dist/access-http.js +25 -17
  7. package/dist/access-mcp.d.ts +16 -9
  8. package/dist/access-mcp.js +29 -7
  9. package/dist/access-schema.d.ts +124 -33
  10. package/dist/access-schema.js +5 -1
  11. package/dist/{access-service-HmO1Trrx.d.ts → access-service-Br8ZydTK.d.ts} +158 -63
  12. package/dist/access-service.d.ts +13 -6
  13. package/dist/access-service.js +22 -14
  14. package/dist/bootstrap.d.ts +6 -3
  15. package/dist/briefing.d.ts +1 -0
  16. package/dist/briefing.js +7 -6
  17. package/dist/buffer-surprise-report.d.ts +70 -0
  18. package/dist/buffer-surprise-report.js +7 -0
  19. package/dist/buffer-surprise-report.js.map +1 -0
  20. package/dist/buffer-surprise.d.ts +98 -0
  21. package/dist/buffer-surprise.js +11 -0
  22. package/dist/buffer-surprise.js.map +1 -0
  23. package/dist/buffer.d.ts +100 -2
  24. package/dist/buffer.js +1 -1
  25. package/dist/calibration.js +5 -5
  26. package/dist/causal-behavior.js +4 -4
  27. package/dist/causal-chain.js +2 -2
  28. package/dist/causal-consolidation.js +17 -16
  29. package/dist/causal-consolidation.js.map +1 -1
  30. package/dist/causal-retrieval.js +4 -4
  31. package/dist/causal-trajectory.js +1 -1
  32. package/dist/{chunk-QNJMBKFK.js → chunk-2LGMW3DJ.js} +3 -2
  33. package/dist/chunk-2LGMW3DJ.js.map +1 -0
  34. package/dist/{chunk-QDYXG4CS.js → chunk-3FPTCC3Z.js} +4 -3
  35. package/dist/chunk-3FPTCC3Z.js.map +1 -0
  36. package/dist/chunk-3GPTTA4J.js +57 -0
  37. package/dist/chunk-3GPTTA4J.js.map +1 -0
  38. package/dist/{chunk-44ICJRF3.js → chunk-3GXCSUXR.js} +4 -4
  39. package/dist/{chunk-ITRLGI2T.js → chunk-3OGMS3PE.js} +2 -2
  40. package/dist/chunk-54V4BZWP.js +139 -0
  41. package/dist/chunk-54V4BZWP.js.map +1 -0
  42. package/dist/chunk-5JRF2PZA.js +67 -0
  43. package/dist/chunk-5JRF2PZA.js.map +1 -0
  44. package/dist/chunk-64NJRYU2.js +332 -0
  45. package/dist/chunk-64NJRYU2.js.map +1 -0
  46. package/dist/{chunk-OIT5QGG4.js → chunk-6AUUAZEX.js} +72 -2
  47. package/dist/chunk-6AUUAZEX.js.map +1 -0
  48. package/dist/{chunk-ZVBB3T7V.js → chunk-7I7FKFZH.js} +24 -22
  49. package/dist/chunk-7I7FKFZH.js.map +1 -0
  50. package/dist/chunk-AJU4PJGY.js +126 -0
  51. package/dist/chunk-AJU4PJGY.js.map +1 -0
  52. package/dist/chunk-ASAITVLA.js +64 -0
  53. package/dist/chunk-ASAITVLA.js.map +1 -0
  54. package/dist/{chunk-3QHL5ABG.js → chunk-B5WXLVDY.js} +187 -6
  55. package/dist/chunk-B5WXLVDY.js.map +1 -0
  56. package/dist/{chunk-SYUK3VLY.js → chunk-BGJGXLZ7.js} +111 -2
  57. package/dist/{chunk-SYUK3VLY.js.map → chunk-BGJGXLZ7.js.map} +1 -1
  58. package/dist/{chunk-MBJHSA7F.js → chunk-BK2EFTE2.js} +258 -13
  59. package/dist/chunk-BK2EFTE2.js.map +1 -0
  60. package/dist/chunk-C4SQJZAF.js +486 -0
  61. package/dist/chunk-C4SQJZAF.js.map +1 -0
  62. package/dist/{chunk-6UJ47TVX.js → chunk-CUPFXL3J.js} +2 -2
  63. package/dist/chunk-DF3RVK3X.js +119 -0
  64. package/dist/chunk-DF3RVK3X.js.map +1 -0
  65. package/dist/{chunk-37UIFYWO.js → chunk-DFTTJYSO.js} +108 -9
  66. package/dist/chunk-DFTTJYSO.js.map +1 -0
  67. package/dist/chunk-DGVM5SFL.js +69 -0
  68. package/dist/chunk-DGVM5SFL.js.map +1 -0
  69. package/dist/chunk-EIR5VLIH.js +90 -0
  70. package/dist/chunk-EIR5VLIH.js.map +1 -0
  71. package/dist/{chunk-PAORGQRI.js → chunk-EPQJM2GC.js} +37 -23
  72. package/dist/chunk-EPQJM2GC.js.map +1 -0
  73. package/dist/{chunk-GV6NLQ4X.js → chunk-F5VP6YCB.js} +374 -16
  74. package/dist/chunk-F5VP6YCB.js.map +1 -0
  75. package/dist/{chunk-6ZH4TU6I.js → chunk-FAAFWE4G.js} +2 -1
  76. package/dist/chunk-FAAFWE4G.js.map +1 -0
  77. package/dist/{chunk-7WQ6SLIE.js → chunk-FVA6TGI3.js} +2 -2
  78. package/dist/chunk-GDFS42HT.js +206 -0
  79. package/dist/chunk-GDFS42HT.js.map +1 -0
  80. package/dist/{chunk-MVTHXUBX.js → chunk-GKFXUTJ2.js} +479 -20
  81. package/dist/chunk-GKFXUTJ2.js.map +1 -0
  82. package/dist/{chunk-NQEVYWX6.js → chunk-HK3FGIEW.js} +209 -5
  83. package/dist/chunk-HK3FGIEW.js.map +1 -0
  84. package/dist/chunk-IISBCCWR.js +52 -0
  85. package/dist/chunk-IISBCCWR.js.map +1 -0
  86. package/dist/{chunk-WBSAYXVI.js → chunk-INXV5JBT.js} +198 -42
  87. package/dist/chunk-INXV5JBT.js.map +1 -0
  88. package/dist/chunk-JBMSGZEQ.js +441 -0
  89. package/dist/chunk-JBMSGZEQ.js.map +1 -0
  90. package/dist/{chunk-J4IYOZZ5.js → chunk-JXS5PDQ7.js} +3 -1
  91. package/dist/chunk-JXS5PDQ7.js.map +1 -0
  92. package/dist/{chunk-6LX5ORAS.js → chunk-KUB6JU6H.js} +4 -4
  93. package/dist/chunk-KVBLZUKV.js +173 -0
  94. package/dist/chunk-KVBLZUKV.js.map +1 -0
  95. package/dist/chunk-LBLXEFWK.js +51 -0
  96. package/dist/chunk-LBLXEFWK.js.map +1 -0
  97. package/dist/{chunk-3WHVNEN7.js → chunk-LTCGGW2D.js} +1 -1
  98. package/dist/chunk-LTCGGW2D.js.map +1 -0
  99. package/dist/{chunk-UEYA6UC7.js → chunk-NZLQTHS5.js} +25 -2
  100. package/dist/chunk-NZLQTHS5.js.map +1 -0
  101. package/dist/chunk-PVPWZSSI.js +37 -0
  102. package/dist/chunk-PVPWZSSI.js.map +1 -0
  103. package/dist/{chunk-4NRAJUDS.js → chunk-RBBWYEFJ.js} +1 -1
  104. package/dist/chunk-RFYAYKTD.js +146 -0
  105. package/dist/chunk-RFYAYKTD.js.map +1 -0
  106. package/dist/{chunk-DHHP2Z4X.js → chunk-RGLL5SPU.js} +2 -2
  107. package/dist/{chunk-3SV6CQHO.js → chunk-S3EEFKNY.js} +101 -65
  108. package/dist/chunk-S3EEFKNY.js.map +1 -0
  109. package/dist/chunk-SOBJ6NEY.js +18 -0
  110. package/dist/chunk-SOBJ6NEY.js.map +1 -0
  111. package/dist/{chunk-JIU55F3X.js → chunk-SPI27QT6.js} +2 -2
  112. package/dist/chunk-TVVEYCNW.js +65 -0
  113. package/dist/chunk-TVVEYCNW.js.map +1 -0
  114. package/dist/chunk-ULYOGL6R.js +322 -0
  115. package/dist/chunk-ULYOGL6R.js.map +1 -0
  116. package/dist/{chunk-47UU5PU2.js → chunk-VBVG2M5G.js} +18 -3
  117. package/dist/chunk-VBVG2M5G.js.map +1 -0
  118. package/dist/{chunk-7ECD5ATE.js → chunk-VDX363PS.js} +2 -2
  119. package/dist/{chunk-DEPL3635.js → chunk-VYM3VWOF.js} +1432 -188
  120. package/dist/chunk-VYM3VWOF.js.map +1 -0
  121. package/dist/{chunk-MTLYEMJB.js → chunk-WCLICCGB.js} +18 -3
  122. package/dist/chunk-WCLICCGB.js.map +1 -0
  123. package/dist/{chunk-4LACOVZX.js → chunk-WVVA7F5A.js} +2 -2
  124. package/dist/chunk-X6GF3FX2.js +26 -0
  125. package/dist/chunk-X6GF3FX2.js.map +1 -0
  126. package/dist/{chunk-3QFQGRHO.js → chunk-XMHBH5H6.js} +4 -4
  127. package/dist/{chunk-BLKTA7MM.js → chunk-YNQKWQT4.js} +50 -17
  128. package/dist/chunk-YNQKWQT4.js.map +1 -0
  129. package/dist/chunk-ZAIM4TUE.js +488 -0
  130. package/dist/chunk-ZAIM4TUE.js.map +1 -0
  131. package/dist/{chunk-N42IWANG.js → chunk-ZEM3OK2K.js} +2 -2
  132. package/dist/chunk-ZZTOURJI.js +91 -0
  133. package/dist/chunk-ZZTOURJI.js.map +1 -0
  134. package/dist/{cli-BneVIEvh.d.ts → cli-BkeRaYfk.d.ts} +2 -2
  135. package/dist/cli.d.ts +13 -6
  136. package/dist/cli.js +40 -29
  137. package/dist/config.js +1 -1
  138. package/dist/consolidation-operator.d.ts +41 -0
  139. package/dist/consolidation-operator.js +11 -0
  140. package/dist/consolidation-operator.js.map +1 -0
  141. package/dist/consolidation-provenance-check.d.ts +68 -0
  142. package/dist/consolidation-provenance-check.js +9 -0
  143. package/dist/consolidation-provenance-check.js.map +1 -0
  144. package/dist/consolidation-undo.d.ts +123 -0
  145. package/dist/consolidation-undo.js +426 -0
  146. package/dist/consolidation-undo.js.map +1 -0
  147. package/dist/{contradiction-scan-GR33PONM.js → contradiction-scan-E3GJTI4F.js} +43 -7
  148. package/dist/contradiction-scan-E3GJTI4F.js.map +1 -0
  149. package/dist/cross-namespace-budget.d.ts +133 -0
  150. package/dist/cross-namespace-budget.js +9 -0
  151. package/dist/cross-namespace-budget.js.map +1 -0
  152. package/dist/direct-answer-wiring.js +5 -70
  153. package/dist/direct-answer-wiring.js.map +1 -1
  154. package/dist/{engine-5TIQBYZR.js → engine-F3GOXGE5.js} +8 -7
  155. package/dist/engine-F3GOXGE5.js.map +1 -0
  156. package/dist/entity-retrieval.d.ts +1 -0
  157. package/dist/entity-retrieval.js +7 -6
  158. package/dist/explicit-capture.d.ts +6 -3
  159. package/dist/explicit-capture.js +2 -2
  160. package/dist/extraction-judge-telemetry.d.ts +113 -0
  161. package/dist/extraction-judge-telemetry.js +14 -0
  162. package/dist/extraction-judge-telemetry.js.map +1 -0
  163. package/dist/extraction-judge-training.d.ts +85 -0
  164. package/dist/extraction-judge-training.js +16 -0
  165. package/dist/extraction-judge-training.js.map +1 -0
  166. package/dist/extraction-judge.d.ts +124 -2
  167. package/dist/extraction-judge.js +11 -1
  168. package/dist/extraction.js +6 -5
  169. package/dist/fallback-llm.js +2 -2
  170. package/dist/graph-recall.d.ts +100 -0
  171. package/dist/graph-recall.js +8 -0
  172. package/dist/graph-recall.js.map +1 -0
  173. package/dist/graph-retrieval.d.ts +271 -0
  174. package/dist/graph-retrieval.js +21 -0
  175. package/dist/graph-retrieval.js.map +1 -0
  176. package/dist/importance.js +1 -1
  177. package/dist/index.d.ts +585 -20
  178. package/dist/index.js +503 -312
  179. package/dist/index.js.map +1 -1
  180. package/dist/memory-worth-bench.d.ts +51 -0
  181. package/dist/memory-worth-bench.js +131 -0
  182. package/dist/memory-worth-bench.js.map +1 -0
  183. package/dist/memory-worth-filter.d.ts +128 -0
  184. package/dist/memory-worth-filter.js +10 -0
  185. package/dist/memory-worth-filter.js.map +1 -0
  186. package/dist/memory-worth-outcomes.d.ts +118 -0
  187. package/dist/memory-worth-outcomes.js +9 -0
  188. package/dist/memory-worth-outcomes.js.map +1 -0
  189. package/dist/memory-worth.d.ts +102 -0
  190. package/dist/memory-worth.js +7 -0
  191. package/dist/memory-worth.js.map +1 -0
  192. package/dist/operator-toolkit.d.ts +40 -1
  193. package/dist/operator-toolkit.js +23 -14
  194. package/dist/{orchestrator-DRYA6_lW.d.ts → orchestrator-CmJ-NTdJ.d.ts} +233 -8
  195. package/dist/orchestrator.d.ts +6 -3
  196. package/dist/orchestrator.js +49 -39
  197. package/dist/page-versioning.d.ts +12 -1
  198. package/dist/page-versioning.js +5 -3
  199. package/dist/{port-C1GZFv8h.d.ts → port-BADbLZU5.d.ts} +2 -2
  200. package/dist/qmd-recall-cache.d.ts +1 -1
  201. package/dist/qmd.d.ts +5 -3
  202. package/dist/qmd.js +1 -1
  203. package/dist/reasoning-trace-recall.d.ts +90 -0
  204. package/dist/reasoning-trace-recall.js +13 -0
  205. package/dist/reasoning-trace-recall.js.map +1 -0
  206. package/dist/reasoning-trace-types.d.ts +54 -0
  207. package/dist/reasoning-trace-types.js +17 -0
  208. package/dist/reasoning-trace-types.js.map +1 -0
  209. package/dist/recall-audit-anomaly.d.ts +112 -0
  210. package/dist/recall-audit-anomaly.js +11 -0
  211. package/dist/recall-audit-anomaly.js.map +1 -0
  212. package/dist/recall-audit.js +5 -44
  213. package/dist/recall-audit.js.map +1 -1
  214. package/dist/recall-explain-renderer.d.ts +49 -0
  215. package/dist/recall-explain-renderer.js +18 -0
  216. package/dist/recall-explain-renderer.js.map +1 -0
  217. package/dist/recall-state.d.ts +12 -1
  218. package/dist/recall-state.js +1 -1
  219. package/dist/recall-xray-cli.d.ts +40 -0
  220. package/dist/recall-xray-cli.js +11 -0
  221. package/dist/recall-xray-cli.js.map +1 -0
  222. package/dist/recall-xray-renderer.d.ts +44 -0
  223. package/dist/recall-xray-renderer.js +18 -0
  224. package/dist/recall-xray-renderer.js.map +1 -0
  225. package/dist/recall-xray.d.ts +179 -0
  226. package/dist/recall-xray.js +13 -0
  227. package/dist/recall-xray.js.map +1 -0
  228. package/dist/resume-bundles.js +5 -5
  229. package/dist/retrieval-agents.d.ts +1 -1
  230. package/dist/retrieval-tiers.d.ts +17 -0
  231. package/dist/retrieval-tiers.js +9 -0
  232. package/dist/retrieval-tiers.js.map +1 -0
  233. package/dist/schemas.d.ts +287 -31
  234. package/dist/schemas.js +1 -1
  235. package/dist/{semantic-consolidation-DrvSYRdB.d.ts → semantic-consolidation-CxJU6MJk.d.ts} +62 -1
  236. package/dist/semantic-consolidation.d.ts +2 -1
  237. package/dist/semantic-consolidation.js +21 -7
  238. package/dist/semantic-rule-promotion.js +7 -6
  239. package/dist/semantic-rule-verifier.js +7 -6
  240. package/dist/storage.d.ts +82 -1
  241. package/dist/storage.js +6 -5
  242. package/dist/summarizer.js +3 -3
  243. package/dist/temporal-supersession.d.ts +1 -0
  244. package/dist/tier-migration.d.ts +2 -1
  245. package/dist/types.d.ts +276 -2
  246. package/dist/types.js +1 -1
  247. package/dist/verified-recall.js +7 -6
  248. package/package.json +1 -1
  249. package/dist/chunk-37UIFYWO.js.map +0 -1
  250. package/dist/chunk-3QHL5ABG.js.map +0 -1
  251. package/dist/chunk-3SV6CQHO.js.map +0 -1
  252. package/dist/chunk-3WHVNEN7.js.map +0 -1
  253. package/dist/chunk-47UU5PU2.js.map +0 -1
  254. package/dist/chunk-6ZH4TU6I.js.map +0 -1
  255. package/dist/chunk-BLKTA7MM.js.map +0 -1
  256. package/dist/chunk-DEPL3635.js.map +0 -1
  257. package/dist/chunk-GV6NLQ4X.js.map +0 -1
  258. package/dist/chunk-J4IYOZZ5.js.map +0 -1
  259. package/dist/chunk-LAYN4LDC.js +0 -267
  260. package/dist/chunk-LAYN4LDC.js.map +0 -1
  261. package/dist/chunk-MBJHSA7F.js.map +0 -1
  262. package/dist/chunk-MTLYEMJB.js.map +0 -1
  263. package/dist/chunk-MVTHXUBX.js.map +0 -1
  264. package/dist/chunk-NQEVYWX6.js.map +0 -1
  265. package/dist/chunk-OIT5QGG4.js.map +0 -1
  266. package/dist/chunk-PAORGQRI.js.map +0 -1
  267. package/dist/chunk-QDYXG4CS.js.map +0 -1
  268. package/dist/chunk-QNJMBKFK.js.map +0 -1
  269. package/dist/chunk-UEYA6UC7.js.map +0 -1
  270. package/dist/chunk-UVJFDP7P.js +0 -202
  271. package/dist/chunk-UVJFDP7P.js.map +0 -1
  272. package/dist/chunk-WBSAYXVI.js.map +0 -1
  273. package/dist/chunk-ZVBB3T7V.js.map +0 -1
  274. package/dist/contradiction-scan-GR33PONM.js.map +0 -1
  275. /package/dist/{engine-5TIQBYZR.js.map → access-audit.js.map} +0 -0
  276. /package/dist/{chunk-44ICJRF3.js.map → chunk-3GXCSUXR.js.map} +0 -0
  277. /package/dist/{chunk-ITRLGI2T.js.map → chunk-3OGMS3PE.js.map} +0 -0
  278. /package/dist/{chunk-6UJ47TVX.js.map → chunk-CUPFXL3J.js.map} +0 -0
  279. /package/dist/{chunk-7WQ6SLIE.js.map → chunk-FVA6TGI3.js.map} +0 -0
  280. /package/dist/{chunk-6LX5ORAS.js.map → chunk-KUB6JU6H.js.map} +0 -0
  281. /package/dist/{chunk-4NRAJUDS.js.map → chunk-RBBWYEFJ.js.map} +0 -0
  282. /package/dist/{chunk-DHHP2Z4X.js.map → chunk-RGLL5SPU.js.map} +0 -0
  283. /package/dist/{chunk-JIU55F3X.js.map → chunk-SPI27QT6.js.map} +0 -0
  284. /package/dist/{chunk-7ECD5ATE.js.map → chunk-VDX363PS.js.map} +0 -0
  285. /package/dist/{chunk-4LACOVZX.js.map → chunk-WVVA7F5A.js.map} +0 -0
  286. /package/dist/{chunk-3QFQGRHO.js.map → chunk-XMHBH5H6.js.map} +0 -0
  287. /package/dist/{chunk-N42IWANG.js.map → chunk-ZEM3OK2K.js.map} +0 -0
@@ -0,0 +1,90 @@
1
+ // src/memory-worth-outcomes.ts
2
+ import path from "path";
3
+ var outcomeLocks = /* @__PURE__ */ new Map();
4
+ function runSerialized(key, task) {
5
+ const prev = outcomeLocks.get(key) ?? Promise.resolve();
6
+ const next = prev.catch(() => void 0).then(task);
7
+ outcomeLocks.set(key, next);
8
+ next.then(
9
+ () => {
10
+ if (outcomeLocks.get(key) === next) outcomeLocks.delete(key);
11
+ },
12
+ () => {
13
+ if (outcomeLocks.get(key) === next) outcomeLocks.delete(key);
14
+ }
15
+ ).catch(() => {
16
+ });
17
+ return next;
18
+ }
19
+ var MEMORY_WORTH_OUTCOME_ELIGIBLE_CATEGORIES = /* @__PURE__ */ new Set(["fact"]);
20
+ function memoryWorthOutcomeEligibleCategories() {
21
+ return new Set(MEMORY_WORTH_OUTCOME_ELIGIBLE_CATEGORIES);
22
+ }
23
+ function memoryIdFromPath(memoryPath) {
24
+ if (!memoryPath || typeof memoryPath !== "string") return null;
25
+ if (!memoryPath.endsWith(".md")) return null;
26
+ const basename = path.basename(memoryPath, ".md");
27
+ if (!basename) return null;
28
+ return basename;
29
+ }
30
+ async function recordMemoryOutcome(storage, input) {
31
+ if (input.outcome !== "success" && input.outcome !== "failure") {
32
+ return {
33
+ ok: false,
34
+ reason: "invalid_outcome",
35
+ message: `outcome must be "success" or "failure"; got ${JSON.stringify(input.outcome)}`
36
+ };
37
+ }
38
+ const memoryId = memoryIdFromPath(input.memoryPath);
39
+ if (memoryId === null) {
40
+ return {
41
+ ok: false,
42
+ reason: "invalid_path",
43
+ message: `memoryPath must end in .md; got ${JSON.stringify(input.memoryPath)}`
44
+ };
45
+ }
46
+ return runSerialized(memoryId, async () => {
47
+ const memory = await storage.getMemoryById(memoryId);
48
+ if (!memory) {
49
+ return {
50
+ ok: false,
51
+ reason: "not_found",
52
+ message: `no memory with id ${memoryId}`
53
+ };
54
+ }
55
+ if (!MEMORY_WORTH_OUTCOME_ELIGIBLE_CATEGORIES.has(memory.frontmatter.category)) {
56
+ return {
57
+ ok: false,
58
+ reason: "ineligible_category",
59
+ message: `category ${memory.frontmatter.category} is not instrumented for Memory Worth`
60
+ };
61
+ }
62
+ const currentSuccess = memory.frontmatter.mw_success ?? 0;
63
+ const currentFail = memory.frontmatter.mw_fail ?? 0;
64
+ const nextSuccess = input.outcome === "success" ? currentSuccess + 1 : currentSuccess;
65
+ const nextFail = input.outcome === "failure" ? currentFail + 1 : currentFail;
66
+ const updated = await storage.updateMemoryFrontmatter(memoryId, {
67
+ mw_success: nextSuccess,
68
+ mw_fail: nextFail
69
+ });
70
+ if (!updated) {
71
+ return {
72
+ ok: false,
73
+ reason: "not_found",
74
+ message: `memory ${memoryId} disappeared between read and write`
75
+ };
76
+ }
77
+ return {
78
+ ok: true,
79
+ memoryId,
80
+ mw_success: nextSuccess,
81
+ mw_fail: nextFail
82
+ };
83
+ });
84
+ }
85
+
86
+ export {
87
+ memoryWorthOutcomeEligibleCategories,
88
+ recordMemoryOutcome
89
+ };
90
+ //# sourceMappingURL=chunk-EIR5VLIH.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/memory-worth-outcomes.ts"],"sourcesContent":["/**\n * Issue #560 PR 3 — Memory Worth outcome signal pipeline.\n *\n * PR 1 added `mw_success` / `mw_fail` fields to MemoryFrontmatter. PR 2 added\n * a pure scoring helper. This module adds the one piece tying the two\n * together: a way for callers to record a single outcome observation against\n * a memory, which increments the appropriate counter in frontmatter.\n *\n * The public entry point is `recordMemoryOutcome({ memoryPath, outcome, ... })`.\n * Callers pass the full path to the memory file (not just the ID) because in\n * the usual outcome source — the observation ledger — the memory path is\n * already captured in the event payload, and path-based lookup avoids a\n * full-corpus scan.\n *\n * Intentional properties:\n * - Works on a per-memory basis (no bulk API in this slice). Bulk update is\n * an easy layer on top of this once a second caller needs it.\n * - Reuses the existing `updateMemoryFrontmatter(id, patch)` write path so\n * unrelated fields (confidence, importance, lifecycle hooks, etc.) are\n * preserved. The PR 1 serializer rejects negative / non-integer counters,\n * so we rely on that for defensive validation rather than duplicating it.\n * - Only instruments categories in `MEMORY_WORTH_OUTCOME_ELIGIBLE_CATEGORIES`\n * (currently `fact`, matching `MEMORY_WORTH_ELIGIBLE_CATEGORIES` in\n * operator-toolkit.ts for the doctor audit). Non-eligible memories return\n * `{ ok: false, reason: \"ineligible_category\" }` rather than throwing so\n * the caller — typically a ledger consumer draining heterogeneous events\n * — doesn't need to pre-filter by category.\n * - Missing / unknown memory IDs return `{ ok: false, reason: \"not_found\" }`\n * rather than throwing, because outcome events may reference memories\n * that were archived/deleted between the session and the ledger drain.\n * That isn't an operator-actionable error.\n * - On success, returns the new counter values so observability surfaces\n * can report the increment without a second read.\n *\n * Out of scope (later PRs):\n * - Recall filter reading the counters (PR 4).\n * - Benchmark + default flip (PR 5).\n * - Automatic increments from extraction or summarization. Only the\n * explicit `MEM_OUTCOME` ledger tag or an MCP tool call drives writes.\n */\n\nimport path from \"node:path\";\n\nimport type { StorageManager } from \"./storage.js\";\nimport type { MemoryFrontmatter } from \"./types.js\";\n\n/**\n * Per-memory-ID serialization of the read-modify-write increment.\n *\n * Codex P1: without this, concurrent calls for the same memory race. Both\n * callers read the same `mw_*` values, each writes +1, and one increment\n * is lost — silently undercounting outcomes. We chain an async promise\n * per memory ID so read-then-write is atomic with respect to other calls\n * into this module.\n *\n * This serializes only THIS module. Direct writers (e.g. hand-rolled\n * frontmatter patches) still bypass the lock, but the documented surface\n * for Memory Worth increments is this function, and the bench only uses\n * this path.\n *\n * The lock map is WeakRef-free by design: the chain self-cleans once the\n * last pending write resolves (we delete the entry inside the `.finally`\n * of the tail), so memory use stays bounded even for long-running\n * processes that touch many different memory IDs.\n */\nconst outcomeLocks = new Map<string, Promise<unknown>>();\n\nfunction runSerialized<T>(key: string, task: () => Promise<T>): Promise<T> {\n const prev = outcomeLocks.get(key) ?? Promise.resolve();\n // Swallow upstream errors so a failed outcome for memory A doesn't\n // permanently poison the chain for memory A. We still propagate our own\n // result/errors to the caller.\n const next = prev.catch(() => undefined).then(task);\n outcomeLocks.set(key, next);\n // Chain the cleanup off `next` BUT attach a `.catch` so the cleanup\n // promise itself never surfaces as an unhandled rejection. The caller\n // gets `next` back and handles it their own way; this detached cleanup\n // chain has no observer, so without the .catch Node would crash the\n // process on a task rejection even when the caller awaited `next` and\n // handled the error correctly.\n next\n .then(\n () => {\n if (outcomeLocks.get(key) === next) outcomeLocks.delete(key);\n },\n () => {\n if (outcomeLocks.get(key) === next) outcomeLocks.delete(key);\n },\n )\n .catch(() => {\n // Defensive no-op in case a hook inside the cleanup branches throws.\n });\n return next;\n}\n\n/**\n * Categories currently instrumented for Memory Worth counters. Must be kept\n * in sync with `MEMORY_WORTH_ELIGIBLE_CATEGORIES` in `operator-toolkit.ts`.\n * Declared here (not imported) to avoid a circular dep with operator-toolkit,\n * which imports from this file's peers. The two constants are validated by a\n * test to stay in lockstep.\n */\nconst MEMORY_WORTH_OUTCOME_ELIGIBLE_CATEGORIES: ReadonlySet<MemoryFrontmatter[\"category\"]> =\n new Set([\"fact\"]);\n\n/**\n * Exported so downstream tests / operators can query the allowlist without\n * re-declaring it. Returned as a frozen copy so consumers cannot mutate the\n * module-internal set.\n */\nexport function memoryWorthOutcomeEligibleCategories(): ReadonlySet<MemoryFrontmatter[\"category\"]> {\n return new Set(MEMORY_WORTH_OUTCOME_ELIGIBLE_CATEGORIES);\n}\n\n/**\n * The direction of an outcome — whether the session that consumed this\n * memory succeeded or failed. Restricted to a string literal union so\n * callers in TypeScript land can't pass arbitrary tags.\n */\nexport type MemoryOutcomeKind = \"success\" | \"failure\";\n\n/**\n * Arguments to `recordMemoryOutcome`.\n *\n * `memoryPath` is the filesystem path to the memory; we derive the ID from\n * the basename, matching how the operator-toolkit and recall layers map\n * paths to IDs.\n */\nexport interface RecordMemoryOutcomeInput {\n /**\n * Absolute or repo-relative path to the memory file. Typically the value\n * of `MemoryFile.path` for a memory returned by `readAllMemories`.\n */\n memoryPath: string;\n /** Outcome direction — \"success\" bumps mw_success; \"failure\" bumps mw_fail. */\n outcome: MemoryOutcomeKind;\n /**\n * Optional observation timestamp for audit / telemetry. This PR doesn't\n * persist the timestamp (PR 4/5 will use `lastAccessed`, which already\n * covers the recency-decay requirement), but accepting it here keeps the\n * call shape stable so future ledger integrations don't need a breaking\n * change.\n */\n timestamp?: Date | string;\n}\n\n/**\n * Outcome of a `recordMemoryOutcome` call.\n *\n * `ok: true` means the counter was incremented and flushed. The returned\n * values reflect the post-increment state, so callers can log\n * `\"fact-xyz: 4/1 → 5/1\"` without re-reading.\n *\n * `ok: false` carries a short machine-readable `reason` so a ledger drainer\n * can aggregate metrics (\"how many events hit not_found this hour?\"). The\n * human-readable `message` is a friendlier version for logs.\n */\nexport type RecordMemoryOutcomeResult =\n | {\n ok: true;\n memoryId: string;\n /** New value of `mw_success` after the increment. */\n mw_success: number;\n /** New value of `mw_fail` after the increment. */\n mw_fail: number;\n }\n | {\n ok: false;\n reason:\n | \"not_found\"\n | \"ineligible_category\"\n | \"invalid_outcome\"\n | \"invalid_path\";\n message: string;\n };\n\n/**\n * Extract the memory ID from a file path. Memory files are stored as\n * `<id>.md`, matching the rest of the system (see `getMemoryById`, which\n * infers paths from IDs).\n *\n * Returns `null` for any path that does not end in `.md`. The check is\n * unconditional — `path.basename` strips directory components before the\n * suffix check, so previous conditional logic silently accepted\n * directory-prefixed paths like `/tmp/facts/2026-01-01/not-a-memory`\n * (the basename `not-a-memory` is not equal to the input, so the `.md`\n * guard was skipped). The new check looks at the raw input once.\n */\nfunction memoryIdFromPath(memoryPath: string): string | null {\n if (!memoryPath || typeof memoryPath !== \"string\") return null;\n if (!memoryPath.endsWith(\".md\")) return null;\n const basename = path.basename(memoryPath, \".md\");\n if (!basename) return null;\n return basename;\n}\n\n/**\n * Record a single outcome observation against a memory. Increments\n * `mw_success` or `mw_fail` on the memory's frontmatter (preserving all\n * other fields) via the existing `updateMemoryFrontmatter` write path.\n *\n * See the top-of-file doc comment for policy details (eligible categories,\n * error semantics, and what is intentionally out of scope).\n */\nexport async function recordMemoryOutcome(\n storage: StorageManager,\n input: RecordMemoryOutcomeInput,\n): Promise<RecordMemoryOutcomeResult> {\n if (input.outcome !== \"success\" && input.outcome !== \"failure\") {\n return {\n ok: false,\n reason: \"invalid_outcome\",\n message: `outcome must be \"success\" or \"failure\"; got ${JSON.stringify(input.outcome)}`,\n };\n }\n\n const memoryId = memoryIdFromPath(input.memoryPath);\n if (memoryId === null) {\n return {\n ok: false,\n reason: \"invalid_path\",\n message: `memoryPath must end in .md; got ${JSON.stringify(input.memoryPath)}`,\n };\n }\n\n // Serialize the read-modify-write per memory ID so concurrent callers\n // (parallel ledger drain, multiple MCP clients, etc.) can't each read\n // the same snapshot and race to write `+1`, losing an increment.\n return runSerialized(memoryId, async () => {\n const memory = await storage.getMemoryById(memoryId);\n if (!memory) {\n return {\n ok: false,\n reason: \"not_found\",\n message: `no memory with id ${memoryId}`,\n };\n }\n\n if (!MEMORY_WORTH_OUTCOME_ELIGIBLE_CATEGORIES.has(memory.frontmatter.category)) {\n return {\n ok: false,\n reason: \"ineligible_category\",\n message: `category ${memory.frontmatter.category} is not instrumented for Memory Worth`,\n };\n }\n\n // Absent counters are treated as 0 (matching the PR 1 semantics — legacy\n // memories implicitly have Beta(1,1) priors). Increments land on the\n // actual counter regardless of whether the field was previously set.\n const currentSuccess = memory.frontmatter.mw_success ?? 0;\n const currentFail = memory.frontmatter.mw_fail ?? 0;\n\n const nextSuccess = input.outcome === \"success\" ? currentSuccess + 1 : currentSuccess;\n const nextFail = input.outcome === \"failure\" ? currentFail + 1 : currentFail;\n\n // `updateMemoryFrontmatter` goes through `writeMemoryFrontmatter`, which\n // routes through the PR 1 serializer — so a stored corrupt value (e.g., a\n // pre-existing float) would be rejected here. That is intentional: we\n // refuse to layer a fresh increment on top of garbage. Operators should\n // use `remnic doctor` to find and fix those rows before PR 4 ships.\n //\n // `updateMemoryFrontmatter` returns `false` when the memory is no\n // longer present (archived / deleted between `getMemoryById` and the\n // write). Surface that as `not_found` so callers see an honest result\n // — silently returning `ok: true` with a counter that never landed\n // would skew downstream worth scoring.\n const updated = await storage.updateMemoryFrontmatter(memoryId, {\n mw_success: nextSuccess,\n mw_fail: nextFail,\n });\n if (!updated) {\n return {\n ok: false,\n reason: \"not_found\",\n message: `memory ${memoryId} disappeared between read and write`,\n };\n }\n\n return {\n ok: true,\n memoryId,\n mw_success: nextSuccess,\n mw_fail: nextFail,\n };\n });\n}\n"],"mappings":";AAyCA,OAAO,UAAU;AAwBjB,IAAM,eAAe,oBAAI,IAA8B;AAEvD,SAAS,cAAiB,KAAa,MAAoC;AACzE,QAAM,OAAO,aAAa,IAAI,GAAG,KAAK,QAAQ,QAAQ;AAItD,QAAM,OAAO,KAAK,MAAM,MAAM,MAAS,EAAE,KAAK,IAAI;AAClD,eAAa,IAAI,KAAK,IAAI;AAO1B,OACG;AAAA,IACC,MAAM;AACJ,UAAI,aAAa,IAAI,GAAG,MAAM,KAAM,cAAa,OAAO,GAAG;AAAA,IAC7D;AAAA,IACA,MAAM;AACJ,UAAI,aAAa,IAAI,GAAG,MAAM,KAAM,cAAa,OAAO,GAAG;AAAA,IAC7D;AAAA,EACF,EACC,MAAM,MAAM;AAAA,EAEb,CAAC;AACH,SAAO;AACT;AASA,IAAM,2CACJ,oBAAI,IAAI,CAAC,MAAM,CAAC;AAOX,SAAS,uCAAmF;AACjG,SAAO,IAAI,IAAI,wCAAwC;AACzD;AA4EA,SAAS,iBAAiB,YAAmC;AAC3D,MAAI,CAAC,cAAc,OAAO,eAAe,SAAU,QAAO;AAC1D,MAAI,CAAC,WAAW,SAAS,KAAK,EAAG,QAAO;AACxC,QAAM,WAAW,KAAK,SAAS,YAAY,KAAK;AAChD,MAAI,CAAC,SAAU,QAAO;AACtB,SAAO;AACT;AAUA,eAAsB,oBACpB,SACA,OACoC;AACpC,MAAI,MAAM,YAAY,aAAa,MAAM,YAAY,WAAW;AAC9D,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,QAAQ;AAAA,MACR,SAAS,+CAA+C,KAAK,UAAU,MAAM,OAAO,CAAC;AAAA,IACvF;AAAA,EACF;AAEA,QAAM,WAAW,iBAAiB,MAAM,UAAU;AAClD,MAAI,aAAa,MAAM;AACrB,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,QAAQ;AAAA,MACR,SAAS,mCAAmC,KAAK,UAAU,MAAM,UAAU,CAAC;AAAA,IAC9E;AAAA,EACF;AAKA,SAAO,cAAc,UAAU,YAAY;AACzC,UAAM,SAAS,MAAM,QAAQ,cAAc,QAAQ;AACnD,QAAI,CAAC,QAAQ;AACX,aAAO;AAAA,QACL,IAAI;AAAA,QACJ,QAAQ;AAAA,QACR,SAAS,qBAAqB,QAAQ;AAAA,MACxC;AAAA,IACF;AAEA,QAAI,CAAC,yCAAyC,IAAI,OAAO,YAAY,QAAQ,GAAG;AAC9E,aAAO;AAAA,QACL,IAAI;AAAA,QACJ,QAAQ;AAAA,QACR,SAAS,YAAY,OAAO,YAAY,QAAQ;AAAA,MAClD;AAAA,IACF;AAKA,UAAM,iBAAiB,OAAO,YAAY,cAAc;AACxD,UAAM,cAAc,OAAO,YAAY,WAAW;AAElD,UAAM,cAAc,MAAM,YAAY,YAAY,iBAAiB,IAAI;AACvE,UAAM,WAAW,MAAM,YAAY,YAAY,cAAc,IAAI;AAajE,UAAM,UAAU,MAAM,QAAQ,wBAAwB,UAAU;AAAA,MAC9D,YAAY;AAAA,MACZ,SAAS;AAAA,IACX,CAAC;AACD,QAAI,CAAC,SAAS;AACZ,aAAO;AAAA,QACL,IAAI;AAAA,QACJ,QAAQ;AAAA,QACR,SAAS,UAAU,QAAQ;AAAA,MAC7B;AAAA,IACF;AAEA,WAAO;AAAA,MACL,IAAI;AAAA,MACJ;AAAA,MACA,YAAY;AAAA,MACZ,SAAS;AAAA,IACX;AAAA,EACF,CAAC;AACH;","names":[]}
@@ -1,6 +1,9 @@
1
+ import {
2
+ resolveHomeDir
3
+ } from "./chunk-MARWOCVP.js";
1
4
  import {
2
5
  validateRouteTarget
3
- } from "./chunk-QNJMBKFK.js";
6
+ } from "./chunk-2LGMW3DJ.js";
4
7
  import {
5
8
  log
6
9
  } from "./chunk-2ODBA7MQ.js";
@@ -136,9 +139,19 @@ function validateReplayTurn(turn, index) {
136
139
  return issues;
137
140
  }
138
141
 
142
+ // src/utils/path.ts
143
+ import path from "path";
144
+ function expandTildePath(p) {
145
+ if (p === "~") return resolveHomeDir();
146
+ if (p.startsWith("~/") || p.startsWith("~\\")) {
147
+ return path.join(resolveHomeDir(), p.slice(2));
148
+ }
149
+ return p;
150
+ }
151
+
139
152
  // src/routing/store.ts
140
153
  import { lstat, mkdir, readFile, realpath, rename, rm, stat, writeFile } from "fs/promises";
141
- import path from "path";
154
+ import path2 from "path";
142
155
  import { createHash } from "crypto";
143
156
  function defaultState() {
144
157
  return {
@@ -157,14 +170,14 @@ function stableRuleId(rule) {
157
170
  return `route-${createHash("sha256").update(seed).digest("hex").slice(0, 12)}`;
158
171
  }
159
172
  function resolveStatePath(memoryDir, stateFile) {
160
- const root = path.resolve(memoryDir);
161
- const defaultPath = path.join(root, "state", "routing-rules.json");
162
- if (path.isAbsolute(stateFile)) {
163
- const absolute = path.resolve(stateFile);
164
- return absolute.startsWith(root + path.sep) ? absolute : defaultPath;
173
+ const root = path2.resolve(memoryDir);
174
+ const defaultPath = path2.join(root, "state", "routing-rules.json");
175
+ if (path2.isAbsolute(stateFile)) {
176
+ const absolute = path2.resolve(stateFile);
177
+ return absolute.startsWith(root + path2.sep) ? absolute : defaultPath;
165
178
  }
166
- const resolved = path.resolve(root, stateFile);
167
- return resolved.startsWith(root + path.sep) ? resolved : defaultPath;
179
+ const resolved = path2.resolve(root, stateFile);
180
+ return resolved.startsWith(root + path2.sep) ? resolved : defaultPath;
168
181
  }
169
182
  function normalizeRule(rule, options) {
170
183
  if (!rule || typeof rule !== "object") return null;
@@ -197,7 +210,7 @@ var RoutingRulesStore = class {
197
210
  lockPath;
198
211
  writeQueue = Promise.resolve();
199
212
  constructor(memoryDir, stateFile = "state/routing-rules.json") {
200
- this.memoryRoot = path.resolve(memoryDir);
213
+ this.memoryRoot = path2.resolve(memoryDir);
201
214
  this.statePath = resolveStatePath(memoryDir, stateFile);
202
215
  this.lockPath = `${this.statePath}.lock`;
203
216
  }
@@ -303,7 +316,7 @@ var RoutingRulesStore = class {
303
316
  const timeoutMs = 5e3;
304
317
  let unexpectedLockError = null;
305
318
  await this.assertStatePathScoped();
306
- await mkdir(path.dirname(this.lockPath), { recursive: true });
319
+ await mkdir(path2.dirname(this.lockPath), { recursive: true });
307
320
  while (Date.now() - start < timeoutMs) {
308
321
  try {
309
322
  await mkdir(this.lockPath);
@@ -338,12 +351,12 @@ var RoutingRulesStore = class {
338
351
  async assertStatePathScoped() {
339
352
  await mkdir(this.memoryRoot, { recursive: true });
340
353
  const canonicalRoot = await realpath(this.memoryRoot);
341
- const canonicalParent = await this.canonicalizePathWithoutCreating(path.dirname(this.statePath));
342
- const canonicalStatePath = path.join(canonicalParent, path.basename(this.statePath));
354
+ const canonicalParent = await this.canonicalizePathWithoutCreating(path2.dirname(this.statePath));
355
+ const canonicalStatePath = path2.join(canonicalParent, path2.basename(this.statePath));
343
356
  if (!this.isPathInside(canonicalRoot, canonicalStatePath)) {
344
357
  throw new Error(`routing rules state path escaped memoryDir: ${canonicalStatePath}`);
345
358
  }
346
- await mkdir(path.dirname(this.statePath), { recursive: true });
359
+ await mkdir(path2.dirname(this.statePath), { recursive: true });
347
360
  try {
348
361
  const stateStats = await lstat(this.statePath);
349
362
  if (stateStats.isSymbolicLink()) {
@@ -360,28 +373,28 @@ var RoutingRulesStore = class {
360
373
  }
361
374
  }
362
375
  isPathInside(root, candidate) {
363
- const normalizedRoot = path.resolve(root);
364
- const normalizedCandidate = path.resolve(candidate);
376
+ const normalizedRoot = path2.resolve(root);
377
+ const normalizedCandidate = path2.resolve(candidate);
365
378
  if (normalizedCandidate === normalizedRoot) return true;
366
- if (normalizedRoot === path.parse(normalizedRoot).root) {
379
+ if (normalizedRoot === path2.parse(normalizedRoot).root) {
367
380
  return normalizedCandidate.startsWith(normalizedRoot);
368
381
  }
369
- return normalizedCandidate.startsWith(`${normalizedRoot}${path.sep}`);
382
+ return normalizedCandidate.startsWith(`${normalizedRoot}${path2.sep}`);
370
383
  }
371
384
  async canonicalizePathWithoutCreating(targetPath) {
372
- const absoluteTarget = path.resolve(targetPath);
385
+ const absoluteTarget = path2.resolve(targetPath);
373
386
  let probe = absoluteTarget;
374
387
  while (true) {
375
388
  try {
376
389
  const canonicalProbe = await realpath(probe);
377
- const remainder = path.relative(probe, absoluteTarget);
378
- return path.resolve(canonicalProbe, remainder);
390
+ const remainder = path2.relative(probe, absoluteTarget);
391
+ return path2.resolve(canonicalProbe, remainder);
379
392
  } catch (err) {
380
393
  const code = err.code;
381
394
  if (code !== "ENOENT") {
382
395
  throw err;
383
396
  }
384
- const parent = path.dirname(probe);
397
+ const parent = path2.dirname(probe);
385
398
  if (parent === probe) {
386
399
  return absoluteTarget;
387
400
  }
@@ -398,6 +411,7 @@ export {
398
411
  normalizeReplaySessionKey,
399
412
  parseIsoTimestamp,
400
413
  validateReplayTurn,
414
+ expandTildePath,
401
415
  RoutingRulesStore
402
416
  };
403
- //# sourceMappingURL=chunk-PAORGQRI.js.map
417
+ //# sourceMappingURL=chunk-EPQJM2GC.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/iso-timestamp.ts","../src/replay/types.ts","../src/utils/path.ts","../src/routing/store.ts"],"sourcesContent":["// ---------------------------------------------------------------------------\n// Shared ISO-8601 / RFC 3339 timestamp validation helpers.\n//\n// Two public entry points — a strict UTC-only parser used by the replay\n// pipeline, and a more permissive parser used by bulk-import adapters that\n// need to preserve source timezone offsets. Both share date-component,\n// offset-range, and round-trip validation so they cannot silently diverge.\n// ---------------------------------------------------------------------------\n\n// UTC-only: `...Z`, 0 or 3 fractional digits (replay canonical form).\nconst ISO_UTC_TIMESTAMP_RE =\n /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(?:\\.\\d{3})?Z$/;\n\n// Lenient: variable-precision fractional seconds and `Z` or `[+-]HH:MM` offset.\nconst ISO_OFFSET_TIMESTAMP_RE =\n /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(?:\\.\\d+)?(?:Z|[+-]\\d{2}:\\d{2})$/;\n\n/**\n * Validate the date/time components of an ISO timestamp string.\n * Catches overflowed dates like Feb 31 that `Date.parse` silently normalizes.\n */\nfunction validateDateComponents(isoString: string): boolean {\n const match = isoString.match(\n /^(\\d{4})-(\\d{2})-(\\d{2})T(\\d{2}):(\\d{2}):(\\d{2})/,\n );\n if (!match) return false;\n const [, yStr, mStr, dStr, hStr, minStr, sStr] = match;\n const y = Number(yStr);\n const m = Number(mStr);\n const d = Number(dStr);\n const h = Number(hStr);\n const min = Number(minStr);\n const s = Number(sStr);\n if (m < 1 || m > 12) return false;\n if (d < 1 || d > 31) return false;\n if (h > 23 || min > 59 || s > 59) return false;\n // Validate day for the specific month (using Date(y, m, 0) to get days).\n const daysInMonth = new Date(y, m, 0).getDate();\n if (d > daysInMonth) return false;\n return true;\n}\n\n/**\n * Validate the timezone offset range if present.\n * Max offset is +/-14:00 per ISO 8601; minute part must be 0-59.\n */\nfunction validateOffset(isoString: string): boolean {\n const offsetMatch = isoString.match(/([+-])(\\d{2}):(\\d{2})$/);\n if (!offsetMatch) return true; // `Z` form, no offset to validate.\n const oh = Number(offsetMatch[2]);\n const om = Number(offsetMatch[3]);\n if (oh > 14 || om > 59) return false;\n // +14:00 is max; offsets like +14:30 are invalid.\n if (oh === 14 && om > 0) return false;\n return true;\n}\n\n/**\n * Normalize a `Z`-suffixed ISO timestamp to exactly three fractional digits so\n * the round-trip comparison against `Date.prototype.toISOString()` succeeds\n * regardless of input precision (or absence of a fractional part).\n */\nfunction normalizeUtcForComparison(value: string): string {\n const fracMatch = value.match(/\\.(\\d+)Z$/);\n if (fracMatch) {\n const ms = (fracMatch[1] + \"000\").slice(0, 3);\n return value.replace(/\\.\\d+Z$/, `.${ms}Z`);\n }\n return value.replace(/Z$/, \".000Z\");\n}\n\n/**\n * Strict UTC-only parser — accepts `YYYY-MM-DDTHH:MM:SS[.sss]Z`.\n * Returns milliseconds since epoch, or `null` if invalid.\n */\nexport function parseIsoUtcTimestamp(value: string): number | null {\n if (typeof value !== \"string\" || !ISO_UTC_TIMESTAMP_RE.test(value)) {\n return null;\n }\n const ts = Date.parse(value);\n if (!Number.isFinite(ts)) return null;\n if (!validateDateComponents(value)) return null;\n const roundTrip = new Date(ts).toISOString();\n if (roundTrip !== normalizeUtcForComparison(value)) return null;\n return ts;\n}\n\n/**\n * Lenient parser — accepts variable-precision fractional seconds and either\n * a `Z` suffix or a `[+-]HH:MM` offset. Returns milliseconds since epoch, or\n * `null` if the string is not a well-formed RFC 3339 timestamp.\n */\nexport function parseIsoOffsetTimestamp(value: string): number | null {\n if (typeof value !== \"string\" || !ISO_OFFSET_TIMESTAMP_RE.test(value)) {\n return null;\n }\n const ts = Date.parse(value);\n if (!Number.isFinite(ts)) return null;\n if (!validateDateComponents(value)) return null;\n if (!validateOffset(value)) return null;\n // For UTC timestamps (ending in `Z`), verify with a round-trip so that\n // overflowed UTC calendar dates cannot slip through.\n if (value.endsWith(\"Z\")) {\n const roundTrip = new Date(ts).toISOString();\n if (roundTrip !== normalizeUtcForComparison(value)) return null;\n }\n return ts;\n}\n","import { parseIsoUtcTimestamp } from \"../utils/iso-timestamp.js\";\n\nexport type ReplaySource = \"openclaw\" | \"claude\" | \"chatgpt\";\nexport type ReplayRole = \"user\" | \"assistant\";\n\nexport interface ReplayTurn {\n source: ReplaySource;\n sessionKey: string;\n role: ReplayRole;\n content: string;\n timestamp: string;\n externalId?: string;\n metadata?: Record<string, unknown>;\n}\n\nexport interface ReplayWarning {\n code: string;\n message: string;\n index?: number;\n}\n\nexport interface ReplayValidationIssue {\n code: string;\n message: string;\n index?: number;\n}\n\nexport interface ReplayParseOptions {\n from?: string;\n to?: string;\n defaultSessionKey?: string;\n strict?: boolean;\n}\n\nexport interface ReplayParseResult {\n turns: ReplayTurn[];\n warnings: ReplayWarning[];\n}\n\nexport interface ReplayNormalizer {\n source: ReplaySource;\n parse(input: unknown, options?: ReplayParseOptions): Promise<ReplayParseResult> | ReplayParseResult;\n}\n\nconst VALID_SOURCES: ReadonlySet<string> = new Set([\"openclaw\", \"claude\", \"chatgpt\"]);\nconst VALID_ROLES: ReadonlySet<string> = new Set([\"user\", \"assistant\"]);\nexport const REPLAY_UNKNOWN_SESSION_KEY = \"replay:unknown\";\n\nexport function isReplaySource(value: unknown): value is ReplaySource {\n return typeof value === \"string\" && VALID_SOURCES.has(value);\n}\n\nexport function isReplayRole(value: unknown): value is ReplayRole {\n return typeof value === \"string\" && VALID_ROLES.has(value);\n}\n\nexport function normalizeReplaySessionKey(value: unknown): string {\n if (typeof value !== \"string\") return REPLAY_UNKNOWN_SESSION_KEY;\n const trimmed = value.trim();\n return trimmed.length > 0 ? trimmed : REPLAY_UNKNOWN_SESSION_KEY;\n}\n\n/**\n * Strict UTC-only ISO-8601 parser used by the replay pipeline.\n *\n * Delegates to the shared parser in `utils/iso-timestamp.ts` — do not\n * reimplement locally; extend that helper instead. Replay intentionally\n * rejects timezone-offset timestamps to keep canonical form consistent\n * across recorded transcripts.\n */\nexport function parseIsoTimestamp(value: string): number | null {\n return parseIsoUtcTimestamp(value);\n}\n\nexport function validateReplayTurn(turn: ReplayTurn, index?: number): ReplayValidationIssue[] {\n const issues: ReplayValidationIssue[] = [];\n if (!turn || typeof turn !== \"object\") {\n issues.push({\n code: \"turn.invalid\",\n message: \"Replay turn must be an object.\",\n index,\n });\n return issues;\n }\n\n if (!isReplayRole(turn.role)) {\n issues.push({\n code: \"turn.role.invalid\",\n message: `Replay role must be 'user' or 'assistant', received '${String(turn.role)}'.`,\n index,\n });\n }\n\n if (!isReplaySource(turn.source)) {\n issues.push({\n code: \"turn.source.invalid\",\n message: `Replay source must be 'openclaw', 'claude', or 'chatgpt', received '${String(turn.source)}'.`,\n index,\n });\n }\n\n if (!turn.sessionKey || typeof turn.sessionKey !== \"string\" || turn.sessionKey.trim().length === 0) {\n issues.push({\n code: \"turn.sessionKey.invalid\",\n message: \"Replay sessionKey is required.\",\n index,\n });\n }\n\n if (!turn.content || typeof turn.content !== \"string\" || turn.content.trim().length === 0) {\n issues.push({\n code: \"turn.content.invalid\",\n message: \"Replay content must be a non-empty string.\",\n index,\n });\n }\n\n if (!turn.timestamp || typeof turn.timestamp !== \"string\" || parseIsoTimestamp(turn.timestamp) === null) {\n issues.push({\n code: \"turn.timestamp.invalid\",\n message: `Replay timestamp must be a valid ISO timestamp, received '${String(turn.timestamp)}'.`,\n index,\n });\n }\n\n return issues;\n}\n","/**\n * Shared path helpers. CLAUDE.md #17 requires consistent `~` expansion across\n * every user-facing path input, but Node's `fs` does not expand `~`, so every\n * call site must go through this helper.\n */\n\nimport path from \"node:path\";\n\nimport { resolveHomeDir } from \"../runtime/env.js\";\n\n/**\n * Expand a leading `~` or `~/…` to the resolved home directory.\n *\n * Leaves paths without a leading `~` unchanged — including absolute paths,\n * relative paths, and paths that contain `~` in the middle.\n *\n * Accepts both `~/` (POSIX) and `~\\` (Windows) as separators so call sites\n * don't have to branch on platform.\n */\nexport function expandTildePath(p: string): string {\n if (p === \"~\") return resolveHomeDir();\n if (p.startsWith(\"~/\") || p.startsWith(\"~\\\\\")) {\n return path.join(resolveHomeDir(), p.slice(2));\n }\n return p;\n}\n","import { lstat, mkdir, readFile, realpath, rename, rm, stat, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { createHash } from \"node:crypto\";\nimport { log } from \"../logger.js\";\nimport { validateRouteTarget, type RouteRule, type RoutingEngineOptions } from \"./engine.js\";\n\ntype RoutingRulesState = {\n version: 1;\n updatedAt: string;\n rules: RouteRule[];\n};\n\nfunction defaultState(): RoutingRulesState {\n return {\n version: 1,\n updatedAt: new Date(0).toISOString(),\n rules: [],\n };\n}\n\nfunction stableRuleId(rule: Pick<RouteRule, \"patternType\" | \"pattern\" | \"priority\" | \"target\">): string {\n const seed = JSON.stringify({\n patternType: rule.patternType,\n pattern: rule.pattern.trim(),\n priority: rule.priority,\n target: rule.target,\n });\n return `route-${createHash(\"sha256\").update(seed).digest(\"hex\").slice(0, 12)}`;\n}\n\nfunction resolveStatePath(memoryDir: string, stateFile: string): string {\n const root = path.resolve(memoryDir);\n const defaultPath = path.join(root, \"state\", \"routing-rules.json\");\n if (path.isAbsolute(stateFile)) {\n const absolute = path.resolve(stateFile);\n return absolute.startsWith(root + path.sep) ? absolute : defaultPath;\n }\n const resolved = path.resolve(root, stateFile);\n return resolved.startsWith(root + path.sep) ? resolved : defaultPath;\n}\n\nfunction normalizeRule(rule: RouteRule, options?: RoutingEngineOptions): RouteRule | null {\n if (!rule || typeof rule !== \"object\") return null;\n if (rule.enabled === false) return null;\n if (rule.patternType !== \"keyword\" && rule.patternType !== \"regex\") return null;\n if (typeof rule.pattern !== \"string\" || rule.pattern.trim().length === 0) return null;\n if (typeof rule.priority !== \"number\" || !Number.isFinite(rule.priority)) return null;\n\n const targetValidation = validateRouteTarget(rule.target, options);\n if (!targetValidation.ok || !targetValidation.target) return null;\n\n const normalizedPriority = Math.trunc(rule.priority);\n const normalizedTarget = targetValidation.target;\n const id = typeof rule.id === \"string\" && rule.id.trim().length > 0\n ? rule.id.trim()\n : stableRuleId({\n patternType: rule.patternType,\n pattern: rule.pattern.trim(),\n priority: normalizedPriority,\n target: normalizedTarget,\n });\n return {\n id,\n patternType: rule.patternType,\n pattern: rule.pattern.trim(),\n priority: normalizedPriority,\n target: normalizedTarget,\n enabled: true,\n };\n}\n\nexport class RoutingRulesStore {\n private readonly memoryRoot: string;\n private readonly statePath: string;\n private readonly lockPath: string;\n private writeQueue: Promise<void> = Promise.resolve();\n\n constructor(memoryDir: string, stateFile = \"state/routing-rules.json\") {\n this.memoryRoot = path.resolve(memoryDir);\n this.statePath = resolveStatePath(memoryDir, stateFile);\n this.lockPath = `${this.statePath}.lock`;\n }\n\n async read(options?: RoutingEngineOptions): Promise<RouteRule[]> {\n try {\n const persisted = await this.readPersistedRules();\n return persisted\n .map((rule) => normalizeRule(rule, options))\n .filter((rule): rule is RouteRule => rule !== null);\n } catch {\n return [];\n }\n }\n\n async write(rules: RouteRule[], options?: RoutingEngineOptions): Promise<RouteRule[]> {\n return this.withWriteLock(async () => this.writeNormalized(rules, options));\n }\n\n async upsert(rule: RouteRule, options?: RoutingEngineOptions): Promise<RouteRule[]> {\n return this.withWriteLock(async () => {\n const existing = await this.readPersistedRules();\n const normalized = normalizeRule(rule, options);\n if (!normalized) return existing;\n\n const next = existing.filter((entry) => entry.id !== normalized.id);\n next.push(normalized);\n return this.writeNormalized(next);\n });\n }\n\n async removeByPattern(pattern: string): Promise<RouteRule[]> {\n return this.withWriteLock(async () => {\n const trimmed = pattern.trim();\n const existing = await this.readPersistedRules();\n const next = existing.filter((entry) => entry.pattern !== trimmed);\n if (next.length === existing.length) return existing;\n return this.writeNormalized(next);\n });\n }\n\n async reset(): Promise<void> {\n await this.withWriteLock(async () => {\n const payload = defaultState();\n await this.assertStatePathScoped();\n await writeFile(this.statePath, JSON.stringify(payload, null, 2), \"utf-8\");\n });\n }\n\n private dedupeById(rules: RouteRule[]): RouteRule[] {\n const byId = new Map<string, RouteRule>();\n for (const rule of rules) {\n byId.set(rule.id, rule);\n }\n return Array.from(byId.values());\n }\n\n private async readPersistedRules(): Promise<RouteRule[]> {\n try {\n await this.assertStatePathScoped();\n const raw = await readFile(this.statePath, \"utf-8\");\n const parsed = JSON.parse(raw) as Partial<RoutingRulesState>;\n if (!parsed || typeof parsed !== \"object\" || !Array.isArray(parsed.rules)) return [];\n const normalized = parsed.rules\n .map((rule) => normalizeRule(rule))\n .filter((rule): rule is RouteRule => rule !== null);\n return this.dedupeById(normalized);\n } catch {\n return [];\n }\n }\n\n private async writeNormalized(rules: RouteRule[], options?: RoutingEngineOptions): Promise<RouteRule[]> {\n const normalized = this.dedupeById(\n rules\n .map((rule) => normalizeRule(rule, options))\n .filter((rule): rule is RouteRule => rule !== null),\n );\n\n const payload: RoutingRulesState = {\n version: 1,\n updatedAt: new Date().toISOString(),\n rules: normalized,\n };\n\n const tmpPath = `${this.statePath}.tmp-${process.pid}-${Date.now()}`;\n try {\n await this.assertStatePathScoped();\n await writeFile(tmpPath, JSON.stringify(payload, null, 2), \"utf-8\");\n await rename(tmpPath, this.statePath);\n } catch (err) {\n log.debug(`routing rules write failed: ${err}`);\n throw err;\n } finally {\n await rm(tmpPath, { force: true }).catch(() => {});\n }\n\n return normalized;\n }\n\n private async withWriteLock<T>(op: () => Promise<T>): Promise<T> {\n const previous = this.writeQueue;\n let release: () => void = () => {};\n this.writeQueue = new Promise<void>((resolve) => {\n release = resolve;\n });\n await previous;\n let unlock: (() => Promise<void>) | null = null;\n try {\n unlock = await this.acquireFileLock();\n return await op();\n } finally {\n if (unlock) await unlock();\n release();\n }\n }\n\n private async acquireFileLock(): Promise<() => Promise<void>> {\n const start = Date.now();\n const staleMs = 30_000;\n const timeoutMs = 5_000;\n let unexpectedLockError: unknown = null;\n await this.assertStatePathScoped();\n await mkdir(path.dirname(this.lockPath), { recursive: true });\n\n while (Date.now() - start < timeoutMs) {\n try {\n await mkdir(this.lockPath);\n return async () => {\n try {\n await rm(this.lockPath, { recursive: true, force: true });\n } catch {\n // Fail-open: lock cleanup should not fail writes.\n }\n };\n } catch (err) {\n const code = (err as NodeJS.ErrnoException).code;\n if (code !== \"EEXIST\") {\n unexpectedLockError = err;\n break;\n }\n try {\n const lockStat = await stat(this.lockPath);\n if (Date.now() - lockStat.mtimeMs > staleMs) {\n await rm(this.lockPath, { recursive: true, force: true });\n continue;\n }\n } catch {\n // Lock may have been released between stat/rm attempts.\n }\n await new Promise((resolve) => setTimeout(resolve, 25));\n }\n }\n\n if (unexpectedLockError) {\n throw unexpectedLockError;\n }\n throw new Error(`routing rules lock acquisition timed out after ${timeoutMs}ms`);\n }\n\n private async assertStatePathScoped(): Promise<void> {\n await mkdir(this.memoryRoot, { recursive: true });\n const canonicalRoot = await realpath(this.memoryRoot);\n const canonicalParent = await this.canonicalizePathWithoutCreating(path.dirname(this.statePath));\n const canonicalStatePath = path.join(canonicalParent, path.basename(this.statePath));\n if (!this.isPathInside(canonicalRoot, canonicalStatePath)) {\n throw new Error(`routing rules state path escaped memoryDir: ${canonicalStatePath}`);\n }\n await mkdir(path.dirname(this.statePath), { recursive: true });\n try {\n const stateStats = await lstat(this.statePath);\n if (stateStats.isSymbolicLink()) {\n const canonicalFile = await realpath(this.statePath);\n if (!this.isPathInside(canonicalRoot, canonicalFile)) {\n throw new Error(`routing rules state symlink escaped memoryDir: ${canonicalFile}`);\n }\n }\n } catch (err) {\n const code = (err as NodeJS.ErrnoException).code;\n if (code !== \"ENOENT\") {\n throw err;\n }\n }\n }\n\n private isPathInside(root: string, candidate: string): boolean {\n const normalizedRoot = path.resolve(root);\n const normalizedCandidate = path.resolve(candidate);\n if (normalizedCandidate === normalizedRoot) return true;\n if (normalizedRoot === path.parse(normalizedRoot).root) {\n return normalizedCandidate.startsWith(normalizedRoot);\n }\n return normalizedCandidate.startsWith(`${normalizedRoot}${path.sep}`);\n }\n\n private async canonicalizePathWithoutCreating(targetPath: string): Promise<string> {\n const absoluteTarget = path.resolve(targetPath);\n let probe = absoluteTarget;\n while (true) {\n try {\n const canonicalProbe = await realpath(probe);\n const remainder = path.relative(probe, absoluteTarget);\n return path.resolve(canonicalProbe, remainder);\n } catch (err) {\n const code = (err as NodeJS.ErrnoException).code;\n if (code !== \"ENOENT\") {\n throw err;\n }\n const parent = path.dirname(probe);\n if (parent === probe) {\n return absoluteTarget;\n }\n probe = parent;\n }\n }\n }\n}\n"],"mappings":"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","names":["path","path"]}