@etiquekit/etq 1.0.12 → 1.0.14
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/AGENTS.md +19 -26
- package/LICENSE +2 -3
- package/NOTICE +6 -4
- package/QuickStart.md +35 -47
- package/README.md +54 -54
- package/bin/etiquette +1 -5
- package/bin/etiquette-core +1 -5
- package/docs/ARCHITECTURE.md +5 -5
- package/docs/CODEX_CLIENT_COMPATIBILITY.md +1 -1
- package/docs/CONCEPTS.md +7 -23
- package/docs/CONCEPT_STATUS.md +66 -0
- package/docs/CORE_PROFILE.md +3 -5
- package/docs/LANE_PROVISIONING.md +7 -2
- package/docs/README.md +4 -4
- package/docs/RELEASE_SURFACE_AUDIT.md +8 -7
- package/docs/SEAT_DISCIPLINE.md +55 -91
- package/docs/SEAT_PROVISIONING.md +19 -22
- package/docs/TEAM_HANDOFF.md +21 -21
- package/docs/WORKTREE_QOL.md +7 -6
- package/docs/contracts/ledger-entry/README.md +11 -11
- package/docs/contracts/ledger-entry/ledger-entry.v0.2.md +3 -3
- package/docs/contracts/ledger-entry/ledger-entry.v0.md +8 -8
- package/package.json +9 -9
- package/packages/control/src/authority/lease.ts +261 -0
- package/packages/control/src/authority/node-delegation.ts +257 -0
- package/packages/control/src/authority/rig-conductor.ts +632 -0
- package/packages/control/src/cli/argv.ts +155 -0
- package/packages/control/src/cli/commands/console.ts +200 -0
- package/packages/control/src/cli/commands/dispatch-core.ts +89 -0
- package/packages/control/src/cli/commands/dispatch.ts +279 -0
- package/packages/control/src/cli/commands/harness.ts +89 -0
- package/packages/control/src/cli/commands/hook.ts +50 -0
- package/packages/control/src/cli/commands/ledger.ts +91 -0
- package/packages/control/src/cli/commands/local-workflow.ts +4690 -0
- package/packages/control/src/cli/commands/memory.ts +445 -0
- package/packages/control/src/cli/commands/release.ts +108 -0
- package/packages/control/src/cli/commands/rubric.ts +103 -0
- package/packages/control/src/cli/commands/seat.ts +179 -0
- package/packages/control/src/cli/commands/session.ts +127 -0
- package/packages/control/src/cli/commands/supervision.ts +246 -0
- package/packages/control/src/cli/commands/sync.ts +119 -0
- package/packages/control/src/cli/commands/workflow.ts +86 -0
- package/packages/control/src/cli/commands/workspace.ts +50 -0
- package/packages/control/src/cli/core-usage.ts +34 -0
- package/packages/control/src/cli/prompt.ts +67 -0
- package/packages/control/src/cli/supervision-deps.ts +44 -0
- package/packages/control/src/cli/usage.ts +241 -0
- package/packages/control/src/cli.ts +207 -0
- package/packages/control/src/core-cli.ts +50 -0
- package/packages/control/src/dispatch/decision.ts +202 -0
- package/packages/control/src/dispatch/projection.ts +293 -0
- package/packages/control/src/dispatch/record.ts +153 -0
- package/packages/control/src/engagement/project.ts +170 -0
- package/packages/control/src/fs.ts +19 -0
- package/packages/control/src/harness/pruning.ts +406 -0
- package/packages/control/src/hooks/dispatcher.ts +117 -0
- package/packages/control/src/hooks/outbox.ts +86 -0
- package/packages/control/src/hooks/sanitize.ts +6 -0
- package/packages/control/src/hooks/types.ts +34 -0
- package/packages/control/src/index.ts +384 -0
- package/packages/control/src/ledger/entry.ts +303 -0
- package/packages/control/src/ledger/indexer.ts +542 -0
- package/packages/control/src/memory/context.ts +149 -0
- package/packages/control/src/memory/drain-import.ts +207 -0
- package/packages/control/src/memory/indexer.ts +284 -0
- package/packages/control/src/memory/query.ts +75 -0
- package/packages/control/src/memory/sanitize.ts +50 -0
- package/packages/control/src/memory/sharded-drain-import.ts +212 -0
- package/packages/control/src/memory/status.ts +211 -0
- package/packages/control/src/memory/store-lifecycle.ts +509 -0
- package/packages/control/src/memory/store.ts +284 -0
- package/packages/control/src/memory/types.ts +146 -0
- package/packages/control/src/parity/surfaces.ts +748 -0
- package/packages/control/src/project.ts +141 -0
- package/packages/control/src/projection/local-ledger-view.ts +373 -0
- package/packages/control/src/projection/return-enforcement.ts +48 -0
- package/packages/control/src/projection/timeline-preview.ts +539 -0
- package/packages/control/src/projection/timeline.ts +708 -0
- package/packages/control/src/release/readiness.ts +842 -0
- package/packages/control/src/rubric/loader.ts +326 -0
- package/packages/control/src/rubric/promotion.ts +54 -0
- package/packages/control/src/rubric/runner.ts +159 -0
- package/packages/control/src/rubric/types.ts +158 -0
- package/packages/control/src/seat/owner-card.ts +388 -0
- package/packages/control/src/seat/readiness.ts +834 -0
- package/packages/control/src/session/runbook.ts +431 -0
- package/packages/control/src/shared/sanitize.ts +49 -0
- package/packages/control/src/supervision/action-classes.ts +192 -0
- package/packages/control/src/supervision/command-apply.ts +378 -0
- package/packages/control/src/supervision/errors.ts +14 -0
- package/packages/control/src/supervision/event-replay.ts +155 -0
- package/packages/control/src/supervision/events.ts +109 -0
- package/packages/control/src/supervision/index.ts +16 -0
- package/packages/control/src/supervision/manifest.ts +127 -0
- package/packages/control/src/supervision/paths.ts +49 -0
- package/packages/control/src/supervision/projection-adapter.ts +274 -0
- package/packages/control/src/supervision/projection.ts +75 -0
- package/packages/control/src/supervision/rebuild.ts +99 -0
- package/packages/control/src/supervision/session-open.ts +131 -0
- package/packages/control/src/supervision/session-read.ts +99 -0
- package/packages/control/src/supervision/sqlite-impl.ts +71 -0
- package/packages/control/src/supervision/sqlite.ts +121 -0
- package/packages/control/src/supervision/store-rows.ts +371 -0
- package/packages/control/src/supervision/turn-close.ts +154 -0
- package/packages/control/src/supervision/turn-open.ts +284 -0
- package/packages/control/src/sync/event-log-merge-driver.ts +263 -0
- package/packages/control/src/sync/join-plan.ts +375 -0
- package/packages/control/src/sync/outbox.ts +492 -0
- package/packages/control/src/workflow/evaluator.ts +140 -0
- package/packages/control/src/workflow/loader.ts +200 -0
- package/packages/control/src/workflow/types.ts +90 -0
- package/packages/control/src/workspace/authority.ts +499 -0
- package/packages/protocol/src/guards.ts +119 -0
- package/packages/protocol/src/huddle-board.ts +198 -0
- package/packages/protocol/src/huddle.ts +295 -0
- package/packages/protocol/src/incident.ts +251 -0
- package/packages/protocol/src/index.ts +8 -0
- package/packages/protocol/src/interfaces.ts +107 -0
- package/packages/protocol/src/packet-profile.ts +195 -0
- package/packages/protocol/src/state.ts +81 -0
- package/packages/protocol/src/types.ts +434 -0
- package/release/lineage.v0.json +15 -0
- package/scripts/release-candidate-verify.sh +175 -0
- package/scripts/release-checksum.sh +25 -0
- package/scripts/release-pack-canary.sh +97 -0
- package/scripts/release-scan.sh +249 -0
- package/scripts/release-sign.sh +34 -0
- package/templates/etiquette-vanilla-v0/README.md +2 -3
- package/templates/etiquette-vanilla-v0/source/control-seat/README.md +0 -6
- package/templates/etiquette-vanilla-v0/source/control-seat/bin/seat-doctor +0 -5
- package/templates/etiquette-vanilla-v0/validate-vanilla.sh +0 -5
- package/templates/seat-packs-v0/README.md +3 -2
- package/templates/seat-packs-v0/source/claude-code-seat/README.md +3 -29
- package/templates/seat-packs-v0/source/codex-seat/README.md +3 -17
- package/templates/seat-packs-v0/source/gemini-seat/README.md +3 -23
- package/templates/seat-packs-v0/source/ollama-seat/README.md +3 -3
- package/templates/seat-packs-v0/source/openrouter-seat/README.md +3 -3
- package/docs/AGENT_SPAWNING.md +0 -78
- package/docs/INTEGRATION_UI.md +0 -215
- package/docs/OPERATOR_PLAYBOOK.md +0 -77
- package/docs/TAG_ROUTE.md +0 -95
- package/lib/etiquette-core.js +0 -315
- package/lib/etiquette.js +0 -1160
- package/templates/DISPATCH_PREMISES.md +0 -39
- package/templates/etiquette-vanilla-v0/source/control-seat/bin/access-assurance-check +0 -55
- package/templates/etiquette-vanilla-v0/source/control-seat/docs/work/access/ACCESS-ASSURANCE.md +0 -39
- package/templates/etiquette-vanilla-v0/source/control-seat/docs/work/access/workspace-secure-profile.v0.json +0 -53
- package/templates/hosted-receiver/README.md +0 -41
- package/templates/hosted-receiver/w1-github-webhook-receiver.mjs +0 -129
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
import { Database } from 'bun:sqlite';
|
|
2
|
+
import { mkdirSync } from 'node:fs';
|
|
3
|
+
import { dirname } from 'node:path';
|
|
4
|
+
import type { CompactMemoryResult, MemoryCandidate, RecallCapsule, RejectedMemoryCandidate } from './types';
|
|
5
|
+
|
|
6
|
+
export interface MemoryStore {
|
|
7
|
+
dbPath: string;
|
|
8
|
+
close: () => void;
|
|
9
|
+
reset: () => void;
|
|
10
|
+
stats: () => MemoryStoreStats;
|
|
11
|
+
insertCandidate: (candidate: MemoryCandidate) => void;
|
|
12
|
+
markCandidate: (candidateId: string, status: 'promoted' | 'rejected', reasons: string[]) => void;
|
|
13
|
+
insertCapsule: (capsule: RecallCapsule, searchText?: string) => void;
|
|
14
|
+
search: (query: string, limit: number) => CompactMemoryResult[];
|
|
15
|
+
show: (capsuleId: string) => RecallCapsule | null;
|
|
16
|
+
stale: (limit: number) => CompactMemoryResult[];
|
|
17
|
+
rejected: (limit: number) => RejectedMemoryCandidate[];
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface MemoryStoreStats {
|
|
21
|
+
candidates: {
|
|
22
|
+
total: number;
|
|
23
|
+
pending: number;
|
|
24
|
+
promoted: number;
|
|
25
|
+
rejected: number;
|
|
26
|
+
};
|
|
27
|
+
recall_capsules: number;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
interface CapsuleRow {
|
|
31
|
+
capsule_id: string;
|
|
32
|
+
title: string;
|
|
33
|
+
category: string;
|
|
34
|
+
confidence: string;
|
|
35
|
+
stale_status: string;
|
|
36
|
+
evidence_count: number;
|
|
37
|
+
capsule_json: string;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
interface CandidateRow {
|
|
41
|
+
candidate_id: string;
|
|
42
|
+
title: string;
|
|
43
|
+
category: string;
|
|
44
|
+
risk_flags_json: string;
|
|
45
|
+
rejection_reasons_json: string;
|
|
46
|
+
candidate_json: string;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function hasColumn(db: Database, table: string, column: string): boolean {
|
|
50
|
+
const rows = db.query<{ name: string }, []>(`PRAGMA table_info(${table})`).all();
|
|
51
|
+
return rows.some((row) => row.name === column);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function addColumnIfMissing(db: Database, table: string, column: string, ddl: string): void {
|
|
55
|
+
if (!hasColumn(db, table, column)) {
|
|
56
|
+
db.exec(`ALTER TABLE ${table} ADD COLUMN ${ddl}`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function ensureFtsSchema(db: Database): void {
|
|
61
|
+
const columns = db.query<{ name: string }, []>('PRAGMA table_info(memory_capsule_fts)').all();
|
|
62
|
+
if (columns.length > 0 && !columns.some((row) => row.name === 'search_text')) {
|
|
63
|
+
db.exec('DROP TABLE memory_capsule_fts;');
|
|
64
|
+
}
|
|
65
|
+
db.exec(`
|
|
66
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS memory_capsule_fts
|
|
67
|
+
USING fts5(capsule_id UNINDEXED, title, summary, category, evidence_refs_text, search_text);
|
|
68
|
+
`);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function tokenizeQuery(query: string): string[] {
|
|
72
|
+
return [...new Set(query.toLowerCase().split(/[^a-z0-9_]+/).filter((part) => part.length >= 2))];
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function escapeFtsToken(token: string): string {
|
|
76
|
+
return token.replace(/"/g, '""');
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function ftsExpression(tokens: string[], joiner: 'AND' | 'OR'): string {
|
|
80
|
+
return tokens.map((token) => `"${escapeFtsToken(token)}"*`).join(` ${joiner} `);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function appendUniqueRows(target: CapsuleRow[], rows: CapsuleRow[], limit: number): void {
|
|
84
|
+
const seen = new Set(target.map((row) => row.capsule_id));
|
|
85
|
+
for (const row of rows) {
|
|
86
|
+
if (seen.has(row.capsule_id)) continue;
|
|
87
|
+
target.push(row);
|
|
88
|
+
seen.add(row.capsule_id);
|
|
89
|
+
if (target.length >= limit) return;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function openMemoryStore(dbPath: string): MemoryStore {
|
|
94
|
+
mkdirSync(dirname(dbPath), { recursive: true });
|
|
95
|
+
const db = new Database(dbPath);
|
|
96
|
+
db.exec(`
|
|
97
|
+
PRAGMA journal_mode = WAL;
|
|
98
|
+
PRAGMA busy_timeout = 5000;
|
|
99
|
+
CREATE TABLE IF NOT EXISTS memory_candidates (
|
|
100
|
+
candidate_id TEXT PRIMARY KEY,
|
|
101
|
+
category TEXT NOT NULL,
|
|
102
|
+
title TEXT NOT NULL,
|
|
103
|
+
summary TEXT NOT NULL,
|
|
104
|
+
risk_flags_json TEXT NOT NULL,
|
|
105
|
+
candidate_json TEXT NOT NULL,
|
|
106
|
+
promotion_status TEXT NOT NULL DEFAULT 'pending',
|
|
107
|
+
rejection_reasons_json TEXT NOT NULL DEFAULT '[]',
|
|
108
|
+
indexed_at TEXT NOT NULL
|
|
109
|
+
);
|
|
110
|
+
CREATE TABLE IF NOT EXISTS recall_capsules (
|
|
111
|
+
capsule_id TEXT PRIMARY KEY,
|
|
112
|
+
title TEXT NOT NULL,
|
|
113
|
+
category TEXT NOT NULL,
|
|
114
|
+
summary TEXT NOT NULL,
|
|
115
|
+
confidence TEXT NOT NULL,
|
|
116
|
+
stale_status TEXT NOT NULL,
|
|
117
|
+
evidence_count INTEGER NOT NULL,
|
|
118
|
+
evidence_refs_text TEXT NOT NULL DEFAULT '',
|
|
119
|
+
capsule_json TEXT NOT NULL,
|
|
120
|
+
updated_at TEXT NOT NULL
|
|
121
|
+
);
|
|
122
|
+
`);
|
|
123
|
+
addColumnIfMissing(db, 'memory_candidates', 'promotion_status', "promotion_status TEXT NOT NULL DEFAULT 'pending'");
|
|
124
|
+
addColumnIfMissing(db, 'memory_candidates', 'rejection_reasons_json', "rejection_reasons_json TEXT NOT NULL DEFAULT '[]'");
|
|
125
|
+
addColumnIfMissing(db, 'recall_capsules', 'evidence_refs_text', "evidence_refs_text TEXT NOT NULL DEFAULT ''");
|
|
126
|
+
addColumnIfMissing(db, 'recall_capsules', 'search_text', "search_text TEXT NOT NULL DEFAULT ''");
|
|
127
|
+
ensureFtsSchema(db);
|
|
128
|
+
|
|
129
|
+
const mapCompact = (row: CapsuleRow): CompactMemoryResult => ({
|
|
130
|
+
capsule_id: row.capsule_id,
|
|
131
|
+
title: row.title,
|
|
132
|
+
category: row.category as CompactMemoryResult['category'],
|
|
133
|
+
confidence: row.confidence as CompactMemoryResult['confidence'],
|
|
134
|
+
stale_status: row.stale_status as CompactMemoryResult['stale_status'],
|
|
135
|
+
evidence_count: row.evidence_count,
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
return {
|
|
139
|
+
dbPath,
|
|
140
|
+
close: () => db.close(),
|
|
141
|
+
reset: () => {
|
|
142
|
+
db.exec('DELETE FROM memory_candidates; DELETE FROM recall_capsules;');
|
|
143
|
+
db.exec('DELETE FROM memory_capsule_fts;');
|
|
144
|
+
},
|
|
145
|
+
stats: () => {
|
|
146
|
+
const count = (sql: string): number => db.query<{ count: number }, []>(sql).get()?.count ?? 0;
|
|
147
|
+
return {
|
|
148
|
+
candidates: {
|
|
149
|
+
total: count('SELECT COUNT(*) AS count FROM memory_candidates'),
|
|
150
|
+
pending: count("SELECT COUNT(*) AS count FROM memory_candidates WHERE promotion_status = 'pending'"),
|
|
151
|
+
promoted: count("SELECT COUNT(*) AS count FROM memory_candidates WHERE promotion_status = 'promoted'"),
|
|
152
|
+
rejected: count("SELECT COUNT(*) AS count FROM memory_candidates WHERE promotion_status = 'rejected'"),
|
|
153
|
+
},
|
|
154
|
+
recall_capsules: count('SELECT COUNT(*) AS count FROM recall_capsules'),
|
|
155
|
+
};
|
|
156
|
+
},
|
|
157
|
+
insertCandidate: (candidate) => {
|
|
158
|
+
db.query(`
|
|
159
|
+
INSERT OR REPLACE INTO memory_candidates
|
|
160
|
+
(candidate_id, category, title, summary, risk_flags_json, candidate_json, promotion_status, rejection_reasons_json, indexed_at)
|
|
161
|
+
VALUES (?, ?, ?, ?, ?, ?, 'pending', '[]', ?)
|
|
162
|
+
`).run(
|
|
163
|
+
candidate.candidate_id,
|
|
164
|
+
candidate.category,
|
|
165
|
+
candidate.title,
|
|
166
|
+
candidate.summary,
|
|
167
|
+
JSON.stringify(candidate.risk_flags),
|
|
168
|
+
JSON.stringify(candidate),
|
|
169
|
+
new Date().toISOString(),
|
|
170
|
+
);
|
|
171
|
+
},
|
|
172
|
+
markCandidate: (candidateId, status, reasons) => {
|
|
173
|
+
db.query(`
|
|
174
|
+
UPDATE memory_candidates
|
|
175
|
+
SET promotion_status = ?, rejection_reasons_json = ?
|
|
176
|
+
WHERE candidate_id = ?
|
|
177
|
+
`).run(status, JSON.stringify(reasons), candidateId);
|
|
178
|
+
},
|
|
179
|
+
insertCapsule: (capsule, searchText = '') => {
|
|
180
|
+
const evidenceRefsText = capsule.evidence_refs.map((ref) => `${ref.type}:${ref.ref}`).join(' ');
|
|
181
|
+
db.query(`
|
|
182
|
+
INSERT OR REPLACE INTO recall_capsules
|
|
183
|
+
(capsule_id, title, category, summary, confidence, stale_status, evidence_count, evidence_refs_text, search_text, capsule_json, updated_at)
|
|
184
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
185
|
+
`).run(
|
|
186
|
+
capsule.capsule_id,
|
|
187
|
+
capsule.title,
|
|
188
|
+
capsule.category,
|
|
189
|
+
capsule.summary,
|
|
190
|
+
capsule.confidence,
|
|
191
|
+
capsule.staleness.status,
|
|
192
|
+
capsule.evidence_refs.length,
|
|
193
|
+
evidenceRefsText,
|
|
194
|
+
searchText,
|
|
195
|
+
JSON.stringify(capsule),
|
|
196
|
+
capsule.updated_at,
|
|
197
|
+
);
|
|
198
|
+
db.query('DELETE FROM memory_capsule_fts WHERE capsule_id = ?').run(capsule.capsule_id);
|
|
199
|
+
db.query(`
|
|
200
|
+
INSERT INTO memory_capsule_fts (capsule_id, title, summary, category, evidence_refs_text, search_text)
|
|
201
|
+
VALUES (?, ?, ?, ?, ?, ?)
|
|
202
|
+
`).run(capsule.capsule_id, capsule.title, capsule.summary, capsule.category, evidenceRefsText, searchText);
|
|
203
|
+
},
|
|
204
|
+
search: (query, limit) => {
|
|
205
|
+
const tokens = tokenizeQuery(query);
|
|
206
|
+
if (tokens.length === 0) return [];
|
|
207
|
+
const hasIdentifierToken = tokens.some((token) => token.includes('_'));
|
|
208
|
+
const rows: CapsuleRow[] = [];
|
|
209
|
+
const runFts = (remaining: number): CapsuleRow[] => db.query<CapsuleRow, [string, number]>(`
|
|
210
|
+
SELECT c.capsule_id, c.title, c.category, c.confidence, c.stale_status, c.evidence_count, c.capsule_json
|
|
211
|
+
FROM memory_capsule_fts
|
|
212
|
+
JOIN recall_capsules c ON c.capsule_id = memory_capsule_fts.capsule_id
|
|
213
|
+
WHERE memory_capsule_fts MATCH ?
|
|
214
|
+
ORDER BY bm25(memory_capsule_fts, 0.0, 3.0, 1.5, 1.0, 2.0, 0.6), c.updated_at DESC, c.capsule_id ASC
|
|
215
|
+
LIMIT ?
|
|
216
|
+
`).all(ftsExpression(tokens, 'AND'), remaining);
|
|
217
|
+
|
|
218
|
+
if (!hasIdentifierToken) {
|
|
219
|
+
try {
|
|
220
|
+
appendUniqueRows(rows, runFts(limit), limit);
|
|
221
|
+
} catch {
|
|
222
|
+
// Fall through to the tokenized LIKE fallback below. FTS should normally
|
|
223
|
+
// handle sanitized tokens, but fallback keeps existing databases usable.
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
if (rows.length < limit) {
|
|
228
|
+
const clauses = tokens.map(() => [
|
|
229
|
+
'lower(title) LIKE ?',
|
|
230
|
+
'lower(summary) LIKE ?',
|
|
231
|
+
'lower(category) LIKE ?',
|
|
232
|
+
'lower(evidence_refs_text) LIKE ?',
|
|
233
|
+
'lower(search_text) LIKE ?',
|
|
234
|
+
].join(' OR '));
|
|
235
|
+
const params = tokens.flatMap((token) => Array(5).fill(`%${token}%`));
|
|
236
|
+
const fallbackRows = db.query<CapsuleRow, [...string[], number]>(`
|
|
237
|
+
SELECT capsule_id, title, category, confidence, stale_status, evidence_count, capsule_json
|
|
238
|
+
FROM recall_capsules
|
|
239
|
+
WHERE ${clauses.map((clause) => `(${clause})`).join(' AND ')}
|
|
240
|
+
ORDER BY updated_at DESC, capsule_id ASC
|
|
241
|
+
LIMIT ?
|
|
242
|
+
`).all(...params, limit - rows.length);
|
|
243
|
+
appendUniqueRows(rows, fallbackRows, limit);
|
|
244
|
+
}
|
|
245
|
+
return rows.map(mapCompact);
|
|
246
|
+
},
|
|
247
|
+
show: (capsuleId) => {
|
|
248
|
+
const row = db.query<{ capsule_json: string }, [string]>(
|
|
249
|
+
'SELECT capsule_json FROM recall_capsules WHERE capsule_id = ?',
|
|
250
|
+
).get(capsuleId);
|
|
251
|
+
return row ? JSON.parse(row.capsule_json) as RecallCapsule : null;
|
|
252
|
+
},
|
|
253
|
+
stale: (limit) => {
|
|
254
|
+
const rows = db.query<CapsuleRow, [number]>(`
|
|
255
|
+
SELECT capsule_id, title, category, confidence, stale_status, evidence_count, capsule_json
|
|
256
|
+
FROM recall_capsules
|
|
257
|
+
WHERE stale_status != 'current'
|
|
258
|
+
ORDER BY updated_at DESC, capsule_id ASC
|
|
259
|
+
LIMIT ?
|
|
260
|
+
`).all(limit);
|
|
261
|
+
return rows.map(mapCompact);
|
|
262
|
+
},
|
|
263
|
+
rejected: (limit) => {
|
|
264
|
+
const rows = db.query<CandidateRow, [number]>(`
|
|
265
|
+
SELECT candidate_id, title, category, risk_flags_json, rejection_reasons_json, candidate_json
|
|
266
|
+
FROM memory_candidates
|
|
267
|
+
WHERE promotion_status = 'rejected'
|
|
268
|
+
ORDER BY indexed_at DESC, candidate_id ASC
|
|
269
|
+
LIMIT ?
|
|
270
|
+
`).all(limit);
|
|
271
|
+
return rows.map((row) => {
|
|
272
|
+
const candidate = JSON.parse(row.candidate_json) as MemoryCandidate;
|
|
273
|
+
return {
|
|
274
|
+
candidate_id: row.candidate_id,
|
|
275
|
+
title: row.title,
|
|
276
|
+
category: row.category as RejectedMemoryCandidate['category'],
|
|
277
|
+
risk_flags: JSON.parse(row.risk_flags_json),
|
|
278
|
+
rejection_reasons: JSON.parse(row.rejection_reasons_json),
|
|
279
|
+
source_refs: candidate.source_refs,
|
|
280
|
+
};
|
|
281
|
+
});
|
|
282
|
+
},
|
|
283
|
+
};
|
|
284
|
+
}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
export const MEMORY_CATEGORIES = [
|
|
2
|
+
'decision',
|
|
3
|
+
'pattern',
|
|
4
|
+
'risk',
|
|
5
|
+
'mistake',
|
|
6
|
+
'playback_candidate',
|
|
7
|
+
'onboarding',
|
|
8
|
+
'adapter_note',
|
|
9
|
+
] as const;
|
|
10
|
+
|
|
11
|
+
export type MemoryCategory = (typeof MEMORY_CATEGORIES)[number];
|
|
12
|
+
|
|
13
|
+
export const EVIDENCE_REF_TYPES = [
|
|
14
|
+
'ledger',
|
|
15
|
+
'receipt',
|
|
16
|
+
'playback',
|
|
17
|
+
'event',
|
|
18
|
+
'doc',
|
|
19
|
+
'bus',
|
|
20
|
+
'commit',
|
|
21
|
+
] as const;
|
|
22
|
+
|
|
23
|
+
export type EvidenceRefType = (typeof EVIDENCE_REF_TYPES)[number];
|
|
24
|
+
|
|
25
|
+
export interface EvidenceRef {
|
|
26
|
+
type: EvidenceRefType;
|
|
27
|
+
ref: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export const MEMORY_CONFIDENCE = ['high', 'medium', 'low'] as const;
|
|
31
|
+
export type MemoryConfidence = (typeof MEMORY_CONFIDENCE)[number];
|
|
32
|
+
|
|
33
|
+
export const STALENESS_STATUS = ['current', 'watch', 'stale'] as const;
|
|
34
|
+
export type StalenessStatus = (typeof STALENESS_STATUS)[number];
|
|
35
|
+
|
|
36
|
+
export const RECOMMENDED_ACTION_TYPES = [
|
|
37
|
+
'none',
|
|
38
|
+
'read_before_work',
|
|
39
|
+
'create_ledger_entry',
|
|
40
|
+
'run_playback',
|
|
41
|
+
'update_docs',
|
|
42
|
+
'open_review',
|
|
43
|
+
] as const;
|
|
44
|
+
|
|
45
|
+
export type RecommendedActionType = (typeof RECOMMENDED_ACTION_TYPES)[number];
|
|
46
|
+
|
|
47
|
+
export const MEMORY_RISK_FLAGS = [
|
|
48
|
+
'no_durable_evidence',
|
|
49
|
+
'stale',
|
|
50
|
+
'contains_private_context',
|
|
51
|
+
'contradicts_current_ledger',
|
|
52
|
+
'contains_raw_prompt',
|
|
53
|
+
'contains_raw_tool_output',
|
|
54
|
+
'contains_source_snippet',
|
|
55
|
+
'contains_local_path',
|
|
56
|
+
'contains_hostname',
|
|
57
|
+
'contains_credential',
|
|
58
|
+
'confidence_low_for_shared_export',
|
|
59
|
+
] as const;
|
|
60
|
+
|
|
61
|
+
export type MemoryRiskFlag = (typeof MEMORY_RISK_FLAGS)[number];
|
|
62
|
+
|
|
63
|
+
export const ACTIVE_MEMORY_ADAPTERS = ['local_importer', 'manual'] as const;
|
|
64
|
+
|
|
65
|
+
export const RESERVED_MEMORY_ADAPTERS = [
|
|
66
|
+
'claude_memory',
|
|
67
|
+
'claude_mem',
|
|
68
|
+
'mempalace',
|
|
69
|
+
'vector_search',
|
|
70
|
+
] as const;
|
|
71
|
+
|
|
72
|
+
export const MEMORY_ADAPTERS = [
|
|
73
|
+
...ACTIVE_MEMORY_ADAPTERS,
|
|
74
|
+
...RESERVED_MEMORY_ADAPTERS,
|
|
75
|
+
] as const;
|
|
76
|
+
|
|
77
|
+
export type MemoryAdapter = (typeof MEMORY_ADAPTERS)[number];
|
|
78
|
+
|
|
79
|
+
export interface MemoryCandidate {
|
|
80
|
+
candidate_id: string;
|
|
81
|
+
adapter: MemoryAdapter;
|
|
82
|
+
query: string;
|
|
83
|
+
category: MemoryCategory;
|
|
84
|
+
title: string;
|
|
85
|
+
summary: string;
|
|
86
|
+
source_refs: EvidenceRef[];
|
|
87
|
+
confidence: MemoryConfidence;
|
|
88
|
+
risk_flags: MemoryRiskFlag[];
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export interface RecallCapsule {
|
|
92
|
+
schema: 'recall-capsule.v0';
|
|
93
|
+
capsule_id: string;
|
|
94
|
+
created_at: string;
|
|
95
|
+
updated_at: string;
|
|
96
|
+
scope: {
|
|
97
|
+
org_id?: string;
|
|
98
|
+
workspace_id?: string;
|
|
99
|
+
repo_ref?: string;
|
|
100
|
+
lane_ref?: string;
|
|
101
|
+
};
|
|
102
|
+
category: MemoryCategory;
|
|
103
|
+
title: string;
|
|
104
|
+
summary: string;
|
|
105
|
+
why_it_matters: string;
|
|
106
|
+
evidence_refs: EvidenceRef[];
|
|
107
|
+
confidence: MemoryConfidence;
|
|
108
|
+
staleness: {
|
|
109
|
+
status: StalenessStatus;
|
|
110
|
+
stale_if?: string;
|
|
111
|
+
};
|
|
112
|
+
recommended_action: {
|
|
113
|
+
type: RecommendedActionType;
|
|
114
|
+
ref?: string;
|
|
115
|
+
};
|
|
116
|
+
authority_boundary: {
|
|
117
|
+
can_authorize_work: false;
|
|
118
|
+
can_close_task: false;
|
|
119
|
+
can_replace_receipt: false;
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export interface MemoryIndexResult {
|
|
124
|
+
candidates: number;
|
|
125
|
+
promoted: number;
|
|
126
|
+
rejected: number;
|
|
127
|
+
capsuleIds: string[];
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export interface CompactMemoryResult {
|
|
131
|
+
capsule_id: string;
|
|
132
|
+
title: string;
|
|
133
|
+
category: MemoryCategory;
|
|
134
|
+
confidence: MemoryConfidence;
|
|
135
|
+
stale_status: StalenessStatus;
|
|
136
|
+
evidence_count: number;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export interface RejectedMemoryCandidate {
|
|
140
|
+
candidate_id: string;
|
|
141
|
+
title: string;
|
|
142
|
+
category: MemoryCategory;
|
|
143
|
+
risk_flags: MemoryRiskFlag[];
|
|
144
|
+
rejection_reasons: MemoryRiskFlag[];
|
|
145
|
+
source_refs: EvidenceRef[];
|
|
146
|
+
}
|