agent-recall-core 3.4.31 → 3.4.35
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 +52 -11
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +48 -9
- 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/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 +32 -0
- package/dist/storage/classification.d.ts.map +1 -0
- package/dist/storage/classification.js +74 -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 +246 -21
- package/dist/storage/corrections.d.ts.map +1 -1
- package/dist/storage/corrections.js +605 -56
- 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 +8 -0
- package/dist/supabase/config.d.ts.map +1 -1
- package/dist/supabase/config.js +5 -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.map +1 -1
- package/dist/supabase/sync.js +30 -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 +31 -2
- 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/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 +57 -0
- package/dist/tools-logic/prior-builder.js.map +1 -0
- package/dist/tools-logic/recognition-builder.d.ts +116 -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 +68 -29
- package/dist/tools-logic/session-end-reflect.js.map +1 -1
- package/dist/tools-logic/session-end.d.ts +9 -0
- package/dist/tools-logic/session-end.d.ts.map +1 -1
- package/dist/tools-logic/session-end.js +111 -13
- 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 +10 -0
- package/dist/tools-logic/session-start-lite.js.map +1 -1
- package/dist/tools-logic/session-start.d.ts +46 -0
- package/dist/tools-logic/session-start.d.ts.map +1 -1
- package/dist/tools-logic/session-start.js +96 -3
- 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/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/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 +1 -1
- 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,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* consolidation-prompt.ts — the versioned, in-repo consolidation prompt
|
|
3
|
+
* (Wave 5, the compression remainder).
|
|
4
|
+
*
|
|
5
|
+
* This is the single source for the "reflect on recent work → surface
|
|
6
|
+
* crystallization candidates" prompt that the dreaming loop runs. It ports ONLY
|
|
7
|
+
* Phase B (candidate-finding) of the external ~/.aam T1 Step 4.5 prompt; Phase C
|
|
8
|
+
* (synthesis) deliberately stays the LLM's job (Decision #3 — core never
|
|
9
|
+
* synthesizes). `session-end-reflect.ts:buildPrompt()` imports `buildConsolidationPrompt`
|
|
10
|
+
* so there is exactly one prompt generator.
|
|
11
|
+
*
|
|
12
|
+
* The template is VERSIONED so a change to the consolidation contract is
|
|
13
|
+
* observable (and the `ar consolidate` CLI / dreaming repoint can pin a version).
|
|
14
|
+
*/
|
|
15
|
+
/** Bump when the consolidation contract changes. */
|
|
16
|
+
export const CONSOLIDATION_PROMPT_VERSION = "v1";
|
|
17
|
+
export const CONSOLIDATION_PROMPT_TEMPLATE = `# AgentRecall consolidation prompt ${CONSOLIDATION_PROMPT_VERSION}
|
|
18
|
+
|
|
19
|
+
You are the agent reviewing your own recent work. From the inputs below, produce:
|
|
20
|
+
|
|
21
|
+
1. **Three high-level questions** this period raised (Park 2023 style).
|
|
22
|
+
2. **Procedural skills** that crystallized — anything repeated >=2x is a candidate (call skill_write).
|
|
23
|
+
3. **Cross-session patterns** not yet in awareness — distilled insights worth promoting.
|
|
24
|
+
4. **Noise to archive** — corrections with low precision that should be retired.
|
|
25
|
+
|
|
26
|
+
PHASE B (candidate-finding) is done for you: crystallization candidates below are
|
|
27
|
+
clusters of related insights. PHASE C (synthesis) is YOURS — the system does NOT
|
|
28
|
+
synthesize a principle for you; decide whether/how to crystallize each cluster.
|
|
29
|
+
|
|
30
|
+
Be terse. One bullet per finding. Cite journal dates / phase orders / correction ids as evidence.
|
|
31
|
+
`;
|
|
32
|
+
/**
|
|
33
|
+
* Build the consolidation prompt for a project from a reflect bundle. Mirrors
|
|
34
|
+
* the structured sections the reflect tool previously inlined — now shared so
|
|
35
|
+
* `ar consolidate` and `session_end_reflect` render identically.
|
|
36
|
+
*/
|
|
37
|
+
export function buildConsolidationPrompt(slug, bundle, lookbackDays) {
|
|
38
|
+
const lines = [];
|
|
39
|
+
const header = lookbackDays
|
|
40
|
+
? `# Consolidate ${slug} — last ${lookbackDays} days (${CONSOLIDATION_PROMPT_VERSION})`
|
|
41
|
+
: `# Consolidate ${slug} (${CONSOLIDATION_PROMPT_VERSION})`;
|
|
42
|
+
lines.push(header);
|
|
43
|
+
lines.push("");
|
|
44
|
+
lines.push(CONSOLIDATION_PROMPT_TEMPLATE.trim());
|
|
45
|
+
lines.push("");
|
|
46
|
+
lines.push("---");
|
|
47
|
+
lines.push("");
|
|
48
|
+
lines.push(`## Journals (${bundle.recent_journals.length})`);
|
|
49
|
+
for (const j of bundle.recent_journals) {
|
|
50
|
+
lines.push(`### ${j.date} — ${j.file}`);
|
|
51
|
+
lines.push(j.excerpt);
|
|
52
|
+
lines.push("");
|
|
53
|
+
}
|
|
54
|
+
lines.push(`## Active corrections (${bundle.active_corrections.length})`);
|
|
55
|
+
for (const c of bundle.active_corrections) {
|
|
56
|
+
const p = c.precision !== null && c.precision !== undefined ? ` p=${c.precision}` : "";
|
|
57
|
+
lines.push(`- [${c.id}] (${c.severity}${p}) ${c.rule}`);
|
|
58
|
+
}
|
|
59
|
+
lines.push("");
|
|
60
|
+
lines.push(`## Recent closed phases (${bundle.recent_phases.length})`);
|
|
61
|
+
for (const ph of bundle.recent_phases) {
|
|
62
|
+
lines.push(`- Phase ${ph.order} — ${ph.phase}: ${ph.synthesis}`);
|
|
63
|
+
}
|
|
64
|
+
if (bundle.raw_unconsumed && bundle.raw_unconsumed.length > 0) {
|
|
65
|
+
lines.push("");
|
|
66
|
+
lines.push(`## Unconsumed raw archive (${bundle.raw_unconsumed.length})`);
|
|
67
|
+
lines.push("These verbatim session dumps have NOT been distilled yet. Read them, " +
|
|
68
|
+
"extract any reusable pattern/decision/skill, then advance the " +
|
|
69
|
+
"journal/archive/raw/.consumed.json marker so they aren't re-processed.");
|
|
70
|
+
for (const r of bundle.raw_unconsumed) {
|
|
71
|
+
lines.push(`### ${r.file} (${r.bytes} bytes)`);
|
|
72
|
+
lines.push(r.excerpt);
|
|
73
|
+
lines.push("");
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
if (bundle.crystallization_candidates && bundle.crystallization_candidates.length > 0) {
|
|
77
|
+
lines.push("");
|
|
78
|
+
lines.push(`## Crystallization candidates (${bundle.crystallization_candidates.length})`);
|
|
79
|
+
lines.push("These insight clusters share >=2 trigger keywords and enough confirmations to " +
|
|
80
|
+
"be worth crystallizing into ONE principle. Decide whether to synthesize each " +
|
|
81
|
+
"(awareness_update) — the system does not synthesize for you.");
|
|
82
|
+
for (const c of bundle.crystallization_candidates) {
|
|
83
|
+
lines.push(`### [${c.shared_keywords.join(" + ")}] — ${c.size} insights, ${c.total_confirmations}x confirmed`);
|
|
84
|
+
for (const t of c.insight_titles)
|
|
85
|
+
lines.push(`- ${t}`);
|
|
86
|
+
lines.push("");
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return lines.join("\n");
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=consolidation-prompt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consolidation-prompt.js","sourceRoot":"","sources":["../../src/prompts/consolidation-prompt.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* archive-prune.ts — retention pass for the lossless raw archive tier (Wave 2).
|
|
3
|
+
*
|
|
4
|
+
* Companion to archive-write.ts. Bounds ~/.agent-recall growth by gzipping (or
|
|
5
|
+
* removing) raw session segments under journal/archive/raw/ that are BOTH:
|
|
6
|
+
* (a) older than `olderThanDays` (by file mtime), AND
|
|
7
|
+
* (b) already CONSUMED — i.e. their mtime is at or before
|
|
8
|
+
* journal/archive/raw/.consumed.json `lastConsumedAt`.
|
|
9
|
+
*
|
|
10
|
+
* "Consumed" (single agreed definition, shared with advanceConsumeMarker in
|
|
11
|
+
* safety-consolidation.ts): a raw segment whose content has been folded into the
|
|
12
|
+
* palace by the login-free, regex journal→palace consolidation. The marker is
|
|
13
|
+
* advanced monotonically to `now − retentionWindow` by advanceConsumeMarker on
|
|
14
|
+
* the login-free safety pass (the optional dreaming loop MAY also advance it, but
|
|
15
|
+
* is no longer required to — that was the original Wave-5 plan, superseded).
|
|
16
|
+
*
|
|
17
|
+
* The consumed gate is load-bearing: while `lastConsumedAt` is null (nothing
|
|
18
|
+
* advanced the marker yet) this pass prunes NOTHING — we never discard raw bytes
|
|
19
|
+
* that have not been distilled into the palace.
|
|
20
|
+
*
|
|
21
|
+
* Mirrors journal-archive.ts's older_than_days / dry-run shape. Unlike
|
|
22
|
+
* archive-write.ts (which must never throw inside the Stop turn), this is an
|
|
23
|
+
* explicitly-invoked maintenance op: it surfaces no error to the caller but
|
|
24
|
+
* skips any single file it cannot process rather than aborting the whole pass.
|
|
25
|
+
*/
|
|
26
|
+
export interface PruneRawArchiveOptions {
|
|
27
|
+
/** Segments whose mtime is older than this many days are prune candidates. Default 30. */
|
|
28
|
+
olderThanDays?: number;
|
|
29
|
+
/** When true, report what WOULD be pruned but write/delete nothing. Default false. */
|
|
30
|
+
dryRun?: boolean;
|
|
31
|
+
/** "gzip" (default) compresses to `<file>.gz` then removes the original; "remove" deletes outright. */
|
|
32
|
+
mode?: "gzip" | "remove";
|
|
33
|
+
}
|
|
34
|
+
export interface PruneRawArchiveResult {
|
|
35
|
+
/** The journal/archive/raw directory inspected. */
|
|
36
|
+
dir: string;
|
|
37
|
+
/** Raw `.md` segments examined. */
|
|
38
|
+
scanned: number;
|
|
39
|
+
/** Segments gzipped (0 in dryRun). */
|
|
40
|
+
gzipped: number;
|
|
41
|
+
/** Segments removed outright (0 in dryRun; only when mode === "remove"). */
|
|
42
|
+
removed: number;
|
|
43
|
+
/** Candidates matching BOTH gates (old AND consumed). Equals gzipped+removed when !dryRun and no per-file error. */
|
|
44
|
+
eligible: number;
|
|
45
|
+
/** Segments kept: too new, or not yet consumed. */
|
|
46
|
+
kept: number;
|
|
47
|
+
dryRun: boolean;
|
|
48
|
+
/** `lastConsumedAt` from .consumed.json; null when nothing is consumed yet (⇒ nothing pruned). */
|
|
49
|
+
consumedThrough: string | null;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Gzip-or-remove consumed, aged raw archive segments to bound disk growth.
|
|
53
|
+
* Safe by construction: with no consume marker advanced, it prunes nothing.
|
|
54
|
+
*/
|
|
55
|
+
export declare function pruneRawArchive(project: string, options?: PruneRawArchiveOptions): PruneRawArchiveResult;
|
|
56
|
+
//# sourceMappingURL=archive-prune.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"archive-prune.d.ts","sourceRoot":"","sources":["../../src/storage/archive-prune.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAeH,MAAM,WAAW,sBAAsB;IACrC,0FAA0F;IAC1F,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,sFAAsF;IACtF,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,uGAAuG;IACvG,IAAI,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC;CAC1B;AAED,MAAM,WAAW,qBAAqB;IACpC,mDAAmD;IACnD,GAAG,EAAE,MAAM,CAAC;IACZ,mCAAmC;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,sCAAsC;IACtC,OAAO,EAAE,MAAM,CAAC;IAChB,4EAA4E;IAC5E,OAAO,EAAE,MAAM,CAAC;IAChB,oHAAoH;IACpH,QAAQ,EAAE,MAAM,CAAC;IACjB,mDAAmD;IACnD,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;IAChB,kGAAkG;IAClG,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,sBAA2B,GACnC,qBAAqB,CAqFvB"}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* archive-prune.ts — retention pass for the lossless raw archive tier (Wave 2).
|
|
3
|
+
*
|
|
4
|
+
* Companion to archive-write.ts. Bounds ~/.agent-recall growth by gzipping (or
|
|
5
|
+
* removing) raw session segments under journal/archive/raw/ that are BOTH:
|
|
6
|
+
* (a) older than `olderThanDays` (by file mtime), AND
|
|
7
|
+
* (b) already CONSUMED — i.e. their mtime is at or before
|
|
8
|
+
* journal/archive/raw/.consumed.json `lastConsumedAt`.
|
|
9
|
+
*
|
|
10
|
+
* "Consumed" (single agreed definition, shared with advanceConsumeMarker in
|
|
11
|
+
* safety-consolidation.ts): a raw segment whose content has been folded into the
|
|
12
|
+
* palace by the login-free, regex journal→palace consolidation. The marker is
|
|
13
|
+
* advanced monotonically to `now − retentionWindow` by advanceConsumeMarker on
|
|
14
|
+
* the login-free safety pass (the optional dreaming loop MAY also advance it, but
|
|
15
|
+
* is no longer required to — that was the original Wave-5 plan, superseded).
|
|
16
|
+
*
|
|
17
|
+
* The consumed gate is load-bearing: while `lastConsumedAt` is null (nothing
|
|
18
|
+
* advanced the marker yet) this pass prunes NOTHING — we never discard raw bytes
|
|
19
|
+
* that have not been distilled into the palace.
|
|
20
|
+
*
|
|
21
|
+
* Mirrors journal-archive.ts's older_than_days / dry-run shape. Unlike
|
|
22
|
+
* archive-write.ts (which must never throw inside the Stop turn), this is an
|
|
23
|
+
* explicitly-invoked maintenance op: it surfaces no error to the caller but
|
|
24
|
+
* skips any single file it cannot process rather than aborting the whole pass.
|
|
25
|
+
*/
|
|
26
|
+
import * as fs from "node:fs";
|
|
27
|
+
import * as path from "node:path";
|
|
28
|
+
import { gzipSync } from "node:zlib";
|
|
29
|
+
import { archiveRawDir, sanitizeSlug } from "./paths.js";
|
|
30
|
+
import { readJsonSafe } from "./fs-utils.js";
|
|
31
|
+
const DAY_MS = 86_400_000;
|
|
32
|
+
// Raw segment filenames are `<YYYY-MM-DD>--<sid>.md` (see archive-write.ts).
|
|
33
|
+
// This deliberately excludes `.consumed.json`, `index.md`, and already-gzipped
|
|
34
|
+
// `*.md.gz` segments.
|
|
35
|
+
const RAW_SEGMENT_RE = /^\d{4}-\d{2}-\d{2}--.+\.md$/;
|
|
36
|
+
/**
|
|
37
|
+
* Gzip-or-remove consumed, aged raw archive segments to bound disk growth.
|
|
38
|
+
* Safe by construction: with no consume marker advanced, it prunes nothing.
|
|
39
|
+
*/
|
|
40
|
+
export function pruneRawArchive(project, options = {}) {
|
|
41
|
+
const olderThanDays = options.olderThanDays ?? 30;
|
|
42
|
+
const dryRun = options.dryRun ?? false;
|
|
43
|
+
const mode = options.mode ?? "gzip";
|
|
44
|
+
const slug = sanitizeSlug(project);
|
|
45
|
+
const dir = archiveRawDir(slug);
|
|
46
|
+
const result = {
|
|
47
|
+
dir,
|
|
48
|
+
scanned: 0,
|
|
49
|
+
gzipped: 0,
|
|
50
|
+
removed: 0,
|
|
51
|
+
eligible: 0,
|
|
52
|
+
kept: 0,
|
|
53
|
+
dryRun,
|
|
54
|
+
consumedThrough: null,
|
|
55
|
+
};
|
|
56
|
+
if (!fs.existsSync(dir))
|
|
57
|
+
return result;
|
|
58
|
+
// Consume marker: only prune what the dreaming loop has already distilled.
|
|
59
|
+
const marker = readJsonSafe(path.join(dir, ".consumed.json"));
|
|
60
|
+
const lastConsumedAt = marker?.lastConsumedAt ?? null;
|
|
61
|
+
result.consumedThrough = lastConsumedAt;
|
|
62
|
+
// Guard: nothing consumed yet → never discard undistilled raw bytes.
|
|
63
|
+
const consumedCutoffMs = lastConsumedAt ? new Date(lastConsumedAt).getTime() : null;
|
|
64
|
+
const ageCutoffMs = Date.now() - olderThanDays * DAY_MS;
|
|
65
|
+
let entries;
|
|
66
|
+
try {
|
|
67
|
+
entries = fs.readdirSync(dir);
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
return result;
|
|
71
|
+
}
|
|
72
|
+
for (const name of entries) {
|
|
73
|
+
if (!RAW_SEGMENT_RE.test(name))
|
|
74
|
+
continue;
|
|
75
|
+
result.scanned++;
|
|
76
|
+
const full = path.join(dir, name);
|
|
77
|
+
let mtimeMs;
|
|
78
|
+
try {
|
|
79
|
+
mtimeMs = fs.statSync(full).mtimeMs;
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
continue; // vanished mid-pass; ignore
|
|
83
|
+
}
|
|
84
|
+
// Inclusive boundaries (deterministic; the consumed gate uses the exact
|
|
85
|
+
// `mtime <= lastConsumedAt` contract from the plan).
|
|
86
|
+
const isOld = mtimeMs <= ageCutoffMs;
|
|
87
|
+
const isConsumed = consumedCutoffMs !== null && mtimeMs <= consumedCutoffMs;
|
|
88
|
+
if (!(isOld && isConsumed)) {
|
|
89
|
+
result.kept++;
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
result.eligible++;
|
|
93
|
+
if (dryRun)
|
|
94
|
+
continue; // report only; touch nothing
|
|
95
|
+
try {
|
|
96
|
+
if (mode === "gzip") {
|
|
97
|
+
const gzPath = full + ".gz";
|
|
98
|
+
if (!fs.existsSync(gzPath)) {
|
|
99
|
+
const raw = fs.readFileSync(full);
|
|
100
|
+
const tmp = gzPath + ".tmp." + process.pid;
|
|
101
|
+
fs.writeFileSync(tmp, gzipSync(raw));
|
|
102
|
+
fs.renameSync(tmp, gzPath);
|
|
103
|
+
}
|
|
104
|
+
fs.unlinkSync(full);
|
|
105
|
+
result.gzipped++;
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
fs.unlinkSync(full);
|
|
109
|
+
result.removed++;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
// A single failed file must not abort the pass; it simply is not counted.
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return result;
|
|
117
|
+
}
|
|
118
|
+
//# sourceMappingURL=archive-prune.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"archive-prune.js","sourceRoot":"","sources":["../../src/storage/archive-prune.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* archive-write.ts — the lossless, mechanical, judgment-free verbatim tier
|
|
3
|
+
* (Wave 2). Written on EVERY session end, BEFORE any capture/summary logic, so
|
|
4
|
+
* a session can never be "lost" just because nothing was captured.
|
|
5
|
+
*
|
|
6
|
+
* Hard invariants (privacy + safety):
|
|
7
|
+
* - LOCAL-ONLY. This module MUST NOT import journal-write or syncToSupabase.
|
|
8
|
+
* The raw tier never leaves the machine. (Verified by a structural test.)
|
|
9
|
+
* - NEVER throws to the caller. Any failure returns { path:"", bytes:0 } so a
|
|
10
|
+
* crash here can never break the Stop turn.
|
|
11
|
+
* - sessionId is UNTRUSTED (arrives from hook stdin) → MUST pass through
|
|
12
|
+
* sanitizeSlug before any path.join (MCP-security rule).
|
|
13
|
+
* - Idempotent on the session UUID: a second call for the same session is a
|
|
14
|
+
* no-op (returns bytes:0) and never overwrites the original verbatim bytes.
|
|
15
|
+
*/
|
|
16
|
+
export interface ArchiveSessionInput {
|
|
17
|
+
project: string;
|
|
18
|
+
/** UNTRUSTED — sanitized before use. The dedup key (session UUID). */
|
|
19
|
+
sessionId: string;
|
|
20
|
+
/** The transcript file path, recorded in frontmatter for provenance only. */
|
|
21
|
+
transcriptPath?: string;
|
|
22
|
+
/** The verbatim transcript bytes (head+tail). Written as-is, no truncation. */
|
|
23
|
+
rawTranscript: string;
|
|
24
|
+
/** Optional one-line human summary (first user message), for the index line. */
|
|
25
|
+
summary?: string;
|
|
26
|
+
}
|
|
27
|
+
export interface ArchiveSessionResult {
|
|
28
|
+
/** Absolute path of the written (or pre-existing) raw file; "" on failure. */
|
|
29
|
+
path: string;
|
|
30
|
+
/** Bytes of rawTranscript written; 0 if idempotent no-op or on failure. */
|
|
31
|
+
bytes: number;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Write a verbatim, lossless dump of a session under journal/archive/raw/.
|
|
35
|
+
* Mechanical and judgment-free: no min-length gate, no summarization, no sync.
|
|
36
|
+
*/
|
|
37
|
+
export declare function archiveSession(input: ArchiveSessionInput): ArchiveSessionResult;
|
|
38
|
+
//# sourceMappingURL=archive-write.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"archive-write.d.ts","sourceRoot":"","sources":["../../src/storage/archive-write.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAQH,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,sEAAsE;IACtE,SAAS,EAAE,MAAM,CAAC;IAClB,6EAA6E;IAC7E,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,+EAA+E;IAC/E,aAAa,EAAE,MAAM,CAAC;IACtB,gFAAgF;IAChF,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,oBAAoB;IACnC,8EAA8E;IAC9E,IAAI,EAAE,MAAM,CAAC;IACb,2EAA2E;IAC3E,KAAK,EAAE,MAAM,CAAC;CACf;AAsCD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,mBAAmB,GAAG,oBAAoB,CAmD/E"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* archive-write.ts — the lossless, mechanical, judgment-free verbatim tier
|
|
3
|
+
* (Wave 2). Written on EVERY session end, BEFORE any capture/summary logic, so
|
|
4
|
+
* a session can never be "lost" just because nothing was captured.
|
|
5
|
+
*
|
|
6
|
+
* Hard invariants (privacy + safety):
|
|
7
|
+
* - LOCAL-ONLY. This module MUST NOT import journal-write or syncToSupabase.
|
|
8
|
+
* The raw tier never leaves the machine. (Verified by a structural test.)
|
|
9
|
+
* - NEVER throws to the caller. Any failure returns { path:"", bytes:0 } so a
|
|
10
|
+
* crash here can never break the Stop turn.
|
|
11
|
+
* - sessionId is UNTRUSTED (arrives from hook stdin) → MUST pass through
|
|
12
|
+
* sanitizeSlug before any path.join (MCP-security rule).
|
|
13
|
+
* - Idempotent on the session UUID: a second call for the same session is a
|
|
14
|
+
* no-op (returns bytes:0) and never overwrites the original verbatim bytes.
|
|
15
|
+
*/
|
|
16
|
+
import * as fs from "node:fs";
|
|
17
|
+
import * as path from "node:path";
|
|
18
|
+
import { archiveRawDir, sanitizeSlug } from "./paths.js";
|
|
19
|
+
import { ensureDir, todayISO, writeJsonAtomic } from "./fs-utils.js";
|
|
20
|
+
import { writeMemoryProtocol } from "./memory-protocol.js";
|
|
21
|
+
function buildFrontmatter(meta) {
|
|
22
|
+
const lines = [
|
|
23
|
+
"---",
|
|
24
|
+
`project: ${meta.project}`,
|
|
25
|
+
`sessionId: ${meta.sessionId}`,
|
|
26
|
+
`savedAt: ${meta.savedAt}`,
|
|
27
|
+
`source: ${meta.source}`,
|
|
28
|
+
];
|
|
29
|
+
if (meta.transcriptPath) {
|
|
30
|
+
// JSON-encode to neutralize any newline/colon in the untrusted path.
|
|
31
|
+
lines.push(`transcriptPath: ${JSON.stringify(meta.transcriptPath)}`);
|
|
32
|
+
}
|
|
33
|
+
lines.push("---", "");
|
|
34
|
+
return lines.join("\n");
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Append a single line to journal/archive/index.md. Best-effort; swallows errors.
|
|
38
|
+
*/
|
|
39
|
+
function appendIndexLine(slug, line) {
|
|
40
|
+
try {
|
|
41
|
+
// archiveRawDir = .../journal/archive/raw ; index.md lives one level up.
|
|
42
|
+
const indexPath = path.join(path.dirname(archiveRawDir(slug)), "index.md");
|
|
43
|
+
ensureDir(path.dirname(indexPath));
|
|
44
|
+
fs.appendFileSync(indexPath, line + "\n", "utf-8");
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
// index is a convenience; failure must not abort the archive write.
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Write a verbatim, lossless dump of a session under journal/archive/raw/.
|
|
52
|
+
* Mechanical and judgment-free: no min-length gate, no summarization, no sync.
|
|
53
|
+
*/
|
|
54
|
+
export function archiveSession(input) {
|
|
55
|
+
try {
|
|
56
|
+
if (typeof input.rawTranscript !== "string") {
|
|
57
|
+
// Defensive: a non-string body would throw on .length / write below.
|
|
58
|
+
return { path: "", bytes: 0 };
|
|
59
|
+
}
|
|
60
|
+
const slug = sanitizeSlug(input.project); // also hardens the project name
|
|
61
|
+
const sid = sanitizeSlug(input.sessionId); // UNTRUSTED → sanitize first
|
|
62
|
+
const dir = archiveRawDir(slug);
|
|
63
|
+
ensureDir(dir);
|
|
64
|
+
const dest = path.join(dir, `${todayISO()}--${sid}.md`);
|
|
65
|
+
// Idempotent on the session UUID: never overwrite an existing dump.
|
|
66
|
+
if (fs.existsSync(dest)) {
|
|
67
|
+
return { path: dest, bytes: 0 };
|
|
68
|
+
}
|
|
69
|
+
const savedAt = new Date().toISOString();
|
|
70
|
+
const frontmatter = buildFrontmatter({
|
|
71
|
+
project: slug,
|
|
72
|
+
sessionId: sid,
|
|
73
|
+
savedAt,
|
|
74
|
+
source: "hook-archive",
|
|
75
|
+
transcriptPath: input.transcriptPath,
|
|
76
|
+
});
|
|
77
|
+
// Atomic write: tmp + rename so a partial dump never appears as complete.
|
|
78
|
+
const tmp = dest + ".tmp." + process.pid;
|
|
79
|
+
fs.writeFileSync(tmp, frontmatter + input.rawTranscript, "utf-8");
|
|
80
|
+
fs.renameSync(tmp, dest);
|
|
81
|
+
// One append-only index line.
|
|
82
|
+
const summary = (input.summary ?? "").replace(/\s+/g, " ").trim().slice(0, 200);
|
|
83
|
+
appendIndexLine(slug, `${todayISO()} ${sid} ${summary}`.trimEnd());
|
|
84
|
+
// Seed the consume marker if absent (the dreaming loop advances it).
|
|
85
|
+
const consumed = path.join(dir, ".consumed.json");
|
|
86
|
+
if (!fs.existsSync(consumed)) {
|
|
87
|
+
writeJsonAtomic(consumed, { lastConsumedOffset: 0, lastConsumedAt: null });
|
|
88
|
+
}
|
|
89
|
+
// Write the self-describing protocol doc once.
|
|
90
|
+
writeMemoryProtocol(slug);
|
|
91
|
+
return { path: dest, bytes: input.rawTranscript.length };
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
// NEVER throw into the Stop turn.
|
|
95
|
+
return { path: "", bytes: 0 };
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=archive-write.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"archive-write.js","sourceRoot":"","sources":["../../src/storage/archive-write.ts"],"names":[],"mappings":"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"}
|
|
@@ -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"}
|