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,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* capture-router.ts — two-lane pivot at the top of the capture path.
|
|
3
|
+
*
|
|
4
|
+
* LANE 1 (explicit-save): writes ONLY the local raw archive (archive-write).
|
|
5
|
+
* Structurally impossible for Lane 1 to reach journalWrite or syncToSupabase:
|
|
6
|
+
* - This module imports archiveSession from archive-write.ts ONLY.
|
|
7
|
+
* - archive-write.ts is LOCAL-ONLY (verified by its own structural test).
|
|
8
|
+
* - Neither this file nor archive-write.ts imports journal-write or sync.ts.
|
|
9
|
+
*
|
|
10
|
+
* LANE 2 (correction-signal): returns the text for the caller to route through
|
|
11
|
+
* the corrections pipeline (writeCorrection / check.ts). This module does NOT
|
|
12
|
+
* call writeCorrection directly — it just classifies and hands off, keeping the
|
|
13
|
+
* correction path unmodified.
|
|
14
|
+
*
|
|
15
|
+
* Both lanes share the same pre-filter: dropHardNoise runs FIRST on the raw text.
|
|
16
|
+
* A text that fails a hard gate is dropped before lane assignment.
|
|
17
|
+
*
|
|
18
|
+
* Cross-process dedup: a lightweight on-disk arbiter (.capture-intent-seen) is
|
|
19
|
+
* written after a lane fires. hook-save and hook-correction share this file so
|
|
20
|
+
* the same message cannot double-save across hooks.
|
|
21
|
+
*
|
|
22
|
+
* LOCAL-ONLY: MUST NOT import journal-write, palace-write, or syncToSupabase.
|
|
23
|
+
*/
|
|
24
|
+
import * as crypto from "node:crypto";
|
|
25
|
+
import * as fs from "node:fs";
|
|
26
|
+
import * as path from "node:path";
|
|
27
|
+
import { archiveSession } from "./archive-write.js";
|
|
28
|
+
import { dropHardNoise } from "./corrections.js";
|
|
29
|
+
import { saveTriggerKind } from "./durable-intent.js";
|
|
30
|
+
import { withLock } from "./filelock.js";
|
|
31
|
+
import { getRoot } from "../types.js";
|
|
32
|
+
// ---------------------------------------------------------------------------
|
|
33
|
+
// Cross-process dedup arbiter
|
|
34
|
+
// ---------------------------------------------------------------------------
|
|
35
|
+
/** Computed at call-time so setRoot() in tests takes effect. */
|
|
36
|
+
function dedupFilePath() {
|
|
37
|
+
return path.join(getRoot(), ".capture-intent-seen");
|
|
38
|
+
}
|
|
39
|
+
const DEDUP_MAX_ENTRIES = 50;
|
|
40
|
+
function quickHash(text) {
|
|
41
|
+
return crypto.createHash("sha256").update(text, "utf-8").digest("hex").slice(0, 16);
|
|
42
|
+
}
|
|
43
|
+
function readDedupEntries() {
|
|
44
|
+
try {
|
|
45
|
+
const file = dedupFilePath();
|
|
46
|
+
if (!fs.existsSync(file))
|
|
47
|
+
return [];
|
|
48
|
+
const parsed = JSON.parse(fs.readFileSync(file, "utf-8"));
|
|
49
|
+
if (Array.isArray(parsed))
|
|
50
|
+
return parsed;
|
|
51
|
+
return [];
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
return [];
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
function isDuplicate(hash, entries) {
|
|
58
|
+
return entries.some((e) => e.hash === hash);
|
|
59
|
+
}
|
|
60
|
+
function writeDedupEntry(entry) {
|
|
61
|
+
try {
|
|
62
|
+
const file = dedupFilePath();
|
|
63
|
+
const dir = path.dirname(file);
|
|
64
|
+
if (!fs.existsSync(dir))
|
|
65
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
66
|
+
withLock("capture-dedup", () => {
|
|
67
|
+
let entries = readDedupEntries();
|
|
68
|
+
entries.push(entry);
|
|
69
|
+
if (entries.length > DEDUP_MAX_ENTRIES)
|
|
70
|
+
entries = entries.slice(-DEDUP_MAX_ENTRIES);
|
|
71
|
+
fs.writeFileSync(file, JSON.stringify(entries), "utf-8");
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
// Best-effort — dedup failure must never block the capture path.
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
// ---------------------------------------------------------------------------
|
|
79
|
+
// routeCapture — the two-lane pivot
|
|
80
|
+
// ---------------------------------------------------------------------------
|
|
81
|
+
/**
|
|
82
|
+
* Route a user message through the two-lane capture path.
|
|
83
|
+
*
|
|
84
|
+
* Order of operations:
|
|
85
|
+
* 1. dropHardNoise(text) — if false, return 'dropped-hard-noise'
|
|
86
|
+
* 2. saveTriggerKind(text) — classify intent
|
|
87
|
+
* 3. Check cross-process dedup arbiter — if duplicate, return 'dropped-duplicate'
|
|
88
|
+
* 4. LANE 1 (explicit-save) → archiveSession (local only, never syncs)
|
|
89
|
+
* 5. LANE 2 (correction-signal) → return correctionText for caller to capture
|
|
90
|
+
* 6. none → 'dropped-no-intent'
|
|
91
|
+
*/
|
|
92
|
+
export function routeCapture(input) {
|
|
93
|
+
const text = (typeof input.text === "string" ? input.text : "").trim();
|
|
94
|
+
// Step 1: hard noise gate (both lanes share this pre-filter)
|
|
95
|
+
if (!dropHardNoise(text)) {
|
|
96
|
+
return { kind: "dropped-hard-noise" };
|
|
97
|
+
}
|
|
98
|
+
// Step 2: classify intent
|
|
99
|
+
const intent = saveTriggerKind(text);
|
|
100
|
+
if (intent === "none") {
|
|
101
|
+
return { kind: "dropped-no-intent" };
|
|
102
|
+
}
|
|
103
|
+
// Step 3: cross-process dedup
|
|
104
|
+
const hash = quickHash(text);
|
|
105
|
+
const seen = readDedupEntries();
|
|
106
|
+
if (isDuplicate(hash, seen)) {
|
|
107
|
+
return { kind: "dropped-duplicate" };
|
|
108
|
+
}
|
|
109
|
+
// Record this entry BEFORE doing any I/O so a concurrent hook sees it.
|
|
110
|
+
writeDedupEntry({ hash, kind: intent, ts: new Date().toISOString() });
|
|
111
|
+
// Step 4 — LANE 1: explicit-save → local archive ONLY
|
|
112
|
+
if (intent === "explicit-save") {
|
|
113
|
+
const archiveInput = {
|
|
114
|
+
project: input.project,
|
|
115
|
+
sessionId: input.sessionId,
|
|
116
|
+
rawTranscript: input.rawTranscript ?? text,
|
|
117
|
+
summary: input.summary,
|
|
118
|
+
transcriptPath: input.transcriptPath,
|
|
119
|
+
};
|
|
120
|
+
const result = archiveSession(archiveInput);
|
|
121
|
+
return {
|
|
122
|
+
kind: "lane1-archived",
|
|
123
|
+
archivePath: result.path,
|
|
124
|
+
archiveBytes: result.bytes,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
// Step 5 — LANE 2: correction-signal → return text for caller's corrections pipeline
|
|
128
|
+
return {
|
|
129
|
+
kind: "lane2-correction",
|
|
130
|
+
correctionText: text,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
//# sourceMappingURL=capture-router.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capture-router.js","sourceRoot":"","sources":["../../src/storage/capture-router.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export type Tier = "personal" | "project";
|
|
2
|
+
/**
|
|
3
|
+
* The only personal value reachable via the sync `store` union
|
|
4
|
+
* ("journal" | "palace" | "awareness" | "digest"). Awareness carries the
|
|
5
|
+
* corrections-derived behavioral layer (Blind Spots), so it is personal.
|
|
6
|
+
*
|
|
7
|
+
* NB (single-source guarantee): every member here MUST classifyStore() =>
|
|
8
|
+
* "personal" so the gate in supabase/sync.ts catches it. A unit test asserts
|
|
9
|
+
* exactly that.
|
|
10
|
+
*/
|
|
11
|
+
export declare const PERSONAL_STORES: ReadonlySet<string>;
|
|
12
|
+
/**
|
|
13
|
+
* Classify a Supabase sync `store` (+ optional project) onto the privacy tier.
|
|
14
|
+
*
|
|
15
|
+
* - `awareness` store ⇒ personal (the behavioral layer leak we are gating).
|
|
16
|
+
* - any write tagged with the `_global` project ⇒ personal (bootstrap writes
|
|
17
|
+
* palace under the `_global` sentinel).
|
|
18
|
+
* - everything else ⇒ project.
|
|
19
|
+
*
|
|
20
|
+
* Total over any input (unknown/undefined store ⇒ "project") — never throws.
|
|
21
|
+
*/
|
|
22
|
+
export declare function classifyStore(store: string | undefined, opts?: {
|
|
23
|
+
project?: string;
|
|
24
|
+
}): Tier;
|
|
25
|
+
/**
|
|
26
|
+
* Classify an absolute path onto the privacy tier. Substring match on the
|
|
27
|
+
* personal markers; default project. Never throws.
|
|
28
|
+
*/
|
|
29
|
+
export declare function classifyPath(absPath: string): Tier;
|
|
30
|
+
/** A project slug is personal iff it is the `_global` cross-project sentinel. */
|
|
31
|
+
export declare function isPersonalProject(slug: string): boolean;
|
|
32
|
+
//# sourceMappingURL=classification.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"classification.d.ts","sourceRoot":"","sources":["../../src/storage/classification.ts"],"names":[],"mappings":"AAgBA,MAAM,MAAM,IAAI,GAAG,UAAU,GAAG,SAAS,CAAC;AAE1C;;;;;;;;GAQG;AACH,eAAO,MAAM,eAAe,EAAE,WAAW,CAAC,MAAM,CAA0B,CAAC;AAE3E;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAC3B,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,IAAI,CAAC,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GAC1B,IAAI,CAIN;AAmBD;;;GAGG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAKlD;AAED,iFAAiF;AACjF,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEvD"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
// packages/core/src/storage/classification.ts
|
|
2
|
+
//
|
|
3
|
+
// Wave 1 — Privacy classification: the SINGLE source of truth for the
|
|
4
|
+
// personal-vs-project split. Pure, no IO.
|
|
5
|
+
//
|
|
6
|
+
// Two disjoint surfaces, by design:
|
|
7
|
+
// - classifyStore() covers the SYNC surface. Only `awareness` (and `_global`
|
|
8
|
+
// palace writes) are reachable as personal through the Supabase `store`
|
|
9
|
+
// union — corrections are never synced.
|
|
10
|
+
// - classifyPath() covers the GIT/.gitignore surface — corrections,
|
|
11
|
+
// behavior-policies.json, the future `personal/` tier — none of which flow
|
|
12
|
+
// through syncToSupabase today.
|
|
13
|
+
//
|
|
14
|
+
// Keeping these explicit means the moment someone adds a new personal artifact
|
|
15
|
+
// they register it HERE, and the sync gate + (future) .gitignore both honor it.
|
|
16
|
+
/**
|
|
17
|
+
* The only personal value reachable via the sync `store` union
|
|
18
|
+
* ("journal" | "palace" | "awareness" | "digest"). Awareness carries the
|
|
19
|
+
* corrections-derived behavioral layer (Blind Spots), so it is personal.
|
|
20
|
+
*
|
|
21
|
+
* NB (single-source guarantee): every member here MUST classifyStore() =>
|
|
22
|
+
* "personal" so the gate in supabase/sync.ts catches it. A unit test asserts
|
|
23
|
+
* exactly that.
|
|
24
|
+
*/
|
|
25
|
+
export const PERSONAL_STORES = new Set(["awareness"]);
|
|
26
|
+
/**
|
|
27
|
+
* Classify a Supabase sync `store` (+ optional project) onto the privacy tier.
|
|
28
|
+
*
|
|
29
|
+
* - `awareness` store ⇒ personal (the behavioral layer leak we are gating).
|
|
30
|
+
* - any write tagged with the `_global` project ⇒ personal (bootstrap writes
|
|
31
|
+
* palace under the `_global` sentinel).
|
|
32
|
+
* - everything else ⇒ project.
|
|
33
|
+
*
|
|
34
|
+
* Total over any input (unknown/undefined store ⇒ "project") — never throws.
|
|
35
|
+
*/
|
|
36
|
+
export function classifyStore(store, opts) {
|
|
37
|
+
if (store !== undefined && PERSONAL_STORES.has(store))
|
|
38
|
+
return "personal";
|
|
39
|
+
if (opts?.project === "_global")
|
|
40
|
+
return "personal";
|
|
41
|
+
return "project";
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Markers that mean a filesystem path holds personal data. Used by the
|
|
45
|
+
* git/.gitignore surface (Wave 5 onward). Disjoint from classifyStore by design
|
|
46
|
+
* — these artifacts do not flow through syncToSupabase.
|
|
47
|
+
*/
|
|
48
|
+
const PERSONAL_PATH_MARKERS = [
|
|
49
|
+
"/corrections/",
|
|
50
|
+
"/awareness",
|
|
51
|
+
"behavior-policies.json",
|
|
52
|
+
"/projects/_global/",
|
|
53
|
+
// No trailing slash (mirrors "/awareness") so it matches BOTH the bare
|
|
54
|
+
// `projects/<slug>/personal` directory and every file under it. A path that
|
|
55
|
+
// legitimately ends in "personal" inside a project is exactly the personal
|
|
56
|
+
// tier we mean to gate.
|
|
57
|
+
"/personal",
|
|
58
|
+
];
|
|
59
|
+
/**
|
|
60
|
+
* Classify an absolute path onto the privacy tier. Substring match on the
|
|
61
|
+
* personal markers; default project. Never throws.
|
|
62
|
+
*/
|
|
63
|
+
export function classifyPath(absPath) {
|
|
64
|
+
for (const marker of PERSONAL_PATH_MARKERS) {
|
|
65
|
+
if (absPath.includes(marker))
|
|
66
|
+
return "personal";
|
|
67
|
+
}
|
|
68
|
+
return "project";
|
|
69
|
+
}
|
|
70
|
+
/** A project slug is personal iff it is the `_global` cross-project sentinel. */
|
|
71
|
+
export function isPersonalProject(slug) {
|
|
72
|
+
return slug === "_global";
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=classification.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"classification.js","sourceRoot":"","sources":["../../src/storage/classification.ts"],"names":[],"mappings":"AAAA,8CAA8C;AAC9C,EAAE;AACF,sEAAsE;AACtE,0CAA0C;AAC1C,EAAE;AACF,oCAAoC;AACpC,+EAA+E;AAC/E,4EAA4E;AAC5E,4CAA4C;AAC5C,sEAAsE;AACtE,+EAA+E;AAC/E,oCAAoC;AACpC,EAAE;AACF,+EAA+E;AAC/E,gFAAgF;AAIhF;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,eAAe,GAAwB,IAAI,GAAG,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC;AAE3E;;;;;;;;;GASG;AACH,MAAM,UAAU,aAAa,CAC3B,KAAyB,EACzB,IAA2B;IAE3B,IAAI,KAAK,KAAK,SAAS,IAAI,eAAe,CAAC,GAAG,CAAC,KAAK,CAAC;QAAE,OAAO,UAAU,CAAC;IACzE,IAAI,IAAI,EAAE,OAAO,KAAK,SAAS;QAAE,OAAO,UAAU,CAAC;IACnD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;GAIG;AACH,MAAM,qBAAqB,GAAsB;IAC/C,eAAe;IACf,YAAY;IACZ,wBAAwB;IACxB,oBAAoB;IACpB,uEAAuE;IACvE,4EAA4E;IAC5E,2EAA2E;IAC3E,wBAAwB;IACxB,WAAW;CACZ,CAAC;AAEF;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,OAAe;IAC1C,KAAK,MAAM,MAAM,IAAI,qBAAqB,EAAE,CAAC;QAC3C,IAAI,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC;YAAE,OAAO,UAAU,CAAC;IAClD,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,iFAAiF;AACjF,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,OAAO,IAAI,KAAK,SAAS,CAAC;AAC5B,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* consolidation-queue.ts — the async consume seam (Wave 2, Decision #3).
|
|
3
|
+
*
|
|
4
|
+
* The Stop hook archives verbatim (lossless) then ENQUEUES a job here. Quality
|
|
5
|
+
* compression (palace consolidation, distillation) happens later, out of the
|
|
6
|
+
* Stop turn, by draining this queue. Retrieval stays a function; consolidation
|
|
7
|
+
* stays the async dreaming loop.
|
|
8
|
+
*
|
|
9
|
+
* Storage: JSONL, one job per line, under ~/.agent-recall/.consolidation-queue/.
|
|
10
|
+
* Append-only; drain marks lines done by rewriting the file with done:true.
|
|
11
|
+
*/
|
|
12
|
+
export interface ConsolidationJob {
|
|
13
|
+
project: string;
|
|
14
|
+
sessionId: string;
|
|
15
|
+
reason?: string;
|
|
16
|
+
/** ISO timestamp the job was enqueued. */
|
|
17
|
+
at?: string;
|
|
18
|
+
/** Marked true once drained. */
|
|
19
|
+
done?: boolean;
|
|
20
|
+
}
|
|
21
|
+
export interface DrainReport {
|
|
22
|
+
/** Jobs whose handler ran without throwing. */
|
|
23
|
+
processed: number;
|
|
24
|
+
/** Jobs whose handler threw (counted, never fatal). */
|
|
25
|
+
failed: number;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Append a consolidation job to today's queue file. Best-effort: never throws.
|
|
29
|
+
*/
|
|
30
|
+
export declare function enqueueConsolidation(job: ConsolidationJob): void;
|
|
31
|
+
/**
|
|
32
|
+
* Drain all pending (not-done) jobs across every queue file. For each pending
|
|
33
|
+
* job, invoke `handler(job)`; a throwing handler counts as failed but does NOT
|
|
34
|
+
* block the rest. Successfully-handled jobs are marked done:true and rewritten.
|
|
35
|
+
*
|
|
36
|
+
* Best-effort: never throws to the caller.
|
|
37
|
+
*/
|
|
38
|
+
export declare function drainConsolidationQueue(handler: (job: ConsolidationJob) => void): DrainReport;
|
|
39
|
+
//# sourceMappingURL=consolidation-queue.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consolidation-queue.d.ts","sourceRoot":"","sources":["../../src/storage/consolidation-queue.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAOH,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,0CAA0C;IAC1C,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,gCAAgC;IAChC,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,WAAW;IAC1B,+CAA+C;IAC/C,SAAS,EAAE,MAAM,CAAC;IAClB,uDAAuD;IACvD,MAAM,EAAE,MAAM,CAAC;CAChB;AAUD;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,gBAAgB,GAAG,IAAI,CAehE;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,CAAC,GAAG,EAAE,gBAAgB,KAAK,IAAI,GACvC,WAAW,CAsEb"}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* consolidation-queue.ts — the async consume seam (Wave 2, Decision #3).
|
|
3
|
+
*
|
|
4
|
+
* The Stop hook archives verbatim (lossless) then ENQUEUES a job here. Quality
|
|
5
|
+
* compression (palace consolidation, distillation) happens later, out of the
|
|
6
|
+
* Stop turn, by draining this queue. Retrieval stays a function; consolidation
|
|
7
|
+
* stays the async dreaming loop.
|
|
8
|
+
*
|
|
9
|
+
* Storage: JSONL, one job per line, under ~/.agent-recall/.consolidation-queue/.
|
|
10
|
+
* Append-only; drain marks lines done by rewriting the file with done:true.
|
|
11
|
+
*/
|
|
12
|
+
import * as fs from "node:fs";
|
|
13
|
+
import * as path from "node:path";
|
|
14
|
+
import { getRoot } from "../types.js";
|
|
15
|
+
import { ensureDir, todayISO } from "./fs-utils.js";
|
|
16
|
+
function queueDir() {
|
|
17
|
+
return path.join(getRoot(), ".consolidation-queue");
|
|
18
|
+
}
|
|
19
|
+
function queueFileForToday() {
|
|
20
|
+
return path.join(queueDir(), `${todayISO()}.jsonl`);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Append a consolidation job to today's queue file. Best-effort: never throws.
|
|
24
|
+
*/
|
|
25
|
+
export function enqueueConsolidation(job) {
|
|
26
|
+
try {
|
|
27
|
+
const dir = queueDir();
|
|
28
|
+
ensureDir(dir);
|
|
29
|
+
const record = {
|
|
30
|
+
project: job.project,
|
|
31
|
+
sessionId: job.sessionId,
|
|
32
|
+
reason: job.reason,
|
|
33
|
+
at: job.at ?? new Date().toISOString(),
|
|
34
|
+
done: false,
|
|
35
|
+
};
|
|
36
|
+
fs.appendFileSync(queueFileForToday(), JSON.stringify(record) + "\n", "utf-8");
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
// Enqueue is fire-and-forget — never break the caller (the Stop hook).
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Drain all pending (not-done) jobs across every queue file. For each pending
|
|
44
|
+
* job, invoke `handler(job)`; a throwing handler counts as failed but does NOT
|
|
45
|
+
* block the rest. Successfully-handled jobs are marked done:true and rewritten.
|
|
46
|
+
*
|
|
47
|
+
* Best-effort: never throws to the caller.
|
|
48
|
+
*/
|
|
49
|
+
export function drainConsolidationQueue(handler) {
|
|
50
|
+
const report = { processed: 0, failed: 0 };
|
|
51
|
+
let dir;
|
|
52
|
+
try {
|
|
53
|
+
dir = queueDir();
|
|
54
|
+
if (!fs.existsSync(dir))
|
|
55
|
+
return report;
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
return report;
|
|
59
|
+
}
|
|
60
|
+
let files;
|
|
61
|
+
try {
|
|
62
|
+
files = fs.readdirSync(dir).filter((f) => f.endsWith(".jsonl"));
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
return report;
|
|
66
|
+
}
|
|
67
|
+
for (const file of files) {
|
|
68
|
+
const full = path.join(dir, file);
|
|
69
|
+
let lines;
|
|
70
|
+
try {
|
|
71
|
+
lines = fs.readFileSync(full, "utf-8").split("\n");
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
continue; // unreadable file → skip, don't block the rest
|
|
75
|
+
}
|
|
76
|
+
const rewritten = [];
|
|
77
|
+
let mutated = false;
|
|
78
|
+
for (const line of lines) {
|
|
79
|
+
const trimmed = line.trim();
|
|
80
|
+
if (!trimmed)
|
|
81
|
+
continue;
|
|
82
|
+
let job;
|
|
83
|
+
try {
|
|
84
|
+
job = JSON.parse(trimmed);
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
rewritten.push(line); // malformed line — preserve verbatim, don't drop
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
if (job.done) {
|
|
91
|
+
rewritten.push(trimmed);
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
try {
|
|
95
|
+
handler(job);
|
|
96
|
+
report.processed++;
|
|
97
|
+
rewritten.push(JSON.stringify({ ...job, done: true }));
|
|
98
|
+
mutated = true;
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
101
|
+
// One bad job never blocks the rest — leave it pending for a retry.
|
|
102
|
+
report.failed++;
|
|
103
|
+
rewritten.push(trimmed);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
if (mutated) {
|
|
107
|
+
try {
|
|
108
|
+
const tmp = full + ".tmp." + process.pid;
|
|
109
|
+
fs.writeFileSync(tmp, rewritten.join("\n") + "\n", "utf-8");
|
|
110
|
+
fs.renameSync(tmp, full); // atomic on POSIX
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
// If we can't persist the done-marks, the worst case is a re-run of
|
|
114
|
+
// already-processed jobs next drain — acceptable, never fatal.
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return report;
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=consolidation-queue.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consolidation-queue.js","sourceRoot":"","sources":["../../src/storage/consolidation-queue.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* content-guard.ts — pre-sync content scrubbing for opt-in cloud users.
|
|
3
|
+
*
|
|
4
|
+
* Applied BEFORE any journalWrite → syncToSupabase call so that secrets and
|
|
5
|
+
* prompt-injection attempts do not reach Supabase or the embedding API.
|
|
6
|
+
*
|
|
7
|
+
* Two-layer scrub:
|
|
8
|
+
* 1. scrubPromptInjection — strip XML system-marker tags, bidi overrides,
|
|
9
|
+
* null bytes, and explicit injection phrases. Extracted from bootstrap.ts
|
|
10
|
+
* and re-exported here so journal-write/palace-write can import from a
|
|
11
|
+
* single source of truth.
|
|
12
|
+
* 2. scrubSecretContent — redact known secret token prefixes (AKIA…, ghp_…,
|
|
13
|
+
* gho_…, ghs_…, sk-…, xoxb-…, PEM markers). Operates on content, not
|
|
14
|
+
* filenames (bootstrap.ts isSecretFile() handles filename-level rejection).
|
|
15
|
+
*
|
|
16
|
+
* scrubForCloud(content) = scrubSecretContent(scrubPromptInjection(content))
|
|
17
|
+
*
|
|
18
|
+
* Design guarantees:
|
|
19
|
+
* - Never throws — any failure returns the original content unchanged.
|
|
20
|
+
* - Pure function, no I/O, no Supabase imports.
|
|
21
|
+
* - Returns a SecretScanResult so callers can log/block if desired.
|
|
22
|
+
*
|
|
23
|
+
* Usage: call scrubForCloud(content) in journal-write.ts and palace-write.ts
|
|
24
|
+
* before passing content to syncToSupabase.
|
|
25
|
+
*/
|
|
26
|
+
/**
|
|
27
|
+
* Strip prompt-injection patterns from content before it leaves the machine.
|
|
28
|
+
* Same logic as bootstrap.ts:scrubPromptInjection but exported here for
|
|
29
|
+
* journal-write and palace-write to use at sync time.
|
|
30
|
+
*/
|
|
31
|
+
export declare function scrubPromptInjection(s: string): string;
|
|
32
|
+
export interface SecretScanResult {
|
|
33
|
+
/** Content after redaction (same as input if nothing was found). */
|
|
34
|
+
content: string;
|
|
35
|
+
/** Number of secret patterns found and redacted. */
|
|
36
|
+
redactedCount: number;
|
|
37
|
+
/** Which labels were found (for logging). */
|
|
38
|
+
labels: string[];
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Scan content for known secret token patterns and redact them in-place.
|
|
42
|
+
* Returns the redacted content and a count of how many matches were replaced.
|
|
43
|
+
*/
|
|
44
|
+
export declare function scrubSecretContent(content: string): SecretScanResult;
|
|
45
|
+
/**
|
|
46
|
+
* scrubForCloud(content) applies both layers in order:
|
|
47
|
+
* 1. scrubPromptInjection — removes injection/override attempts
|
|
48
|
+
* 2. scrubSecretContent — redacts known secret token patterns
|
|
49
|
+
*
|
|
50
|
+
* Returns the sanitised string. Never throws.
|
|
51
|
+
*/
|
|
52
|
+
export declare function scrubForCloud(content: string): string;
|
|
53
|
+
/**
|
|
54
|
+
* Raised by scrubForExport when a secret survives scrubbing. Distinct error type
|
|
55
|
+
* so callers can abort an export and name the offending record.
|
|
56
|
+
*/
|
|
57
|
+
export declare class SecretScanError extends Error {
|
|
58
|
+
readonly label: string;
|
|
59
|
+
constructor(label: string);
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* scrubForExport(content) — the fail-CLOSED sibling of scrubForCloud.
|
|
63
|
+
*
|
|
64
|
+
* scrubForCloud is fail-OPEN: on any internal error it returns the ORIGINAL
|
|
65
|
+
* content unchanged, which is the right call on the sync hot-path (never block a
|
|
66
|
+
* write) but the WRONG call for a deliberate export that will be handed to an
|
|
67
|
+
* external store. scrubForExport adds a post-condition: it re-scans the scrubbed
|
|
68
|
+
* output and THROWS SecretScanError if any known secret pattern still matches —
|
|
69
|
+
* so a redaction that silently failed open aborts the export instead of leaking.
|
|
70
|
+
*
|
|
71
|
+
* Use this for every string that leaves AgentRecall via an export/adapter path.
|
|
72
|
+
*/
|
|
73
|
+
export declare function scrubForExport(content: string): string;
|
|
74
|
+
//# sourceMappingURL=content-guard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content-guard.d.ts","sourceRoot":"","sources":["../../src/storage/content-guard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAMH;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAiBtD;AA2CD,MAAM,WAAW,gBAAgB;IAC/B,oEAAoE;IACpE,OAAO,EAAE,MAAM,CAAC;IAChB,oDAAoD;IACpD,aAAa,EAAE,MAAM,CAAC;IACtB,6CAA6C;IAC7C,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,gBAAgB,CAuBpE;AAMD;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAQrD;AAMD;;;GAGG;AACH,qBAAa,eAAgB,SAAQ,KAAK;aACZ,KAAK,EAAE,MAAM;gBAAb,KAAK,EAAE,MAAM;CAI1C;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAmBtD"}
|