claude-memory-layer 1.0.7 → 1.0.9
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/.claude/settings.local.json +10 -1
- package/.claude-memory/test.sqlite +0 -0
- package/.history/package_20260201192048.json +47 -0
- package/.history/package_20260202114053.json +49 -0
- package/HANDOFF.md +92 -0
- package/dist/cli/index.js +1711 -102
- package/dist/cli/index.js.map +4 -4
- package/dist/core/index.js +1257 -84
- package/dist/core/index.js.map +4 -4
- package/dist/hooks/post-tool-use.js +5589 -0
- package/dist/hooks/post-tool-use.js.map +7 -0
- package/dist/hooks/session-end.js +1382 -85
- package/dist/hooks/session-end.js.map +4 -4
- package/dist/hooks/session-start.js +1377 -84
- package/dist/hooks/session-start.js.map +4 -4
- package/dist/hooks/stop.js +1383 -86
- package/dist/hooks/stop.js.map +4 -4
- package/dist/hooks/user-prompt-submit.js +1412 -84
- package/dist/hooks/user-prompt-submit.js.map +4 -4
- package/dist/server/api/index.js +1576 -136
- package/dist/server/api/index.js.map +4 -4
- package/dist/server/index.js +1585 -143
- package/dist/server/index.js.map +4 -4
- package/dist/services/memory-service.js +1392 -84
- package/dist/services/memory-service.js.map +4 -4
- package/dist/ui/app.js +304 -0
- package/dist/ui/index.html +202 -715
- package/dist/ui/style.css +595 -0
- package/package.json +4 -1
- package/scripts/build.ts +5 -2
- package/src/cli/index.ts +226 -0
- package/src/core/db-wrapper.ts +8 -1
- package/src/core/event-store.ts +70 -3
- package/src/core/graduation-worker.ts +171 -0
- package/src/core/graduation.ts +15 -2
- package/src/core/index.ts +4 -0
- package/src/core/retriever.ts +21 -0
- package/src/core/sqlite-event-store.ts +849 -0
- package/src/core/sqlite-wrapper.ts +108 -0
- package/src/core/sync-worker.ts +228 -0
- package/src/core/vector-worker.ts +44 -14
- package/src/hooks/user-prompt-submit.ts +53 -4
- package/src/server/api/citations.ts +7 -3
- package/src/server/api/events.ts +7 -3
- package/src/server/api/search.ts +7 -3
- package/src/server/api/sessions.ts +7 -3
- package/src/server/api/stats.ts +159 -12
- package/src/server/index.ts +18 -9
- package/src/services/memory-service.ts +263 -46
- package/src/ui/app.js +304 -0
- package/src/ui/index.html +202 -715
- package/src/ui/style.css +595 -0
- package/test_access.js +49 -0
package/dist/core/index.js
CHANGED
|
@@ -639,7 +639,10 @@ function toDate(value) {
|
|
|
639
639
|
return new Date(value);
|
|
640
640
|
return new Date(String(value));
|
|
641
641
|
}
|
|
642
|
-
function createDatabase(path) {
|
|
642
|
+
function createDatabase(path, options) {
|
|
643
|
+
if (options?.readOnly) {
|
|
644
|
+
return new duckdb.Database(path, { access_mode: "READ_ONLY" });
|
|
645
|
+
}
|
|
643
646
|
return new duckdb.Database(path);
|
|
644
647
|
}
|
|
645
648
|
function dbRun(db, sql, params = []) {
|
|
@@ -693,18 +696,24 @@ function dbClose(db) {
|
|
|
693
696
|
|
|
694
697
|
// src/core/event-store.ts
|
|
695
698
|
var EventStore = class {
|
|
696
|
-
constructor(dbPath) {
|
|
699
|
+
constructor(dbPath, options) {
|
|
697
700
|
this.dbPath = dbPath;
|
|
698
|
-
this.
|
|
701
|
+
this.readOnly = options?.readOnly ?? false;
|
|
702
|
+
this.db = createDatabase(dbPath, { readOnly: this.readOnly });
|
|
699
703
|
}
|
|
700
704
|
db;
|
|
701
705
|
initialized = false;
|
|
706
|
+
readOnly;
|
|
702
707
|
/**
|
|
703
708
|
* Initialize database schema
|
|
704
709
|
*/
|
|
705
710
|
async initialize() {
|
|
706
711
|
if (this.initialized)
|
|
707
712
|
return;
|
|
713
|
+
if (this.readOnly) {
|
|
714
|
+
this.initialized = true;
|
|
715
|
+
return;
|
|
716
|
+
}
|
|
708
717
|
await dbRun(this.db, `
|
|
709
718
|
CREATE TABLE IF NOT EXISTS events (
|
|
710
719
|
id VARCHAR PRIMARY KEY,
|
|
@@ -1076,20 +1085,761 @@ var EventStore = class {
|
|
|
1076
1085
|
const row = rows[0];
|
|
1077
1086
|
return {
|
|
1078
1087
|
id: row.id,
|
|
1079
|
-
startedAt: toDate(row.started_at),
|
|
1080
|
-
endedAt: row.ended_at ? toDate(row.ended_at) : void 0,
|
|
1088
|
+
startedAt: toDate(row.started_at),
|
|
1089
|
+
endedAt: row.ended_at ? toDate(row.ended_at) : void 0,
|
|
1090
|
+
projectPath: row.project_path,
|
|
1091
|
+
summary: row.summary,
|
|
1092
|
+
tags: row.tags ? JSON.parse(row.tags) : void 0
|
|
1093
|
+
};
|
|
1094
|
+
}
|
|
1095
|
+
/**
|
|
1096
|
+
* Add to embedding outbox (Single-Writer Pattern)
|
|
1097
|
+
*/
|
|
1098
|
+
async enqueueForEmbedding(eventId, content) {
|
|
1099
|
+
await this.initialize();
|
|
1100
|
+
const id = randomUUID();
|
|
1101
|
+
await dbRun(
|
|
1102
|
+
this.db,
|
|
1103
|
+
`INSERT INTO embedding_outbox (id, event_id, content, status, retry_count)
|
|
1104
|
+
VALUES (?, ?, ?, 'pending', 0)`,
|
|
1105
|
+
[id, eventId, content]
|
|
1106
|
+
);
|
|
1107
|
+
return id;
|
|
1108
|
+
}
|
|
1109
|
+
/**
|
|
1110
|
+
* Get pending outbox items
|
|
1111
|
+
*/
|
|
1112
|
+
async getPendingOutboxItems(limit = 32) {
|
|
1113
|
+
await this.initialize();
|
|
1114
|
+
const pending = await dbAll(
|
|
1115
|
+
this.db,
|
|
1116
|
+
`SELECT * FROM embedding_outbox
|
|
1117
|
+
WHERE status = 'pending'
|
|
1118
|
+
ORDER BY created_at
|
|
1119
|
+
LIMIT ?`,
|
|
1120
|
+
[limit]
|
|
1121
|
+
);
|
|
1122
|
+
if (pending.length === 0)
|
|
1123
|
+
return [];
|
|
1124
|
+
const ids = pending.map((r) => r.id);
|
|
1125
|
+
const placeholders = ids.map(() => "?").join(",");
|
|
1126
|
+
await dbRun(
|
|
1127
|
+
this.db,
|
|
1128
|
+
`UPDATE embedding_outbox SET status = 'processing' WHERE id IN (${placeholders})`,
|
|
1129
|
+
ids
|
|
1130
|
+
);
|
|
1131
|
+
return pending.map((row) => ({
|
|
1132
|
+
id: row.id,
|
|
1133
|
+
eventId: row.event_id,
|
|
1134
|
+
content: row.content,
|
|
1135
|
+
status: "processing",
|
|
1136
|
+
retryCount: row.retry_count,
|
|
1137
|
+
createdAt: toDate(row.created_at),
|
|
1138
|
+
errorMessage: row.error_message
|
|
1139
|
+
}));
|
|
1140
|
+
}
|
|
1141
|
+
/**
|
|
1142
|
+
* Mark outbox items as done
|
|
1143
|
+
*/
|
|
1144
|
+
async completeOutboxItems(ids) {
|
|
1145
|
+
if (ids.length === 0)
|
|
1146
|
+
return;
|
|
1147
|
+
const placeholders = ids.map(() => "?").join(",");
|
|
1148
|
+
await dbRun(
|
|
1149
|
+
this.db,
|
|
1150
|
+
`DELETE FROM embedding_outbox WHERE id IN (${placeholders})`,
|
|
1151
|
+
ids
|
|
1152
|
+
);
|
|
1153
|
+
}
|
|
1154
|
+
/**
|
|
1155
|
+
* Mark outbox items as failed
|
|
1156
|
+
*/
|
|
1157
|
+
async failOutboxItems(ids, error) {
|
|
1158
|
+
if (ids.length === 0)
|
|
1159
|
+
return;
|
|
1160
|
+
const placeholders = ids.map(() => "?").join(",");
|
|
1161
|
+
await dbRun(
|
|
1162
|
+
this.db,
|
|
1163
|
+
`UPDATE embedding_outbox
|
|
1164
|
+
SET status = CASE WHEN retry_count >= 3 THEN 'failed' ELSE 'pending' END,
|
|
1165
|
+
retry_count = retry_count + 1,
|
|
1166
|
+
error_message = ?
|
|
1167
|
+
WHERE id IN (${placeholders})`,
|
|
1168
|
+
[error, ...ids]
|
|
1169
|
+
);
|
|
1170
|
+
}
|
|
1171
|
+
/**
|
|
1172
|
+
* Update memory level
|
|
1173
|
+
*/
|
|
1174
|
+
async updateMemoryLevel(eventId, level) {
|
|
1175
|
+
await this.initialize();
|
|
1176
|
+
await dbRun(
|
|
1177
|
+
this.db,
|
|
1178
|
+
`UPDATE memory_levels SET level = ?, promoted_at = CURRENT_TIMESTAMP WHERE event_id = ?`,
|
|
1179
|
+
[level, eventId]
|
|
1180
|
+
);
|
|
1181
|
+
}
|
|
1182
|
+
/**
|
|
1183
|
+
* Get memory level statistics
|
|
1184
|
+
*/
|
|
1185
|
+
async getLevelStats() {
|
|
1186
|
+
await this.initialize();
|
|
1187
|
+
const rows = await dbAll(
|
|
1188
|
+
this.db,
|
|
1189
|
+
`SELECT level, COUNT(*) as count FROM memory_levels GROUP BY level`
|
|
1190
|
+
);
|
|
1191
|
+
return rows;
|
|
1192
|
+
}
|
|
1193
|
+
/**
|
|
1194
|
+
* Get events by memory level
|
|
1195
|
+
*/
|
|
1196
|
+
async getEventsByLevel(level, options) {
|
|
1197
|
+
await this.initialize();
|
|
1198
|
+
const limit = options?.limit || 50;
|
|
1199
|
+
const offset = options?.offset || 0;
|
|
1200
|
+
const rows = await dbAll(
|
|
1201
|
+
this.db,
|
|
1202
|
+
`SELECT e.* FROM events e
|
|
1203
|
+
INNER JOIN memory_levels ml ON e.id = ml.event_id
|
|
1204
|
+
WHERE ml.level = ?
|
|
1205
|
+
ORDER BY e.timestamp DESC
|
|
1206
|
+
LIMIT ? OFFSET ?`,
|
|
1207
|
+
[level, limit, offset]
|
|
1208
|
+
);
|
|
1209
|
+
return rows.map((row) => this.rowToEvent(row));
|
|
1210
|
+
}
|
|
1211
|
+
/**
|
|
1212
|
+
* Get memory level for a specific event
|
|
1213
|
+
*/
|
|
1214
|
+
async getEventLevel(eventId) {
|
|
1215
|
+
await this.initialize();
|
|
1216
|
+
const rows = await dbAll(
|
|
1217
|
+
this.db,
|
|
1218
|
+
`SELECT level FROM memory_levels WHERE event_id = ?`,
|
|
1219
|
+
[eventId]
|
|
1220
|
+
);
|
|
1221
|
+
return rows.length > 0 ? rows[0].level : null;
|
|
1222
|
+
}
|
|
1223
|
+
// ============================================================
|
|
1224
|
+
// Endless Mode Helper Methods
|
|
1225
|
+
// ============================================================
|
|
1226
|
+
/**
|
|
1227
|
+
* Get database instance for Endless Mode stores
|
|
1228
|
+
*/
|
|
1229
|
+
getDatabase() {
|
|
1230
|
+
return this.db;
|
|
1231
|
+
}
|
|
1232
|
+
/**
|
|
1233
|
+
* Get config value for endless mode
|
|
1234
|
+
*/
|
|
1235
|
+
async getEndlessConfig(key) {
|
|
1236
|
+
await this.initialize();
|
|
1237
|
+
const rows = await dbAll(
|
|
1238
|
+
this.db,
|
|
1239
|
+
`SELECT value FROM endless_config WHERE key = ?`,
|
|
1240
|
+
[key]
|
|
1241
|
+
);
|
|
1242
|
+
if (rows.length === 0)
|
|
1243
|
+
return null;
|
|
1244
|
+
return JSON.parse(rows[0].value);
|
|
1245
|
+
}
|
|
1246
|
+
/**
|
|
1247
|
+
* Set config value for endless mode
|
|
1248
|
+
*/
|
|
1249
|
+
async setEndlessConfig(key, value) {
|
|
1250
|
+
await this.initialize();
|
|
1251
|
+
await dbRun(
|
|
1252
|
+
this.db,
|
|
1253
|
+
`INSERT OR REPLACE INTO endless_config (key, value, updated_at)
|
|
1254
|
+
VALUES (?, ?, CURRENT_TIMESTAMP)`,
|
|
1255
|
+
[key, JSON.stringify(value)]
|
|
1256
|
+
);
|
|
1257
|
+
}
|
|
1258
|
+
/**
|
|
1259
|
+
* Get all sessions
|
|
1260
|
+
*/
|
|
1261
|
+
async getAllSessions() {
|
|
1262
|
+
await this.initialize();
|
|
1263
|
+
const rows = await dbAll(
|
|
1264
|
+
this.db,
|
|
1265
|
+
`SELECT * FROM sessions ORDER BY started_at DESC`
|
|
1266
|
+
);
|
|
1267
|
+
return rows.map((row) => ({
|
|
1268
|
+
id: row.id,
|
|
1269
|
+
startedAt: toDate(row.started_at),
|
|
1270
|
+
endedAt: row.ended_at ? toDate(row.ended_at) : void 0,
|
|
1271
|
+
projectPath: row.project_path,
|
|
1272
|
+
summary: row.summary,
|
|
1273
|
+
tags: row.tags ? JSON.parse(row.tags) : void 0
|
|
1274
|
+
}));
|
|
1275
|
+
}
|
|
1276
|
+
/**
|
|
1277
|
+
* Increment access count for events (stub for compatibility)
|
|
1278
|
+
*/
|
|
1279
|
+
async incrementAccessCount(eventIds) {
|
|
1280
|
+
return Promise.resolve();
|
|
1281
|
+
}
|
|
1282
|
+
/**
|
|
1283
|
+
* Get most accessed memories (stub for compatibility)
|
|
1284
|
+
*/
|
|
1285
|
+
async getMostAccessed(limit = 10) {
|
|
1286
|
+
return [];
|
|
1287
|
+
}
|
|
1288
|
+
/**
|
|
1289
|
+
* Close database connection
|
|
1290
|
+
*/
|
|
1291
|
+
async close() {
|
|
1292
|
+
await dbClose(this.db);
|
|
1293
|
+
}
|
|
1294
|
+
/**
|
|
1295
|
+
* Convert database row to MemoryEvent
|
|
1296
|
+
*/
|
|
1297
|
+
rowToEvent(row) {
|
|
1298
|
+
return {
|
|
1299
|
+
id: row.id,
|
|
1300
|
+
eventType: row.event_type,
|
|
1301
|
+
sessionId: row.session_id,
|
|
1302
|
+
timestamp: toDate(row.timestamp),
|
|
1303
|
+
content: row.content,
|
|
1304
|
+
canonicalKey: row.canonical_key,
|
|
1305
|
+
dedupeKey: row.dedupe_key,
|
|
1306
|
+
metadata: row.metadata ? JSON.parse(row.metadata) : void 0
|
|
1307
|
+
};
|
|
1308
|
+
}
|
|
1309
|
+
};
|
|
1310
|
+
|
|
1311
|
+
// src/core/sqlite-wrapper.ts
|
|
1312
|
+
import Database from "better-sqlite3";
|
|
1313
|
+
function createSQLiteDatabase(path, options) {
|
|
1314
|
+
const db = new Database(path, {
|
|
1315
|
+
readonly: options?.readonly ?? false
|
|
1316
|
+
});
|
|
1317
|
+
if (!options?.readonly && (options?.walMode ?? true)) {
|
|
1318
|
+
db.pragma("journal_mode = WAL");
|
|
1319
|
+
db.pragma("synchronous = NORMAL");
|
|
1320
|
+
db.pragma("busy_timeout = 5000");
|
|
1321
|
+
}
|
|
1322
|
+
return db;
|
|
1323
|
+
}
|
|
1324
|
+
function sqliteRun(db, sql, params = []) {
|
|
1325
|
+
const stmt = db.prepare(sql);
|
|
1326
|
+
return stmt.run(...params);
|
|
1327
|
+
}
|
|
1328
|
+
function sqliteAll(db, sql, params = []) {
|
|
1329
|
+
const stmt = db.prepare(sql);
|
|
1330
|
+
return stmt.all(...params);
|
|
1331
|
+
}
|
|
1332
|
+
function sqliteGet(db, sql, params = []) {
|
|
1333
|
+
const stmt = db.prepare(sql);
|
|
1334
|
+
return stmt.get(...params);
|
|
1335
|
+
}
|
|
1336
|
+
function sqliteExec(db, sql) {
|
|
1337
|
+
db.exec(sql);
|
|
1338
|
+
}
|
|
1339
|
+
function sqliteClose(db) {
|
|
1340
|
+
db.close();
|
|
1341
|
+
}
|
|
1342
|
+
function sqliteTransaction(db, fn) {
|
|
1343
|
+
return db.transaction(fn)();
|
|
1344
|
+
}
|
|
1345
|
+
function toDateFromSQLite(value) {
|
|
1346
|
+
if (value instanceof Date)
|
|
1347
|
+
return value;
|
|
1348
|
+
if (typeof value === "string")
|
|
1349
|
+
return new Date(value);
|
|
1350
|
+
if (typeof value === "number")
|
|
1351
|
+
return new Date(value);
|
|
1352
|
+
return new Date(String(value));
|
|
1353
|
+
}
|
|
1354
|
+
function toSQLiteTimestamp(date) {
|
|
1355
|
+
return date.toISOString();
|
|
1356
|
+
}
|
|
1357
|
+
|
|
1358
|
+
// src/core/sqlite-event-store.ts
|
|
1359
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
1360
|
+
var SQLiteEventStore = class {
|
|
1361
|
+
constructor(dbPath, options) {
|
|
1362
|
+
this.dbPath = dbPath;
|
|
1363
|
+
this.readOnly = options?.readonly ?? false;
|
|
1364
|
+
this.db = createSQLiteDatabase(dbPath, {
|
|
1365
|
+
readonly: this.readOnly,
|
|
1366
|
+
walMode: !this.readOnly
|
|
1367
|
+
});
|
|
1368
|
+
}
|
|
1369
|
+
db;
|
|
1370
|
+
initialized = false;
|
|
1371
|
+
readOnly;
|
|
1372
|
+
/**
|
|
1373
|
+
* Initialize database schema
|
|
1374
|
+
*/
|
|
1375
|
+
async initialize() {
|
|
1376
|
+
if (this.initialized)
|
|
1377
|
+
return;
|
|
1378
|
+
if (this.readOnly) {
|
|
1379
|
+
this.initialized = true;
|
|
1380
|
+
return;
|
|
1381
|
+
}
|
|
1382
|
+
sqliteExec(this.db, `
|
|
1383
|
+
-- L0 EventStore: Single Source of Truth (immutable, append-only)
|
|
1384
|
+
CREATE TABLE IF NOT EXISTS events (
|
|
1385
|
+
id TEXT PRIMARY KEY,
|
|
1386
|
+
event_type TEXT NOT NULL,
|
|
1387
|
+
session_id TEXT NOT NULL,
|
|
1388
|
+
timestamp TEXT NOT NULL,
|
|
1389
|
+
content TEXT NOT NULL,
|
|
1390
|
+
canonical_key TEXT NOT NULL,
|
|
1391
|
+
dedupe_key TEXT UNIQUE,
|
|
1392
|
+
metadata TEXT,
|
|
1393
|
+
access_count INTEGER DEFAULT 0,
|
|
1394
|
+
last_accessed_at TEXT
|
|
1395
|
+
);
|
|
1396
|
+
|
|
1397
|
+
-- Dedup table for idempotency
|
|
1398
|
+
CREATE TABLE IF NOT EXISTS event_dedup (
|
|
1399
|
+
dedupe_key TEXT PRIMARY KEY,
|
|
1400
|
+
event_id TEXT NOT NULL,
|
|
1401
|
+
created_at TEXT DEFAULT (datetime('now'))
|
|
1402
|
+
);
|
|
1403
|
+
|
|
1404
|
+
-- Session metadata
|
|
1405
|
+
CREATE TABLE IF NOT EXISTS sessions (
|
|
1406
|
+
id TEXT PRIMARY KEY,
|
|
1407
|
+
started_at TEXT NOT NULL,
|
|
1408
|
+
ended_at TEXT,
|
|
1409
|
+
project_path TEXT,
|
|
1410
|
+
summary TEXT,
|
|
1411
|
+
tags TEXT
|
|
1412
|
+
);
|
|
1413
|
+
|
|
1414
|
+
-- Insights (derived data, rebuildable)
|
|
1415
|
+
CREATE TABLE IF NOT EXISTS insights (
|
|
1416
|
+
id TEXT PRIMARY KEY,
|
|
1417
|
+
insight_type TEXT NOT NULL,
|
|
1418
|
+
content TEXT NOT NULL,
|
|
1419
|
+
canonical_key TEXT NOT NULL,
|
|
1420
|
+
confidence REAL,
|
|
1421
|
+
source_events TEXT,
|
|
1422
|
+
created_at TEXT,
|
|
1423
|
+
last_updated TEXT
|
|
1424
|
+
);
|
|
1425
|
+
|
|
1426
|
+
-- Embedding Outbox (Single-Writer Pattern)
|
|
1427
|
+
CREATE TABLE IF NOT EXISTS embedding_outbox (
|
|
1428
|
+
id TEXT PRIMARY KEY,
|
|
1429
|
+
event_id TEXT NOT NULL,
|
|
1430
|
+
content TEXT NOT NULL,
|
|
1431
|
+
status TEXT DEFAULT 'pending',
|
|
1432
|
+
retry_count INTEGER DEFAULT 0,
|
|
1433
|
+
created_at TEXT DEFAULT (datetime('now')),
|
|
1434
|
+
processed_at TEXT,
|
|
1435
|
+
error_message TEXT
|
|
1436
|
+
);
|
|
1437
|
+
|
|
1438
|
+
-- Projection offset tracking
|
|
1439
|
+
CREATE TABLE IF NOT EXISTS projection_offsets (
|
|
1440
|
+
projection_name TEXT PRIMARY KEY,
|
|
1441
|
+
last_event_id TEXT,
|
|
1442
|
+
last_timestamp TEXT,
|
|
1443
|
+
updated_at TEXT DEFAULT (datetime('now'))
|
|
1444
|
+
);
|
|
1445
|
+
|
|
1446
|
+
-- Memory level tracking
|
|
1447
|
+
CREATE TABLE IF NOT EXISTS memory_levels (
|
|
1448
|
+
event_id TEXT PRIMARY KEY,
|
|
1449
|
+
level TEXT NOT NULL DEFAULT 'L0',
|
|
1450
|
+
promoted_at TEXT DEFAULT (datetime('now'))
|
|
1451
|
+
);
|
|
1452
|
+
|
|
1453
|
+
-- Entries (immutable memory units)
|
|
1454
|
+
CREATE TABLE IF NOT EXISTS entries (
|
|
1455
|
+
entry_id TEXT PRIMARY KEY,
|
|
1456
|
+
created_ts TEXT NOT NULL,
|
|
1457
|
+
entry_type TEXT NOT NULL,
|
|
1458
|
+
title TEXT NOT NULL,
|
|
1459
|
+
content_json TEXT NOT NULL,
|
|
1460
|
+
stage TEXT NOT NULL DEFAULT 'raw',
|
|
1461
|
+
status TEXT DEFAULT 'active',
|
|
1462
|
+
superseded_by TEXT,
|
|
1463
|
+
build_id TEXT,
|
|
1464
|
+
evidence_json TEXT,
|
|
1465
|
+
canonical_key TEXT,
|
|
1466
|
+
created_at TEXT DEFAULT (datetime('now'))
|
|
1467
|
+
);
|
|
1468
|
+
|
|
1469
|
+
-- Entities (task/condition/artifact)
|
|
1470
|
+
CREATE TABLE IF NOT EXISTS entities (
|
|
1471
|
+
entity_id TEXT PRIMARY KEY,
|
|
1472
|
+
entity_type TEXT NOT NULL,
|
|
1473
|
+
canonical_key TEXT NOT NULL,
|
|
1474
|
+
title TEXT NOT NULL,
|
|
1475
|
+
stage TEXT NOT NULL DEFAULT 'raw',
|
|
1476
|
+
status TEXT NOT NULL DEFAULT 'active',
|
|
1477
|
+
current_json TEXT NOT NULL,
|
|
1478
|
+
title_norm TEXT,
|
|
1479
|
+
search_text TEXT,
|
|
1480
|
+
created_at TEXT DEFAULT (datetime('now')),
|
|
1481
|
+
updated_at TEXT DEFAULT (datetime('now'))
|
|
1482
|
+
);
|
|
1483
|
+
|
|
1484
|
+
-- Entity aliases for canonical key lookup
|
|
1485
|
+
CREATE TABLE IF NOT EXISTS entity_aliases (
|
|
1486
|
+
entity_type TEXT NOT NULL,
|
|
1487
|
+
canonical_key TEXT NOT NULL,
|
|
1488
|
+
entity_id TEXT NOT NULL,
|
|
1489
|
+
is_primary INTEGER DEFAULT 0,
|
|
1490
|
+
created_at TEXT DEFAULT (datetime('now')),
|
|
1491
|
+
PRIMARY KEY(entity_type, canonical_key)
|
|
1492
|
+
);
|
|
1493
|
+
|
|
1494
|
+
-- Edges (relationships between entries/entities)
|
|
1495
|
+
CREATE TABLE IF NOT EXISTS edges (
|
|
1496
|
+
edge_id TEXT PRIMARY KEY,
|
|
1497
|
+
src_type TEXT NOT NULL,
|
|
1498
|
+
src_id TEXT NOT NULL,
|
|
1499
|
+
rel_type TEXT NOT NULL,
|
|
1500
|
+
dst_type TEXT NOT NULL,
|
|
1501
|
+
dst_id TEXT NOT NULL,
|
|
1502
|
+
meta_json TEXT,
|
|
1503
|
+
created_at TEXT DEFAULT (datetime('now'))
|
|
1504
|
+
);
|
|
1505
|
+
|
|
1506
|
+
-- Vector Outbox V2 Table
|
|
1507
|
+
CREATE TABLE IF NOT EXISTS vector_outbox (
|
|
1508
|
+
job_id TEXT PRIMARY KEY,
|
|
1509
|
+
item_kind TEXT NOT NULL,
|
|
1510
|
+
item_id TEXT NOT NULL,
|
|
1511
|
+
embedding_version TEXT NOT NULL,
|
|
1512
|
+
status TEXT NOT NULL DEFAULT 'pending',
|
|
1513
|
+
retry_count INTEGER DEFAULT 0,
|
|
1514
|
+
error TEXT,
|
|
1515
|
+
created_at TEXT DEFAULT (datetime('now')),
|
|
1516
|
+
updated_at TEXT DEFAULT (datetime('now')),
|
|
1517
|
+
UNIQUE(item_kind, item_id, embedding_version)
|
|
1518
|
+
);
|
|
1519
|
+
|
|
1520
|
+
-- Build Runs
|
|
1521
|
+
CREATE TABLE IF NOT EXISTS build_runs (
|
|
1522
|
+
build_id TEXT PRIMARY KEY,
|
|
1523
|
+
started_at TEXT NOT NULL,
|
|
1524
|
+
finished_at TEXT,
|
|
1525
|
+
extractor_model TEXT NOT NULL,
|
|
1526
|
+
extractor_prompt_hash TEXT NOT NULL,
|
|
1527
|
+
embedder_model TEXT NOT NULL,
|
|
1528
|
+
embedding_version TEXT NOT NULL,
|
|
1529
|
+
idris_version TEXT NOT NULL,
|
|
1530
|
+
schema_version TEXT NOT NULL,
|
|
1531
|
+
status TEXT NOT NULL DEFAULT 'running',
|
|
1532
|
+
error TEXT
|
|
1533
|
+
);
|
|
1534
|
+
|
|
1535
|
+
-- Pipeline Metrics
|
|
1536
|
+
CREATE TABLE IF NOT EXISTS pipeline_metrics (
|
|
1537
|
+
id TEXT PRIMARY KEY,
|
|
1538
|
+
ts TEXT NOT NULL,
|
|
1539
|
+
stage TEXT NOT NULL,
|
|
1540
|
+
latency_ms REAL NOT NULL,
|
|
1541
|
+
success INTEGER NOT NULL,
|
|
1542
|
+
error TEXT,
|
|
1543
|
+
session_id TEXT
|
|
1544
|
+
);
|
|
1545
|
+
|
|
1546
|
+
-- Working Set table (active memory window)
|
|
1547
|
+
CREATE TABLE IF NOT EXISTS working_set (
|
|
1548
|
+
id TEXT PRIMARY KEY,
|
|
1549
|
+
event_id TEXT NOT NULL,
|
|
1550
|
+
added_at TEXT DEFAULT (datetime('now')),
|
|
1551
|
+
relevance_score REAL DEFAULT 1.0,
|
|
1552
|
+
topics TEXT,
|
|
1553
|
+
expires_at TEXT
|
|
1554
|
+
);
|
|
1555
|
+
|
|
1556
|
+
-- Consolidated Memories table (long-term integrated memories)
|
|
1557
|
+
CREATE TABLE IF NOT EXISTS consolidated_memories (
|
|
1558
|
+
memory_id TEXT PRIMARY KEY,
|
|
1559
|
+
summary TEXT NOT NULL,
|
|
1560
|
+
topics TEXT,
|
|
1561
|
+
source_events TEXT,
|
|
1562
|
+
confidence REAL DEFAULT 0.5,
|
|
1563
|
+
created_at TEXT DEFAULT (datetime('now')),
|
|
1564
|
+
accessed_at TEXT,
|
|
1565
|
+
access_count INTEGER DEFAULT 0
|
|
1566
|
+
);
|
|
1567
|
+
|
|
1568
|
+
-- Continuity Log table (tracks context transitions)
|
|
1569
|
+
CREATE TABLE IF NOT EXISTS continuity_log (
|
|
1570
|
+
log_id TEXT PRIMARY KEY,
|
|
1571
|
+
from_context_id TEXT,
|
|
1572
|
+
to_context_id TEXT,
|
|
1573
|
+
continuity_score REAL,
|
|
1574
|
+
transition_type TEXT,
|
|
1575
|
+
created_at TEXT DEFAULT (datetime('now'))
|
|
1576
|
+
);
|
|
1577
|
+
|
|
1578
|
+
-- Endless Mode Config table
|
|
1579
|
+
CREATE TABLE IF NOT EXISTS endless_config (
|
|
1580
|
+
key TEXT PRIMARY KEY,
|
|
1581
|
+
value TEXT,
|
|
1582
|
+
updated_at TEXT DEFAULT (datetime('now'))
|
|
1583
|
+
);
|
|
1584
|
+
|
|
1585
|
+
-- Sync position tracking (for SQLite -> DuckDB sync)
|
|
1586
|
+
CREATE TABLE IF NOT EXISTS sync_positions (
|
|
1587
|
+
target_name TEXT PRIMARY KEY,
|
|
1588
|
+
last_event_id TEXT,
|
|
1589
|
+
last_timestamp TEXT,
|
|
1590
|
+
updated_at TEXT DEFAULT (datetime('now'))
|
|
1591
|
+
);
|
|
1592
|
+
|
|
1593
|
+
-- Create indexes
|
|
1594
|
+
CREATE INDEX IF NOT EXISTS idx_events_session ON events(session_id);
|
|
1595
|
+
CREATE INDEX IF NOT EXISTS idx_events_timestamp ON events(timestamp);
|
|
1596
|
+
CREATE INDEX IF NOT EXISTS idx_entries_type ON entries(entry_type);
|
|
1597
|
+
CREATE INDEX IF NOT EXISTS idx_entries_stage ON entries(stage);
|
|
1598
|
+
CREATE INDEX IF NOT EXISTS idx_entries_canonical ON entries(canonical_key);
|
|
1599
|
+
CREATE INDEX IF NOT EXISTS idx_entities_type_key ON entities(entity_type, canonical_key);
|
|
1600
|
+
CREATE INDEX IF NOT EXISTS idx_entities_status ON entities(status);
|
|
1601
|
+
CREATE INDEX IF NOT EXISTS idx_edges_src ON edges(src_id, rel_type);
|
|
1602
|
+
CREATE INDEX IF NOT EXISTS idx_edges_dst ON edges(dst_id, rel_type);
|
|
1603
|
+
CREATE INDEX IF NOT EXISTS idx_edges_rel ON edges(rel_type);
|
|
1604
|
+
CREATE INDEX IF NOT EXISTS idx_outbox_status ON vector_outbox(status);
|
|
1605
|
+
CREATE INDEX IF NOT EXISTS idx_working_set_expires ON working_set(expires_at);
|
|
1606
|
+
CREATE INDEX IF NOT EXISTS idx_working_set_relevance ON working_set(relevance_score);
|
|
1607
|
+
CREATE INDEX IF NOT EXISTS idx_consolidated_confidence ON consolidated_memories(confidence);
|
|
1608
|
+
CREATE INDEX IF NOT EXISTS idx_continuity_created ON continuity_log(created_at);
|
|
1609
|
+
CREATE INDEX IF NOT EXISTS idx_embedding_outbox_status ON embedding_outbox(status);
|
|
1610
|
+
`);
|
|
1611
|
+
const tableInfo = sqliteAll(this.db, "PRAGMA table_info(events)", []);
|
|
1612
|
+
const columnNames = tableInfo.map((col) => col.name);
|
|
1613
|
+
if (!columnNames.includes("access_count")) {
|
|
1614
|
+
try {
|
|
1615
|
+
sqliteExec(this.db, `
|
|
1616
|
+
ALTER TABLE events ADD COLUMN access_count INTEGER DEFAULT 0;
|
|
1617
|
+
`);
|
|
1618
|
+
} catch (err) {
|
|
1619
|
+
console.error("Error adding access_count column:", err);
|
|
1620
|
+
}
|
|
1621
|
+
}
|
|
1622
|
+
if (!columnNames.includes("last_accessed_at")) {
|
|
1623
|
+
try {
|
|
1624
|
+
sqliteExec(this.db, `
|
|
1625
|
+
ALTER TABLE events ADD COLUMN last_accessed_at TEXT;
|
|
1626
|
+
`);
|
|
1627
|
+
} catch (err) {
|
|
1628
|
+
console.error("Error adding last_accessed_at column:", err);
|
|
1629
|
+
}
|
|
1630
|
+
}
|
|
1631
|
+
try {
|
|
1632
|
+
sqliteExec(this.db, `
|
|
1633
|
+
CREATE INDEX IF NOT EXISTS idx_events_access_count ON events(access_count DESC);
|
|
1634
|
+
`);
|
|
1635
|
+
} catch (err) {
|
|
1636
|
+
}
|
|
1637
|
+
try {
|
|
1638
|
+
sqliteExec(this.db, `
|
|
1639
|
+
CREATE INDEX IF NOT EXISTS idx_events_last_accessed ON events(last_accessed_at DESC);
|
|
1640
|
+
`);
|
|
1641
|
+
} catch (err) {
|
|
1642
|
+
}
|
|
1643
|
+
this.initialized = true;
|
|
1644
|
+
}
|
|
1645
|
+
/**
|
|
1646
|
+
* Append event to store (Append-only, Idempotent)
|
|
1647
|
+
*/
|
|
1648
|
+
async append(input) {
|
|
1649
|
+
await this.initialize();
|
|
1650
|
+
const canonicalKey = makeCanonicalKey(input.content);
|
|
1651
|
+
const dedupeKey = makeDedupeKey(input.content, input.sessionId);
|
|
1652
|
+
const existing = sqliteGet(
|
|
1653
|
+
this.db,
|
|
1654
|
+
`SELECT event_id FROM event_dedup WHERE dedupe_key = ?`,
|
|
1655
|
+
[dedupeKey]
|
|
1656
|
+
);
|
|
1657
|
+
if (existing) {
|
|
1658
|
+
return {
|
|
1659
|
+
success: true,
|
|
1660
|
+
eventId: existing.event_id,
|
|
1661
|
+
isDuplicate: true
|
|
1662
|
+
};
|
|
1663
|
+
}
|
|
1664
|
+
const id = randomUUID2();
|
|
1665
|
+
const timestamp = toSQLiteTimestamp(input.timestamp);
|
|
1666
|
+
try {
|
|
1667
|
+
const insertEvent = this.db.prepare(`
|
|
1668
|
+
INSERT INTO events (id, event_type, session_id, timestamp, content, canonical_key, dedupe_key, metadata)
|
|
1669
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
1670
|
+
`);
|
|
1671
|
+
const insertDedup = this.db.prepare(`
|
|
1672
|
+
INSERT INTO event_dedup (dedupe_key, event_id) VALUES (?, ?)
|
|
1673
|
+
`);
|
|
1674
|
+
const insertLevel = this.db.prepare(`
|
|
1675
|
+
INSERT INTO memory_levels (event_id, level) VALUES (?, 'L0')
|
|
1676
|
+
`);
|
|
1677
|
+
const transaction = this.db.transaction(() => {
|
|
1678
|
+
insertEvent.run(
|
|
1679
|
+
id,
|
|
1680
|
+
input.eventType,
|
|
1681
|
+
input.sessionId,
|
|
1682
|
+
timestamp,
|
|
1683
|
+
input.content,
|
|
1684
|
+
canonicalKey,
|
|
1685
|
+
dedupeKey,
|
|
1686
|
+
JSON.stringify(input.metadata || {})
|
|
1687
|
+
);
|
|
1688
|
+
insertDedup.run(dedupeKey, id);
|
|
1689
|
+
insertLevel.run(id);
|
|
1690
|
+
});
|
|
1691
|
+
transaction();
|
|
1692
|
+
return { success: true, eventId: id, isDuplicate: false };
|
|
1693
|
+
} catch (error) {
|
|
1694
|
+
return {
|
|
1695
|
+
success: false,
|
|
1696
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1697
|
+
};
|
|
1698
|
+
}
|
|
1699
|
+
}
|
|
1700
|
+
/**
|
|
1701
|
+
* Get events by session ID
|
|
1702
|
+
*/
|
|
1703
|
+
async getSessionEvents(sessionId) {
|
|
1704
|
+
await this.initialize();
|
|
1705
|
+
const rows = sqliteAll(
|
|
1706
|
+
this.db,
|
|
1707
|
+
`SELECT * FROM events WHERE session_id = ? ORDER BY timestamp ASC`,
|
|
1708
|
+
[sessionId]
|
|
1709
|
+
);
|
|
1710
|
+
return rows.map(this.rowToEvent);
|
|
1711
|
+
}
|
|
1712
|
+
/**
|
|
1713
|
+
* Get recent events
|
|
1714
|
+
*/
|
|
1715
|
+
async getRecentEvents(limit = 100) {
|
|
1716
|
+
await this.initialize();
|
|
1717
|
+
const rows = sqliteAll(
|
|
1718
|
+
this.db,
|
|
1719
|
+
`SELECT * FROM events ORDER BY timestamp DESC LIMIT ?`,
|
|
1720
|
+
[limit]
|
|
1721
|
+
);
|
|
1722
|
+
return rows.map(this.rowToEvent);
|
|
1723
|
+
}
|
|
1724
|
+
/**
|
|
1725
|
+
* Get event by ID
|
|
1726
|
+
*/
|
|
1727
|
+
async getEvent(id) {
|
|
1728
|
+
await this.initialize();
|
|
1729
|
+
const row = sqliteGet(
|
|
1730
|
+
this.db,
|
|
1731
|
+
`SELECT * FROM events WHERE id = ?`,
|
|
1732
|
+
[id]
|
|
1733
|
+
);
|
|
1734
|
+
if (!row)
|
|
1735
|
+
return null;
|
|
1736
|
+
return this.rowToEvent(row);
|
|
1737
|
+
}
|
|
1738
|
+
/**
|
|
1739
|
+
* Get events since a timestamp (for sync)
|
|
1740
|
+
*/
|
|
1741
|
+
async getEventsSince(timestamp, limit = 1e3) {
|
|
1742
|
+
await this.initialize();
|
|
1743
|
+
const rows = sqliteAll(
|
|
1744
|
+
this.db,
|
|
1745
|
+
`SELECT * FROM events WHERE timestamp > ? ORDER BY timestamp ASC LIMIT ?`,
|
|
1746
|
+
[timestamp, limit]
|
|
1747
|
+
);
|
|
1748
|
+
return rows.map(this.rowToEvent);
|
|
1749
|
+
}
|
|
1750
|
+
/**
|
|
1751
|
+
* Create or update session
|
|
1752
|
+
*/
|
|
1753
|
+
async upsertSession(session) {
|
|
1754
|
+
await this.initialize();
|
|
1755
|
+
const existing = sqliteGet(
|
|
1756
|
+
this.db,
|
|
1757
|
+
`SELECT id FROM sessions WHERE id = ?`,
|
|
1758
|
+
[session.id]
|
|
1759
|
+
);
|
|
1760
|
+
if (!existing) {
|
|
1761
|
+
sqliteRun(
|
|
1762
|
+
this.db,
|
|
1763
|
+
`INSERT INTO sessions (id, started_at, project_path, tags)
|
|
1764
|
+
VALUES (?, ?, ?, ?)`,
|
|
1765
|
+
[
|
|
1766
|
+
session.id,
|
|
1767
|
+
toSQLiteTimestamp(session.startedAt || /* @__PURE__ */ new Date()),
|
|
1768
|
+
session.projectPath || null,
|
|
1769
|
+
JSON.stringify(session.tags || [])
|
|
1770
|
+
]
|
|
1771
|
+
);
|
|
1772
|
+
} else {
|
|
1773
|
+
const updates = [];
|
|
1774
|
+
const values = [];
|
|
1775
|
+
if (session.endedAt) {
|
|
1776
|
+
updates.push("ended_at = ?");
|
|
1777
|
+
values.push(toSQLiteTimestamp(session.endedAt));
|
|
1778
|
+
}
|
|
1779
|
+
if (session.summary) {
|
|
1780
|
+
updates.push("summary = ?");
|
|
1781
|
+
values.push(session.summary);
|
|
1782
|
+
}
|
|
1783
|
+
if (session.tags) {
|
|
1784
|
+
updates.push("tags = ?");
|
|
1785
|
+
values.push(JSON.stringify(session.tags));
|
|
1786
|
+
}
|
|
1787
|
+
if (updates.length > 0) {
|
|
1788
|
+
values.push(session.id);
|
|
1789
|
+
sqliteRun(
|
|
1790
|
+
this.db,
|
|
1791
|
+
`UPDATE sessions SET ${updates.join(", ")} WHERE id = ?`,
|
|
1792
|
+
values
|
|
1793
|
+
);
|
|
1794
|
+
}
|
|
1795
|
+
}
|
|
1796
|
+
}
|
|
1797
|
+
/**
|
|
1798
|
+
* Get session by ID
|
|
1799
|
+
*/
|
|
1800
|
+
async getSession(id) {
|
|
1801
|
+
await this.initialize();
|
|
1802
|
+
const row = sqliteGet(
|
|
1803
|
+
this.db,
|
|
1804
|
+
`SELECT * FROM sessions WHERE id = ?`,
|
|
1805
|
+
[id]
|
|
1806
|
+
);
|
|
1807
|
+
if (!row)
|
|
1808
|
+
return null;
|
|
1809
|
+
return {
|
|
1810
|
+
id: row.id,
|
|
1811
|
+
startedAt: toDateFromSQLite(row.started_at),
|
|
1812
|
+
endedAt: row.ended_at ? toDateFromSQLite(row.ended_at) : void 0,
|
|
1813
|
+
projectPath: row.project_path,
|
|
1814
|
+
summary: row.summary,
|
|
1815
|
+
tags: row.tags ? JSON.parse(row.tags) : void 0
|
|
1816
|
+
};
|
|
1817
|
+
}
|
|
1818
|
+
/**
|
|
1819
|
+
* Get all sessions
|
|
1820
|
+
*/
|
|
1821
|
+
async getAllSessions() {
|
|
1822
|
+
await this.initialize();
|
|
1823
|
+
const rows = sqliteAll(
|
|
1824
|
+
this.db,
|
|
1825
|
+
`SELECT * FROM sessions ORDER BY started_at DESC`
|
|
1826
|
+
);
|
|
1827
|
+
return rows.map((row) => ({
|
|
1828
|
+
id: row.id,
|
|
1829
|
+
startedAt: toDateFromSQLite(row.started_at),
|
|
1830
|
+
endedAt: row.ended_at ? toDateFromSQLite(row.ended_at) : void 0,
|
|
1081
1831
|
projectPath: row.project_path,
|
|
1082
1832
|
summary: row.summary,
|
|
1083
1833
|
tags: row.tags ? JSON.parse(row.tags) : void 0
|
|
1084
|
-
};
|
|
1834
|
+
}));
|
|
1085
1835
|
}
|
|
1086
1836
|
/**
|
|
1087
|
-
* Add to embedding outbox
|
|
1837
|
+
* Add to embedding outbox
|
|
1088
1838
|
*/
|
|
1089
1839
|
async enqueueForEmbedding(eventId, content) {
|
|
1090
1840
|
await this.initialize();
|
|
1091
|
-
const id =
|
|
1092
|
-
|
|
1841
|
+
const id = randomUUID2();
|
|
1842
|
+
sqliteRun(
|
|
1093
1843
|
this.db,
|
|
1094
1844
|
`INSERT INTO embedding_outbox (id, event_id, content, status, retry_count)
|
|
1095
1845
|
VALUES (?, ?, ?, 'pending', 0)`,
|
|
@@ -1102,7 +1852,7 @@ var EventStore = class {
|
|
|
1102
1852
|
*/
|
|
1103
1853
|
async getPendingOutboxItems(limit = 32) {
|
|
1104
1854
|
await this.initialize();
|
|
1105
|
-
const pending =
|
|
1855
|
+
const pending = sqliteAll(
|
|
1106
1856
|
this.db,
|
|
1107
1857
|
`SELECT * FROM embedding_outbox
|
|
1108
1858
|
WHERE status = 'pending'
|
|
@@ -1114,7 +1864,7 @@ var EventStore = class {
|
|
|
1114
1864
|
return [];
|
|
1115
1865
|
const ids = pending.map((r) => r.id);
|
|
1116
1866
|
const placeholders = ids.map(() => "?").join(",");
|
|
1117
|
-
|
|
1867
|
+
sqliteRun(
|
|
1118
1868
|
this.db,
|
|
1119
1869
|
`UPDATE embedding_outbox SET status = 'processing' WHERE id IN (${placeholders})`,
|
|
1120
1870
|
ids
|
|
@@ -1125,7 +1875,7 @@ var EventStore = class {
|
|
|
1125
1875
|
content: row.content,
|
|
1126
1876
|
status: "processing",
|
|
1127
1877
|
retryCount: row.retry_count,
|
|
1128
|
-
createdAt:
|
|
1878
|
+
createdAt: toDateFromSQLite(row.created_at),
|
|
1129
1879
|
errorMessage: row.error_message
|
|
1130
1880
|
}));
|
|
1131
1881
|
}
|
|
@@ -1136,7 +1886,7 @@ var EventStore = class {
|
|
|
1136
1886
|
if (ids.length === 0)
|
|
1137
1887
|
return;
|
|
1138
1888
|
const placeholders = ids.map(() => "?").join(",");
|
|
1139
|
-
|
|
1889
|
+
sqliteRun(
|
|
1140
1890
|
this.db,
|
|
1141
1891
|
`DELETE FROM embedding_outbox WHERE id IN (${placeholders})`,
|
|
1142
1892
|
ids
|
|
@@ -1149,7 +1899,7 @@ var EventStore = class {
|
|
|
1149
1899
|
if (ids.length === 0)
|
|
1150
1900
|
return;
|
|
1151
1901
|
const placeholders = ids.map(() => "?").join(",");
|
|
1152
|
-
|
|
1902
|
+
sqliteRun(
|
|
1153
1903
|
this.db,
|
|
1154
1904
|
`UPDATE embedding_outbox
|
|
1155
1905
|
SET status = CASE WHEN retry_count >= 3 THEN 'failed' ELSE 'pending' END,
|
|
@@ -1164,9 +1914,9 @@ var EventStore = class {
|
|
|
1164
1914
|
*/
|
|
1165
1915
|
async updateMemoryLevel(eventId, level) {
|
|
1166
1916
|
await this.initialize();
|
|
1167
|
-
|
|
1917
|
+
sqliteRun(
|
|
1168
1918
|
this.db,
|
|
1169
|
-
`UPDATE memory_levels SET level = ?, promoted_at =
|
|
1919
|
+
`UPDATE memory_levels SET level = ?, promoted_at = datetime('now') WHERE event_id = ?`,
|
|
1170
1920
|
[level, eventId]
|
|
1171
1921
|
);
|
|
1172
1922
|
}
|
|
@@ -1175,90 +1925,329 @@ var EventStore = class {
|
|
|
1175
1925
|
*/
|
|
1176
1926
|
async getLevelStats() {
|
|
1177
1927
|
await this.initialize();
|
|
1178
|
-
const rows =
|
|
1928
|
+
const rows = sqliteAll(
|
|
1179
1929
|
this.db,
|
|
1180
1930
|
`SELECT level, COUNT(*) as count FROM memory_levels GROUP BY level`
|
|
1181
1931
|
);
|
|
1182
1932
|
return rows;
|
|
1183
1933
|
}
|
|
1184
|
-
// ============================================================
|
|
1185
|
-
// Endless Mode Helper Methods
|
|
1186
|
-
// ============================================================
|
|
1187
1934
|
/**
|
|
1188
|
-
* Get
|
|
1935
|
+
* Get events by memory level
|
|
1189
1936
|
*/
|
|
1190
|
-
|
|
1191
|
-
|
|
1937
|
+
async getEventsByLevel(level, options) {
|
|
1938
|
+
await this.initialize();
|
|
1939
|
+
const limit = options?.limit || 50;
|
|
1940
|
+
const offset = options?.offset || 0;
|
|
1941
|
+
const rows = sqliteAll(
|
|
1942
|
+
this.db,
|
|
1943
|
+
`SELECT e.* FROM events e
|
|
1944
|
+
INNER JOIN memory_levels ml ON e.id = ml.event_id
|
|
1945
|
+
WHERE ml.level = ?
|
|
1946
|
+
ORDER BY e.timestamp DESC
|
|
1947
|
+
LIMIT ? OFFSET ?`,
|
|
1948
|
+
[level, limit, offset]
|
|
1949
|
+
);
|
|
1950
|
+
return rows.map((row) => this.rowToEvent(row));
|
|
1951
|
+
}
|
|
1952
|
+
/**
|
|
1953
|
+
* Get memory level for a specific event
|
|
1954
|
+
*/
|
|
1955
|
+
async getEventLevel(eventId) {
|
|
1956
|
+
await this.initialize();
|
|
1957
|
+
const row = sqliteGet(
|
|
1958
|
+
this.db,
|
|
1959
|
+
`SELECT level FROM memory_levels WHERE event_id = ?`,
|
|
1960
|
+
[eventId]
|
|
1961
|
+
);
|
|
1962
|
+
return row ? row.level : null;
|
|
1963
|
+
}
|
|
1964
|
+
/**
|
|
1965
|
+
* Get sync position for a target
|
|
1966
|
+
*/
|
|
1967
|
+
async getSyncPosition(targetName) {
|
|
1968
|
+
await this.initialize();
|
|
1969
|
+
const row = sqliteGet(
|
|
1970
|
+
this.db,
|
|
1971
|
+
`SELECT last_event_id, last_timestamp FROM sync_positions WHERE target_name = ?`,
|
|
1972
|
+
[targetName]
|
|
1973
|
+
);
|
|
1974
|
+
return {
|
|
1975
|
+
lastEventId: row?.last_event_id ?? null,
|
|
1976
|
+
lastTimestamp: row?.last_timestamp ?? null
|
|
1977
|
+
};
|
|
1978
|
+
}
|
|
1979
|
+
/**
|
|
1980
|
+
* Update sync position for a target
|
|
1981
|
+
*/
|
|
1982
|
+
async updateSyncPosition(targetName, lastEventId, lastTimestamp) {
|
|
1983
|
+
await this.initialize();
|
|
1984
|
+
sqliteRun(
|
|
1985
|
+
this.db,
|
|
1986
|
+
`INSERT OR REPLACE INTO sync_positions (target_name, last_event_id, last_timestamp, updated_at)
|
|
1987
|
+
VALUES (?, ?, ?, datetime('now'))`,
|
|
1988
|
+
[targetName, lastEventId, lastTimestamp]
|
|
1989
|
+
);
|
|
1192
1990
|
}
|
|
1193
1991
|
/**
|
|
1194
1992
|
* Get config value for endless mode
|
|
1195
1993
|
*/
|
|
1196
1994
|
async getEndlessConfig(key) {
|
|
1197
1995
|
await this.initialize();
|
|
1198
|
-
const
|
|
1996
|
+
const row = sqliteGet(
|
|
1199
1997
|
this.db,
|
|
1200
1998
|
`SELECT value FROM endless_config WHERE key = ?`,
|
|
1201
1999
|
[key]
|
|
1202
2000
|
);
|
|
1203
|
-
if (
|
|
2001
|
+
if (!row)
|
|
1204
2002
|
return null;
|
|
1205
|
-
return JSON.parse(
|
|
2003
|
+
return JSON.parse(row.value);
|
|
1206
2004
|
}
|
|
1207
2005
|
/**
|
|
1208
2006
|
* Set config value for endless mode
|
|
1209
2007
|
*/
|
|
1210
2008
|
async setEndlessConfig(key, value) {
|
|
1211
2009
|
await this.initialize();
|
|
1212
|
-
|
|
2010
|
+
sqliteRun(
|
|
1213
2011
|
this.db,
|
|
1214
2012
|
`INSERT OR REPLACE INTO endless_config (key, value, updated_at)
|
|
1215
|
-
VALUES (?, ?,
|
|
2013
|
+
VALUES (?, ?, datetime('now'))`,
|
|
1216
2014
|
[key, JSON.stringify(value)]
|
|
1217
2015
|
);
|
|
1218
2016
|
}
|
|
1219
2017
|
/**
|
|
1220
|
-
*
|
|
2018
|
+
* Increment access count for events
|
|
1221
2019
|
*/
|
|
1222
|
-
async
|
|
2020
|
+
async incrementAccessCount(eventIds) {
|
|
2021
|
+
if (eventIds.length === 0 || this.readOnly)
|
|
2022
|
+
return;
|
|
1223
2023
|
await this.initialize();
|
|
1224
|
-
const
|
|
2024
|
+
const placeholders = eventIds.map(() => "?").join(",");
|
|
2025
|
+
const currentTime = toSQLiteTimestamp(/* @__PURE__ */ new Date());
|
|
2026
|
+
sqliteRun(
|
|
1225
2027
|
this.db,
|
|
1226
|
-
`
|
|
2028
|
+
`UPDATE events
|
|
2029
|
+
SET access_count = access_count + 1,
|
|
2030
|
+
last_accessed_at = ?
|
|
2031
|
+
WHERE id IN (${placeholders})`,
|
|
2032
|
+
[currentTime, ...eventIds]
|
|
1227
2033
|
);
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
2034
|
+
}
|
|
2035
|
+
/**
|
|
2036
|
+
* Get most accessed memories
|
|
2037
|
+
*/
|
|
2038
|
+
async getMostAccessed(limit = 10) {
|
|
2039
|
+
await this.initialize();
|
|
2040
|
+
const rows = sqliteAll(
|
|
2041
|
+
this.db,
|
|
2042
|
+
`SELECT * FROM events
|
|
2043
|
+
WHERE access_count > 0
|
|
2044
|
+
ORDER BY access_count DESC, last_accessed_at DESC
|
|
2045
|
+
LIMIT ?`,
|
|
2046
|
+
[limit]
|
|
2047
|
+
);
|
|
2048
|
+
return rows.map((row) => this.rowToEvent(row));
|
|
2049
|
+
}
|
|
2050
|
+
/**
|
|
2051
|
+
* Get database instance for direct access
|
|
2052
|
+
*/
|
|
2053
|
+
getDatabase() {
|
|
2054
|
+
return this.db;
|
|
1236
2055
|
}
|
|
1237
2056
|
/**
|
|
1238
2057
|
* Close database connection
|
|
1239
2058
|
*/
|
|
1240
2059
|
async close() {
|
|
1241
|
-
|
|
2060
|
+
sqliteClose(this.db);
|
|
1242
2061
|
}
|
|
1243
2062
|
/**
|
|
1244
2063
|
* Convert database row to MemoryEvent
|
|
1245
2064
|
*/
|
|
1246
2065
|
rowToEvent(row) {
|
|
1247
|
-
|
|
2066
|
+
const event = {
|
|
1248
2067
|
id: row.id,
|
|
1249
2068
|
eventType: row.event_type,
|
|
1250
2069
|
sessionId: row.session_id,
|
|
1251
|
-
timestamp:
|
|
2070
|
+
timestamp: toDateFromSQLite(row.timestamp),
|
|
1252
2071
|
content: row.content,
|
|
1253
2072
|
canonicalKey: row.canonical_key,
|
|
1254
2073
|
dedupeKey: row.dedupe_key,
|
|
1255
2074
|
metadata: row.metadata ? JSON.parse(row.metadata) : void 0
|
|
1256
2075
|
};
|
|
2076
|
+
if (row.access_count !== void 0) {
|
|
2077
|
+
event.access_count = row.access_count;
|
|
2078
|
+
}
|
|
2079
|
+
if (row.last_accessed_at !== void 0) {
|
|
2080
|
+
event.last_accessed_at = row.last_accessed_at;
|
|
2081
|
+
}
|
|
2082
|
+
return event;
|
|
2083
|
+
}
|
|
2084
|
+
};
|
|
2085
|
+
|
|
2086
|
+
// src/core/sync-worker.ts
|
|
2087
|
+
var DEFAULT_CONFIG = {
|
|
2088
|
+
intervalMs: 3e4,
|
|
2089
|
+
batchSize: 500,
|
|
2090
|
+
maxRetries: 3,
|
|
2091
|
+
retryDelayMs: 5e3
|
|
2092
|
+
};
|
|
2093
|
+
var SyncWorker = class {
|
|
2094
|
+
constructor(sqliteStore, duckdbStore, config) {
|
|
2095
|
+
this.sqliteStore = sqliteStore;
|
|
2096
|
+
this.duckdbStore = duckdbStore;
|
|
2097
|
+
this.config = { ...DEFAULT_CONFIG, ...config };
|
|
2098
|
+
}
|
|
2099
|
+
config;
|
|
2100
|
+
intervalHandle = null;
|
|
2101
|
+
running = false;
|
|
2102
|
+
stats = {
|
|
2103
|
+
lastSyncAt: null,
|
|
2104
|
+
eventsSynced: 0,
|
|
2105
|
+
sessionsSynced: 0,
|
|
2106
|
+
errors: 0,
|
|
2107
|
+
status: "idle"
|
|
2108
|
+
};
|
|
2109
|
+
/**
|
|
2110
|
+
* Start the sync worker
|
|
2111
|
+
*/
|
|
2112
|
+
start() {
|
|
2113
|
+
if (this.running)
|
|
2114
|
+
return;
|
|
2115
|
+
this.running = true;
|
|
2116
|
+
this.stats.status = "idle";
|
|
2117
|
+
this.syncNow().catch((err) => {
|
|
2118
|
+
console.error("[SyncWorker] Initial sync failed:", err);
|
|
2119
|
+
});
|
|
2120
|
+
this.intervalHandle = setInterval(() => {
|
|
2121
|
+
this.syncNow().catch((err) => {
|
|
2122
|
+
console.error("[SyncWorker] Periodic sync failed:", err);
|
|
2123
|
+
});
|
|
2124
|
+
}, this.config.intervalMs);
|
|
2125
|
+
}
|
|
2126
|
+
/**
|
|
2127
|
+
* Stop the sync worker
|
|
2128
|
+
*/
|
|
2129
|
+
stop() {
|
|
2130
|
+
this.running = false;
|
|
2131
|
+
this.stats.status = "stopped";
|
|
2132
|
+
if (this.intervalHandle) {
|
|
2133
|
+
clearInterval(this.intervalHandle);
|
|
2134
|
+
this.intervalHandle = null;
|
|
2135
|
+
}
|
|
2136
|
+
}
|
|
2137
|
+
/**
|
|
2138
|
+
* Trigger immediate sync
|
|
2139
|
+
*/
|
|
2140
|
+
async syncNow() {
|
|
2141
|
+
if (this.stats.status === "syncing") {
|
|
2142
|
+
return;
|
|
2143
|
+
}
|
|
2144
|
+
this.stats.status = "syncing";
|
|
2145
|
+
try {
|
|
2146
|
+
await this.syncEvents();
|
|
2147
|
+
await this.syncSessions();
|
|
2148
|
+
this.stats.lastSyncAt = /* @__PURE__ */ new Date();
|
|
2149
|
+
this.stats.status = "idle";
|
|
2150
|
+
} catch (error) {
|
|
2151
|
+
this.stats.errors++;
|
|
2152
|
+
this.stats.status = "error";
|
|
2153
|
+
throw error;
|
|
2154
|
+
}
|
|
2155
|
+
}
|
|
2156
|
+
/**
|
|
2157
|
+
* Sync events from SQLite to DuckDB
|
|
2158
|
+
*/
|
|
2159
|
+
async syncEvents() {
|
|
2160
|
+
const targetName = "duckdb_analytics";
|
|
2161
|
+
const position = await this.sqliteStore.getSyncPosition(targetName);
|
|
2162
|
+
const lastTimestamp = position.lastTimestamp || "1970-01-01T00:00:00.000Z";
|
|
2163
|
+
let hasMore = true;
|
|
2164
|
+
let totalSynced = 0;
|
|
2165
|
+
while (hasMore) {
|
|
2166
|
+
const events = await this.sqliteStore.getEventsSince(lastTimestamp, this.config.batchSize);
|
|
2167
|
+
if (events.length === 0) {
|
|
2168
|
+
hasMore = false;
|
|
2169
|
+
break;
|
|
2170
|
+
}
|
|
2171
|
+
await this.retryWithBackoff(async () => {
|
|
2172
|
+
for (const event of events) {
|
|
2173
|
+
await this.insertEventToDuckDB(event);
|
|
2174
|
+
}
|
|
2175
|
+
});
|
|
2176
|
+
totalSynced += events.length;
|
|
2177
|
+
const lastEvent = events[events.length - 1];
|
|
2178
|
+
await this.sqliteStore.updateSyncPosition(
|
|
2179
|
+
targetName,
|
|
2180
|
+
lastEvent.id,
|
|
2181
|
+
lastEvent.timestamp.toISOString()
|
|
2182
|
+
);
|
|
2183
|
+
hasMore = events.length === this.config.batchSize;
|
|
2184
|
+
}
|
|
2185
|
+
this.stats.eventsSynced += totalSynced;
|
|
2186
|
+
}
|
|
2187
|
+
/**
|
|
2188
|
+
* Sync sessions from SQLite to DuckDB
|
|
2189
|
+
*/
|
|
2190
|
+
async syncSessions() {
|
|
2191
|
+
const sessions = await this.sqliteStore.getAllSessions();
|
|
2192
|
+
for (const session of sessions) {
|
|
2193
|
+
await this.retryWithBackoff(async () => {
|
|
2194
|
+
await this.duckdbStore.upsertSession(session);
|
|
2195
|
+
});
|
|
2196
|
+
}
|
|
2197
|
+
this.stats.sessionsSynced = sessions.length;
|
|
2198
|
+
}
|
|
2199
|
+
/**
|
|
2200
|
+
* Insert a single event into DuckDB
|
|
2201
|
+
*/
|
|
2202
|
+
async insertEventToDuckDB(event) {
|
|
2203
|
+
await this.duckdbStore.append({
|
|
2204
|
+
eventType: event.eventType,
|
|
2205
|
+
sessionId: event.sessionId,
|
|
2206
|
+
timestamp: event.timestamp,
|
|
2207
|
+
content: event.content,
|
|
2208
|
+
metadata: event.metadata
|
|
2209
|
+
});
|
|
2210
|
+
}
|
|
2211
|
+
/**
|
|
2212
|
+
* Retry operation with exponential backoff
|
|
2213
|
+
*/
|
|
2214
|
+
async retryWithBackoff(fn) {
|
|
2215
|
+
let lastError = null;
|
|
2216
|
+
for (let attempt = 0; attempt < this.config.maxRetries; attempt++) {
|
|
2217
|
+
try {
|
|
2218
|
+
return await fn();
|
|
2219
|
+
} catch (error) {
|
|
2220
|
+
lastError = error instanceof Error ? error : new Error(String(error));
|
|
2221
|
+
if (attempt < this.config.maxRetries - 1) {
|
|
2222
|
+
const delay = this.config.retryDelayMs * Math.pow(2, attempt);
|
|
2223
|
+
await this.sleep(delay);
|
|
2224
|
+
}
|
|
2225
|
+
}
|
|
2226
|
+
}
|
|
2227
|
+
throw lastError;
|
|
2228
|
+
}
|
|
2229
|
+
/**
|
|
2230
|
+
* Sleep utility
|
|
2231
|
+
*/
|
|
2232
|
+
sleep(ms) {
|
|
2233
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
2234
|
+
}
|
|
2235
|
+
/**
|
|
2236
|
+
* Get sync statistics
|
|
2237
|
+
*/
|
|
2238
|
+
getStats() {
|
|
2239
|
+
return { ...this.stats };
|
|
2240
|
+
}
|
|
2241
|
+
/**
|
|
2242
|
+
* Check if worker is running
|
|
2243
|
+
*/
|
|
2244
|
+
isRunning() {
|
|
2245
|
+
return this.running;
|
|
1257
2246
|
}
|
|
1258
2247
|
};
|
|
1259
2248
|
|
|
1260
2249
|
// src/core/entity-repo.ts
|
|
1261
|
-
import { randomUUID as
|
|
2250
|
+
import { randomUUID as randomUUID3 } from "crypto";
|
|
1262
2251
|
var EntityRepo = class {
|
|
1263
2252
|
constructor(db) {
|
|
1264
2253
|
this.db = db;
|
|
@@ -1267,7 +2256,7 @@ var EntityRepo = class {
|
|
|
1267
2256
|
* Create a new entity
|
|
1268
2257
|
*/
|
|
1269
2258
|
async create(input) {
|
|
1270
|
-
const entityId =
|
|
2259
|
+
const entityId = randomUUID3();
|
|
1271
2260
|
const canonicalKey = makeEntityCanonicalKey(input.entityType, input.title, {
|
|
1272
2261
|
project: input.project
|
|
1273
2262
|
});
|
|
@@ -1521,7 +2510,7 @@ var EntityRepo = class {
|
|
|
1521
2510
|
};
|
|
1522
2511
|
|
|
1523
2512
|
// src/core/edge-repo.ts
|
|
1524
|
-
import { randomUUID as
|
|
2513
|
+
import { randomUUID as randomUUID4 } from "crypto";
|
|
1525
2514
|
var EdgeRepo = class {
|
|
1526
2515
|
constructor(db) {
|
|
1527
2516
|
this.db = db;
|
|
@@ -1530,7 +2519,7 @@ var EdgeRepo = class {
|
|
|
1530
2519
|
* Create a new edge (idempotent - ignores duplicates)
|
|
1531
2520
|
*/
|
|
1532
2521
|
async create(input) {
|
|
1533
|
-
const edgeId =
|
|
2522
|
+
const edgeId = randomUUID4();
|
|
1534
2523
|
const now = /* @__PURE__ */ new Date();
|
|
1535
2524
|
await dbRun(
|
|
1536
2525
|
this.db,
|
|
@@ -2003,8 +2992,8 @@ function getDefaultEmbedder() {
|
|
|
2003
2992
|
}
|
|
2004
2993
|
|
|
2005
2994
|
// src/core/vector-outbox.ts
|
|
2006
|
-
import { randomUUID as
|
|
2007
|
-
var
|
|
2995
|
+
import { randomUUID as randomUUID5 } from "crypto";
|
|
2996
|
+
var DEFAULT_CONFIG2 = {
|
|
2008
2997
|
embeddingVersion: "v1",
|
|
2009
2998
|
maxRetries: 3,
|
|
2010
2999
|
stuckThresholdMs: 5 * 60 * 1e3,
|
|
@@ -2014,7 +3003,7 @@ var DEFAULT_CONFIG = {
|
|
|
2014
3003
|
var VectorOutbox = class {
|
|
2015
3004
|
constructor(db, config) {
|
|
2016
3005
|
this.db = db;
|
|
2017
|
-
this.config = { ...
|
|
3006
|
+
this.config = { ...DEFAULT_CONFIG2, ...config };
|
|
2018
3007
|
}
|
|
2019
3008
|
config;
|
|
2020
3009
|
/**
|
|
@@ -2022,7 +3011,7 @@ var VectorOutbox = class {
|
|
|
2022
3011
|
*/
|
|
2023
3012
|
async enqueue(itemKind, itemId, embeddingVersion) {
|
|
2024
3013
|
const version = embeddingVersion ?? this.config.embeddingVersion;
|
|
2025
|
-
const jobId =
|
|
3014
|
+
const jobId = randomUUID5();
|
|
2026
3015
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
2027
3016
|
await dbRun(
|
|
2028
3017
|
this.db,
|
|
@@ -2242,7 +3231,7 @@ var VectorOutbox = class {
|
|
|
2242
3231
|
};
|
|
2243
3232
|
|
|
2244
3233
|
// src/core/vector-worker.ts
|
|
2245
|
-
var
|
|
3234
|
+
var DEFAULT_CONFIG3 = {
|
|
2246
3235
|
batchSize: 32,
|
|
2247
3236
|
pollIntervalMs: 1e3,
|
|
2248
3237
|
maxRetries: 3
|
|
@@ -2253,12 +3242,13 @@ var VectorWorker = class {
|
|
|
2253
3242
|
embedder;
|
|
2254
3243
|
config;
|
|
2255
3244
|
running = false;
|
|
3245
|
+
stopping = false;
|
|
2256
3246
|
pollTimeout = null;
|
|
2257
3247
|
constructor(eventStore, vectorStore, embedder, config = {}) {
|
|
2258
3248
|
this.eventStore = eventStore;
|
|
2259
3249
|
this.vectorStore = vectorStore;
|
|
2260
3250
|
this.embedder = embedder;
|
|
2261
|
-
this.config = { ...
|
|
3251
|
+
this.config = { ...DEFAULT_CONFIG3, ...config };
|
|
2262
3252
|
}
|
|
2263
3253
|
/**
|
|
2264
3254
|
* Start the worker polling loop
|
|
@@ -2267,6 +3257,7 @@ var VectorWorker = class {
|
|
|
2267
3257
|
if (this.running)
|
|
2268
3258
|
return;
|
|
2269
3259
|
this.running = true;
|
|
3260
|
+
this.stopping = false;
|
|
2270
3261
|
this.poll();
|
|
2271
3262
|
}
|
|
2272
3263
|
/**
|
|
@@ -2274,6 +3265,7 @@ var VectorWorker = class {
|
|
|
2274
3265
|
*/
|
|
2275
3266
|
stop() {
|
|
2276
3267
|
this.running = false;
|
|
3268
|
+
this.stopping = true;
|
|
2277
3269
|
if (this.pollTimeout) {
|
|
2278
3270
|
clearTimeout(this.pollTimeout);
|
|
2279
3271
|
this.pollTimeout = null;
|
|
@@ -2323,9 +3315,15 @@ var VectorWorker = class {
|
|
|
2323
3315
|
}
|
|
2324
3316
|
return successful.length;
|
|
2325
3317
|
} catch (error) {
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
3318
|
+
if (!this.stopping) {
|
|
3319
|
+
try {
|
|
3320
|
+
const allIds = items.map((i) => i.id);
|
|
3321
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
3322
|
+
await this.eventStore.failOutboxItems(allIds, errorMessage);
|
|
3323
|
+
} catch (failError) {
|
|
3324
|
+
console.warn("Could not mark outbox items as failed (database may be closed)");
|
|
3325
|
+
}
|
|
3326
|
+
}
|
|
2329
3327
|
throw error;
|
|
2330
3328
|
}
|
|
2331
3329
|
}
|
|
@@ -2333,14 +3331,18 @@ var VectorWorker = class {
|
|
|
2333
3331
|
* Poll for new items
|
|
2334
3332
|
*/
|
|
2335
3333
|
async poll() {
|
|
2336
|
-
if (!this.running)
|
|
3334
|
+
if (!this.running || this.stopping)
|
|
2337
3335
|
return;
|
|
2338
3336
|
try {
|
|
2339
3337
|
await this.processBatch();
|
|
2340
3338
|
} catch (error) {
|
|
2341
|
-
|
|
3339
|
+
if (!this.stopping) {
|
|
3340
|
+
console.error("Vector worker error:", error);
|
|
3341
|
+
}
|
|
3342
|
+
}
|
|
3343
|
+
if (this.running && !this.stopping) {
|
|
3344
|
+
this.pollTimeout = setTimeout(() => this.poll(), this.config.pollIntervalMs);
|
|
2342
3345
|
}
|
|
2343
|
-
this.pollTimeout = setTimeout(() => this.poll(), this.config.pollIntervalMs);
|
|
2344
3346
|
}
|
|
2345
3347
|
/**
|
|
2346
3348
|
* Process all pending items (blocking)
|
|
@@ -2450,6 +3452,7 @@ var VectorWorkerV2 = class {
|
|
|
2450
3452
|
contentProvider;
|
|
2451
3453
|
config;
|
|
2452
3454
|
running = false;
|
|
3455
|
+
stopping = false;
|
|
2453
3456
|
pollTimeout = null;
|
|
2454
3457
|
constructor(db, vectorStore, embedder, config = {}, contentProvider) {
|
|
2455
3458
|
this.outbox = new VectorOutbox(db, {
|
|
@@ -2468,6 +3471,7 @@ var VectorWorkerV2 = class {
|
|
|
2468
3471
|
if (this.running)
|
|
2469
3472
|
return;
|
|
2470
3473
|
this.running = true;
|
|
3474
|
+
this.stopping = false;
|
|
2471
3475
|
this.poll();
|
|
2472
3476
|
}
|
|
2473
3477
|
/**
|
|
@@ -2475,6 +3479,7 @@ var VectorWorkerV2 = class {
|
|
|
2475
3479
|
*/
|
|
2476
3480
|
stop() {
|
|
2477
3481
|
this.running = false;
|
|
3482
|
+
this.stopping = true;
|
|
2478
3483
|
if (this.pollTimeout) {
|
|
2479
3484
|
clearTimeout(this.pollTimeout);
|
|
2480
3485
|
this.pollTimeout = null;
|
|
@@ -2495,8 +3500,13 @@ var VectorWorkerV2 = class {
|
|
|
2495
3500
|
await this.outbox.markDone(job.jobId);
|
|
2496
3501
|
successCount++;
|
|
2497
3502
|
} catch (error) {
|
|
2498
|
-
|
|
2499
|
-
|
|
3503
|
+
if (!this.stopping) {
|
|
3504
|
+
try {
|
|
3505
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
3506
|
+
await this.outbox.markFailed(job.jobId, errorMessage);
|
|
3507
|
+
} catch {
|
|
3508
|
+
}
|
|
3509
|
+
}
|
|
2500
3510
|
}
|
|
2501
3511
|
}
|
|
2502
3512
|
return successCount;
|
|
@@ -2529,14 +3539,18 @@ var VectorWorkerV2 = class {
|
|
|
2529
3539
|
* Poll for new jobs
|
|
2530
3540
|
*/
|
|
2531
3541
|
async poll() {
|
|
2532
|
-
if (!this.running)
|
|
3542
|
+
if (!this.running || this.stopping)
|
|
2533
3543
|
return;
|
|
2534
3544
|
try {
|
|
2535
3545
|
await this.processBatch();
|
|
2536
3546
|
} catch (error) {
|
|
2537
|
-
|
|
3547
|
+
if (!this.stopping) {
|
|
3548
|
+
console.error("Vector worker V2 error:", error);
|
|
3549
|
+
}
|
|
3550
|
+
}
|
|
3551
|
+
if (this.running && !this.stopping) {
|
|
3552
|
+
this.pollTimeout = setTimeout(() => this.poll(), this.config.pollIntervalMs);
|
|
2538
3553
|
}
|
|
2539
|
-
this.pollTimeout = setTimeout(() => this.poll(), this.config.pollIntervalMs);
|
|
2540
3554
|
}
|
|
2541
3555
|
/**
|
|
2542
3556
|
* Process all pending jobs (blocking)
|
|
@@ -2580,7 +3594,7 @@ function createVectorWorkerV2(db, vectorStore, embedder, config) {
|
|
|
2580
3594
|
}
|
|
2581
3595
|
|
|
2582
3596
|
// src/core/matcher.ts
|
|
2583
|
-
var
|
|
3597
|
+
var DEFAULT_CONFIG4 = {
|
|
2584
3598
|
weights: {
|
|
2585
3599
|
semanticSimilarity: 0.4,
|
|
2586
3600
|
ftsScore: 0.25,
|
|
@@ -2595,9 +3609,9 @@ var Matcher = class {
|
|
|
2595
3609
|
config;
|
|
2596
3610
|
constructor(config = {}) {
|
|
2597
3611
|
this.config = {
|
|
2598
|
-
...
|
|
3612
|
+
...DEFAULT_CONFIG4,
|
|
2599
3613
|
...config,
|
|
2600
|
-
weights: { ...
|
|
3614
|
+
weights: { ...DEFAULT_CONFIG4.weights, ...config.weights }
|
|
2601
3615
|
};
|
|
2602
3616
|
}
|
|
2603
3617
|
/**
|
|
@@ -3167,6 +4181,7 @@ var Retriever = class {
|
|
|
3167
4181
|
matcher;
|
|
3168
4182
|
sharedStore;
|
|
3169
4183
|
sharedVectorStore;
|
|
4184
|
+
graduation;
|
|
3170
4185
|
constructor(eventStore, vectorStore, embedder, matcher, sharedOptions) {
|
|
3171
4186
|
this.eventStore = eventStore;
|
|
3172
4187
|
this.vectorStore = vectorStore;
|
|
@@ -3175,6 +4190,12 @@ var Retriever = class {
|
|
|
3175
4190
|
this.sharedStore = sharedOptions?.sharedStore;
|
|
3176
4191
|
this.sharedVectorStore = sharedOptions?.sharedVectorStore;
|
|
3177
4192
|
}
|
|
4193
|
+
/**
|
|
4194
|
+
* Set graduation pipeline for access tracking
|
|
4195
|
+
*/
|
|
4196
|
+
setGraduationPipeline(graduation) {
|
|
4197
|
+
this.graduation = graduation;
|
|
4198
|
+
}
|
|
3178
4199
|
/**
|
|
3179
4200
|
* Set shared stores after construction
|
|
3180
4201
|
*/
|
|
@@ -3297,6 +4318,13 @@ var Retriever = class {
|
|
|
3297
4318
|
const event = await this.eventStore.getEvent(result.eventId);
|
|
3298
4319
|
if (!event)
|
|
3299
4320
|
continue;
|
|
4321
|
+
if (this.graduation) {
|
|
4322
|
+
this.graduation.recordAccess(
|
|
4323
|
+
event.id,
|
|
4324
|
+
options.sessionId || "unknown",
|
|
4325
|
+
result.score
|
|
4326
|
+
);
|
|
4327
|
+
}
|
|
3300
4328
|
let sessionContext;
|
|
3301
4329
|
if (options.includeSessionContext) {
|
|
3302
4330
|
sessionContext = await this.getSessionContext(event.sessionId, event.id);
|
|
@@ -3418,15 +4446,26 @@ var GraduationPipeline = class {
|
|
|
3418
4446
|
L3toL4: { ...DEFAULT_CRITERIA.L3toL4, ...criteria.L3toL4 }
|
|
3419
4447
|
};
|
|
3420
4448
|
}
|
|
4449
|
+
// Track which sessions have accessed each event
|
|
4450
|
+
sessionAccesses = /* @__PURE__ */ new Map();
|
|
3421
4451
|
/**
|
|
3422
4452
|
* Record an access to an event (used for graduation scoring)
|
|
3423
4453
|
*/
|
|
3424
4454
|
recordAccess(eventId, fromSessionId, confidence = 1) {
|
|
3425
4455
|
const existing = this.metrics.get(eventId);
|
|
4456
|
+
if (!this.sessionAccesses.has(eventId)) {
|
|
4457
|
+
this.sessionAccesses.set(eventId, /* @__PURE__ */ new Set());
|
|
4458
|
+
}
|
|
4459
|
+
const sessions = this.sessionAccesses.get(eventId);
|
|
4460
|
+
const isNewSession = !sessions.has(fromSessionId);
|
|
4461
|
+
sessions.add(fromSessionId);
|
|
3426
4462
|
if (existing) {
|
|
3427
4463
|
existing.accessCount++;
|
|
3428
4464
|
existing.lastAccessed = /* @__PURE__ */ new Date();
|
|
3429
4465
|
existing.confidence = Math.max(existing.confidence, confidence);
|
|
4466
|
+
if (isNewSession && sessions.size > 1) {
|
|
4467
|
+
existing.crossSessionRefs = sessions.size - 1;
|
|
4468
|
+
}
|
|
3430
4469
|
} else {
|
|
3431
4470
|
this.metrics.set(eventId, {
|
|
3432
4471
|
eventId,
|
|
@@ -3631,8 +4670,129 @@ function createGraduationPipeline(eventStore) {
|
|
|
3631
4670
|
return new GraduationPipeline(eventStore);
|
|
3632
4671
|
}
|
|
3633
4672
|
|
|
4673
|
+
// src/core/graduation-worker.ts
|
|
4674
|
+
var DEFAULT_CONFIG5 = {
|
|
4675
|
+
evaluationIntervalMs: 3e5,
|
|
4676
|
+
// 5 minutes
|
|
4677
|
+
batchSize: 50,
|
|
4678
|
+
cooldownMs: 36e5
|
|
4679
|
+
// 1 hour cooldown between evaluations
|
|
4680
|
+
};
|
|
4681
|
+
var GraduationWorker = class {
|
|
4682
|
+
constructor(eventStore, graduation, config = DEFAULT_CONFIG5) {
|
|
4683
|
+
this.eventStore = eventStore;
|
|
4684
|
+
this.graduation = graduation;
|
|
4685
|
+
this.config = config;
|
|
4686
|
+
}
|
|
4687
|
+
running = false;
|
|
4688
|
+
timeout = null;
|
|
4689
|
+
lastEvaluated = /* @__PURE__ */ new Map();
|
|
4690
|
+
/**
|
|
4691
|
+
* Start the graduation worker
|
|
4692
|
+
*/
|
|
4693
|
+
start() {
|
|
4694
|
+
if (this.running)
|
|
4695
|
+
return;
|
|
4696
|
+
this.running = true;
|
|
4697
|
+
this.scheduleNext();
|
|
4698
|
+
}
|
|
4699
|
+
/**
|
|
4700
|
+
* Stop the graduation worker
|
|
4701
|
+
*/
|
|
4702
|
+
stop() {
|
|
4703
|
+
this.running = false;
|
|
4704
|
+
if (this.timeout) {
|
|
4705
|
+
clearTimeout(this.timeout);
|
|
4706
|
+
this.timeout = null;
|
|
4707
|
+
}
|
|
4708
|
+
}
|
|
4709
|
+
/**
|
|
4710
|
+
* Check if currently running
|
|
4711
|
+
*/
|
|
4712
|
+
isRunning() {
|
|
4713
|
+
return this.running;
|
|
4714
|
+
}
|
|
4715
|
+
/**
|
|
4716
|
+
* Force a graduation evaluation run
|
|
4717
|
+
*/
|
|
4718
|
+
async forceRun() {
|
|
4719
|
+
return await this.runGraduation();
|
|
4720
|
+
}
|
|
4721
|
+
/**
|
|
4722
|
+
* Schedule the next graduation check
|
|
4723
|
+
*/
|
|
4724
|
+
scheduleNext() {
|
|
4725
|
+
if (!this.running)
|
|
4726
|
+
return;
|
|
4727
|
+
this.timeout = setTimeout(
|
|
4728
|
+
() => this.run(),
|
|
4729
|
+
this.config.evaluationIntervalMs
|
|
4730
|
+
);
|
|
4731
|
+
}
|
|
4732
|
+
/**
|
|
4733
|
+
* Run graduation evaluation
|
|
4734
|
+
*/
|
|
4735
|
+
async run() {
|
|
4736
|
+
if (!this.running)
|
|
4737
|
+
return;
|
|
4738
|
+
try {
|
|
4739
|
+
await this.runGraduation();
|
|
4740
|
+
} catch (error) {
|
|
4741
|
+
console.error("Graduation error:", error);
|
|
4742
|
+
}
|
|
4743
|
+
this.scheduleNext();
|
|
4744
|
+
}
|
|
4745
|
+
/**
|
|
4746
|
+
* Perform graduation evaluation across all levels
|
|
4747
|
+
*/
|
|
4748
|
+
async runGraduation() {
|
|
4749
|
+
const result = {
|
|
4750
|
+
evaluated: 0,
|
|
4751
|
+
graduated: 0,
|
|
4752
|
+
byLevel: {}
|
|
4753
|
+
};
|
|
4754
|
+
const levels = ["L0", "L1", "L2", "L3"];
|
|
4755
|
+
const now = Date.now();
|
|
4756
|
+
for (const level of levels) {
|
|
4757
|
+
const events = await this.eventStore.getEventsByLevel(level, {
|
|
4758
|
+
limit: this.config.batchSize
|
|
4759
|
+
});
|
|
4760
|
+
let levelGraduated = 0;
|
|
4761
|
+
for (const event of events) {
|
|
4762
|
+
const lastEval = this.lastEvaluated.get(event.id);
|
|
4763
|
+
if (lastEval && now - lastEval < this.config.cooldownMs) {
|
|
4764
|
+
continue;
|
|
4765
|
+
}
|
|
4766
|
+
result.evaluated++;
|
|
4767
|
+
this.lastEvaluated.set(event.id, now);
|
|
4768
|
+
const gradResult = await this.graduation.evaluateGraduation(event.id, level);
|
|
4769
|
+
if (gradResult.success) {
|
|
4770
|
+
result.graduated++;
|
|
4771
|
+
levelGraduated++;
|
|
4772
|
+
}
|
|
4773
|
+
}
|
|
4774
|
+
if (levelGraduated > 0) {
|
|
4775
|
+
result.byLevel[level] = levelGraduated;
|
|
4776
|
+
}
|
|
4777
|
+
}
|
|
4778
|
+
if (this.lastEvaluated.size > 1e3) {
|
|
4779
|
+
const entries = Array.from(this.lastEvaluated.entries());
|
|
4780
|
+
entries.sort((a, b) => b[1] - a[1]);
|
|
4781
|
+
this.lastEvaluated = new Map(entries.slice(0, 1e3));
|
|
4782
|
+
}
|
|
4783
|
+
return result;
|
|
4784
|
+
}
|
|
4785
|
+
};
|
|
4786
|
+
function createGraduationWorker(eventStore, graduation, config) {
|
|
4787
|
+
return new GraduationWorker(
|
|
4788
|
+
eventStore,
|
|
4789
|
+
graduation,
|
|
4790
|
+
{ ...DEFAULT_CONFIG5, ...config }
|
|
4791
|
+
);
|
|
4792
|
+
}
|
|
4793
|
+
|
|
3634
4794
|
// src/core/task/task-matcher.ts
|
|
3635
|
-
var
|
|
4795
|
+
var DEFAULT_CONFIG6 = {
|
|
3636
4796
|
minCombinedScore: MATCH_THRESHOLDS.minCombinedScore,
|
|
3637
4797
|
minGap: MATCH_THRESHOLDS.minGap,
|
|
3638
4798
|
suggestionThreshold: MATCH_THRESHOLDS.suggestionThreshold,
|
|
@@ -3641,7 +4801,7 @@ var DEFAULT_CONFIG4 = {
|
|
|
3641
4801
|
var TaskMatcher = class {
|
|
3642
4802
|
constructor(db, config) {
|
|
3643
4803
|
this.db = db;
|
|
3644
|
-
this.config = { ...
|
|
4804
|
+
this.config = { ...DEFAULT_CONFIG6, ...config };
|
|
3645
4805
|
}
|
|
3646
4806
|
config;
|
|
3647
4807
|
/**
|
|
@@ -3805,7 +4965,7 @@ var TaskMatcher = class {
|
|
|
3805
4965
|
};
|
|
3806
4966
|
|
|
3807
4967
|
// src/core/task/blocker-resolver.ts
|
|
3808
|
-
import { randomUUID as
|
|
4968
|
+
import { randomUUID as randomUUID6 } from "crypto";
|
|
3809
4969
|
var URL_PATTERN = /^https?:\/\/.+/;
|
|
3810
4970
|
var JIRA_PATTERN = /^[A-Z]+-\d+$/;
|
|
3811
4971
|
var GITHUB_ISSUE_PATTERN = /^[^\/]+\/[^#]+#\d+$/;
|
|
@@ -3942,7 +5102,7 @@ var BlockerResolver = class {
|
|
|
3942
5102
|
* Declare a new condition entity
|
|
3943
5103
|
*/
|
|
3944
5104
|
async declareCondition(text, canonicalKey, candidates) {
|
|
3945
|
-
const entityId =
|
|
5105
|
+
const entityId = randomUUID6();
|
|
3946
5106
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
3947
5107
|
const currentJson = {
|
|
3948
5108
|
text,
|
|
@@ -3985,7 +5145,7 @@ var BlockerResolver = class {
|
|
|
3985
5145
|
* Declare a new artifact entity
|
|
3986
5146
|
*/
|
|
3987
5147
|
async declareArtifact(identifier, canonicalKey) {
|
|
3988
|
-
const entityId =
|
|
5148
|
+
const entityId = randomUUID6();
|
|
3989
5149
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
3990
5150
|
let artifactType = "generic";
|
|
3991
5151
|
if (URL_PATTERN.test(identifier)) {
|
|
@@ -4050,7 +5210,7 @@ var BlockerResolver = class {
|
|
|
4050
5210
|
};
|
|
4051
5211
|
|
|
4052
5212
|
// src/core/task/task-resolver.ts
|
|
4053
|
-
import { randomUUID as
|
|
5213
|
+
import { randomUUID as randomUUID7 } from "crypto";
|
|
4054
5214
|
var VALID_TRANSITIONS = {
|
|
4055
5215
|
pending: ["in_progress", "cancelled"],
|
|
4056
5216
|
in_progress: ["blocked", "done", "cancelled"],
|
|
@@ -4125,7 +5285,7 @@ var TaskResolver = class {
|
|
|
4125
5285
|
isNew: false
|
|
4126
5286
|
};
|
|
4127
5287
|
}
|
|
4128
|
-
const taskId =
|
|
5288
|
+
const taskId = randomUUID7();
|
|
4129
5289
|
const canonicalKey = makeEntityCanonicalKey("task", extracted.title, {
|
|
4130
5290
|
project: extracted.project
|
|
4131
5291
|
});
|
|
@@ -4278,7 +5438,7 @@ var TaskResolver = class {
|
|
|
4278
5438
|
* Emit task event to events table
|
|
4279
5439
|
*/
|
|
4280
5440
|
async emitTaskEvent(eventType, payload) {
|
|
4281
|
-
const eventId =
|
|
5441
|
+
const eventId = randomUUID7();
|
|
4282
5442
|
const now = /* @__PURE__ */ new Date();
|
|
4283
5443
|
const dedupeKey = makeTaskEventDedupeKey(
|
|
4284
5444
|
eventType,
|
|
@@ -4336,14 +5496,14 @@ var TaskResolver = class {
|
|
|
4336
5496
|
`INSERT INTO edges (edge_id, src_type, src_id, rel_type, dst_type, dst_id, meta_json)
|
|
4337
5497
|
VALUES (?, 'entity', ?, 'resolves_to', 'entity', ?, ?)
|
|
4338
5498
|
ON CONFLICT DO NOTHING`,
|
|
4339
|
-
[
|
|
5499
|
+
[randomUUID7(), conditionId, taskId, JSON.stringify({ resolved_at: (/* @__PURE__ */ new Date()).toISOString() })]
|
|
4340
5500
|
);
|
|
4341
5501
|
return eventId;
|
|
4342
5502
|
}
|
|
4343
5503
|
};
|
|
4344
5504
|
|
|
4345
5505
|
// src/core/task/task-projector.ts
|
|
4346
|
-
import { randomUUID as
|
|
5506
|
+
import { randomUUID as randomUUID8 } from "crypto";
|
|
4347
5507
|
var PROJECTOR_NAME = "task_projector";
|
|
4348
5508
|
var TASK_EVENT_TYPES = [
|
|
4349
5509
|
"task_created",
|
|
@@ -4539,7 +5699,7 @@ var TaskProjector = class {
|
|
|
4539
5699
|
* Create blocker edge
|
|
4540
5700
|
*/
|
|
4541
5701
|
async createBlockerEdge(taskId, blocker, relType) {
|
|
4542
|
-
const edgeId =
|
|
5702
|
+
const edgeId = randomUUID8();
|
|
4543
5703
|
await dbRun(
|
|
4544
5704
|
this.db,
|
|
4545
5705
|
`INSERT INTO edges (edge_id, src_type, src_id, rel_type, dst_type, dst_id, meta_json, created_at)
|
|
@@ -4577,7 +5737,7 @@ var TaskProjector = class {
|
|
|
4577
5737
|
* Enqueue entity for vectorization
|
|
4578
5738
|
*/
|
|
4579
5739
|
async enqueueForVectorization(itemId, itemKind) {
|
|
4580
|
-
const jobId =
|
|
5740
|
+
const jobId = randomUUID8();
|
|
4581
5741
|
const embeddingVersion = "v1";
|
|
4582
5742
|
await dbRun(
|
|
4583
5743
|
this.db,
|
|
@@ -4697,7 +5857,7 @@ function createSharedEventStore(dbPath) {
|
|
|
4697
5857
|
}
|
|
4698
5858
|
|
|
4699
5859
|
// src/core/shared-store.ts
|
|
4700
|
-
import { randomUUID as
|
|
5860
|
+
import { randomUUID as randomUUID9 } from "crypto";
|
|
4701
5861
|
var SharedStore = class {
|
|
4702
5862
|
constructor(sharedEventStore) {
|
|
4703
5863
|
this.sharedEventStore = sharedEventStore;
|
|
@@ -4709,7 +5869,7 @@ var SharedStore = class {
|
|
|
4709
5869
|
* Promote a verified troubleshooting entry to shared storage
|
|
4710
5870
|
*/
|
|
4711
5871
|
async promoteEntry(input) {
|
|
4712
|
-
const entryId =
|
|
5872
|
+
const entryId = randomUUID9();
|
|
4713
5873
|
await dbRun(
|
|
4714
5874
|
this.db,
|
|
4715
5875
|
`INSERT INTO shared_troubleshooting (
|
|
@@ -5074,7 +6234,7 @@ function createSharedVectorStore(dbPath) {
|
|
|
5074
6234
|
}
|
|
5075
6235
|
|
|
5076
6236
|
// src/core/shared-promoter.ts
|
|
5077
|
-
import { randomUUID as
|
|
6237
|
+
import { randomUUID as randomUUID10 } from "crypto";
|
|
5078
6238
|
var SharedPromoter = class {
|
|
5079
6239
|
constructor(sharedStore, sharedVectorStore, embedder, config) {
|
|
5080
6240
|
this.sharedStore = sharedStore;
|
|
@@ -5142,7 +6302,7 @@ var SharedPromoter = class {
|
|
|
5142
6302
|
const embeddingContent = this.createEmbeddingContent(input);
|
|
5143
6303
|
const embedding = await this.embedder.embed(embeddingContent);
|
|
5144
6304
|
await this.sharedVectorStore.upsert({
|
|
5145
|
-
id:
|
|
6305
|
+
id: randomUUID10(),
|
|
5146
6306
|
entryId,
|
|
5147
6307
|
entryType: "troubleshooting",
|
|
5148
6308
|
content: embeddingContent,
|
|
@@ -5291,6 +6451,7 @@ export {
|
|
|
5291
6451
|
FullDetailSchema,
|
|
5292
6452
|
GraduationPipeline,
|
|
5293
6453
|
GraduationResultSchema,
|
|
6454
|
+
GraduationWorker,
|
|
5294
6455
|
InsightSchema,
|
|
5295
6456
|
InsightTypeSchema,
|
|
5296
6457
|
MATCH_THRESHOLDS,
|
|
@@ -5311,6 +6472,7 @@ export {
|
|
|
5311
6472
|
ProgressiveSearchResultSchema,
|
|
5312
6473
|
RelationTypeSchema,
|
|
5313
6474
|
Retriever,
|
|
6475
|
+
SQLiteEventStore,
|
|
5314
6476
|
SearchIndexItemSchema,
|
|
5315
6477
|
SessionSchema,
|
|
5316
6478
|
SharedEntryTypeSchema,
|
|
@@ -5320,6 +6482,7 @@ export {
|
|
|
5320
6482
|
SharedStoreConfigSchema,
|
|
5321
6483
|
SharedTroubleshootingEntrySchema,
|
|
5322
6484
|
SharedVectorStore,
|
|
6485
|
+
SyncWorker,
|
|
5323
6486
|
TaskBlockersSetPayloadSchema,
|
|
5324
6487
|
TaskCreatedPayloadSchema,
|
|
5325
6488
|
TaskCurrentJsonSchema,
|
|
@@ -5341,7 +6504,9 @@ export {
|
|
|
5341
6504
|
VectorWorkerV2,
|
|
5342
6505
|
WorkingSetItemSchema,
|
|
5343
6506
|
createGraduationPipeline,
|
|
6507
|
+
createGraduationWorker,
|
|
5344
6508
|
createRetriever,
|
|
6509
|
+
createSQLiteDatabase,
|
|
5345
6510
|
createSharedEventStore,
|
|
5346
6511
|
createSharedPromoter,
|
|
5347
6512
|
createSharedStore,
|
|
@@ -5358,6 +6523,14 @@ export {
|
|
|
5358
6523
|
makeDedupeKey,
|
|
5359
6524
|
makeEntityCanonicalKey,
|
|
5360
6525
|
makeTaskEventDedupeKey,
|
|
5361
|
-
parseEntityCanonicalKey
|
|
6526
|
+
parseEntityCanonicalKey,
|
|
6527
|
+
sqliteAll,
|
|
6528
|
+
sqliteClose,
|
|
6529
|
+
sqliteExec,
|
|
6530
|
+
sqliteGet,
|
|
6531
|
+
sqliteRun,
|
|
6532
|
+
sqliteTransaction,
|
|
6533
|
+
toDateFromSQLite,
|
|
6534
|
+
toSQLiteTimestamp
|
|
5362
6535
|
};
|
|
5363
6536
|
//# sourceMappingURL=index.js.map
|