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,387 @@
1
+ /**
2
+ * store-doctor.ts — READ-ONLY integrity diagnostics for the on-disk store.
3
+ *
4
+ * This is the round-table's integrity recommendation: a sibling to
5
+ * `palace-lint.ts`, NOT an extension of it. The distinction is deliberate:
6
+ *
7
+ * - palace-lint = per-project CONTENT hygiene (stale rooms, orphans, low
8
+ * salience). It MUTATES (auto-archives) when `fix:true`.
9
+ * - store-doctor = STORE-level structural integrity across ALL projects:
10
+ * index↔disk drift, stuck locks, broken dreaming, orphaned
11
+ * consume markers. It is strictly READ-ONLY.
12
+ *
13
+ * HARD INVARIANTS:
14
+ * 1. NEVER mutates. No write, no mkdir, no rename, no unlink. Only fs reads.
15
+ * 2. NEVER acquires a write lock. It must run — and return — even while
16
+ * another process holds a palace/room lock (no deadlock, no blocking).
17
+ * 3. NEVER throws to the caller. Any per-check failure degrades that check to
18
+ * a best-effort result; the doctor as a whole always returns.
19
+ *
20
+ * It is safe to call on the session_start hot path because it does no locking
21
+ * and bounds its work to directory listings + small JSON/markdown reads.
22
+ */
23
+ import * as fs from "node:fs";
24
+ import * as path from "node:path";
25
+ import { getRoot } from "../types.js";
26
+ import { readJsonSafe } from "../storage/fs-utils.js";
27
+ import { listAllProjects } from "../storage/project.js";
28
+ import { countRoomEntries } from "../palace/rooms.js";
29
+ import { palaceDir, archiveRawDir } from "../storage/paths.js";
30
+ import { STALE_LOCK_MS } from "../storage/filelock.js";
31
+ import { getDreamHealth } from "../storage/dream-health.js";
32
+ import { resolveRetentionDays } from "../storage/retention.js";
33
+ // ───────────────────────────────────────────────────────────────────────────
34
+ // Tunable thresholds (documented; not data-fit — see MATH.md §a for the broader
35
+ // "hand-tuned" stance). All are policy knobs for WHEN to surface a warning.
36
+ // ───────────────────────────────────────────────────────────────────────────
37
+ /**
38
+ * Index-vs-disk drift tolerance, in ENTRY COUNT, per room. A drift of exactly 1
39
+ * is tolerated because a single in-flight palace write can land a `### ` block
40
+ * on disk before `updatePalaceIndex()` refreshes the cached `memory_count`
41
+ * (the room .md is the source of truth, the index is a derived cache). A drift
42
+ * of 2+ means the index is genuinely out of sync → RED.
43
+ */
44
+ export const INDEX_DRIFT_TOLERANCE = 1;
45
+ /** A held lock older than this is escalated from WARN (merely stale) to RED. */
46
+ export const LOCK_RED_MS = 5 * 60 * 1000; // 5 minutes
47
+ /**
48
+ * A `.consumed.json` marker that has NEVER advanced (lastConsumedAt null/absent)
49
+ * while raw segments older than this sit in the archive → WARN. It signals the
50
+ * login-free consolidation seam (which advances the marker at every session_end)
51
+ * has not run even once for that project — a silently-failing `advanceConsumeMarker`
52
+ * — WITHOUT the false positive of flagging a day-old fresh store. Distinct from
53
+ * the RED retention window (resolved live via resolveRetentionDays) so the two
54
+ * severities can't be conflated.
55
+ */
56
+ export const DREAM_NULL_MARKER_WARN_DAYS = 7;
57
+ // ───────────────────────────────────────────────────────────────────────────
58
+ // Helpers
59
+ // ───────────────────────────────────────────────────────────────────────────
60
+ /** Roll the highest level seen so far. red > warn > ok. */
61
+ function maxLevel(a, b) {
62
+ if (a === "red" || b === "red")
63
+ return "red";
64
+ if (a === "warn" || b === "warn")
65
+ return "warn";
66
+ return "ok";
67
+ }
68
+ /** Reduce all check levels into one overall status. */
69
+ function rollupStatus(checks) {
70
+ return checks.reduce((acc, c) => maxLevel(acc, c.level), "ok");
71
+ }
72
+ function safeReaddir(dir) {
73
+ try {
74
+ return fs.existsSync(dir) ? fs.readdirSync(dir) : [];
75
+ }
76
+ catch {
77
+ return [];
78
+ }
79
+ }
80
+ // ───────────────────────────────────────────────────────────────────────────
81
+ // Check 1 — VECTOR-INDEX vs .md DRIFT
82
+ // ───────────────────────────────────────────────────────────────────────────
83
+ /**
84
+ * For every project, compare the palace-index.json cached `memory_count` for
85
+ * each room against the LIVE `### ` block count in that room's .md files.
86
+ * A per-room drift greater than INDEX_DRIFT_TOLERANCE flips the check to RED.
87
+ *
88
+ * READ-ONLY: reads the index JSON and counts blocks via countRoomEntries (which
89
+ * is itself read-only and lock-free). Never calls updatePalaceIndex().
90
+ */
91
+ function checkIndexDrift() {
92
+ const base = {
93
+ name: "vector_index_drift",
94
+ level: "ok",
95
+ detail: "palace-index.json memory_count matches on-disk `### ` block counts.",
96
+ fix_hint: "",
97
+ };
98
+ const drifts = [];
99
+ let level = "ok";
100
+ try {
101
+ for (const proj of listAllProjects()) {
102
+ const idxPath = path.join(palaceDir(proj.slug), "palace-index.json");
103
+ const index = readJsonSafe(idxPath);
104
+ if (!index || !index.rooms)
105
+ continue;
106
+ for (const [slug, room] of Object.entries(index.rooms)) {
107
+ const indexed = room?.memory_count ?? 0;
108
+ const live = countRoomEntries(proj.slug, slug);
109
+ const delta = Math.abs(indexed - live);
110
+ if (delta > INDEX_DRIFT_TOLERANCE) {
111
+ level = "red";
112
+ drifts.push(`${proj.slug}/${slug}: index=${indexed} disk=${live} (Δ${delta})`);
113
+ }
114
+ }
115
+ }
116
+ }
117
+ catch {
118
+ // Degrade to ok-with-note rather than throwing — never break orientation.
119
+ return {
120
+ ...base,
121
+ detail: "index-drift scan could not complete (store unreadable); skipped.",
122
+ };
123
+ }
124
+ if (level === "red") {
125
+ return {
126
+ name: "vector_index_drift",
127
+ level,
128
+ detail: `Index/disk drift > ${INDEX_DRIFT_TOLERANCE} entry in ${drifts.length} room(s): ${drifts.slice(0, 8).join("; ")}`,
129
+ fix_hint: "Run `ar palace lint` (or palaceWrite once) on the affected project to rebuild palace-index.json from the .md source of truth.",
130
+ };
131
+ }
132
+ return base;
133
+ }
134
+ // ───────────────────────────────────────────────────────────────────────────
135
+ // Check 2 — STALE / FORCE-BROKEN LOCK
136
+ // ───────────────────────────────────────────────────────────────────────────
137
+ /**
138
+ * Scan getRoot()/.lock-* dirs. A lock whose mtime is older than STALE_LOCK_MS
139
+ * is WARN (it will be force-broken on the next acquire, but its presence hints
140
+ * a process crashed mid-write); older than LOCK_RED_MS is RED.
141
+ *
142
+ * READ-ONLY: stat only. Does NOT remove the lock (acquireLock does that); the
143
+ * doctor only reports. Never blocks waiting for a lock.
144
+ */
145
+ function checkStaleLock() {
146
+ const base = {
147
+ name: "stale_lock",
148
+ level: "ok",
149
+ detail: "No stale .lock-* directories.",
150
+ fix_hint: "",
151
+ };
152
+ let level = "ok";
153
+ const offenders = [];
154
+ const now = Date.now();
155
+ try {
156
+ const root = getRoot();
157
+ for (const entry of safeReaddir(root)) {
158
+ if (!entry.startsWith(".lock-"))
159
+ continue;
160
+ const full = path.join(root, entry);
161
+ let ageMs;
162
+ try {
163
+ ageMs = now - fs.statSync(full).mtimeMs;
164
+ }
165
+ catch {
166
+ continue; // raced with a release — fine, it's gone
167
+ }
168
+ if (ageMs > LOCK_RED_MS) {
169
+ level = maxLevel(level, "red");
170
+ offenders.push(`${entry} (${Math.round(ageMs / 60000)}m old)`);
171
+ }
172
+ else if (ageMs > STALE_LOCK_MS) {
173
+ level = maxLevel(level, "warn");
174
+ offenders.push(`${entry} (${Math.round(ageMs / 1000)}s old)`);
175
+ }
176
+ }
177
+ }
178
+ catch {
179
+ return base;
180
+ }
181
+ if (level === "ok")
182
+ return base;
183
+ return {
184
+ name: "stale_lock",
185
+ level,
186
+ detail: `${offenders.length} stale lock dir(s): ${offenders.slice(0, 8).join(", ")}.`,
187
+ fix_hint: level === "red"
188
+ ? "A writer likely crashed. After confirming no `ar` process is running, remove the stale `.lock-*` dir under ~/.agent-recall."
189
+ : "Lock is older than the stale threshold; it will be auto-broken on the next write. Investigate if it persists.",
190
+ };
191
+ }
192
+ // ───────────────────────────────────────────────────────────────────────────
193
+ // Check 3 — STALLED CONSOLIDATION SEAM
194
+ // ───────────────────────────────────────────────────────────────────────────
195
+ /**
196
+ * Dreaming/consolidation health. Severity tiers:
197
+ *
198
+ * RED — (a) the AAM LLM dream cron is actively failing (getDreamHealth banner,
199
+ * the known OAuth/network-expiry mode), OR (b) a raw segment OLDER than
200
+ * the retention window is still UNCONSUMED (mtime newer than the
201
+ * `.consumed.json` marker) → the seam that folds raw into the palace and
202
+ * prunes the backup has stalled, so the archive will grow unbounded.
203
+ * WARN — the marker has NEVER advanced (null/absent) while raw segments older
204
+ * than DREAM_NULL_MARKER_WARN_DAYS exist → the login-free seam (which
205
+ * advances the marker at every session_end) likely failed silently for
206
+ * that project, even though nothing is unbounded yet.
207
+ * OK — everything else, notably a login-free store whose raw is all RECENT.
208
+ * That is the normal lossless backup buffer: the content is already
209
+ * regex-folded into the palace at session_end and the segments simply
210
+ * await their retention-window prune. The earlier "consumed within 24h"
211
+ * rule false-positived on EVERY healthy login-free store; anchoring on
212
+ * the (config-resolved) retention window fixes that without going blind
213
+ * to a genuinely stuck marker (the WARN tier).
214
+ *
215
+ * The retention window is resolved LIVE (resolveRetentionDays) from the SAME
216
+ * source the pruner uses, so the doctor can never flag at a different threshold
217
+ * than safety-consolidation actually prunes at.
218
+ *
219
+ * READ-ONLY: directory listing + per-segment stat + marker read + dream log read.
220
+ */
221
+ function checkDreamingStale() {
222
+ const base = {
223
+ name: "dreaming_stale",
224
+ level: "ok",
225
+ detail: "Consolidation seam healthy: no raw segment older than the retention window is unconsumed.",
226
+ fix_hint: "",
227
+ };
228
+ const now = Date.now();
229
+ const DAY_MS = 24 * 60 * 60 * 1000;
230
+ const retentionMs = resolveRetentionDays() * DAY_MS;
231
+ const warnMs = DREAM_NULL_MARKER_WARN_DAYS * DAY_MS;
232
+ const agedUnconsumed = []; // RED evidence (project slugs)
233
+ const nullMarkerStale = []; // WARN evidence (project slugs)
234
+ try {
235
+ for (const proj of listAllProjects()) {
236
+ const rawDir = archiveRawDir(proj.slug);
237
+ const rawFiles = safeReaddir(rawDir).filter((f) => f.endsWith(".md") && f !== "index.md");
238
+ if (rawFiles.length === 0)
239
+ continue;
240
+ const marker = readJsonSafe(path.join(rawDir, ".consumed.json"));
241
+ const lastConsumed = marker?.lastConsumedAt ?? null;
242
+ const markerNeverAdvanced = lastConsumed === null;
243
+ const lastMs = lastConsumed ? new Date(lastConsumed).getTime() : 0;
244
+ let projAged = false;
245
+ let projNullStale = false;
246
+ for (const f of rawFiles) {
247
+ let mtime;
248
+ try {
249
+ mtime = fs.statSync(path.join(rawDir, f)).mtimeMs;
250
+ }
251
+ catch {
252
+ continue; // raced with a prune — skip
253
+ }
254
+ const age = now - mtime;
255
+ const unconsumed = mtime > lastMs; // matches pruneRawArchive's `mtime <= lastConsumedAt` consumed contract
256
+ if (age > retentionMs && unconsumed) {
257
+ projAged = true;
258
+ break; // RED beats WARN — no need to look further in this project
259
+ }
260
+ if (markerNeverAdvanced && age > warnMs) {
261
+ projNullStale = true;
262
+ }
263
+ }
264
+ if (projAged)
265
+ agedUnconsumed.push(proj.slug);
266
+ else if (projNullStale)
267
+ nullMarkerStale.push(proj.slug);
268
+ }
269
+ }
270
+ catch {
271
+ return base; // unreadable store → don't fabricate a failure
272
+ }
273
+ // Independent signal: AAM dream cron failure streak (auth/network expiry).
274
+ let dreamBanner = null;
275
+ try {
276
+ dreamBanner = getDreamHealth().banner;
277
+ }
278
+ catch {
279
+ dreamBanner = null;
280
+ }
281
+ // RED tier — genuine unbounded growth or an actively-failing cron.
282
+ if (agedUnconsumed.length > 0 || dreamBanner) {
283
+ const parts = [];
284
+ if (agedUnconsumed.length > 0) {
285
+ parts.push(`${agedUnconsumed.length} project(s) with raw older than the retention window still unconsumed: ${agedUnconsumed.slice(0, 6).join(", ")}`);
286
+ }
287
+ if (dreamBanner)
288
+ parts.push(dreamBanner);
289
+ return {
290
+ name: "dreaming_stale",
291
+ level: "red",
292
+ detail: `Consolidation seam appears stalled: ${parts.join(" · ")}`,
293
+ fix_hint: "Run `ar repair --apply` (login-free drain: advances the consume marker + prunes aged raw). If the dream-cron banner is set, also check the dreaming agent's auth (known OAuth-expiry mode).",
294
+ };
295
+ }
296
+ // WARN tier — a marker that never advanced while raw aged past the warn floor.
297
+ if (nullMarkerStale.length > 0) {
298
+ return {
299
+ name: "dreaming_stale",
300
+ level: "warn",
301
+ detail: `${nullMarkerStale.length} project(s) have raw segments older than ${DREAM_NULL_MARKER_WARN_DAYS}d but a consume marker that never advanced (login-free seam may have failed silently): ${nullMarkerStale.slice(0, 6).join(", ")}.`,
302
+ fix_hint: "Run `ar repair --apply` to drain (advances the consume marker). If it recurs, the session_end safety-consolidation pass is not firing for that project.",
303
+ };
304
+ }
305
+ return base;
306
+ }
307
+ // ───────────────────────────────────────────────────────────────────────────
308
+ // Check 4 — ORPHANED CONSUME MARKERS
309
+ // ───────────────────────────────────────────────────────────────────────────
310
+ /**
311
+ * A `.consumed.json` claiming progress (lastConsumedAt set) but whose raw
312
+ * archive directory has NO raw .md segments is an orphan — the marker outlived
313
+ * the data it tracked (manual rm, prune bug, or a half-restored backup). It
314
+ * means the consume seam can never reconcile → WARN, escalating to RED when
315
+ * several projects show the same orphan (systemic, not a one-off).
316
+ *
317
+ * READ-ONLY: directory listing + marker read only.
318
+ */
319
+ function checkOrphanedConsumeMarkers() {
320
+ const base = {
321
+ name: "orphaned_consume_marker",
322
+ level: "ok",
323
+ detail: "No orphaned .consumed.json markers.",
324
+ fix_hint: "",
325
+ };
326
+ const orphans = [];
327
+ try {
328
+ for (const proj of listAllProjects()) {
329
+ const rawDir = archiveRawDir(proj.slug);
330
+ const markerPath = path.join(rawDir, ".consumed.json");
331
+ if (!fs.existsSync(markerPath))
332
+ continue;
333
+ const marker = readJsonSafe(markerPath);
334
+ // Only a marker that claims progress is an "orphan" risk; a freshly seeded
335
+ // marker (lastConsumedAt=null) with no data is the normal empty state.
336
+ if (!marker || marker.lastConsumedAt === null)
337
+ continue;
338
+ const rawFiles = safeReaddir(rawDir).filter((f) => f.endsWith(".md") && f !== "index.md");
339
+ if (rawFiles.length === 0) {
340
+ orphans.push(proj.slug);
341
+ }
342
+ }
343
+ }
344
+ catch {
345
+ return base;
346
+ }
347
+ if (orphans.length === 0)
348
+ return base;
349
+ const level = orphans.length >= 3 ? "red" : "warn";
350
+ return {
351
+ name: "orphaned_consume_marker",
352
+ level,
353
+ detail: `${orphans.length} project(s) have a .consumed.json claiming progress but no raw segments: ${orphans.slice(0, 8).join(", ")}.`,
354
+ fix_hint: "The consume marker outlived its raw archive (manual delete or prune bug). Verify backups; re-seeding the marker or restoring the raw segments reconciles the seam.",
355
+ };
356
+ }
357
+ // ───────────────────────────────────────────────────────────────────────────
358
+ // Public entry point
359
+ // ───────────────────────────────────────────────────────────────────────────
360
+ /**
361
+ * Run all integrity checks. READ-ONLY, lock-free, never throws.
362
+ * `status` is the worst level across checks ('ok' | 'warn' | 'red').
363
+ */
364
+ export function runStoreDoctor() {
365
+ const checks = [
366
+ checkIndexDrift(),
367
+ checkStaleLock(),
368
+ checkDreamingStale(),
369
+ checkOrphanedConsumeMarkers(),
370
+ ];
371
+ return { status: rollupStatus(checks), checks };
372
+ }
373
+ /**
374
+ * One-line health summary for the session_start hot path. Returns null when
375
+ * status === 'ok' so callers can stay SILENT on a healthy store (never block
376
+ * recall). On warn/red, returns a compact, single-line banner naming the
377
+ * failing checks.
378
+ */
379
+ export function storeDoctorBanner(result = runStoreDoctor()) {
380
+ if (result.status === "ok")
381
+ return null;
382
+ const flagged = result.checks.filter((c) => c.level !== "ok");
383
+ const icon = result.status === "red" ? "⛔" : "⚠";
384
+ const names = flagged.map((c) => `${c.name}[${c.level}]`).join(", ");
385
+ return `${icon} store-doctor: ${result.status.toUpperCase()} — ${names}. Run \`ar doctor\` for detail.`;
386
+ }
387
+ //# sourceMappingURL=store-doctor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store-doctor.js","sourceRoot":"","sources":["../../src/tools-logic/store-doctor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,64 @@
1
+ /**
2
+ * store-repair.ts — WRITE-side remediation, the deliberate sibling to the
3
+ * read-only store-doctor.ts.
4
+ *
5
+ * store-doctor = DIAGNOSE. Strictly read-only, lock-free, never throws.
6
+ * store-repair = REMEDIATE. Re-derives the same conditions the doctor
7
+ * detects and applies the minimal, idempotent fix each
8
+ * `fix_hint` prescribes.
9
+ *
10
+ * SAFETY INVARIANTS:
11
+ * 1. DRY-RUN BY DEFAULT. `opts.apply` must be EXPLICITLY true to mutate. A
12
+ * dry-run computes the full plan (what WOULD change) and writes nothing.
13
+ * 2. PER-STEP ISOLATION. Each step runs in its own try/catch (mirrors
14
+ * safety-consolidation.ts) — one failing step never aborts the others.
15
+ * 3. IDEMPOTENT. A re-run on an already-clean store is a no-op: drift is
16
+ * recomputed from disk truth, locks are re-scanned, and the consume marker
17
+ * the drain advances is monotonic.
18
+ * 4. LOCK SAFETY. Only `.lock-*` dirs older than LOCK_RED_MS (the doctor's RED
19
+ * threshold) are removed. The locker's acquire timeout is 5s and it
20
+ * force-breaks stale locks at 30s, so a dir older than 5min cannot belong
21
+ * to a live writer — removal is safe WITHOUT scanning for processes.
22
+ *
23
+ * NOT on any hot path. Invoked manually via `ar repair [--apply]`.
24
+ */
25
+ import { type StoreDoctorResult } from "./store-doctor.js";
26
+ export interface RepairStepProjects {
27
+ /** Projects this step acted on (or WOULD act on, in dry-run). */
28
+ projects: string[];
29
+ error?: string;
30
+ }
31
+ export interface RepairStepLocks {
32
+ /** `.lock-*` dir names removed (or that WOULD be, in dry-run). */
33
+ names: string[];
34
+ error?: string;
35
+ }
36
+ export interface RepairSnapshot {
37
+ status: StoreDoctorResult["status"];
38
+ /** Names of checks at RED level. */
39
+ red: string[];
40
+ }
41
+ export interface StoreRepairResult {
42
+ /** false = dry-run (default). true = mutations were applied. */
43
+ apply: boolean;
44
+ /** Doctor status BEFORE any repair. */
45
+ before: RepairSnapshot;
46
+ reindexed: RepairStepProjects;
47
+ locksRemoved: RepairStepLocks;
48
+ drained: RepairStepProjects;
49
+ /** Doctor status AFTER applying — null in dry-run (nothing changed to re-check). */
50
+ after: RepairSnapshot | null;
51
+ }
52
+ export interface StoreRepairOptions {
53
+ /** Must be EXPLICITLY true to mutate. Default false (dry-run). */
54
+ apply?: boolean;
55
+ }
56
+ /**
57
+ * Run all repairs. DRY-RUN unless `opts.apply === true`. Each step is isolated;
58
+ * the result reports exactly what was (or would be) changed, plus the doctor
59
+ * status before and (when applied) after.
60
+ */
61
+ export declare function runStoreRepair(opts?: StoreRepairOptions): Promise<StoreRepairResult>;
62
+ /** One-line summary for CLI / logs. */
63
+ export declare function storeRepairSummary(r: StoreRepairResult): string;
64
+ //# sourceMappingURL=store-repair.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store-repair.d.ts","sourceRoot":"","sources":["../../src/tools-logic/store-repair.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAYH,OAAO,EAKL,KAAK,iBAAiB,EACvB,MAAM,mBAAmB,CAAC;AAG3B,MAAM,WAAW,kBAAkB;IACjC,iEAAiE;IACjE,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,eAAe;IAC9B,kEAAkE;IAClE,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,iBAAiB,CAAC,QAAQ,CAAC,CAAC;IACpC,oCAAoC;IACpC,GAAG,EAAE,MAAM,EAAE,CAAC;CACf;AAED,MAAM,WAAW,iBAAiB;IAChC,gEAAgE;IAChE,KAAK,EAAE,OAAO,CAAC;IACf,uCAAuC;IACvC,MAAM,EAAE,cAAc,CAAC;IACvB,SAAS,EAAE,kBAAkB,CAAC;IAC9B,YAAY,EAAE,eAAe,CAAC;IAC9B,OAAO,EAAE,kBAAkB,CAAC;IAC5B,oFAAoF;IACpF,KAAK,EAAE,cAAc,GAAG,IAAI,CAAC;CAC9B;AAED,MAAM,WAAW,kBAAkB;IACjC,kEAAkE;IAClE,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAuHD;;;;GAIG;AACH,wBAAsB,cAAc,CAClC,IAAI,GAAE,kBAAuB,GAC5B,OAAO,CAAC,iBAAiB,CAAC,CAwE5B;AAED,uCAAuC;AACvC,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,iBAAiB,GAAG,MAAM,CAS/D"}