agent-recall-core 3.4.31 → 3.4.36

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 (270) hide show
  1. package/README.md +121 -441
  2. package/dist/digest/store.d.ts.map +1 -1
  3. package/dist/digest/store.js +4 -3
  4. package/dist/digest/store.js.map +1 -1
  5. package/dist/display/board-render.d.ts +61 -0
  6. package/dist/display/board-render.d.ts.map +1 -0
  7. package/dist/display/board-render.js +223 -0
  8. package/dist/display/board-render.js.map +1 -0
  9. package/dist/helpers/alignment-patterns.d.ts +10 -0
  10. package/dist/helpers/alignment-patterns.d.ts.map +1 -1
  11. package/dist/helpers/alignment-patterns.js +5 -1
  12. package/dist/helpers/alignment-patterns.js.map +1 -1
  13. package/dist/helpers/blind-spots.d.ts +86 -0
  14. package/dist/helpers/blind-spots.d.ts.map +1 -0
  15. package/dist/helpers/blind-spots.js +205 -0
  16. package/dist/helpers/blind-spots.js.map +1 -0
  17. package/dist/helpers/conflict-scan.d.ts +10 -0
  18. package/dist/helpers/conflict-scan.d.ts.map +1 -1
  19. package/dist/helpers/conflict-scan.js +3 -3
  20. package/dist/helpers/conflict-scan.js.map +1 -1
  21. package/dist/helpers/semantic-match.d.ts +82 -0
  22. package/dist/helpers/semantic-match.d.ts.map +1 -0
  23. package/dist/helpers/semantic-match.js +229 -0
  24. package/dist/helpers/semantic-match.js.map +1 -0
  25. package/dist/index.d.ts +57 -17
  26. package/dist/index.d.ts.map +1 -1
  27. package/dist/index.js +60 -14
  28. package/dist/index.js.map +1 -1
  29. package/dist/palace/awareness.d.ts +30 -0
  30. package/dist/palace/awareness.d.ts.map +1 -1
  31. package/dist/palace/awareness.js +65 -2
  32. package/dist/palace/awareness.js.map +1 -1
  33. package/dist/palace/consolidate.d.ts.map +1 -1
  34. package/dist/palace/consolidate.js +17 -0
  35. package/dist/palace/consolidate.js.map +1 -1
  36. package/dist/palace/decay-pass.d.ts +46 -0
  37. package/dist/palace/decay-pass.d.ts.map +1 -0
  38. package/dist/palace/decay-pass.js +87 -0
  39. package/dist/palace/decay-pass.js.map +1 -0
  40. package/dist/palace/insights-index.d.ts.map +1 -1
  41. package/dist/palace/insights-index.js +4 -2
  42. package/dist/palace/insights-index.js.map +1 -1
  43. package/dist/palace/skills.d.ts +41 -2
  44. package/dist/palace/skills.d.ts.map +1 -1
  45. package/dist/palace/skills.js +106 -4
  46. package/dist/palace/skills.js.map +1 -1
  47. package/dist/prompts/consolidation-prompt.d.ts +25 -0
  48. package/dist/prompts/consolidation-prompt.d.ts.map +1 -0
  49. package/dist/prompts/consolidation-prompt.js +91 -0
  50. package/dist/prompts/consolidation-prompt.js.map +1 -0
  51. package/dist/storage/ab-experiment.d.ts +184 -0
  52. package/dist/storage/ab-experiment.d.ts.map +1 -0
  53. package/dist/storage/ab-experiment.js +294 -0
  54. package/dist/storage/ab-experiment.js.map +1 -0
  55. package/dist/storage/archive-prune.d.ts +56 -0
  56. package/dist/storage/archive-prune.d.ts.map +1 -0
  57. package/dist/storage/archive-prune.js +118 -0
  58. package/dist/storage/archive-prune.js.map +1 -0
  59. package/dist/storage/archive-write.d.ts +38 -0
  60. package/dist/storage/archive-write.d.ts.map +1 -0
  61. package/dist/storage/archive-write.js +98 -0
  62. package/dist/storage/archive-write.js.map +1 -0
  63. package/dist/storage/blind-spots-store.d.ts +30 -0
  64. package/dist/storage/blind-spots-store.d.ts.map +1 -0
  65. package/dist/storage/blind-spots-store.js +91 -0
  66. package/dist/storage/blind-spots-store.js.map +1 -0
  67. package/dist/storage/capture-router.d.ts +60 -0
  68. package/dist/storage/capture-router.d.ts.map +1 -0
  69. package/dist/storage/capture-router.js +133 -0
  70. package/dist/storage/capture-router.js.map +1 -0
  71. package/dist/storage/classification.d.ts +36 -0
  72. package/dist/storage/classification.d.ts.map +1 -0
  73. package/dist/storage/classification.js +78 -0
  74. package/dist/storage/classification.js.map +1 -0
  75. package/dist/storage/consolidation-queue.d.ts +39 -0
  76. package/dist/storage/consolidation-queue.d.ts.map +1 -0
  77. package/dist/storage/consolidation-queue.js +120 -0
  78. package/dist/storage/consolidation-queue.js.map +1 -0
  79. package/dist/storage/content-guard.d.ts +74 -0
  80. package/dist/storage/content-guard.d.ts.map +1 -0
  81. package/dist/storage/content-guard.js +179 -0
  82. package/dist/storage/content-guard.js.map +1 -0
  83. package/dist/storage/corrections.d.ts +329 -22
  84. package/dist/storage/corrections.d.ts.map +1 -1
  85. package/dist/storage/corrections.js +788 -58
  86. package/dist/storage/corrections.js.map +1 -1
  87. package/dist/storage/durable-intent.d.ts +49 -0
  88. package/dist/storage/durable-intent.d.ts.map +1 -0
  89. package/dist/storage/durable-intent.js +124 -0
  90. package/dist/storage/durable-intent.js.map +1 -0
  91. package/dist/storage/filelock.d.ts +6 -0
  92. package/dist/storage/filelock.d.ts.map +1 -1
  93. package/dist/storage/filelock.js +6 -1
  94. package/dist/storage/filelock.js.map +1 -1
  95. package/dist/storage/memory-protocol.d.ts +19 -0
  96. package/dist/storage/memory-protocol.d.ts.map +1 -0
  97. package/dist/storage/memory-protocol.js +101 -0
  98. package/dist/storage/memory-protocol.js.map +1 -0
  99. package/dist/storage/paths.d.ts +23 -0
  100. package/dist/storage/paths.d.ts.map +1 -1
  101. package/dist/storage/paths.js +39 -0
  102. package/dist/storage/paths.js.map +1 -1
  103. package/dist/storage/retention.d.ts +23 -0
  104. package/dist/storage/retention.d.ts.map +1 -0
  105. package/dist/storage/retention.js +48 -0
  106. package/dist/storage/retention.js.map +1 -0
  107. package/dist/storage/session.d.ts +2 -2
  108. package/dist/storage/session.d.ts.map +1 -1
  109. package/dist/storage/session.js +11 -1
  110. package/dist/storage/session.js.map +1 -1
  111. package/dist/supabase/config.d.ts +26 -0
  112. package/dist/supabase/config.d.ts.map +1 -1
  113. package/dist/supabase/config.js +11 -0
  114. package/dist/supabase/config.js.map +1 -1
  115. package/dist/supabase/recall-backend.d.ts +1 -0
  116. package/dist/supabase/recall-backend.d.ts.map +1 -1
  117. package/dist/supabase/recall-backend.js +13 -13
  118. package/dist/supabase/recall-backend.js.map +1 -1
  119. package/dist/supabase/sync.d.ts +1 -1
  120. package/dist/supabase/sync.d.ts.map +1 -1
  121. package/dist/supabase/sync.js +85 -3
  122. package/dist/supabase/sync.js.map +1 -1
  123. package/dist/tools-logic/bootstrap.d.ts +15 -0
  124. package/dist/tools-logic/bootstrap.d.ts.map +1 -1
  125. package/dist/tools-logic/bootstrap.js +238 -47
  126. package/dist/tools-logic/bootstrap.js.map +1 -1
  127. package/dist/tools-logic/brief.d.ts +84 -0
  128. package/dist/tools-logic/brief.d.ts.map +1 -0
  129. package/dist/tools-logic/brief.js +193 -0
  130. package/dist/tools-logic/brief.js.map +1 -0
  131. package/dist/tools-logic/check-action.d.ts +9 -0
  132. package/dist/tools-logic/check-action.d.ts.map +1 -1
  133. package/dist/tools-logic/check-action.js +61 -3
  134. package/dist/tools-logic/check-action.js.map +1 -1
  135. package/dist/tools-logic/check.d.ts +7 -0
  136. package/dist/tools-logic/check.d.ts.map +1 -1
  137. package/dist/tools-logic/check.js +24 -2
  138. package/dist/tools-logic/check.js.map +1 -1
  139. package/dist/tools-logic/confidence.d.ts +50 -0
  140. package/dist/tools-logic/confidence.d.ts.map +1 -0
  141. package/dist/tools-logic/confidence.js +70 -0
  142. package/dist/tools-logic/confidence.js.map +1 -0
  143. package/dist/tools-logic/drill-down.d.ts +37 -0
  144. package/dist/tools-logic/drill-down.d.ts.map +1 -0
  145. package/dist/tools-logic/drill-down.js +63 -0
  146. package/dist/tools-logic/drill-down.js.map +1 -0
  147. package/dist/tools-logic/export-corrections.d.ts +63 -0
  148. package/dist/tools-logic/export-corrections.d.ts.map +1 -0
  149. package/dist/tools-logic/export-corrections.js +124 -0
  150. package/dist/tools-logic/export-corrections.js.map +1 -0
  151. package/dist/tools-logic/journal-capture.d.ts.map +1 -1
  152. package/dist/tools-logic/journal-capture.js +4 -1
  153. package/dist/tools-logic/journal-capture.js.map +1 -1
  154. package/dist/tools-logic/journal-write.d.ts.map +1 -1
  155. package/dist/tools-logic/journal-write.js +3 -2
  156. package/dist/tools-logic/journal-write.js.map +1 -1
  157. package/dist/tools-logic/local-archive-backend.d.ts +33 -0
  158. package/dist/tools-logic/local-archive-backend.d.ts.map +1 -0
  159. package/dist/tools-logic/local-archive-backend.js +124 -0
  160. package/dist/tools-logic/local-archive-backend.js.map +1 -0
  161. package/dist/tools-logic/memory-backend.d.ts +74 -0
  162. package/dist/tools-logic/memory-backend.d.ts.map +1 -0
  163. package/dist/tools-logic/memory-backend.js +172 -0
  164. package/dist/tools-logic/memory-backend.js.map +1 -0
  165. package/dist/tools-logic/memory-query.d.ts +10 -3
  166. package/dist/tools-logic/memory-query.d.ts.map +1 -1
  167. package/dist/tools-logic/memory-query.js +31 -7
  168. package/dist/tools-logic/memory-query.js.map +1 -1
  169. package/dist/tools-logic/mirror-builder.d.ts +115 -0
  170. package/dist/tools-logic/mirror-builder.d.ts.map +1 -0
  171. package/dist/tools-logic/mirror-builder.js +348 -0
  172. package/dist/tools-logic/mirror-builder.js.map +1 -0
  173. package/dist/tools-logic/palace-write.d.ts.map +1 -1
  174. package/dist/tools-logic/palace-write.js +3 -2
  175. package/dist/tools-logic/palace-write.js.map +1 -1
  176. package/dist/tools-logic/pipeline-close.d.ts.map +1 -1
  177. package/dist/tools-logic/pipeline-close.js +2 -1
  178. package/dist/tools-logic/pipeline-close.js.map +1 -1
  179. package/dist/tools-logic/pipeline-open.d.ts.map +1 -1
  180. package/dist/tools-logic/pipeline-open.js +2 -1
  181. package/dist/tools-logic/pipeline-open.js.map +1 -1
  182. package/dist/tools-logic/predict-correction.d.ts +47 -0
  183. package/dist/tools-logic/predict-correction.d.ts.map +1 -0
  184. package/dist/tools-logic/predict-correction.js +137 -0
  185. package/dist/tools-logic/predict-correction.js.map +1 -0
  186. package/dist/tools-logic/prior-builder.d.ts +27 -0
  187. package/dist/tools-logic/prior-builder.d.ts.map +1 -0
  188. package/dist/tools-logic/prior-builder.js +90 -0
  189. package/dist/tools-logic/prior-builder.js.map +1 -0
  190. package/dist/tools-logic/recognition-builder.d.ts +122 -0
  191. package/dist/tools-logic/recognition-builder.d.ts.map +1 -0
  192. package/dist/tools-logic/recognition-builder.js +289 -0
  193. package/dist/tools-logic/recognition-builder.js.map +1 -0
  194. package/dist/tools-logic/safety-consolidation.d.ts +104 -0
  195. package/dist/tools-logic/safety-consolidation.d.ts.map +1 -0
  196. package/dist/tools-logic/safety-consolidation.js +256 -0
  197. package/dist/tools-logic/safety-consolidation.js.map +1 -0
  198. package/dist/tools-logic/session-end-reflect.d.ts +18 -0
  199. package/dist/tools-logic/session-end-reflect.d.ts.map +1 -1
  200. package/dist/tools-logic/session-end-reflect.js +69 -30
  201. package/dist/tools-logic/session-end-reflect.js.map +1 -1
  202. package/dist/tools-logic/session-end.d.ts +18 -0
  203. package/dist/tools-logic/session-end.d.ts.map +1 -1
  204. package/dist/tools-logic/session-end.js +189 -34
  205. package/dist/tools-logic/session-end.js.map +1 -1
  206. package/dist/tools-logic/session-start-lite.d.ts +2 -0
  207. package/dist/tools-logic/session-start-lite.d.ts.map +1 -1
  208. package/dist/tools-logic/session-start-lite.js +11 -2
  209. package/dist/tools-logic/session-start-lite.js.map +1 -1
  210. package/dist/tools-logic/session-start.d.ts +81 -2
  211. package/dist/tools-logic/session-start.d.ts.map +1 -1
  212. package/dist/tools-logic/session-start.js +357 -40
  213. package/dist/tools-logic/session-start.js.map +1 -1
  214. package/dist/tools-logic/skill-propose.d.ts +27 -0
  215. package/dist/tools-logic/skill-propose.d.ts.map +1 -0
  216. package/dist/tools-logic/skill-propose.js +66 -0
  217. package/dist/tools-logic/skill-propose.js.map +1 -0
  218. package/dist/tools-logic/skill-recall.d.ts +5 -0
  219. package/dist/tools-logic/skill-recall.d.ts.map +1 -1
  220. package/dist/tools-logic/skill-recall.js +14 -1
  221. package/dist/tools-logic/skill-recall.js.map +1 -1
  222. package/dist/tools-logic/smart-recall.d.ts +17 -0
  223. package/dist/tools-logic/smart-recall.d.ts.map +1 -1
  224. package/dist/tools-logic/smart-recall.js +51 -16
  225. package/dist/tools-logic/smart-recall.js.map +1 -1
  226. package/dist/tools-logic/smart-remember.js +8 -9
  227. package/dist/tools-logic/smart-remember.js.map +1 -1
  228. package/dist/tools-logic/store-doctor.d.ts +71 -0
  229. package/dist/tools-logic/store-doctor.d.ts.map +1 -0
  230. package/dist/tools-logic/store-doctor.js +387 -0
  231. package/dist/tools-logic/store-doctor.js.map +1 -0
  232. package/dist/tools-logic/store-repair.d.ts +64 -0
  233. package/dist/tools-logic/store-repair.d.ts.map +1 -0
  234. package/dist/tools-logic/store-repair.js +243 -0
  235. package/dist/tools-logic/store-repair.js.map +1 -0
  236. package/dist/tools-logic/supersession.d.ts +34 -0
  237. package/dist/tools-logic/supersession.d.ts.map +1 -0
  238. package/dist/tools-logic/supersession.js +103 -0
  239. package/dist/tools-logic/supersession.js.map +1 -0
  240. package/dist/types.d.ts +7 -1
  241. package/dist/types.d.ts.map +1 -1
  242. package/dist/types.js +1 -1
  243. package/dist/vector/embedding.d.ts +8 -0
  244. package/dist/vector/embedding.d.ts.map +1 -1
  245. package/dist/vector/embedding.js +9 -1
  246. package/dist/vector/embedding.js.map +1 -1
  247. package/dist/vector/local-vector-backend.d.ts.map +1 -1
  248. package/dist/vector/local-vector-backend.js +14 -17
  249. package/dist/vector/local-vector-backend.js.map +1 -1
  250. package/package.json +2 -2
  251. package/dist/relevance/injector.d.ts +0 -51
  252. package/dist/relevance/injector.d.ts.map +0 -1
  253. package/dist/relevance/injector.js +0 -121
  254. package/dist/relevance/injector.js.map +0 -1
  255. package/dist/relevance/precision.d.ts +0 -109
  256. package/dist/relevance/precision.d.ts.map +0 -1
  257. package/dist/relevance/precision.js +0 -279
  258. package/dist/relevance/precision.js.map +0 -1
  259. package/dist/relevance/promoter.d.ts +0 -60
  260. package/dist/relevance/promoter.d.ts.map +0 -1
  261. package/dist/relevance/promoter.js +0 -336
  262. package/dist/relevance/promoter.js.map +0 -1
  263. package/dist/relevance/stager.d.ts +0 -61
  264. package/dist/relevance/stager.d.ts.map +0 -1
  265. package/dist/relevance/stager.js +0 -251
  266. package/dist/relevance/stager.js.map +0 -1
  267. package/dist/relevance/surfacer.d.ts +0 -34
  268. package/dist/relevance/surfacer.d.ts.map +0 -1
  269. package/dist/relevance/surfacer.js +0 -333
  270. package/dist/relevance/surfacer.js.map +0 -1
@@ -0,0 +1,30 @@
1
+ /**
2
+ * blind-spots-store.ts — persist the corrections-derived behavioral profile to
3
+ * the PERSONAL tier (Wave 5, Decision #6).
4
+ *
5
+ * Storage: ~/.agent-recall/projects/<slug>/personal/blind-spots.json (mode 0600)
6
+ *
7
+ * The personal tier is the highest-sensitivity artifact (it models the human's
8
+ * behavioral tendencies). It is registered in classification.ts (`/personal/`
9
+ * marker) so it is EXCLUDED from Supabase sync and the future git mirror by
10
+ * default. A one-line `personal/README` marks the directory sync-excluded for a
11
+ * cold human/agent reading the folder.
12
+ */
13
+ import { type BlindSpotProfile } from "../helpers/blind-spots.js";
14
+ /**
15
+ * Write the profile atomically with mode 0600. Also drops a sync-exclusion
16
+ * README marker into the personal/ dir (write-once). Best-effort directory
17
+ * creation; throws only if the write itself fails (caller wraps in try/catch).
18
+ */
19
+ export declare function writeBlindSpots(project: string, profile: BlindSpotProfile): string;
20
+ /** Read the stored profile; null when absent or unreadable (never throws). */
21
+ export declare function readBlindSpots(project: string): BlindSpotProfile | null;
22
+ /**
23
+ * Re-derive the Blind-Spots profile from this project's active corrections +
24
+ * alignment log, persist it, and return it. Called from async consolidation
25
+ * (NOT the Stop hook) and lazily by predictCorrection when the profile is
26
+ * missing. Best-effort persistence — if the write fails, the freshly derived
27
+ * profile is still returned so callers can use it in-memory.
28
+ */
29
+ export declare function recomputeBlindSpots(project: string): BlindSpotProfile;
30
+ //# sourceMappingURL=blind-spots-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"blind-spots-store.d.ts","sourceRoot":"","sources":["../../src/storage/blind-spots-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAQH,OAAO,EAAoB,KAAK,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAapF;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,gBAAgB,GAAG,MAAM,CA0BlF;AAED,8EAA8E;AAC9E,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAQvE;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,gBAAgB,CAUrE"}
@@ -0,0 +1,91 @@
1
+ /**
2
+ * blind-spots-store.ts — persist the corrections-derived behavioral profile to
3
+ * the PERSONAL tier (Wave 5, Decision #6).
4
+ *
5
+ * Storage: ~/.agent-recall/projects/<slug>/personal/blind-spots.json (mode 0600)
6
+ *
7
+ * The personal tier is the highest-sensitivity artifact (it models the human's
8
+ * behavioral tendencies). It is registered in classification.ts (`/personal/`
9
+ * marker) so it is EXCLUDED from Supabase sync and the future git mirror by
10
+ * default. A one-line `personal/README` marks the directory sync-excluded for a
11
+ * cold human/agent reading the folder.
12
+ */
13
+ import * as fs from "node:fs";
14
+ import * as path from "node:path";
15
+ import { personalDir } from "./paths.js";
16
+ import { ensureDir } from "./fs-utils.js";
17
+ import { readActiveCorrections } from "./corrections.js";
18
+ import { readAlignmentLog } from "../helpers/alignment-patterns.js";
19
+ import { deriveBlindSpots } from "../helpers/blind-spots.js";
20
+ function blindSpotsPath(project) {
21
+ return path.join(personalDir(project), "blind-spots.json");
22
+ }
23
+ const README_BODY = "# personal/ — DO NOT sync\n\n" +
24
+ "This directory holds the corrections-derived behavioral profile (Blind Spots).\n" +
25
+ "It is the highest-sensitivity artifact in AgentRecall and is EXCLUDED from\n" +
26
+ "Supabase sync and any git mirror by default (Decision #6). classifyPath()\n" +
27
+ "returns \"personal\" for everything under here. Do not move it out of personal/.\n";
28
+ /**
29
+ * Write the profile atomically with mode 0600. Also drops a sync-exclusion
30
+ * README marker into the personal/ dir (write-once). Best-effort directory
31
+ * creation; throws only if the write itself fails (caller wraps in try/catch).
32
+ */
33
+ export function writeBlindSpots(project, profile) {
34
+ const dir = personalDir(project);
35
+ ensureDir(dir);
36
+ // Write-once sync-exclusion marker.
37
+ const readmePath = path.join(dir, "README");
38
+ if (!fs.existsSync(readmePath)) {
39
+ try {
40
+ fs.writeFileSync(readmePath, README_BODY, { encoding: "utf-8", mode: 0o600 });
41
+ }
42
+ catch {
43
+ // README is advisory — never block the profile write.
44
+ }
45
+ }
46
+ const dest = blindSpotsPath(project);
47
+ // Atomic tmp + rename, mode 0600.
48
+ const tmp = `${dest}.tmp.${process.pid}.${Date.now()}`;
49
+ fs.writeFileSync(tmp, JSON.stringify(profile, null, 2), { encoding: "utf-8", mode: 0o600 });
50
+ fs.renameSync(tmp, dest);
51
+ // rename preserves the tmp file's mode on POSIX; assert 0600 defensively.
52
+ try {
53
+ fs.chmodSync(dest, 0o600);
54
+ }
55
+ catch {
56
+ // best-effort
57
+ }
58
+ return dest;
59
+ }
60
+ /** Read the stored profile; null when absent or unreadable (never throws). */
61
+ export function readBlindSpots(project) {
62
+ const p = blindSpotsPath(project);
63
+ if (!fs.existsSync(p))
64
+ return null;
65
+ try {
66
+ return JSON.parse(fs.readFileSync(p, "utf-8"));
67
+ }
68
+ catch {
69
+ return null;
70
+ }
71
+ }
72
+ /**
73
+ * Re-derive the Blind-Spots profile from this project's active corrections +
74
+ * alignment log, persist it, and return it. Called from async consolidation
75
+ * (NOT the Stop hook) and lazily by predictCorrection when the profile is
76
+ * missing. Best-effort persistence — if the write fails, the freshly derived
77
+ * profile is still returned so callers can use it in-memory.
78
+ */
79
+ export function recomputeBlindSpots(project) {
80
+ const corrections = readActiveCorrections(project);
81
+ const alignmentLog = readAlignmentLog(project);
82
+ const profile = deriveBlindSpots(corrections, alignmentLog);
83
+ try {
84
+ writeBlindSpots(project, profile);
85
+ }
86
+ catch {
87
+ // Persistence is best-effort — caller still gets the in-memory profile.
88
+ }
89
+ return profile;
90
+ }
91
+ //# sourceMappingURL=blind-spots-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"blind-spots-store.js","sourceRoot":"","sources":["../../src/storage/blind-spots-store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,60 @@
1
+ /**
2
+ * capture-router.ts — two-lane pivot at the top of the capture path.
3
+ *
4
+ * LANE 1 (explicit-save): writes ONLY the local raw archive (archive-write).
5
+ * Structurally impossible for Lane 1 to reach journalWrite or syncToSupabase:
6
+ * - This module imports archiveSession from archive-write.ts ONLY.
7
+ * - archive-write.ts is LOCAL-ONLY (verified by its own structural test).
8
+ * - Neither this file nor archive-write.ts imports journal-write or sync.ts.
9
+ *
10
+ * LANE 2 (correction-signal): returns the text for the caller to route through
11
+ * the corrections pipeline (writeCorrection / check.ts). This module does NOT
12
+ * call writeCorrection directly — it just classifies and hands off, keeping the
13
+ * correction path unmodified.
14
+ *
15
+ * Both lanes share the same pre-filter: dropHardNoise runs FIRST on the raw text.
16
+ * A text that fails a hard gate is dropped before lane assignment.
17
+ *
18
+ * Cross-process dedup: a lightweight on-disk arbiter (.capture-intent-seen) is
19
+ * written after a lane fires. hook-save and hook-correction share this file so
20
+ * the same message cannot double-save across hooks.
21
+ *
22
+ * LOCAL-ONLY: MUST NOT import journal-write, palace-write, or syncToSupabase.
23
+ */
24
+ export type CaptureRouteKind = "lane1-archived" | "lane2-correction" | "dropped-hard-noise" | "dropped-duplicate" | "dropped-no-intent";
25
+ export interface CaptureRouteResult {
26
+ kind: CaptureRouteKind;
27
+ /** Absolute path written (lane 1 only). */
28
+ archivePath?: string;
29
+ /** Bytes written (lane 1 only). */
30
+ archiveBytes?: number;
31
+ /** The text that should flow into writeCorrection / check() (lane 2 only). */
32
+ correctionText?: string;
33
+ }
34
+ export interface CaptureRouteInput {
35
+ /** Raw user message text. */
36
+ text: string;
37
+ /** Project slug — used for the archive destination. */
38
+ project: string;
39
+ /** Session UUID — used as the archive dedup key. Passed UNTRUSTED; sanitized inside archiveSession. */
40
+ sessionId: string;
41
+ /** Optional: verbatim transcript for the raw archive. Defaults to text if absent. */
42
+ rawTranscript?: string;
43
+ /** Optional: one-line summary for the archive index. */
44
+ summary?: string;
45
+ /** Optional: transcript path for archive frontmatter provenance. */
46
+ transcriptPath?: string;
47
+ }
48
+ /**
49
+ * Route a user message through the two-lane capture path.
50
+ *
51
+ * Order of operations:
52
+ * 1. dropHardNoise(text) — if false, return 'dropped-hard-noise'
53
+ * 2. saveTriggerKind(text) — classify intent
54
+ * 3. Check cross-process dedup arbiter — if duplicate, return 'dropped-duplicate'
55
+ * 4. LANE 1 (explicit-save) → archiveSession (local only, never syncs)
56
+ * 5. LANE 2 (correction-signal) → return correctionText for caller to capture
57
+ * 6. none → 'dropped-no-intent'
58
+ */
59
+ export declare function routeCapture(input: CaptureRouteInput): CaptureRouteResult;
60
+ //# sourceMappingURL=capture-router.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capture-router.d.ts","sourceRoot":"","sources":["../../src/storage/capture-router.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAqEH,MAAM,MAAM,gBAAgB,GACxB,gBAAgB,GAChB,kBAAkB,GAClB,oBAAoB,GACpB,mBAAmB,GACnB,mBAAmB,CAAC;AAExB,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,gBAAgB,CAAC;IACvB,2CAA2C;IAC3C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mCAAmC;IACnC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,8EAA8E;IAC9E,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,iBAAiB;IAChC,6BAA6B;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,uDAAuD;IACvD,OAAO,EAAE,MAAM,CAAC;IAChB,uGAAuG;IACvG,SAAS,EAAE,MAAM,CAAC;IAClB,qFAAqF;IACrF,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,wDAAwD;IACxD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,oEAAoE;IACpE,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAMD;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,iBAAiB,GAAG,kBAAkB,CA8CzE"}
@@ -0,0 +1,133 @@
1
+ /**
2
+ * capture-router.ts — two-lane pivot at the top of the capture path.
3
+ *
4
+ * LANE 1 (explicit-save): writes ONLY the local raw archive (archive-write).
5
+ * Structurally impossible for Lane 1 to reach journalWrite or syncToSupabase:
6
+ * - This module imports archiveSession from archive-write.ts ONLY.
7
+ * - archive-write.ts is LOCAL-ONLY (verified by its own structural test).
8
+ * - Neither this file nor archive-write.ts imports journal-write or sync.ts.
9
+ *
10
+ * LANE 2 (correction-signal): returns the text for the caller to route through
11
+ * the corrections pipeline (writeCorrection / check.ts). This module does NOT
12
+ * call writeCorrection directly — it just classifies and hands off, keeping the
13
+ * correction path unmodified.
14
+ *
15
+ * Both lanes share the same pre-filter: dropHardNoise runs FIRST on the raw text.
16
+ * A text that fails a hard gate is dropped before lane assignment.
17
+ *
18
+ * Cross-process dedup: a lightweight on-disk arbiter (.capture-intent-seen) is
19
+ * written after a lane fires. hook-save and hook-correction share this file so
20
+ * the same message cannot double-save across hooks.
21
+ *
22
+ * LOCAL-ONLY: MUST NOT import journal-write, palace-write, or syncToSupabase.
23
+ */
24
+ import * as crypto from "node:crypto";
25
+ import * as fs from "node:fs";
26
+ import * as path from "node:path";
27
+ import { archiveSession } from "./archive-write.js";
28
+ import { dropHardNoise } from "./corrections.js";
29
+ import { saveTriggerKind } from "./durable-intent.js";
30
+ import { withLock } from "./filelock.js";
31
+ import { getRoot } from "../types.js";
32
+ // ---------------------------------------------------------------------------
33
+ // Cross-process dedup arbiter
34
+ // ---------------------------------------------------------------------------
35
+ /** Computed at call-time so setRoot() in tests takes effect. */
36
+ function dedupFilePath() {
37
+ return path.join(getRoot(), ".capture-intent-seen");
38
+ }
39
+ const DEDUP_MAX_ENTRIES = 50;
40
+ function quickHash(text) {
41
+ return crypto.createHash("sha256").update(text, "utf-8").digest("hex").slice(0, 16);
42
+ }
43
+ function readDedupEntries() {
44
+ try {
45
+ const file = dedupFilePath();
46
+ if (!fs.existsSync(file))
47
+ return [];
48
+ const parsed = JSON.parse(fs.readFileSync(file, "utf-8"));
49
+ if (Array.isArray(parsed))
50
+ return parsed;
51
+ return [];
52
+ }
53
+ catch {
54
+ return [];
55
+ }
56
+ }
57
+ function isDuplicate(hash, entries) {
58
+ return entries.some((e) => e.hash === hash);
59
+ }
60
+ function writeDedupEntry(entry) {
61
+ try {
62
+ const file = dedupFilePath();
63
+ const dir = path.dirname(file);
64
+ if (!fs.existsSync(dir))
65
+ fs.mkdirSync(dir, { recursive: true });
66
+ withLock("capture-dedup", () => {
67
+ let entries = readDedupEntries();
68
+ entries.push(entry);
69
+ if (entries.length > DEDUP_MAX_ENTRIES)
70
+ entries = entries.slice(-DEDUP_MAX_ENTRIES);
71
+ fs.writeFileSync(file, JSON.stringify(entries), "utf-8");
72
+ });
73
+ }
74
+ catch {
75
+ // Best-effort — dedup failure must never block the capture path.
76
+ }
77
+ }
78
+ // ---------------------------------------------------------------------------
79
+ // routeCapture — the two-lane pivot
80
+ // ---------------------------------------------------------------------------
81
+ /**
82
+ * Route a user message through the two-lane capture path.
83
+ *
84
+ * Order of operations:
85
+ * 1. dropHardNoise(text) — if false, return 'dropped-hard-noise'
86
+ * 2. saveTriggerKind(text) — classify intent
87
+ * 3. Check cross-process dedup arbiter — if duplicate, return 'dropped-duplicate'
88
+ * 4. LANE 1 (explicit-save) → archiveSession (local only, never syncs)
89
+ * 5. LANE 2 (correction-signal) → return correctionText for caller to capture
90
+ * 6. none → 'dropped-no-intent'
91
+ */
92
+ export function routeCapture(input) {
93
+ const text = (typeof input.text === "string" ? input.text : "").trim();
94
+ // Step 1: hard noise gate (both lanes share this pre-filter)
95
+ if (!dropHardNoise(text)) {
96
+ return { kind: "dropped-hard-noise" };
97
+ }
98
+ // Step 2: classify intent
99
+ const intent = saveTriggerKind(text);
100
+ if (intent === "none") {
101
+ return { kind: "dropped-no-intent" };
102
+ }
103
+ // Step 3: cross-process dedup
104
+ const hash = quickHash(text);
105
+ const seen = readDedupEntries();
106
+ if (isDuplicate(hash, seen)) {
107
+ return { kind: "dropped-duplicate" };
108
+ }
109
+ // Record this entry BEFORE doing any I/O so a concurrent hook sees it.
110
+ writeDedupEntry({ hash, kind: intent, ts: new Date().toISOString() });
111
+ // Step 4 — LANE 1: explicit-save → local archive ONLY
112
+ if (intent === "explicit-save") {
113
+ const archiveInput = {
114
+ project: input.project,
115
+ sessionId: input.sessionId,
116
+ rawTranscript: input.rawTranscript ?? text,
117
+ summary: input.summary,
118
+ transcriptPath: input.transcriptPath,
119
+ };
120
+ const result = archiveSession(archiveInput);
121
+ return {
122
+ kind: "lane1-archived",
123
+ archivePath: result.path,
124
+ archiveBytes: result.bytes,
125
+ };
126
+ }
127
+ // Step 5 — LANE 2: correction-signal → return text for caller's corrections pipeline
128
+ return {
129
+ kind: "lane2-correction",
130
+ correctionText: text,
131
+ };
132
+ }
133
+ //# sourceMappingURL=capture-router.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capture-router.js","sourceRoot":"","sources":["../../src/storage/capture-router.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ export type Tier = "personal" | "project";
2
+ /**
3
+ * The personal values reachable via the sync `store` union
4
+ * ("journal" | "palace" | "awareness" | "digest" | "corrections"). Awareness
5
+ * carries the corrections-derived behavioral layer (Blind Spots), so it is
6
+ * personal. `corrections` is also personal — it is a PERSONAL_PATH_MARKER
7
+ * (see below) and requires the double opt-in gate in supabase/sync.ts
8
+ * (sync_personal AND sync_corrections) before leaving the machine.
9
+ *
10
+ * NB (single-source guarantee): every member here MUST classifyStore() =>
11
+ * "personal" so the gate in supabase/sync.ts catches it. A unit test asserts
12
+ * exactly that.
13
+ */
14
+ export declare const PERSONAL_STORES: ReadonlySet<string>;
15
+ /**
16
+ * Classify a Supabase sync `store` (+ optional project) onto the privacy tier.
17
+ *
18
+ * - `awareness` store ⇒ personal (the behavioral layer leak we are gating).
19
+ * - `corrections` store ⇒ personal (PERSONAL_PATH_MARKER, double opt-in in sync.ts).
20
+ * - any write tagged with the `_global` project ⇒ personal (bootstrap writes
21
+ * palace under the `_global` sentinel).
22
+ * - everything else ⇒ project.
23
+ *
24
+ * Total over any input (unknown/undefined store ⇒ "project") — never throws.
25
+ */
26
+ export declare function classifyStore(store: string | undefined, opts?: {
27
+ project?: string;
28
+ }): Tier;
29
+ /**
30
+ * Classify an absolute path onto the privacy tier. Substring match on the
31
+ * personal markers; default project. Never throws.
32
+ */
33
+ export declare function classifyPath(absPath: string): Tier;
34
+ /** A project slug is personal iff it is the `_global` cross-project sentinel. */
35
+ export declare function isPersonalProject(slug: string): boolean;
36
+ //# sourceMappingURL=classification.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"classification.d.ts","sourceRoot":"","sources":["../../src/storage/classification.ts"],"names":[],"mappings":"AAgBA,MAAM,MAAM,IAAI,GAAG,UAAU,GAAG,SAAS,CAAC;AAE1C;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,eAAe,EAAE,WAAW,CAAC,MAAM,CAAyC,CAAC;AAE1F;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAC3B,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,IAAI,CAAC,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GAC1B,IAAI,CAIN;AAmBD;;;GAGG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAKlD;AAED,iFAAiF;AACjF,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEvD"}
@@ -0,0 +1,78 @@
1
+ // packages/core/src/storage/classification.ts
2
+ //
3
+ // Wave 1 — Privacy classification: the SINGLE source of truth for the
4
+ // personal-vs-project split. Pure, no IO.
5
+ //
6
+ // Two disjoint surfaces, by design:
7
+ // - classifyStore() covers the SYNC surface. `awareness` and `corrections` (and
8
+ // `_global` palace writes) are personal through the Supabase `store` union.
9
+ // `corrections` requires the double opt-in (sync_personal AND sync_corrections)
10
+ // before it flows through syncToSupabase — it is not silently ignored.
11
+ // - classifyPath() covers the GIT/.gitignore surface — corrections,
12
+ // behavior-policies.json, the future `personal/` tier.
13
+ //
14
+ // Keeping these explicit means the moment someone adds a new personal artifact
15
+ // they register it HERE, and the sync gate + (future) .gitignore both honor it.
16
+ /**
17
+ * The personal values reachable via the sync `store` union
18
+ * ("journal" | "palace" | "awareness" | "digest" | "corrections"). Awareness
19
+ * carries the corrections-derived behavioral layer (Blind Spots), so it is
20
+ * personal. `corrections` is also personal — it is a PERSONAL_PATH_MARKER
21
+ * (see below) and requires the double opt-in gate in supabase/sync.ts
22
+ * (sync_personal AND sync_corrections) before leaving the machine.
23
+ *
24
+ * NB (single-source guarantee): every member here MUST classifyStore() =>
25
+ * "personal" so the gate in supabase/sync.ts catches it. A unit test asserts
26
+ * exactly that.
27
+ */
28
+ export const PERSONAL_STORES = new Set(["awareness", "corrections"]);
29
+ /**
30
+ * Classify a Supabase sync `store` (+ optional project) onto the privacy tier.
31
+ *
32
+ * - `awareness` store ⇒ personal (the behavioral layer leak we are gating).
33
+ * - `corrections` store ⇒ personal (PERSONAL_PATH_MARKER, double opt-in in sync.ts).
34
+ * - any write tagged with the `_global` project ⇒ personal (bootstrap writes
35
+ * palace under the `_global` sentinel).
36
+ * - everything else ⇒ project.
37
+ *
38
+ * Total over any input (unknown/undefined store ⇒ "project") — never throws.
39
+ */
40
+ export function classifyStore(store, opts) {
41
+ if (store !== undefined && PERSONAL_STORES.has(store))
42
+ return "personal";
43
+ if (opts?.project === "_global")
44
+ return "personal";
45
+ return "project";
46
+ }
47
+ /**
48
+ * Markers that mean a filesystem path holds personal data. Used by the
49
+ * git/.gitignore surface (Wave 5 onward). Disjoint from classifyStore by design
50
+ * — these artifacts do not flow through syncToSupabase.
51
+ */
52
+ const PERSONAL_PATH_MARKERS = [
53
+ "/corrections/",
54
+ "/awareness",
55
+ "behavior-policies.json",
56
+ "/projects/_global/",
57
+ // No trailing slash (mirrors "/awareness") so it matches BOTH the bare
58
+ // `projects/<slug>/personal` directory and every file under it. A path that
59
+ // legitimately ends in "personal" inside a project is exactly the personal
60
+ // tier we mean to gate.
61
+ "/personal",
62
+ ];
63
+ /**
64
+ * Classify an absolute path onto the privacy tier. Substring match on the
65
+ * personal markers; default project. Never throws.
66
+ */
67
+ export function classifyPath(absPath) {
68
+ for (const marker of PERSONAL_PATH_MARKERS) {
69
+ if (absPath.includes(marker))
70
+ return "personal";
71
+ }
72
+ return "project";
73
+ }
74
+ /** A project slug is personal iff it is the `_global` cross-project sentinel. */
75
+ export function isPersonalProject(slug) {
76
+ return slug === "_global";
77
+ }
78
+ //# sourceMappingURL=classification.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"classification.js","sourceRoot":"","sources":["../../src/storage/classification.ts"],"names":[],"mappings":"AAAA,8CAA8C;AAC9C,EAAE;AACF,sEAAsE;AACtE,0CAA0C;AAC1C,EAAE;AACF,oCAAoC;AACpC,kFAAkF;AAClF,gFAAgF;AAChF,oFAAoF;AACpF,2EAA2E;AAC3E,sEAAsE;AACtE,2DAA2D;AAC3D,EAAE;AACF,+EAA+E;AAC/E,gFAAgF;AAIhF;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,eAAe,GAAwB,IAAI,GAAG,CAAC,CAAC,WAAW,EAAE,aAAa,CAAC,CAAC,CAAC;AAE1F;;;;;;;;;;GAUG;AACH,MAAM,UAAU,aAAa,CAC3B,KAAyB,EACzB,IAA2B;IAE3B,IAAI,KAAK,KAAK,SAAS,IAAI,eAAe,CAAC,GAAG,CAAC,KAAK,CAAC;QAAE,OAAO,UAAU,CAAC;IACzE,IAAI,IAAI,EAAE,OAAO,KAAK,SAAS;QAAE,OAAO,UAAU,CAAC;IACnD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;GAIG;AACH,MAAM,qBAAqB,GAAsB;IAC/C,eAAe;IACf,YAAY;IACZ,wBAAwB;IACxB,oBAAoB;IACpB,uEAAuE;IACvE,4EAA4E;IAC5E,2EAA2E;IAC3E,wBAAwB;IACxB,WAAW;CACZ,CAAC;AAEF;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,OAAe;IAC1C,KAAK,MAAM,MAAM,IAAI,qBAAqB,EAAE,CAAC;QAC3C,IAAI,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC;YAAE,OAAO,UAAU,CAAC;IAClD,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,iFAAiF;AACjF,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,OAAO,IAAI,KAAK,SAAS,CAAC;AAC5B,CAAC"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * consolidation-queue.ts — the async consume seam (Wave 2, Decision #3).
3
+ *
4
+ * The Stop hook archives verbatim (lossless) then ENQUEUES a job here. Quality
5
+ * compression (palace consolidation, distillation) happens later, out of the
6
+ * Stop turn, by draining this queue. Retrieval stays a function; consolidation
7
+ * stays the async dreaming loop.
8
+ *
9
+ * Storage: JSONL, one job per line, under ~/.agent-recall/.consolidation-queue/.
10
+ * Append-only; drain marks lines done by rewriting the file with done:true.
11
+ */
12
+ export interface ConsolidationJob {
13
+ project: string;
14
+ sessionId: string;
15
+ reason?: string;
16
+ /** ISO timestamp the job was enqueued. */
17
+ at?: string;
18
+ /** Marked true once drained. */
19
+ done?: boolean;
20
+ }
21
+ export interface DrainReport {
22
+ /** Jobs whose handler ran without throwing. */
23
+ processed: number;
24
+ /** Jobs whose handler threw (counted, never fatal). */
25
+ failed: number;
26
+ }
27
+ /**
28
+ * Append a consolidation job to today's queue file. Best-effort: never throws.
29
+ */
30
+ export declare function enqueueConsolidation(job: ConsolidationJob): void;
31
+ /**
32
+ * Drain all pending (not-done) jobs across every queue file. For each pending
33
+ * job, invoke `handler(job)`; a throwing handler counts as failed but does NOT
34
+ * block the rest. Successfully-handled jobs are marked done:true and rewritten.
35
+ *
36
+ * Best-effort: never throws to the caller.
37
+ */
38
+ export declare function drainConsolidationQueue(handler: (job: ConsolidationJob) => void): DrainReport;
39
+ //# sourceMappingURL=consolidation-queue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consolidation-queue.d.ts","sourceRoot":"","sources":["../../src/storage/consolidation-queue.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAOH,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,0CAA0C;IAC1C,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,gCAAgC;IAChC,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,WAAW;IAC1B,+CAA+C;IAC/C,SAAS,EAAE,MAAM,CAAC;IAClB,uDAAuD;IACvD,MAAM,EAAE,MAAM,CAAC;CAChB;AAUD;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,gBAAgB,GAAG,IAAI,CAehE;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,CAAC,GAAG,EAAE,gBAAgB,KAAK,IAAI,GACvC,WAAW,CAsEb"}
@@ -0,0 +1,120 @@
1
+ /**
2
+ * consolidation-queue.ts — the async consume seam (Wave 2, Decision #3).
3
+ *
4
+ * The Stop hook archives verbatim (lossless) then ENQUEUES a job here. Quality
5
+ * compression (palace consolidation, distillation) happens later, out of the
6
+ * Stop turn, by draining this queue. Retrieval stays a function; consolidation
7
+ * stays the async dreaming loop.
8
+ *
9
+ * Storage: JSONL, one job per line, under ~/.agent-recall/.consolidation-queue/.
10
+ * Append-only; drain marks lines done by rewriting the file with done:true.
11
+ */
12
+ import * as fs from "node:fs";
13
+ import * as path from "node:path";
14
+ import { getRoot } from "../types.js";
15
+ import { ensureDir, todayISO } from "./fs-utils.js";
16
+ function queueDir() {
17
+ return path.join(getRoot(), ".consolidation-queue");
18
+ }
19
+ function queueFileForToday() {
20
+ return path.join(queueDir(), `${todayISO()}.jsonl`);
21
+ }
22
+ /**
23
+ * Append a consolidation job to today's queue file. Best-effort: never throws.
24
+ */
25
+ export function enqueueConsolidation(job) {
26
+ try {
27
+ const dir = queueDir();
28
+ ensureDir(dir);
29
+ const record = {
30
+ project: job.project,
31
+ sessionId: job.sessionId,
32
+ reason: job.reason,
33
+ at: job.at ?? new Date().toISOString(),
34
+ done: false,
35
+ };
36
+ fs.appendFileSync(queueFileForToday(), JSON.stringify(record) + "\n", "utf-8");
37
+ }
38
+ catch {
39
+ // Enqueue is fire-and-forget — never break the caller (the Stop hook).
40
+ }
41
+ }
42
+ /**
43
+ * Drain all pending (not-done) jobs across every queue file. For each pending
44
+ * job, invoke `handler(job)`; a throwing handler counts as failed but does NOT
45
+ * block the rest. Successfully-handled jobs are marked done:true and rewritten.
46
+ *
47
+ * Best-effort: never throws to the caller.
48
+ */
49
+ export function drainConsolidationQueue(handler) {
50
+ const report = { processed: 0, failed: 0 };
51
+ let dir;
52
+ try {
53
+ dir = queueDir();
54
+ if (!fs.existsSync(dir))
55
+ return report;
56
+ }
57
+ catch {
58
+ return report;
59
+ }
60
+ let files;
61
+ try {
62
+ files = fs.readdirSync(dir).filter((f) => f.endsWith(".jsonl"));
63
+ }
64
+ catch {
65
+ return report;
66
+ }
67
+ for (const file of files) {
68
+ const full = path.join(dir, file);
69
+ let lines;
70
+ try {
71
+ lines = fs.readFileSync(full, "utf-8").split("\n");
72
+ }
73
+ catch {
74
+ continue; // unreadable file → skip, don't block the rest
75
+ }
76
+ const rewritten = [];
77
+ let mutated = false;
78
+ for (const line of lines) {
79
+ const trimmed = line.trim();
80
+ if (!trimmed)
81
+ continue;
82
+ let job;
83
+ try {
84
+ job = JSON.parse(trimmed);
85
+ }
86
+ catch {
87
+ rewritten.push(line); // malformed line — preserve verbatim, don't drop
88
+ continue;
89
+ }
90
+ if (job.done) {
91
+ rewritten.push(trimmed);
92
+ continue;
93
+ }
94
+ try {
95
+ handler(job);
96
+ report.processed++;
97
+ rewritten.push(JSON.stringify({ ...job, done: true }));
98
+ mutated = true;
99
+ }
100
+ catch {
101
+ // One bad job never blocks the rest — leave it pending for a retry.
102
+ report.failed++;
103
+ rewritten.push(trimmed);
104
+ }
105
+ }
106
+ if (mutated) {
107
+ try {
108
+ const tmp = full + ".tmp." + process.pid;
109
+ fs.writeFileSync(tmp, rewritten.join("\n") + "\n", "utf-8");
110
+ fs.renameSync(tmp, full); // atomic on POSIX
111
+ }
112
+ catch {
113
+ // If we can't persist the done-marks, the worst case is a re-run of
114
+ // already-processed jobs next drain — acceptable, never fatal.
115
+ }
116
+ }
117
+ }
118
+ return report;
119
+ }
120
+ //# sourceMappingURL=consolidation-queue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consolidation-queue.js","sourceRoot":"","sources":["../../src/storage/consolidation-queue.ts"],"names":[],"mappings":"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"}