@knowzai/local-store 0.1.0
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/LICENSE +21 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/hash.d.ts +3 -0
- package/dist/hash.d.ts.map +1 -0
- package/dist/hash.js +0 -0
- package/dist/hash.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/open.d.ts +7 -0
- package/dist/open.d.ts.map +1 -0
- package/dist/open.js +24 -0
- package/dist/open.js.map +1 -0
- package/dist/pg-provision.d.ts +64 -0
- package/dist/pg-provision.d.ts.map +1 -0
- package/dist/pg-provision.js +270 -0
- package/dist/pg-provision.js.map +1 -0
- package/dist/postgres-store.d.ts +40 -0
- package/dist/postgres-store.d.ts.map +1 -0
- package/dist/postgres-store.js +186 -0
- package/dist/postgres-store.js.map +1 -0
- package/dist/sqlite-store.d.ts +54 -0
- package/dist/sqlite-store.d.ts.map +1 -0
- package/dist/sqlite-store.js +416 -0
- package/dist/sqlite-store.js.map +1 -0
- package/dist/sync-engine.d.ts +118 -0
- package/dist/sync-engine.d.ts.map +1 -0
- package/dist/sync-engine.js +342 -0
- package/dist/sync-engine.js.map +1 -0
- package/dist/types.d.ts +150 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +21 -0
- package/dist/types.js.map +1 -0
- package/package.json +41 -0
|
@@ -0,0 +1,416 @@
|
|
|
1
|
+
import { mkdirSync, chmodSync } from 'node:fs';
|
|
2
|
+
import { dirname } from 'node:path';
|
|
3
|
+
import Database from 'better-sqlite3';
|
|
4
|
+
import * as sqliteVec from 'sqlite-vec';
|
|
5
|
+
import { SCHEMA_VERSION, DEFAULT_DIM, } from './types.js';
|
|
6
|
+
// sqlite-vec accepts a JSON array as float-vector input; this avoids a
|
|
7
|
+
// BLOB-binding path that misparses under better-sqlite3 (spurious rowid error).
|
|
8
|
+
function vecParam(v) {
|
|
9
|
+
return JSON.stringify(Array.from(v));
|
|
10
|
+
}
|
|
11
|
+
export class SqliteStore {
|
|
12
|
+
driver = 'sqlite';
|
|
13
|
+
db;
|
|
14
|
+
dim;
|
|
15
|
+
constructor(dbPath, dim = DEFAULT_DIM) {
|
|
16
|
+
this.dim = dim;
|
|
17
|
+
if (dbPath !== ':memory:')
|
|
18
|
+
mkdirSync(dirname(dbPath), { recursive: true, mode: 0o700 });
|
|
19
|
+
this.db = new Database(dbPath);
|
|
20
|
+
if (dbPath !== ':memory:')
|
|
21
|
+
chmodSync(dbPath, 0o600);
|
|
22
|
+
sqliteVec.load(this.db);
|
|
23
|
+
this.db.pragma('journal_mode = WAL');
|
|
24
|
+
}
|
|
25
|
+
async init() {
|
|
26
|
+
this.db.exec(`
|
|
27
|
+
CREATE TABLE IF NOT EXISTS meta (key TEXT PRIMARY KEY, value TEXT);
|
|
28
|
+
CREATE TABLE IF NOT EXISTS items (
|
|
29
|
+
id TEXT PRIMARY KEY, vault_id TEXT, title TEXT NOT NULL, type TEXT NOT NULL,
|
|
30
|
+
content_hash TEXT NOT NULL, content TEXT, tags TEXT NOT NULL DEFAULT '[]',
|
|
31
|
+
updated_at TEXT NOT NULL, sync_state TEXT NOT NULL, remote_version INTEGER
|
|
32
|
+
);
|
|
33
|
+
CREATE INDEX IF NOT EXISTS idx_items_vault ON items(vault_id);
|
|
34
|
+
CREATE INDEX IF NOT EXISTS idx_items_sync ON items(sync_state);
|
|
35
|
+
CREATE TABLE IF NOT EXISTS chunks (
|
|
36
|
+
rowid INTEGER PRIMARY KEY AUTOINCREMENT, id TEXT UNIQUE NOT NULL, item_id TEXT NOT NULL,
|
|
37
|
+
ordinal INTEGER NOT NULL, text TEXT NOT NULL, start_byte INTEGER, end_byte INTEGER, lang TEXT
|
|
38
|
+
);
|
|
39
|
+
CREATE INDEX IF NOT EXISTS idx_chunks_item ON chunks(item_id);
|
|
40
|
+
CREATE TABLE IF NOT EXISTS file_state (
|
|
41
|
+
path TEXT PRIMARY KEY, hash TEXT NOT NULL, mtime_ms REAL NOT NULL, size INTEGER NOT NULL,
|
|
42
|
+
item_id TEXT, last_indexed_at TEXT
|
|
43
|
+
);
|
|
44
|
+
CREATE TABLE IF NOT EXISTS sync_log (
|
|
45
|
+
ts TEXT NOT NULL, direction TEXT NOT NULL, item_id TEXT, action TEXT, detail TEXT
|
|
46
|
+
);
|
|
47
|
+
CREATE TABLE IF NOT EXISTS observations (
|
|
48
|
+
id TEXT PRIMARY KEY, session_id TEXT NOT NULL, ts TEXT NOT NULL,
|
|
49
|
+
kind TEXT NOT NULL, tool_name TEXT, summary TEXT NOT NULL,
|
|
50
|
+
redacted INTEGER NOT NULL DEFAULT 0, vault_id TEXT, sealed_into_item_id TEXT
|
|
51
|
+
);
|
|
52
|
+
CREATE INDEX IF NOT EXISTS idx_obs_session ON observations(session_id);
|
|
53
|
+
CREATE INDEX IF NOT EXISTS idx_obs_sealed ON observations(sealed_into_item_id);
|
|
54
|
+
CREATE TABLE IF NOT EXISTS capture_outbox (
|
|
55
|
+
idempotency_key TEXT PRIMARY KEY, item_id TEXT NOT NULL, session_id TEXT NOT NULL,
|
|
56
|
+
created_at TEXT NOT NULL, attempts INTEGER NOT NULL DEFAULT 0, last_attempt_at TEXT,
|
|
57
|
+
state TEXT NOT NULL DEFAULT 'pending', last_error TEXT, lease_until TEXT
|
|
58
|
+
);
|
|
59
|
+
CREATE INDEX IF NOT EXISTS idx_outbox_state ON capture_outbox(state);
|
|
60
|
+
`);
|
|
61
|
+
this.db.exec(`CREATE VIRTUAL TABLE IF NOT EXISTS embeddings USING vec0(embedding float[${this.dim}]);`);
|
|
62
|
+
const existingDim = this.getMeta('dim');
|
|
63
|
+
if (existingDim && Number(existingDim) !== this.dim) {
|
|
64
|
+
throw new Error(`Local store dim mismatch: store=${existingDim}, requested=${this.dim}`);
|
|
65
|
+
}
|
|
66
|
+
this.setMeta('schemaVersion', String(SCHEMA_VERSION));
|
|
67
|
+
this.setMeta('dim', String(this.dim));
|
|
68
|
+
}
|
|
69
|
+
getMeta(key) {
|
|
70
|
+
const r = this.db.prepare('SELECT value FROM meta WHERE key = ?').get(key);
|
|
71
|
+
return r?.value;
|
|
72
|
+
}
|
|
73
|
+
setMeta(key, value) {
|
|
74
|
+
this.db
|
|
75
|
+
.prepare('INSERT INTO meta(key,value) VALUES(?,?) ON CONFLICT(key) DO UPDATE SET value=excluded.value')
|
|
76
|
+
.run(key, value);
|
|
77
|
+
}
|
|
78
|
+
rowToItem(r) {
|
|
79
|
+
return {
|
|
80
|
+
id: r.id,
|
|
81
|
+
vaultId: r.vault_id ?? undefined,
|
|
82
|
+
title: r.title,
|
|
83
|
+
type: r.type,
|
|
84
|
+
contentHash: r.content_hash,
|
|
85
|
+
content: r.content ?? undefined,
|
|
86
|
+
tags: JSON.parse(r.tags),
|
|
87
|
+
updatedAt: r.updated_at,
|
|
88
|
+
syncState: r.sync_state,
|
|
89
|
+
remoteVersion: r.remote_version ?? undefined,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
async upsertItem(i) {
|
|
93
|
+
this.db
|
|
94
|
+
.prepare(`INSERT INTO items(id,vault_id,title,type,content_hash,content,tags,updated_at,sync_state,remote_version)
|
|
95
|
+
VALUES(@id,@vault_id,@title,@type,@content_hash,@content,@tags,@updated_at,@sync_state,@remote_version)
|
|
96
|
+
ON CONFLICT(id) DO UPDATE SET vault_id=excluded.vault_id, title=excluded.title, type=excluded.type,
|
|
97
|
+
content_hash=excluded.content_hash, content=excluded.content, tags=excluded.tags,
|
|
98
|
+
updated_at=excluded.updated_at, sync_state=excluded.sync_state, remote_version=excluded.remote_version`)
|
|
99
|
+
.run({
|
|
100
|
+
id: i.id,
|
|
101
|
+
vault_id: i.vaultId ?? null,
|
|
102
|
+
title: i.title,
|
|
103
|
+
type: i.type,
|
|
104
|
+
content_hash: i.contentHash,
|
|
105
|
+
content: i.content ?? null,
|
|
106
|
+
tags: JSON.stringify(i.tags ?? []),
|
|
107
|
+
updated_at: i.updatedAt,
|
|
108
|
+
sync_state: i.syncState,
|
|
109
|
+
remote_version: i.remoteVersion ?? null,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
async getItem(id) {
|
|
113
|
+
const r = this.db.prepare('SELECT * FROM items WHERE id = ?').get(id);
|
|
114
|
+
return r ? this.rowToItem(r) : undefined;
|
|
115
|
+
}
|
|
116
|
+
async listItems(filter = {}) {
|
|
117
|
+
const where = [];
|
|
118
|
+
const params = [];
|
|
119
|
+
if (filter.vaultId) {
|
|
120
|
+
where.push('vault_id = ?');
|
|
121
|
+
params.push(filter.vaultId);
|
|
122
|
+
}
|
|
123
|
+
if (filter.syncState) {
|
|
124
|
+
where.push('sync_state = ?');
|
|
125
|
+
params.push(filter.syncState);
|
|
126
|
+
}
|
|
127
|
+
const sql = `SELECT * FROM items ${where.length ? `WHERE ${where.join(' AND ')}` : ''} ORDER BY updated_at DESC`;
|
|
128
|
+
return this.db.prepare(sql).all(...params).map((r) => this.rowToItem(r));
|
|
129
|
+
}
|
|
130
|
+
async reassignItemId(oldId, newId) {
|
|
131
|
+
const tx = this.db.transaction(() => {
|
|
132
|
+
this.db.prepare('UPDATE items SET id = ? WHERE id = ?').run(newId, oldId);
|
|
133
|
+
this.db.prepare('UPDATE chunks SET item_id = ? WHERE item_id = ?').run(newId, oldId);
|
|
134
|
+
this.db.prepare('UPDATE file_state SET item_id = ? WHERE item_id = ?').run(newId, oldId);
|
|
135
|
+
});
|
|
136
|
+
tx();
|
|
137
|
+
}
|
|
138
|
+
async deleteItem(id) {
|
|
139
|
+
const tx = this.db.transaction((itemId) => {
|
|
140
|
+
const rows = this.db.prepare('SELECT rowid FROM chunks WHERE item_id = ?').all(itemId);
|
|
141
|
+
const del = this.db.prepare('DELETE FROM embeddings WHERE rowid = ?');
|
|
142
|
+
for (const { rowid } of rows)
|
|
143
|
+
del.run(rowid);
|
|
144
|
+
this.db.prepare('DELETE FROM chunks WHERE item_id = ?').run(itemId);
|
|
145
|
+
this.db.prepare('DELETE FROM items WHERE id = ?').run(itemId);
|
|
146
|
+
});
|
|
147
|
+
tx(id);
|
|
148
|
+
}
|
|
149
|
+
async putChunks(itemId, chunks, vectors) {
|
|
150
|
+
const tx = this.db.transaction(() => {
|
|
151
|
+
const old = this.db.prepare('SELECT rowid FROM chunks WHERE item_id = ?').all(itemId);
|
|
152
|
+
const delEmb = this.db.prepare('DELETE FROM embeddings WHERE rowid = ?');
|
|
153
|
+
for (const { rowid } of old)
|
|
154
|
+
delEmb.run(rowid);
|
|
155
|
+
this.db.prepare('DELETE FROM chunks WHERE item_id = ?').run(itemId);
|
|
156
|
+
const insChunk = this.db.prepare(`INSERT INTO chunks(id,item_id,ordinal,text,start_byte,end_byte,lang)
|
|
157
|
+
VALUES(?,?,?,?,?,?,?)`);
|
|
158
|
+
const insEmb = this.db.prepare('INSERT INTO embeddings(rowid, embedding) VALUES(?, ?)');
|
|
159
|
+
chunks.forEach((c, idx) => {
|
|
160
|
+
const info = insChunk.run(c.id, c.itemId, c.ordinal, c.text, c.startByte ?? null, c.endByte ?? null, c.lang ?? null);
|
|
161
|
+
const vec = vectors?.[idx];
|
|
162
|
+
if (vec) {
|
|
163
|
+
if (vec.length !== this.dim)
|
|
164
|
+
throw new Error(`vector dim ${vec.length} != store dim ${this.dim}`);
|
|
165
|
+
// vec0 requires the rowid bound as SQLITE_INTEGER — better-sqlite3
|
|
166
|
+
// only does that for a BigInt, not a plain JS number.
|
|
167
|
+
insEmb.run(BigInt(info.lastInsertRowid), vecParam(vec));
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
});
|
|
171
|
+
tx();
|
|
172
|
+
}
|
|
173
|
+
async knnSearch(queryVec, k, filter) {
|
|
174
|
+
if (queryVec.length !== this.dim)
|
|
175
|
+
throw new Error(`query dim ${queryVec.length} != store dim ${this.dim}`);
|
|
176
|
+
const overfetch = filter?.vaultId ? k * 4 : k;
|
|
177
|
+
const rows = this.db
|
|
178
|
+
.prepare(`SELECT e.rowid AS rowid, e.distance AS distance,
|
|
179
|
+
c.id, c.item_id, c.ordinal, c.text, c.start_byte, c.end_byte, c.lang
|
|
180
|
+
FROM embeddings e JOIN chunks c ON c.rowid = e.rowid
|
|
181
|
+
WHERE e.embedding MATCH ? AND k = ?
|
|
182
|
+
ORDER BY e.distance`)
|
|
183
|
+
.all(vecParam(queryVec), overfetch);
|
|
184
|
+
let hits = rows.map((r) => ({
|
|
185
|
+
distance: r.distance,
|
|
186
|
+
chunk: {
|
|
187
|
+
id: r.id,
|
|
188
|
+
itemId: r.item_id,
|
|
189
|
+
ordinal: r.ordinal,
|
|
190
|
+
text: r.text,
|
|
191
|
+
startByte: r.start_byte ?? undefined,
|
|
192
|
+
endByte: r.end_byte ?? undefined,
|
|
193
|
+
lang: r.lang ?? undefined,
|
|
194
|
+
},
|
|
195
|
+
}));
|
|
196
|
+
if (filter?.vaultId) {
|
|
197
|
+
const inVault = new Set(this.db.prepare('SELECT id FROM items WHERE vault_id = ?').all(filter.vaultId).map((x) => x.id));
|
|
198
|
+
hits = hits.filter((h) => inVault.has(h.chunk.itemId)).slice(0, k);
|
|
199
|
+
}
|
|
200
|
+
return hits;
|
|
201
|
+
}
|
|
202
|
+
async setFileState(s) {
|
|
203
|
+
this.db
|
|
204
|
+
.prepare(`INSERT INTO file_state(path,hash,mtime_ms,size,item_id,last_indexed_at)
|
|
205
|
+
VALUES(@path,@hash,@mtime_ms,@size,@item_id,@last_indexed_at)
|
|
206
|
+
ON CONFLICT(path) DO UPDATE SET hash=excluded.hash, mtime_ms=excluded.mtime_ms,
|
|
207
|
+
size=excluded.size, item_id=excluded.item_id, last_indexed_at=excluded.last_indexed_at`)
|
|
208
|
+
.run({
|
|
209
|
+
path: s.path,
|
|
210
|
+
hash: s.hash,
|
|
211
|
+
mtime_ms: s.mtimeMs,
|
|
212
|
+
size: s.size,
|
|
213
|
+
item_id: s.itemId ?? null,
|
|
214
|
+
last_indexed_at: s.lastIndexedAt ?? null,
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
async getFileState(path) {
|
|
218
|
+
const r = this.db.prepare('SELECT * FROM file_state WHERE path = ?').get(path);
|
|
219
|
+
if (!r)
|
|
220
|
+
return undefined;
|
|
221
|
+
return {
|
|
222
|
+
path: r.path,
|
|
223
|
+
hash: r.hash,
|
|
224
|
+
mtimeMs: r.mtime_ms,
|
|
225
|
+
size: r.size,
|
|
226
|
+
itemId: r.item_id ?? undefined,
|
|
227
|
+
lastIndexedAt: r.last_indexed_at ?? undefined,
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
async listFileStates() {
|
|
231
|
+
const rows = this.db.prepare('SELECT * FROM file_state').all();
|
|
232
|
+
return rows.map((r) => ({
|
|
233
|
+
path: r.path,
|
|
234
|
+
hash: r.hash,
|
|
235
|
+
mtimeMs: r.mtime_ms,
|
|
236
|
+
size: r.size,
|
|
237
|
+
itemId: r.item_id ?? undefined,
|
|
238
|
+
lastIndexedAt: r.last_indexed_at ?? undefined,
|
|
239
|
+
}));
|
|
240
|
+
}
|
|
241
|
+
async meta() {
|
|
242
|
+
const itemCount = this.db.prepare('SELECT COUNT(*) AS n FROM items').get().n;
|
|
243
|
+
const chunkCount = this.db.prepare('SELECT COUNT(*) AS n FROM chunks').get().n;
|
|
244
|
+
return {
|
|
245
|
+
schemaVersion: Number(this.getMeta('schemaVersion') ?? SCHEMA_VERSION),
|
|
246
|
+
dim: Number(this.getMeta('dim') ?? this.dim),
|
|
247
|
+
itemCount,
|
|
248
|
+
chunkCount,
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
// ── Agent-memory capture / outbox (FEAT_AgentMemoryLocalOutbox) ─────────────
|
|
252
|
+
rowToObservation(r) {
|
|
253
|
+
return {
|
|
254
|
+
id: r.id,
|
|
255
|
+
sessionId: r.session_id,
|
|
256
|
+
ts: r.ts,
|
|
257
|
+
kind: r.kind,
|
|
258
|
+
toolName: r.tool_name ?? undefined,
|
|
259
|
+
summary: r.summary,
|
|
260
|
+
redacted: r.redacted === 1,
|
|
261
|
+
vaultId: r.vault_id ?? undefined,
|
|
262
|
+
sealedIntoItemId: r.sealed_into_item_id ?? undefined,
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
rowToOutbox(r) {
|
|
266
|
+
return {
|
|
267
|
+
idempotencyKey: r.idempotency_key,
|
|
268
|
+
itemId: r.item_id,
|
|
269
|
+
sessionId: r.session_id,
|
|
270
|
+
createdAt: r.created_at,
|
|
271
|
+
attempts: r.attempts,
|
|
272
|
+
lastAttemptAt: r.last_attempt_at ?? undefined,
|
|
273
|
+
state: r.state,
|
|
274
|
+
lastError: r.last_error ?? undefined,
|
|
275
|
+
leaseUntil: r.lease_until ?? undefined,
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
async recordObservation(o) {
|
|
279
|
+
this.db
|
|
280
|
+
.prepare(`INSERT INTO observations(id,session_id,ts,kind,tool_name,summary,redacted,vault_id,sealed_into_item_id)
|
|
281
|
+
VALUES(@id,@session_id,@ts,@kind,@tool_name,@summary,@redacted,@vault_id,@sealed_into_item_id)
|
|
282
|
+
ON CONFLICT(id) DO UPDATE SET session_id=excluded.session_id, ts=excluded.ts, kind=excluded.kind,
|
|
283
|
+
tool_name=excluded.tool_name, summary=excluded.summary, redacted=excluded.redacted,
|
|
284
|
+
vault_id=excluded.vault_id, sealed_into_item_id=excluded.sealed_into_item_id`)
|
|
285
|
+
.run({
|
|
286
|
+
id: o.id,
|
|
287
|
+
session_id: o.sessionId,
|
|
288
|
+
ts: o.ts,
|
|
289
|
+
kind: o.kind,
|
|
290
|
+
tool_name: o.toolName ?? null,
|
|
291
|
+
summary: o.summary,
|
|
292
|
+
redacted: o.redacted ? 1 : 0,
|
|
293
|
+
vault_id: o.vaultId ?? null,
|
|
294
|
+
sealed_into_item_id: o.sealedIntoItemId ?? null,
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
async listObservations(filter = {}) {
|
|
298
|
+
const where = [];
|
|
299
|
+
const params = [];
|
|
300
|
+
if (filter.sessionId) {
|
|
301
|
+
where.push('session_id = ?');
|
|
302
|
+
params.push(filter.sessionId);
|
|
303
|
+
}
|
|
304
|
+
if (filter.sealed === true)
|
|
305
|
+
where.push('sealed_into_item_id IS NOT NULL');
|
|
306
|
+
if (filter.sealed === false)
|
|
307
|
+
where.push('sealed_into_item_id IS NULL');
|
|
308
|
+
const sql = `SELECT * FROM observations ${where.length ? `WHERE ${where.join(' AND ')}` : ''} ORDER BY ts ASC`;
|
|
309
|
+
return this.db.prepare(sql).all(...params).map((r) => this.rowToObservation(r));
|
|
310
|
+
}
|
|
311
|
+
async markObservationsSealed(ids, itemId) {
|
|
312
|
+
if (ids.length === 0)
|
|
313
|
+
return;
|
|
314
|
+
const upd = this.db.prepare('UPDATE observations SET sealed_into_item_id = ? WHERE id = ?');
|
|
315
|
+
const tx = this.db.transaction((list) => {
|
|
316
|
+
for (const id of list)
|
|
317
|
+
upd.run(itemId, id);
|
|
318
|
+
});
|
|
319
|
+
tx(ids);
|
|
320
|
+
}
|
|
321
|
+
async enqueueOutbox(e) {
|
|
322
|
+
this.db
|
|
323
|
+
.prepare(`INSERT INTO capture_outbox(idempotency_key,item_id,session_id,created_at,attempts,last_attempt_at,state,last_error,lease_until)
|
|
324
|
+
VALUES(@idempotency_key,@item_id,@session_id,@created_at,@attempts,@last_attempt_at,@state,@last_error,@lease_until)
|
|
325
|
+
ON CONFLICT(idempotency_key) DO NOTHING`)
|
|
326
|
+
.run({
|
|
327
|
+
idempotency_key: e.idempotencyKey,
|
|
328
|
+
item_id: e.itemId,
|
|
329
|
+
session_id: e.sessionId,
|
|
330
|
+
created_at: e.createdAt,
|
|
331
|
+
attempts: e.attempts ?? 0,
|
|
332
|
+
last_attempt_at: e.lastAttemptAt ?? null,
|
|
333
|
+
state: e.state ?? 'pending',
|
|
334
|
+
last_error: e.lastError ?? null,
|
|
335
|
+
lease_until: e.leaseUntil ?? null,
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
async claimOutbox(opts) {
|
|
339
|
+
const claim = this.db.transaction((now, leaseUntil, limit) => {
|
|
340
|
+
// pending whose backoff has elapsed, OR inflight whose lease expired (crash recovery).
|
|
341
|
+
const candidates = this.db
|
|
342
|
+
.prepare(`SELECT idempotency_key FROM capture_outbox
|
|
343
|
+
WHERE (state = 'pending' AND (lease_until IS NULL OR lease_until <= @now))
|
|
344
|
+
OR (state = 'inflight' AND lease_until IS NOT NULL AND lease_until <= @now)
|
|
345
|
+
ORDER BY created_at ASC LIMIT @limit`)
|
|
346
|
+
.all({ now, limit });
|
|
347
|
+
const mark = this.db.prepare(`UPDATE capture_outbox SET state='inflight', lease_until=@lease, last_attempt_at=@now
|
|
348
|
+
WHERE idempotency_key=@key`);
|
|
349
|
+
for (const c of candidates)
|
|
350
|
+
mark.run({ lease: leaseUntil, now, key: c.idempotency_key });
|
|
351
|
+
return candidates.map((c) => c.idempotency_key);
|
|
352
|
+
});
|
|
353
|
+
const keys = claim(opts.now, opts.leaseUntil, opts.limit);
|
|
354
|
+
return keys
|
|
355
|
+
.map((k) => this.db.prepare('SELECT * FROM capture_outbox WHERE idempotency_key = ?').get(k))
|
|
356
|
+
.filter((r) => !!r)
|
|
357
|
+
.map((r) => this.rowToOutbox(r));
|
|
358
|
+
}
|
|
359
|
+
async updateOutbox(key, patch) {
|
|
360
|
+
const colMap = {
|
|
361
|
+
itemId: 'item_id',
|
|
362
|
+
sessionId: 'session_id',
|
|
363
|
+
createdAt: 'created_at',
|
|
364
|
+
attempts: 'attempts',
|
|
365
|
+
lastAttemptAt: 'last_attempt_at',
|
|
366
|
+
state: 'state',
|
|
367
|
+
lastError: 'last_error',
|
|
368
|
+
leaseUntil: 'lease_until',
|
|
369
|
+
};
|
|
370
|
+
const sets = [];
|
|
371
|
+
const params = { key };
|
|
372
|
+
for (const [k, v] of Object.entries(patch)) {
|
|
373
|
+
const col = colMap[k];
|
|
374
|
+
if (!col)
|
|
375
|
+
continue;
|
|
376
|
+
sets.push(`${col} = @${col}`);
|
|
377
|
+
params[col] = v ?? null;
|
|
378
|
+
}
|
|
379
|
+
if (sets.length === 0)
|
|
380
|
+
return;
|
|
381
|
+
this.db
|
|
382
|
+
.prepare(`UPDATE capture_outbox SET ${sets.join(', ')} WHERE idempotency_key = @key`)
|
|
383
|
+
.run(params);
|
|
384
|
+
}
|
|
385
|
+
async getOutbox(key) {
|
|
386
|
+
const r = this.db.prepare('SELECT * FROM capture_outbox WHERE idempotency_key = ?').get(key);
|
|
387
|
+
return r ? this.rowToOutbox(r) : undefined;
|
|
388
|
+
}
|
|
389
|
+
async listOutbox(filter = {}) {
|
|
390
|
+
const sql = `SELECT * FROM capture_outbox ${filter.state ? 'WHERE state = ?' : ''} ORDER BY created_at ASC`;
|
|
391
|
+
const rows = (filter.state
|
|
392
|
+
? this.db.prepare(sql).all(filter.state)
|
|
393
|
+
: this.db.prepare(sql).all());
|
|
394
|
+
return rows.map((r) => this.rowToOutbox(r));
|
|
395
|
+
}
|
|
396
|
+
async outboxStats() {
|
|
397
|
+
const rows = this.db
|
|
398
|
+
.prepare('SELECT state, COUNT(*) AS n FROM capture_outbox GROUP BY state')
|
|
399
|
+
.all();
|
|
400
|
+
const stats = { pending: 0, inflight: 0, done: 0, dead: 0, conflict: 0 };
|
|
401
|
+
for (const r of rows) {
|
|
402
|
+
if (r.state === 'pending' ||
|
|
403
|
+
r.state === 'inflight' ||
|
|
404
|
+
r.state === 'done' ||
|
|
405
|
+
r.state === 'dead' ||
|
|
406
|
+
r.state === 'conflict') {
|
|
407
|
+
stats[r.state] = r.n;
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
return stats;
|
|
411
|
+
}
|
|
412
|
+
async close() {
|
|
413
|
+
this.db.close();
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
//# sourceMappingURL=sqlite-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sqlite-store.js","sourceRoot":"","sources":["../src/sqlite-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import type { KnowzApiClient } from '@knowzai/api-client';
|
|
2
|
+
import type { LocalStore, LocalItem } from './types.js';
|
|
3
|
+
export interface SyncReport {
|
|
4
|
+
pulled: number;
|
|
5
|
+
pushed: number;
|
|
6
|
+
conflicts: string[];
|
|
7
|
+
skipped: number;
|
|
8
|
+
}
|
|
9
|
+
export interface SyncStatus {
|
|
10
|
+
total: number;
|
|
11
|
+
new: number;
|
|
12
|
+
dirty: number;
|
|
13
|
+
synced: number;
|
|
14
|
+
conflict: number;
|
|
15
|
+
deleted: number;
|
|
16
|
+
}
|
|
17
|
+
/** Result of one `flushOutbox()` drain pass. */
|
|
18
|
+
export interface FlushReport {
|
|
19
|
+
/** Entries claimed and attempted this pass. */
|
|
20
|
+
claimed: number;
|
|
21
|
+
/** Successfully delivered to the cloud (outbox → done). */
|
|
22
|
+
sent: number;
|
|
23
|
+
/** Transient failures deferred for retry (outbox → pending w/ backoff). */
|
|
24
|
+
failed: number;
|
|
25
|
+
/** Permanently failed / max-attempts exceeded (outbox → dead). */
|
|
26
|
+
dead: number;
|
|
27
|
+
conflicts: string[];
|
|
28
|
+
}
|
|
29
|
+
export interface FlushOptions {
|
|
30
|
+
/** Max entries to process this pass. Default 100. */
|
|
31
|
+
limit?: number;
|
|
32
|
+
/** Lease window (ms) a claimed entry holds before it can be reclaimed. Default 60s. */
|
|
33
|
+
leaseMs?: number;
|
|
34
|
+
/** Attempts after which a transient failure dead-letters. Default 5. */
|
|
35
|
+
maxAttempts?: number;
|
|
36
|
+
/** Base retry backoff (ms); doubles per attempt, capped at maxBackoffMs. Default 1s. */
|
|
37
|
+
baseBackoffMs?: number;
|
|
38
|
+
/** Backoff ceiling (ms). Default 5min. */
|
|
39
|
+
maxBackoffMs?: number;
|
|
40
|
+
/** Injectable clock (epoch ms) for deterministic tests. Default Date.now. */
|
|
41
|
+
now?: () => number;
|
|
42
|
+
/** Provenance stamped into each created item's metadata (e.g. the profile). */
|
|
43
|
+
source?: string;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Optional content encryptor (Model-3 CMEK). When present, push encrypts item
|
|
47
|
+
* content before it leaves the machine and pull decrypts after fetch, so the
|
|
48
|
+
* cloud only ever stores ciphertext.
|
|
49
|
+
*/
|
|
50
|
+
export interface ContentEncryptor {
|
|
51
|
+
encrypt(plaintext: string): string;
|
|
52
|
+
decrypt(ciphertext: string): string;
|
|
53
|
+
isEncrypted(s: string): boolean;
|
|
54
|
+
}
|
|
55
|
+
export declare class SyncEngine {
|
|
56
|
+
private readonly store;
|
|
57
|
+
private readonly client;
|
|
58
|
+
private readonly encryptor?;
|
|
59
|
+
constructor(store: LocalStore, client: KnowzApiClient, opts?: {
|
|
60
|
+
encryptor?: ContentEncryptor;
|
|
61
|
+
});
|
|
62
|
+
/**
|
|
63
|
+
* Iterate EVERY page of `knowledge.list` for a vault, invoking `onSummary`
|
|
64
|
+
* per remote item. Stops when the cumulative count reaches `total` OR a page
|
|
65
|
+
* returns fewer than `pageSize` items (defensive against a 0/undefined total),
|
|
66
|
+
* so the full remote set is always covered without an infinite loop.
|
|
67
|
+
*/
|
|
68
|
+
private forEachRemote;
|
|
69
|
+
/** Cloud → local. Upserts remote items; flags conflicts; skips unchanged. */
|
|
70
|
+
pull(opts?: {
|
|
71
|
+
vaultId?: string;
|
|
72
|
+
pageSize?: number;
|
|
73
|
+
}): Promise<SyncReport>;
|
|
74
|
+
/** Local dirty/new → cloud. Clears dirty + records remoteVersion. */
|
|
75
|
+
push(opts?: {
|
|
76
|
+
vaultId?: string;
|
|
77
|
+
}): Promise<SyncReport>;
|
|
78
|
+
run(opts?: {
|
|
79
|
+
vaultId?: string;
|
|
80
|
+
}): Promise<SyncReport>;
|
|
81
|
+
status(): Promise<SyncStatus>;
|
|
82
|
+
/** Items currently in conflict (local + remote both changed). */
|
|
83
|
+
listConflicts(): Promise<LocalItem[]>;
|
|
84
|
+
/** Resolve one conflicted item by keeping the remote copy or the local copy. */
|
|
85
|
+
resolveConflict(id: string, strategy: 'remote' | 'local'): Promise<'updated-from-remote' | 'kept-local' | 'not-found'>;
|
|
86
|
+
/**
|
|
87
|
+
* Recovery: re-pull authoritative cloud state to repair the local store
|
|
88
|
+
* (overwrites non-dirty items, preserves dirty-vs-advanced as conflicts) and
|
|
89
|
+
* report any local `synced` items no longer present remotely (orphans).
|
|
90
|
+
*/
|
|
91
|
+
recover(opts?: {
|
|
92
|
+
vaultId?: string;
|
|
93
|
+
pageSize?: number;
|
|
94
|
+
}): Promise<{
|
|
95
|
+
repaired: number;
|
|
96
|
+
conflicts: string[];
|
|
97
|
+
orphanedLocal: string[];
|
|
98
|
+
}>;
|
|
99
|
+
/**
|
|
100
|
+
* Drain the capture outbox to the cloud (FEAT_AgentMemoryLocalOutbox).
|
|
101
|
+
*
|
|
102
|
+
* Each claimed entry's sealed content lives in `items`; we create it via the
|
|
103
|
+
* existing `knowledge.create` path (the batch endpoint is not yet shipped),
|
|
104
|
+
* stamping the idempotency key into item metadata for best-effort server-side
|
|
105
|
+
* dedup. Idempotency is enforced LOCALLY: a `done` entry is never reclaimed,
|
|
106
|
+
* and re-enqueue is a no-op on the idempotency-key PK. The only double-create
|
|
107
|
+
* window is "create succeeded but its ack was lost before we marked done" —
|
|
108
|
+
* acceptable until the content-hash-dedup batch endpoint lands.
|
|
109
|
+
*
|
|
110
|
+
* Resilience: claims `pending` (whose backoff elapsed) plus `inflight` whose
|
|
111
|
+
* lease expired (crash recovery). Transient failures back off exponentially;
|
|
112
|
+
* after `maxAttempts` an entry dead-letters (visible via `outboxStats`). This
|
|
113
|
+
* is what makes the orphaned-pending-captures leak structurally impossible —
|
|
114
|
+
* a capture is a committed row drained by an idempotent, retrying consumer.
|
|
115
|
+
*/
|
|
116
|
+
flushOutbox(opts?: FlushOptions): Promise<FlushReport>;
|
|
117
|
+
}
|
|
118
|
+
//# sourceMappingURL=sync-engine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync-engine.d.ts","sourceRoot":"","sources":["../src/sync-engine.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAIxD,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,gDAAgD;AAChD,MAAM,WAAW,WAAW;IAC1B,+CAA+C;IAC/C,OAAO,EAAE,MAAM,CAAC;IAChB,2DAA2D;IAC3D,IAAI,EAAE,MAAM,CAAC;IACb,2EAA2E;IAC3E,MAAM,EAAE,MAAM,CAAC;IACf,kEAAkE;IAClE,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IAC3B,qDAAqD;IACrD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,uFAAuF;IACvF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,wEAAwE;IACxE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,wFAAwF;IACxF,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,0CAA0C;IAC1C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,6EAA6E;IAC7E,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,+EAA+E;IAC/E,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAC/B,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC;IACnC,OAAO,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAAC;IACpC,WAAW,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACjC;AAMD,qBAAa,UAAU;IAGnB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,MAAM;IAHzB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAmB;gBAE3B,KAAK,EAAE,UAAU,EACjB,MAAM,EAAE,cAAc,EACvC,IAAI,GAAE;QAAE,SAAS,CAAC,EAAE,gBAAgB,CAAA;KAAO;IAK7C;;;;;OAKG;YACW,aAAa;IAmB3B,6EAA6E;IACvE,IAAI,CAAC,IAAI,GAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAO,GAAG,OAAO,CAAC,UAAU,CAAC;IAyCnF,qEAAqE;IAC/D,IAAI,CAAC,IAAI,GAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAO,GAAG,OAAO,CAAC,UAAU,CAAC;IA4D1D,GAAG,CAAC,IAAI,GAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAO,GAAG,OAAO,CAAC,UAAU,CAAC;IAWzD,MAAM,IAAI,OAAO,CAAC,UAAU,CAAC;IAanC,iEAAiE;IAC3D,aAAa,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;IAI3C,gFAAgF;IAC1E,eAAe,CACnB,EAAE,EAAE,MAAM,EACV,QAAQ,EAAE,QAAQ,GAAG,OAAO,GAC3B,OAAO,CAAC,qBAAqB,GAAG,YAAY,GAAG,WAAW,CAAC;IA0B9D;;;;OAIG;IACG,OAAO,CAAC,IAAI,GAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAO,GAAG,OAAO,CAAC;QACzE,QAAQ,EAAE,MAAM,CAAC;QACjB,SAAS,EAAE,MAAM,EAAE,CAAC;QACpB,aAAa,EAAE,MAAM,EAAE,CAAC;KACzB,CAAC;IAsCF;;;;;;;;;;;;;;;;OAgBG;IACG,WAAW,CAAC,IAAI,GAAE,YAAiB,GAAG,OAAO,CAAC,WAAW,CAAC;CA0FjE"}
|