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.
- package/README.md +121 -441
- package/dist/digest/store.d.ts.map +1 -1
- package/dist/digest/store.js +4 -3
- package/dist/digest/store.js.map +1 -1
- package/dist/display/board-render.d.ts +61 -0
- package/dist/display/board-render.d.ts.map +1 -0
- package/dist/display/board-render.js +223 -0
- package/dist/display/board-render.js.map +1 -0
- package/dist/helpers/alignment-patterns.d.ts +10 -0
- package/dist/helpers/alignment-patterns.d.ts.map +1 -1
- package/dist/helpers/alignment-patterns.js +5 -1
- package/dist/helpers/alignment-patterns.js.map +1 -1
- package/dist/helpers/blind-spots.d.ts +86 -0
- package/dist/helpers/blind-spots.d.ts.map +1 -0
- package/dist/helpers/blind-spots.js +205 -0
- package/dist/helpers/blind-spots.js.map +1 -0
- package/dist/helpers/conflict-scan.d.ts +10 -0
- package/dist/helpers/conflict-scan.d.ts.map +1 -1
- package/dist/helpers/conflict-scan.js +3 -3
- package/dist/helpers/conflict-scan.js.map +1 -1
- package/dist/helpers/semantic-match.d.ts +82 -0
- package/dist/helpers/semantic-match.d.ts.map +1 -0
- package/dist/helpers/semantic-match.js +229 -0
- package/dist/helpers/semantic-match.js.map +1 -0
- package/dist/index.d.ts +57 -17
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +60 -14
- package/dist/index.js.map +1 -1
- package/dist/palace/awareness.d.ts +30 -0
- package/dist/palace/awareness.d.ts.map +1 -1
- package/dist/palace/awareness.js +65 -2
- package/dist/palace/awareness.js.map +1 -1
- package/dist/palace/consolidate.d.ts.map +1 -1
- package/dist/palace/consolidate.js +17 -0
- package/dist/palace/consolidate.js.map +1 -1
- package/dist/palace/decay-pass.d.ts +46 -0
- package/dist/palace/decay-pass.d.ts.map +1 -0
- package/dist/palace/decay-pass.js +87 -0
- package/dist/palace/decay-pass.js.map +1 -0
- package/dist/palace/insights-index.d.ts.map +1 -1
- package/dist/palace/insights-index.js +4 -2
- package/dist/palace/insights-index.js.map +1 -1
- package/dist/palace/skills.d.ts +41 -2
- package/dist/palace/skills.d.ts.map +1 -1
- package/dist/palace/skills.js +106 -4
- package/dist/palace/skills.js.map +1 -1
- package/dist/prompts/consolidation-prompt.d.ts +25 -0
- package/dist/prompts/consolidation-prompt.d.ts.map +1 -0
- package/dist/prompts/consolidation-prompt.js +91 -0
- package/dist/prompts/consolidation-prompt.js.map +1 -0
- package/dist/storage/ab-experiment.d.ts +184 -0
- package/dist/storage/ab-experiment.d.ts.map +1 -0
- package/dist/storage/ab-experiment.js +294 -0
- package/dist/storage/ab-experiment.js.map +1 -0
- package/dist/storage/archive-prune.d.ts +56 -0
- package/dist/storage/archive-prune.d.ts.map +1 -0
- package/dist/storage/archive-prune.js +118 -0
- package/dist/storage/archive-prune.js.map +1 -0
- package/dist/storage/archive-write.d.ts +38 -0
- package/dist/storage/archive-write.d.ts.map +1 -0
- package/dist/storage/archive-write.js +98 -0
- package/dist/storage/archive-write.js.map +1 -0
- package/dist/storage/blind-spots-store.d.ts +30 -0
- package/dist/storage/blind-spots-store.d.ts.map +1 -0
- package/dist/storage/blind-spots-store.js +91 -0
- package/dist/storage/blind-spots-store.js.map +1 -0
- package/dist/storage/capture-router.d.ts +60 -0
- package/dist/storage/capture-router.d.ts.map +1 -0
- package/dist/storage/capture-router.js +133 -0
- package/dist/storage/capture-router.js.map +1 -0
- package/dist/storage/classification.d.ts +36 -0
- package/dist/storage/classification.d.ts.map +1 -0
- package/dist/storage/classification.js +78 -0
- package/dist/storage/classification.js.map +1 -0
- package/dist/storage/consolidation-queue.d.ts +39 -0
- package/dist/storage/consolidation-queue.d.ts.map +1 -0
- package/dist/storage/consolidation-queue.js +120 -0
- package/dist/storage/consolidation-queue.js.map +1 -0
- package/dist/storage/content-guard.d.ts +74 -0
- package/dist/storage/content-guard.d.ts.map +1 -0
- package/dist/storage/content-guard.js +179 -0
- package/dist/storage/content-guard.js.map +1 -0
- package/dist/storage/corrections.d.ts +329 -22
- package/dist/storage/corrections.d.ts.map +1 -1
- package/dist/storage/corrections.js +788 -58
- package/dist/storage/corrections.js.map +1 -1
- package/dist/storage/durable-intent.d.ts +49 -0
- package/dist/storage/durable-intent.d.ts.map +1 -0
- package/dist/storage/durable-intent.js +124 -0
- package/dist/storage/durable-intent.js.map +1 -0
- package/dist/storage/filelock.d.ts +6 -0
- package/dist/storage/filelock.d.ts.map +1 -1
- package/dist/storage/filelock.js +6 -1
- package/dist/storage/filelock.js.map +1 -1
- package/dist/storage/memory-protocol.d.ts +19 -0
- package/dist/storage/memory-protocol.d.ts.map +1 -0
- package/dist/storage/memory-protocol.js +101 -0
- package/dist/storage/memory-protocol.js.map +1 -0
- package/dist/storage/paths.d.ts +23 -0
- package/dist/storage/paths.d.ts.map +1 -1
- package/dist/storage/paths.js +39 -0
- package/dist/storage/paths.js.map +1 -1
- package/dist/storage/retention.d.ts +23 -0
- package/dist/storage/retention.d.ts.map +1 -0
- package/dist/storage/retention.js +48 -0
- package/dist/storage/retention.js.map +1 -0
- package/dist/storage/session.d.ts +2 -2
- package/dist/storage/session.d.ts.map +1 -1
- package/dist/storage/session.js +11 -1
- package/dist/storage/session.js.map +1 -1
- package/dist/supabase/config.d.ts +26 -0
- package/dist/supabase/config.d.ts.map +1 -1
- package/dist/supabase/config.js +11 -0
- package/dist/supabase/config.js.map +1 -1
- package/dist/supabase/recall-backend.d.ts +1 -0
- package/dist/supabase/recall-backend.d.ts.map +1 -1
- package/dist/supabase/recall-backend.js +13 -13
- package/dist/supabase/recall-backend.js.map +1 -1
- package/dist/supabase/sync.d.ts +1 -1
- package/dist/supabase/sync.d.ts.map +1 -1
- package/dist/supabase/sync.js +85 -3
- package/dist/supabase/sync.js.map +1 -1
- package/dist/tools-logic/bootstrap.d.ts +15 -0
- package/dist/tools-logic/bootstrap.d.ts.map +1 -1
- package/dist/tools-logic/bootstrap.js +238 -47
- package/dist/tools-logic/bootstrap.js.map +1 -1
- package/dist/tools-logic/brief.d.ts +84 -0
- package/dist/tools-logic/brief.d.ts.map +1 -0
- package/dist/tools-logic/brief.js +193 -0
- package/dist/tools-logic/brief.js.map +1 -0
- package/dist/tools-logic/check-action.d.ts +9 -0
- package/dist/tools-logic/check-action.d.ts.map +1 -1
- package/dist/tools-logic/check-action.js +61 -3
- package/dist/tools-logic/check-action.js.map +1 -1
- package/dist/tools-logic/check.d.ts +7 -0
- package/dist/tools-logic/check.d.ts.map +1 -1
- package/dist/tools-logic/check.js +24 -2
- package/dist/tools-logic/check.js.map +1 -1
- package/dist/tools-logic/confidence.d.ts +50 -0
- package/dist/tools-logic/confidence.d.ts.map +1 -0
- package/dist/tools-logic/confidence.js +70 -0
- package/dist/tools-logic/confidence.js.map +1 -0
- package/dist/tools-logic/drill-down.d.ts +37 -0
- package/dist/tools-logic/drill-down.d.ts.map +1 -0
- package/dist/tools-logic/drill-down.js +63 -0
- package/dist/tools-logic/drill-down.js.map +1 -0
- package/dist/tools-logic/export-corrections.d.ts +63 -0
- package/dist/tools-logic/export-corrections.d.ts.map +1 -0
- package/dist/tools-logic/export-corrections.js +124 -0
- package/dist/tools-logic/export-corrections.js.map +1 -0
- package/dist/tools-logic/journal-capture.d.ts.map +1 -1
- package/dist/tools-logic/journal-capture.js +4 -1
- package/dist/tools-logic/journal-capture.js.map +1 -1
- package/dist/tools-logic/journal-write.d.ts.map +1 -1
- package/dist/tools-logic/journal-write.js +3 -2
- package/dist/tools-logic/journal-write.js.map +1 -1
- package/dist/tools-logic/local-archive-backend.d.ts +33 -0
- package/dist/tools-logic/local-archive-backend.d.ts.map +1 -0
- package/dist/tools-logic/local-archive-backend.js +124 -0
- package/dist/tools-logic/local-archive-backend.js.map +1 -0
- package/dist/tools-logic/memory-backend.d.ts +74 -0
- package/dist/tools-logic/memory-backend.d.ts.map +1 -0
- package/dist/tools-logic/memory-backend.js +172 -0
- package/dist/tools-logic/memory-backend.js.map +1 -0
- package/dist/tools-logic/memory-query.d.ts +10 -3
- package/dist/tools-logic/memory-query.d.ts.map +1 -1
- package/dist/tools-logic/memory-query.js +31 -7
- package/dist/tools-logic/memory-query.js.map +1 -1
- package/dist/tools-logic/mirror-builder.d.ts +115 -0
- package/dist/tools-logic/mirror-builder.d.ts.map +1 -0
- package/dist/tools-logic/mirror-builder.js +348 -0
- package/dist/tools-logic/mirror-builder.js.map +1 -0
- package/dist/tools-logic/palace-write.d.ts.map +1 -1
- package/dist/tools-logic/palace-write.js +3 -2
- package/dist/tools-logic/palace-write.js.map +1 -1
- package/dist/tools-logic/pipeline-close.d.ts.map +1 -1
- package/dist/tools-logic/pipeline-close.js +2 -1
- package/dist/tools-logic/pipeline-close.js.map +1 -1
- package/dist/tools-logic/pipeline-open.d.ts.map +1 -1
- package/dist/tools-logic/pipeline-open.js +2 -1
- package/dist/tools-logic/pipeline-open.js.map +1 -1
- package/dist/tools-logic/predict-correction.d.ts +47 -0
- package/dist/tools-logic/predict-correction.d.ts.map +1 -0
- package/dist/tools-logic/predict-correction.js +137 -0
- package/dist/tools-logic/predict-correction.js.map +1 -0
- package/dist/tools-logic/prior-builder.d.ts +27 -0
- package/dist/tools-logic/prior-builder.d.ts.map +1 -0
- package/dist/tools-logic/prior-builder.js +90 -0
- package/dist/tools-logic/prior-builder.js.map +1 -0
- package/dist/tools-logic/recognition-builder.d.ts +122 -0
- package/dist/tools-logic/recognition-builder.d.ts.map +1 -0
- package/dist/tools-logic/recognition-builder.js +289 -0
- package/dist/tools-logic/recognition-builder.js.map +1 -0
- package/dist/tools-logic/safety-consolidation.d.ts +104 -0
- package/dist/tools-logic/safety-consolidation.d.ts.map +1 -0
- package/dist/tools-logic/safety-consolidation.js +256 -0
- package/dist/tools-logic/safety-consolidation.js.map +1 -0
- package/dist/tools-logic/session-end-reflect.d.ts +18 -0
- package/dist/tools-logic/session-end-reflect.d.ts.map +1 -1
- package/dist/tools-logic/session-end-reflect.js +69 -30
- package/dist/tools-logic/session-end-reflect.js.map +1 -1
- package/dist/tools-logic/session-end.d.ts +18 -0
- package/dist/tools-logic/session-end.d.ts.map +1 -1
- package/dist/tools-logic/session-end.js +189 -34
- package/dist/tools-logic/session-end.js.map +1 -1
- package/dist/tools-logic/session-start-lite.d.ts +2 -0
- package/dist/tools-logic/session-start-lite.d.ts.map +1 -1
- package/dist/tools-logic/session-start-lite.js +11 -2
- package/dist/tools-logic/session-start-lite.js.map +1 -1
- package/dist/tools-logic/session-start.d.ts +81 -2
- package/dist/tools-logic/session-start.d.ts.map +1 -1
- package/dist/tools-logic/session-start.js +357 -40
- package/dist/tools-logic/session-start.js.map +1 -1
- package/dist/tools-logic/skill-propose.d.ts +27 -0
- package/dist/tools-logic/skill-propose.d.ts.map +1 -0
- package/dist/tools-logic/skill-propose.js +66 -0
- package/dist/tools-logic/skill-propose.js.map +1 -0
- package/dist/tools-logic/skill-recall.d.ts +5 -0
- package/dist/tools-logic/skill-recall.d.ts.map +1 -1
- package/dist/tools-logic/skill-recall.js +14 -1
- package/dist/tools-logic/skill-recall.js.map +1 -1
- package/dist/tools-logic/smart-recall.d.ts +17 -0
- package/dist/tools-logic/smart-recall.d.ts.map +1 -1
- package/dist/tools-logic/smart-recall.js +51 -16
- package/dist/tools-logic/smart-recall.js.map +1 -1
- package/dist/tools-logic/smart-remember.js +8 -9
- package/dist/tools-logic/smart-remember.js.map +1 -1
- package/dist/tools-logic/store-doctor.d.ts +71 -0
- package/dist/tools-logic/store-doctor.d.ts.map +1 -0
- package/dist/tools-logic/store-doctor.js +387 -0
- package/dist/tools-logic/store-doctor.js.map +1 -0
- package/dist/tools-logic/store-repair.d.ts +64 -0
- package/dist/tools-logic/store-repair.d.ts.map +1 -0
- package/dist/tools-logic/store-repair.js +243 -0
- package/dist/tools-logic/store-repair.js.map +1 -0
- package/dist/tools-logic/supersession.d.ts +34 -0
- package/dist/tools-logic/supersession.d.ts.map +1 -0
- package/dist/tools-logic/supersession.js +103 -0
- package/dist/tools-logic/supersession.js.map +1 -0
- package/dist/types.d.ts +7 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +1 -1
- package/dist/vector/embedding.d.ts +8 -0
- package/dist/vector/embedding.d.ts.map +1 -1
- package/dist/vector/embedding.js +9 -1
- package/dist/vector/embedding.js.map +1 -1
- package/dist/vector/local-vector-backend.d.ts.map +1 -1
- package/dist/vector/local-vector-backend.js +14 -17
- package/dist/vector/local-vector-backend.js.map +1 -1
- package/package.json +2 -2
- package/dist/relevance/injector.d.ts +0 -51
- package/dist/relevance/injector.d.ts.map +0 -1
- package/dist/relevance/injector.js +0 -121
- package/dist/relevance/injector.js.map +0 -1
- package/dist/relevance/precision.d.ts +0 -109
- package/dist/relevance/precision.d.ts.map +0 -1
- package/dist/relevance/precision.js +0 -279
- package/dist/relevance/precision.js.map +0 -1
- package/dist/relevance/promoter.d.ts +0 -60
- package/dist/relevance/promoter.d.ts.map +0 -1
- package/dist/relevance/promoter.js +0 -336
- package/dist/relevance/promoter.js.map +0 -1
- package/dist/relevance/stager.d.ts +0 -61
- package/dist/relevance/stager.d.ts.map +0 -1
- package/dist/relevance/stager.js +0 -251
- package/dist/relevance/stager.js.map +0 -1
- package/dist/relevance/surfacer.d.ts +0 -34
- package/dist/relevance/surfacer.d.ts.map +0 -1
- package/dist/relevance/surfacer.js +0 -333
- 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"}
|