claude-memory-layer 1.0.0 → 1.0.1
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 +14 -0
- package/.history/package_20260201114632.json +46 -0
- package/dist/cli/index.js +360 -154
- package/dist/cli/index.js.map +4 -4
- package/dist/core/index.js +337 -161
- package/dist/core/index.js.map +3 -3
- package/dist/hooks/session-end.js +320 -130
- package/dist/hooks/session-end.js.map +4 -4
- package/dist/hooks/session-start.js +331 -138
- package/dist/hooks/session-start.js.map +4 -4
- package/dist/hooks/stop.js +320 -130
- package/dist/hooks/stop.js.map +4 -4
- package/dist/hooks/user-prompt-submit.js +320 -130
- package/dist/hooks/user-prompt-submit.js.map +4 -4
- package/dist/services/memory-service.js +349 -128
- package/dist/services/memory-service.js.map +4 -4
- package/package.json +2 -1
- package/src/cli/index.ts +84 -23
- package/src/core/consolidated-store.ts +33 -18
- package/src/core/continuity-manager.ts +12 -7
- package/src/core/db-wrapper.ts +112 -0
- package/src/core/edge-repo.ts +22 -13
- package/src/core/entity-repo.ts +23 -14
- package/src/core/event-store.ts +98 -72
- package/src/core/task/blocker-resolver.ts +17 -9
- package/src/core/task/task-matcher.ts +8 -6
- package/src/core/task/task-projector.ts +29 -16
- package/src/core/task/task-resolver.ts +17 -9
- package/src/core/vector-outbox.ts +29 -16
- package/src/core/vector-store.ts +23 -12
- package/src/core/vector-worker.ts +7 -4
- package/src/core/working-set-store.ts +31 -18
- package/src/hooks/session-end.ts +3 -2
- package/src/hooks/session-start.ts +12 -8
- package/src/hooks/stop.ts +3 -2
- package/src/hooks/user-prompt-submit.ts +3 -2
- package/src/services/memory-service.ts +158 -6
package/dist/cli/index.js
CHANGED
|
@@ -16,7 +16,6 @@ import * as fs from "fs";
|
|
|
16
16
|
import * as crypto2 from "crypto";
|
|
17
17
|
|
|
18
18
|
// src/core/event-store.ts
|
|
19
|
-
import { Database } from "duckdb";
|
|
20
19
|
import { randomUUID } from "crypto";
|
|
21
20
|
|
|
22
21
|
// src/core/canonical-key.ts
|
|
@@ -42,11 +41,92 @@ function makeDedupeKey(content, sessionId) {
|
|
|
42
41
|
return `${sessionId}:${contentHash}`;
|
|
43
42
|
}
|
|
44
43
|
|
|
44
|
+
// src/core/db-wrapper.ts
|
|
45
|
+
import duckdb from "duckdb";
|
|
46
|
+
function convertBigInts(obj) {
|
|
47
|
+
if (obj === null || obj === void 0)
|
|
48
|
+
return obj;
|
|
49
|
+
if (typeof obj === "bigint")
|
|
50
|
+
return Number(obj);
|
|
51
|
+
if (obj instanceof Date)
|
|
52
|
+
return obj;
|
|
53
|
+
if (Array.isArray(obj))
|
|
54
|
+
return obj.map(convertBigInts);
|
|
55
|
+
if (typeof obj === "object") {
|
|
56
|
+
const result = {};
|
|
57
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
58
|
+
result[key] = convertBigInts(value);
|
|
59
|
+
}
|
|
60
|
+
return result;
|
|
61
|
+
}
|
|
62
|
+
return obj;
|
|
63
|
+
}
|
|
64
|
+
function toDate(value) {
|
|
65
|
+
if (value instanceof Date)
|
|
66
|
+
return value;
|
|
67
|
+
if (typeof value === "string")
|
|
68
|
+
return new Date(value);
|
|
69
|
+
if (typeof value === "number")
|
|
70
|
+
return new Date(value);
|
|
71
|
+
return new Date(String(value));
|
|
72
|
+
}
|
|
73
|
+
function createDatabase(path3) {
|
|
74
|
+
return new duckdb.Database(path3);
|
|
75
|
+
}
|
|
76
|
+
function dbRun(db, sql, params = []) {
|
|
77
|
+
return new Promise((resolve2, reject) => {
|
|
78
|
+
if (params.length === 0) {
|
|
79
|
+
db.run(sql, (err) => {
|
|
80
|
+
if (err)
|
|
81
|
+
reject(err);
|
|
82
|
+
else
|
|
83
|
+
resolve2();
|
|
84
|
+
});
|
|
85
|
+
} else {
|
|
86
|
+
db.run(sql, ...params, (err) => {
|
|
87
|
+
if (err)
|
|
88
|
+
reject(err);
|
|
89
|
+
else
|
|
90
|
+
resolve2();
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
function dbAll(db, sql, params = []) {
|
|
96
|
+
return new Promise((resolve2, reject) => {
|
|
97
|
+
if (params.length === 0) {
|
|
98
|
+
db.all(sql, (err, rows) => {
|
|
99
|
+
if (err)
|
|
100
|
+
reject(err);
|
|
101
|
+
else
|
|
102
|
+
resolve2(convertBigInts(rows || []));
|
|
103
|
+
});
|
|
104
|
+
} else {
|
|
105
|
+
db.all(sql, ...params, (err, rows) => {
|
|
106
|
+
if (err)
|
|
107
|
+
reject(err);
|
|
108
|
+
else
|
|
109
|
+
resolve2(convertBigInts(rows || []));
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
function dbClose(db) {
|
|
115
|
+
return new Promise((resolve2, reject) => {
|
|
116
|
+
db.close((err) => {
|
|
117
|
+
if (err)
|
|
118
|
+
reject(err);
|
|
119
|
+
else
|
|
120
|
+
resolve2();
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
|
|
45
125
|
// src/core/event-store.ts
|
|
46
126
|
var EventStore = class {
|
|
47
127
|
constructor(dbPath) {
|
|
48
128
|
this.dbPath = dbPath;
|
|
49
|
-
this.db =
|
|
129
|
+
this.db = createDatabase(dbPath);
|
|
50
130
|
}
|
|
51
131
|
db;
|
|
52
132
|
initialized = false;
|
|
@@ -56,7 +136,7 @@ var EventStore = class {
|
|
|
56
136
|
async initialize() {
|
|
57
137
|
if (this.initialized)
|
|
58
138
|
return;
|
|
59
|
-
await this.db
|
|
139
|
+
await dbRun(this.db, `
|
|
60
140
|
CREATE TABLE IF NOT EXISTS events (
|
|
61
141
|
id VARCHAR PRIMARY KEY,
|
|
62
142
|
event_type VARCHAR NOT NULL,
|
|
@@ -68,14 +148,14 @@ var EventStore = class {
|
|
|
68
148
|
metadata JSON
|
|
69
149
|
)
|
|
70
150
|
`);
|
|
71
|
-
await this.db
|
|
151
|
+
await dbRun(this.db, `
|
|
72
152
|
CREATE TABLE IF NOT EXISTS event_dedup (
|
|
73
153
|
dedupe_key VARCHAR PRIMARY KEY,
|
|
74
154
|
event_id VARCHAR NOT NULL,
|
|
75
155
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
76
156
|
)
|
|
77
157
|
`);
|
|
78
|
-
await this.db
|
|
158
|
+
await dbRun(this.db, `
|
|
79
159
|
CREATE TABLE IF NOT EXISTS sessions (
|
|
80
160
|
id VARCHAR PRIMARY KEY,
|
|
81
161
|
started_at TIMESTAMP NOT NULL,
|
|
@@ -85,7 +165,7 @@ var EventStore = class {
|
|
|
85
165
|
tags JSON
|
|
86
166
|
)
|
|
87
167
|
`);
|
|
88
|
-
await this.db
|
|
168
|
+
await dbRun(this.db, `
|
|
89
169
|
CREATE TABLE IF NOT EXISTS insights (
|
|
90
170
|
id VARCHAR PRIMARY KEY,
|
|
91
171
|
insight_type VARCHAR NOT NULL,
|
|
@@ -97,7 +177,7 @@ var EventStore = class {
|
|
|
97
177
|
last_updated TIMESTAMP
|
|
98
178
|
)
|
|
99
179
|
`);
|
|
100
|
-
await this.db
|
|
180
|
+
await dbRun(this.db, `
|
|
101
181
|
CREATE TABLE IF NOT EXISTS embedding_outbox (
|
|
102
182
|
id VARCHAR PRIMARY KEY,
|
|
103
183
|
event_id VARCHAR NOT NULL,
|
|
@@ -109,7 +189,7 @@ var EventStore = class {
|
|
|
109
189
|
error_message TEXT
|
|
110
190
|
)
|
|
111
191
|
`);
|
|
112
|
-
await this.db
|
|
192
|
+
await dbRun(this.db, `
|
|
113
193
|
CREATE TABLE IF NOT EXISTS projection_offsets (
|
|
114
194
|
projection_name VARCHAR PRIMARY KEY,
|
|
115
195
|
last_event_id VARCHAR,
|
|
@@ -117,14 +197,14 @@ var EventStore = class {
|
|
|
117
197
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
118
198
|
)
|
|
119
199
|
`);
|
|
120
|
-
await this.db
|
|
200
|
+
await dbRun(this.db, `
|
|
121
201
|
CREATE TABLE IF NOT EXISTS memory_levels (
|
|
122
202
|
event_id VARCHAR PRIMARY KEY,
|
|
123
203
|
level VARCHAR NOT NULL DEFAULT 'L0',
|
|
124
204
|
promoted_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
125
205
|
)
|
|
126
206
|
`);
|
|
127
|
-
await this.db
|
|
207
|
+
await dbRun(this.db, `
|
|
128
208
|
CREATE TABLE IF NOT EXISTS entries (
|
|
129
209
|
entry_id VARCHAR PRIMARY KEY,
|
|
130
210
|
created_ts TIMESTAMP NOT NULL,
|
|
@@ -140,7 +220,7 @@ var EventStore = class {
|
|
|
140
220
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
141
221
|
)
|
|
142
222
|
`);
|
|
143
|
-
await this.db
|
|
223
|
+
await dbRun(this.db, `
|
|
144
224
|
CREATE TABLE IF NOT EXISTS entities (
|
|
145
225
|
entity_id VARCHAR PRIMARY KEY,
|
|
146
226
|
entity_type VARCHAR NOT NULL,
|
|
@@ -155,7 +235,7 @@ var EventStore = class {
|
|
|
155
235
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
156
236
|
)
|
|
157
237
|
`);
|
|
158
|
-
await this.db
|
|
238
|
+
await dbRun(this.db, `
|
|
159
239
|
CREATE TABLE IF NOT EXISTS entity_aliases (
|
|
160
240
|
entity_type VARCHAR NOT NULL,
|
|
161
241
|
canonical_key VARCHAR NOT NULL,
|
|
@@ -165,7 +245,7 @@ var EventStore = class {
|
|
|
165
245
|
PRIMARY KEY(entity_type, canonical_key)
|
|
166
246
|
)
|
|
167
247
|
`);
|
|
168
|
-
await this.db
|
|
248
|
+
await dbRun(this.db, `
|
|
169
249
|
CREATE TABLE IF NOT EXISTS edges (
|
|
170
250
|
edge_id VARCHAR PRIMARY KEY,
|
|
171
251
|
src_type VARCHAR NOT NULL,
|
|
@@ -177,7 +257,7 @@ var EventStore = class {
|
|
|
177
257
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
178
258
|
)
|
|
179
259
|
`);
|
|
180
|
-
await this.db
|
|
260
|
+
await dbRun(this.db, `
|
|
181
261
|
CREATE TABLE IF NOT EXISTS vector_outbox (
|
|
182
262
|
job_id VARCHAR PRIMARY KEY,
|
|
183
263
|
item_kind VARCHAR NOT NULL,
|
|
@@ -191,7 +271,7 @@ var EventStore = class {
|
|
|
191
271
|
UNIQUE(item_kind, item_id, embedding_version)
|
|
192
272
|
)
|
|
193
273
|
`);
|
|
194
|
-
await this.db
|
|
274
|
+
await dbRun(this.db, `
|
|
195
275
|
CREATE TABLE IF NOT EXISTS build_runs (
|
|
196
276
|
build_id VARCHAR PRIMARY KEY,
|
|
197
277
|
started_at TIMESTAMP NOT NULL,
|
|
@@ -206,7 +286,7 @@ var EventStore = class {
|
|
|
206
286
|
error VARCHAR
|
|
207
287
|
)
|
|
208
288
|
`);
|
|
209
|
-
await this.db
|
|
289
|
+
await dbRun(this.db, `
|
|
210
290
|
CREATE TABLE IF NOT EXISTS pipeline_metrics (
|
|
211
291
|
id VARCHAR PRIMARY KEY,
|
|
212
292
|
ts TIMESTAMP NOT NULL,
|
|
@@ -217,7 +297,7 @@ var EventStore = class {
|
|
|
217
297
|
session_id VARCHAR
|
|
218
298
|
)
|
|
219
299
|
`);
|
|
220
|
-
await this.db
|
|
300
|
+
await dbRun(this.db, `
|
|
221
301
|
CREATE TABLE IF NOT EXISTS working_set (
|
|
222
302
|
id VARCHAR PRIMARY KEY,
|
|
223
303
|
event_id VARCHAR NOT NULL,
|
|
@@ -227,7 +307,7 @@ var EventStore = class {
|
|
|
227
307
|
expires_at TIMESTAMP
|
|
228
308
|
)
|
|
229
309
|
`);
|
|
230
|
-
await this.db
|
|
310
|
+
await dbRun(this.db, `
|
|
231
311
|
CREATE TABLE IF NOT EXISTS consolidated_memories (
|
|
232
312
|
memory_id VARCHAR PRIMARY KEY,
|
|
233
313
|
summary TEXT NOT NULL,
|
|
@@ -239,7 +319,7 @@ var EventStore = class {
|
|
|
239
319
|
access_count INTEGER DEFAULT 0
|
|
240
320
|
)
|
|
241
321
|
`);
|
|
242
|
-
await this.db
|
|
322
|
+
await dbRun(this.db, `
|
|
243
323
|
CREATE TABLE IF NOT EXISTS continuity_log (
|
|
244
324
|
log_id VARCHAR PRIMARY KEY,
|
|
245
325
|
from_context_id VARCHAR,
|
|
@@ -249,26 +329,26 @@ var EventStore = class {
|
|
|
249
329
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
250
330
|
)
|
|
251
331
|
`);
|
|
252
|
-
await this.db
|
|
332
|
+
await dbRun(this.db, `
|
|
253
333
|
CREATE TABLE IF NOT EXISTS endless_config (
|
|
254
334
|
key VARCHAR PRIMARY KEY,
|
|
255
335
|
value JSON,
|
|
256
336
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
257
337
|
)
|
|
258
338
|
`);
|
|
259
|
-
await this.db
|
|
260
|
-
await this.db
|
|
261
|
-
await this.db
|
|
262
|
-
await this.db
|
|
263
|
-
await this.db
|
|
264
|
-
await this.db
|
|
265
|
-
await this.db
|
|
266
|
-
await this.db
|
|
267
|
-
await this.db
|
|
268
|
-
await this.db
|
|
269
|
-
await this.db
|
|
270
|
-
await this.db
|
|
271
|
-
await this.db
|
|
339
|
+
await dbRun(this.db, `CREATE INDEX IF NOT EXISTS idx_entries_type ON entries(entry_type)`);
|
|
340
|
+
await dbRun(this.db, `CREATE INDEX IF NOT EXISTS idx_entries_stage ON entries(stage)`);
|
|
341
|
+
await dbRun(this.db, `CREATE INDEX IF NOT EXISTS idx_entries_canonical ON entries(canonical_key)`);
|
|
342
|
+
await dbRun(this.db, `CREATE INDEX IF NOT EXISTS idx_entities_type_key ON entities(entity_type, canonical_key)`);
|
|
343
|
+
await dbRun(this.db, `CREATE INDEX IF NOT EXISTS idx_entities_status ON entities(status)`);
|
|
344
|
+
await dbRun(this.db, `CREATE INDEX IF NOT EXISTS idx_edges_src ON edges(src_id, rel_type)`);
|
|
345
|
+
await dbRun(this.db, `CREATE INDEX IF NOT EXISTS idx_edges_dst ON edges(dst_id, rel_type)`);
|
|
346
|
+
await dbRun(this.db, `CREATE INDEX IF NOT EXISTS idx_edges_rel ON edges(rel_type)`);
|
|
347
|
+
await dbRun(this.db, `CREATE INDEX IF NOT EXISTS idx_outbox_status ON vector_outbox(status)`);
|
|
348
|
+
await dbRun(this.db, `CREATE INDEX IF NOT EXISTS idx_working_set_expires ON working_set(expires_at)`);
|
|
349
|
+
await dbRun(this.db, `CREATE INDEX IF NOT EXISTS idx_working_set_relevance ON working_set(relevance_score DESC)`);
|
|
350
|
+
await dbRun(this.db, `CREATE INDEX IF NOT EXISTS idx_consolidated_confidence ON consolidated_memories(confidence DESC)`);
|
|
351
|
+
await dbRun(this.db, `CREATE INDEX IF NOT EXISTS idx_continuity_created ON continuity_log(created_at)`);
|
|
272
352
|
this.initialized = true;
|
|
273
353
|
}
|
|
274
354
|
/**
|
|
@@ -279,7 +359,8 @@ var EventStore = class {
|
|
|
279
359
|
await this.initialize();
|
|
280
360
|
const canonicalKey = makeCanonicalKey(input.content);
|
|
281
361
|
const dedupeKey = makeDedupeKey(input.content, input.sessionId);
|
|
282
|
-
const existing = await
|
|
362
|
+
const existing = await dbAll(
|
|
363
|
+
this.db,
|
|
283
364
|
`SELECT event_id FROM event_dedup WHERE dedupe_key = ?`,
|
|
284
365
|
[dedupeKey]
|
|
285
366
|
);
|
|
@@ -293,7 +374,8 @@ var EventStore = class {
|
|
|
293
374
|
const id = randomUUID();
|
|
294
375
|
const timestamp = input.timestamp.toISOString();
|
|
295
376
|
try {
|
|
296
|
-
await
|
|
377
|
+
await dbRun(
|
|
378
|
+
this.db,
|
|
297
379
|
`INSERT INTO events (id, event_type, session_id, timestamp, content, canonical_key, dedupe_key, metadata)
|
|
298
380
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
299
381
|
[
|
|
@@ -307,11 +389,13 @@ var EventStore = class {
|
|
|
307
389
|
JSON.stringify(input.metadata || {})
|
|
308
390
|
]
|
|
309
391
|
);
|
|
310
|
-
await
|
|
392
|
+
await dbRun(
|
|
393
|
+
this.db,
|
|
311
394
|
`INSERT INTO event_dedup (dedupe_key, event_id) VALUES (?, ?)`,
|
|
312
395
|
[dedupeKey, id]
|
|
313
396
|
);
|
|
314
|
-
await
|
|
397
|
+
await dbRun(
|
|
398
|
+
this.db,
|
|
315
399
|
`INSERT INTO memory_levels (event_id, level) VALUES (?, 'L0')`,
|
|
316
400
|
[id]
|
|
317
401
|
);
|
|
@@ -328,7 +412,8 @@ var EventStore = class {
|
|
|
328
412
|
*/
|
|
329
413
|
async getSessionEvents(sessionId) {
|
|
330
414
|
await this.initialize();
|
|
331
|
-
const rows = await
|
|
415
|
+
const rows = await dbAll(
|
|
416
|
+
this.db,
|
|
332
417
|
`SELECT * FROM events WHERE session_id = ? ORDER BY timestamp ASC`,
|
|
333
418
|
[sessionId]
|
|
334
419
|
);
|
|
@@ -339,7 +424,8 @@ var EventStore = class {
|
|
|
339
424
|
*/
|
|
340
425
|
async getRecentEvents(limit = 100) {
|
|
341
426
|
await this.initialize();
|
|
342
|
-
const rows = await
|
|
427
|
+
const rows = await dbAll(
|
|
428
|
+
this.db,
|
|
343
429
|
`SELECT * FROM events ORDER BY timestamp DESC LIMIT ?`,
|
|
344
430
|
[limit]
|
|
345
431
|
);
|
|
@@ -350,7 +436,8 @@ var EventStore = class {
|
|
|
350
436
|
*/
|
|
351
437
|
async getEvent(id) {
|
|
352
438
|
await this.initialize();
|
|
353
|
-
const rows = await
|
|
439
|
+
const rows = await dbAll(
|
|
440
|
+
this.db,
|
|
354
441
|
`SELECT * FROM events WHERE id = ?`,
|
|
355
442
|
[id]
|
|
356
443
|
);
|
|
@@ -363,12 +450,14 @@ var EventStore = class {
|
|
|
363
450
|
*/
|
|
364
451
|
async upsertSession(session) {
|
|
365
452
|
await this.initialize();
|
|
366
|
-
const existing = await
|
|
453
|
+
const existing = await dbAll(
|
|
454
|
+
this.db,
|
|
367
455
|
`SELECT id FROM sessions WHERE id = ?`,
|
|
368
456
|
[session.id]
|
|
369
457
|
);
|
|
370
458
|
if (existing.length === 0) {
|
|
371
|
-
await
|
|
459
|
+
await dbRun(
|
|
460
|
+
this.db,
|
|
372
461
|
`INSERT INTO sessions (id, started_at, project_path, tags)
|
|
373
462
|
VALUES (?, ?, ?, ?)`,
|
|
374
463
|
[
|
|
@@ -395,7 +484,8 @@ var EventStore = class {
|
|
|
395
484
|
}
|
|
396
485
|
if (updates.length > 0) {
|
|
397
486
|
values.push(session.id);
|
|
398
|
-
await
|
|
487
|
+
await dbRun(
|
|
488
|
+
this.db,
|
|
399
489
|
`UPDATE sessions SET ${updates.join(", ")} WHERE id = ?`,
|
|
400
490
|
values
|
|
401
491
|
);
|
|
@@ -407,7 +497,8 @@ var EventStore = class {
|
|
|
407
497
|
*/
|
|
408
498
|
async getSession(id) {
|
|
409
499
|
await this.initialize();
|
|
410
|
-
const rows = await
|
|
500
|
+
const rows = await dbAll(
|
|
501
|
+
this.db,
|
|
411
502
|
`SELECT * FROM sessions WHERE id = ?`,
|
|
412
503
|
[id]
|
|
413
504
|
);
|
|
@@ -416,8 +507,8 @@ var EventStore = class {
|
|
|
416
507
|
const row = rows[0];
|
|
417
508
|
return {
|
|
418
509
|
id: row.id,
|
|
419
|
-
startedAt:
|
|
420
|
-
endedAt: row.ended_at ?
|
|
510
|
+
startedAt: toDate(row.started_at),
|
|
511
|
+
endedAt: row.ended_at ? toDate(row.ended_at) : void 0,
|
|
421
512
|
projectPath: row.project_path,
|
|
422
513
|
summary: row.summary,
|
|
423
514
|
tags: row.tags ? JSON.parse(row.tags) : void 0
|
|
@@ -429,7 +520,8 @@ var EventStore = class {
|
|
|
429
520
|
async enqueueForEmbedding(eventId, content) {
|
|
430
521
|
await this.initialize();
|
|
431
522
|
const id = randomUUID();
|
|
432
|
-
await
|
|
523
|
+
await dbRun(
|
|
524
|
+
this.db,
|
|
433
525
|
`INSERT INTO embedding_outbox (id, event_id, content, status, retry_count)
|
|
434
526
|
VALUES (?, ?, ?, 'pending', 0)`,
|
|
435
527
|
[id, eventId, content]
|
|
@@ -441,25 +533,30 @@ var EventStore = class {
|
|
|
441
533
|
*/
|
|
442
534
|
async getPendingOutboxItems(limit = 32) {
|
|
443
535
|
await this.initialize();
|
|
444
|
-
const
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
WHERE
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
ORDER BY created_at
|
|
451
|
-
LIMIT ?
|
|
452
|
-
)
|
|
453
|
-
RETURNING *`,
|
|
536
|
+
const pending = await dbAll(
|
|
537
|
+
this.db,
|
|
538
|
+
`SELECT * FROM embedding_outbox
|
|
539
|
+
WHERE status = 'pending'
|
|
540
|
+
ORDER BY created_at
|
|
541
|
+
LIMIT ?`,
|
|
454
542
|
[limit]
|
|
455
543
|
);
|
|
456
|
-
|
|
544
|
+
if (pending.length === 0)
|
|
545
|
+
return [];
|
|
546
|
+
const ids = pending.map((r) => r.id);
|
|
547
|
+
const placeholders = ids.map(() => "?").join(",");
|
|
548
|
+
await dbRun(
|
|
549
|
+
this.db,
|
|
550
|
+
`UPDATE embedding_outbox SET status = 'processing' WHERE id IN (${placeholders})`,
|
|
551
|
+
ids
|
|
552
|
+
);
|
|
553
|
+
return pending.map((row) => ({
|
|
457
554
|
id: row.id,
|
|
458
555
|
eventId: row.event_id,
|
|
459
556
|
content: row.content,
|
|
460
|
-
status:
|
|
557
|
+
status: "processing",
|
|
461
558
|
retryCount: row.retry_count,
|
|
462
|
-
createdAt:
|
|
559
|
+
createdAt: toDate(row.created_at),
|
|
463
560
|
errorMessage: row.error_message
|
|
464
561
|
}));
|
|
465
562
|
}
|
|
@@ -470,7 +567,8 @@ var EventStore = class {
|
|
|
470
567
|
if (ids.length === 0)
|
|
471
568
|
return;
|
|
472
569
|
const placeholders = ids.map(() => "?").join(",");
|
|
473
|
-
await
|
|
570
|
+
await dbRun(
|
|
571
|
+
this.db,
|
|
474
572
|
`DELETE FROM embedding_outbox WHERE id IN (${placeholders})`,
|
|
475
573
|
ids
|
|
476
574
|
);
|
|
@@ -482,7 +580,8 @@ var EventStore = class {
|
|
|
482
580
|
if (ids.length === 0)
|
|
483
581
|
return;
|
|
484
582
|
const placeholders = ids.map(() => "?").join(",");
|
|
485
|
-
await
|
|
583
|
+
await dbRun(
|
|
584
|
+
this.db,
|
|
486
585
|
`UPDATE embedding_outbox
|
|
487
586
|
SET status = CASE WHEN retry_count >= 3 THEN 'failed' ELSE 'pending' END,
|
|
488
587
|
retry_count = retry_count + 1,
|
|
@@ -496,7 +595,8 @@ var EventStore = class {
|
|
|
496
595
|
*/
|
|
497
596
|
async updateMemoryLevel(eventId, level) {
|
|
498
597
|
await this.initialize();
|
|
499
|
-
await
|
|
598
|
+
await dbRun(
|
|
599
|
+
this.db,
|
|
500
600
|
`UPDATE memory_levels SET level = ?, promoted_at = CURRENT_TIMESTAMP WHERE event_id = ?`,
|
|
501
601
|
[level, eventId]
|
|
502
602
|
);
|
|
@@ -506,7 +606,8 @@ var EventStore = class {
|
|
|
506
606
|
*/
|
|
507
607
|
async getLevelStats() {
|
|
508
608
|
await this.initialize();
|
|
509
|
-
const rows = await
|
|
609
|
+
const rows = await dbAll(
|
|
610
|
+
this.db,
|
|
510
611
|
`SELECT level, COUNT(*) as count FROM memory_levels GROUP BY level`
|
|
511
612
|
);
|
|
512
613
|
return rows;
|
|
@@ -525,7 +626,8 @@ var EventStore = class {
|
|
|
525
626
|
*/
|
|
526
627
|
async getEndlessConfig(key) {
|
|
527
628
|
await this.initialize();
|
|
528
|
-
const rows = await
|
|
629
|
+
const rows = await dbAll(
|
|
630
|
+
this.db,
|
|
529
631
|
`SELECT value FROM endless_config WHERE key = ?`,
|
|
530
632
|
[key]
|
|
531
633
|
);
|
|
@@ -538,7 +640,8 @@ var EventStore = class {
|
|
|
538
640
|
*/
|
|
539
641
|
async setEndlessConfig(key, value) {
|
|
540
642
|
await this.initialize();
|
|
541
|
-
await
|
|
643
|
+
await dbRun(
|
|
644
|
+
this.db,
|
|
542
645
|
`INSERT OR REPLACE INTO endless_config (key, value, updated_at)
|
|
543
646
|
VALUES (?, ?, CURRENT_TIMESTAMP)`,
|
|
544
647
|
[key, JSON.stringify(value)]
|
|
@@ -549,13 +652,14 @@ var EventStore = class {
|
|
|
549
652
|
*/
|
|
550
653
|
async getAllSessions() {
|
|
551
654
|
await this.initialize();
|
|
552
|
-
const rows = await
|
|
655
|
+
const rows = await dbAll(
|
|
656
|
+
this.db,
|
|
553
657
|
`SELECT * FROM sessions ORDER BY started_at DESC`
|
|
554
658
|
);
|
|
555
659
|
return rows.map((row) => ({
|
|
556
660
|
id: row.id,
|
|
557
|
-
startedAt:
|
|
558
|
-
endedAt: row.ended_at ?
|
|
661
|
+
startedAt: toDate(row.started_at),
|
|
662
|
+
endedAt: row.ended_at ? toDate(row.ended_at) : void 0,
|
|
559
663
|
projectPath: row.project_path,
|
|
560
664
|
summary: row.summary,
|
|
561
665
|
tags: row.tags ? JSON.parse(row.tags) : void 0
|
|
@@ -565,7 +669,7 @@ var EventStore = class {
|
|
|
565
669
|
* Close database connection
|
|
566
670
|
*/
|
|
567
671
|
async close() {
|
|
568
|
-
await this.db
|
|
672
|
+
await dbClose(this.db);
|
|
569
673
|
}
|
|
570
674
|
/**
|
|
571
675
|
* Convert database row to MemoryEvent
|
|
@@ -575,7 +679,7 @@ var EventStore = class {
|
|
|
575
679
|
id: row.id,
|
|
576
680
|
eventType: row.event_type,
|
|
577
681
|
sessionId: row.session_id,
|
|
578
|
-
timestamp:
|
|
682
|
+
timestamp: toDate(row.timestamp),
|
|
579
683
|
content: row.content,
|
|
580
684
|
canonicalKey: row.canonical_key,
|
|
581
685
|
dedupeKey: row.dedupe_key,
|
|
@@ -668,23 +772,28 @@ var VectorStore = class {
|
|
|
668
772
|
return [];
|
|
669
773
|
}
|
|
670
774
|
const { limit = 5, minScore = 0.7, sessionId } = options;
|
|
671
|
-
let query = this.table.search(queryVector).limit(limit * 2);
|
|
775
|
+
let query = this.table.search(queryVector).distanceType("cosine").limit(limit * 2);
|
|
672
776
|
if (sessionId) {
|
|
673
777
|
query = query.where(`sessionId = '${sessionId}'`);
|
|
674
778
|
}
|
|
675
779
|
const results = await query.toArray();
|
|
676
780
|
return results.filter((r) => {
|
|
677
|
-
const
|
|
781
|
+
const distance = r._distance || 0;
|
|
782
|
+
const score = 1 - distance / 2;
|
|
678
783
|
return score >= minScore;
|
|
679
|
-
}).slice(0, limit).map((r) =>
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
784
|
+
}).slice(0, limit).map((r) => {
|
|
785
|
+
const distance = r._distance || 0;
|
|
786
|
+
const score = 1 - distance / 2;
|
|
787
|
+
return {
|
|
788
|
+
id: r.id,
|
|
789
|
+
eventId: r.eventId,
|
|
790
|
+
content: r.content,
|
|
791
|
+
score,
|
|
792
|
+
sessionId: r.sessionId,
|
|
793
|
+
eventType: r.eventType,
|
|
794
|
+
timestamp: r.timestamp
|
|
795
|
+
};
|
|
796
|
+
});
|
|
688
797
|
}
|
|
689
798
|
/**
|
|
690
799
|
* Delete vector by event ID
|
|
@@ -1510,7 +1619,8 @@ var WorkingSetStore = class {
|
|
|
1510
1619
|
const expiresAt = new Date(
|
|
1511
1620
|
Date.now() + this.config.workingSet.timeWindowHours * 60 * 60 * 1e3
|
|
1512
1621
|
);
|
|
1513
|
-
await
|
|
1622
|
+
await dbRun(
|
|
1623
|
+
this.db,
|
|
1514
1624
|
`INSERT OR REPLACE INTO working_set (id, event_id, added_at, relevance_score, topics, expires_at)
|
|
1515
1625
|
VALUES (?, ?, CURRENT_TIMESTAMP, ?, ?, ?)`,
|
|
1516
1626
|
[
|
|
@@ -1528,7 +1638,8 @@ var WorkingSetStore = class {
|
|
|
1528
1638
|
*/
|
|
1529
1639
|
async get() {
|
|
1530
1640
|
await this.cleanup();
|
|
1531
|
-
const rows = await
|
|
1641
|
+
const rows = await dbAll(
|
|
1642
|
+
this.db,
|
|
1532
1643
|
`SELECT ws.*, e.*
|
|
1533
1644
|
FROM working_set ws
|
|
1534
1645
|
JOIN events e ON ws.event_id = e.id
|
|
@@ -1540,7 +1651,7 @@ var WorkingSetStore = class {
|
|
|
1540
1651
|
id: row.id,
|
|
1541
1652
|
eventType: row.event_type,
|
|
1542
1653
|
sessionId: row.session_id,
|
|
1543
|
-
timestamp:
|
|
1654
|
+
timestamp: toDate(row.timestamp),
|
|
1544
1655
|
content: row.content,
|
|
1545
1656
|
canonicalKey: row.canonical_key,
|
|
1546
1657
|
dedupeKey: row.dedupe_key,
|
|
@@ -1556,23 +1667,25 @@ var WorkingSetStore = class {
|
|
|
1556
1667
|
* Get working set items (metadata only)
|
|
1557
1668
|
*/
|
|
1558
1669
|
async getItems() {
|
|
1559
|
-
const rows = await
|
|
1670
|
+
const rows = await dbAll(
|
|
1671
|
+
this.db,
|
|
1560
1672
|
`SELECT * FROM working_set ORDER BY relevance_score DESC, added_at DESC`
|
|
1561
1673
|
);
|
|
1562
1674
|
return rows.map((row) => ({
|
|
1563
1675
|
id: row.id,
|
|
1564
1676
|
eventId: row.event_id,
|
|
1565
|
-
addedAt:
|
|
1677
|
+
addedAt: toDate(row.added_at),
|
|
1566
1678
|
relevanceScore: row.relevance_score,
|
|
1567
1679
|
topics: row.topics ? JSON.parse(row.topics) : void 0,
|
|
1568
|
-
expiresAt:
|
|
1680
|
+
expiresAt: toDate(row.expires_at)
|
|
1569
1681
|
}));
|
|
1570
1682
|
}
|
|
1571
1683
|
/**
|
|
1572
1684
|
* Update relevance score for an event
|
|
1573
1685
|
*/
|
|
1574
1686
|
async updateRelevance(eventId, score) {
|
|
1575
|
-
await
|
|
1687
|
+
await dbRun(
|
|
1688
|
+
this.db,
|
|
1576
1689
|
`UPDATE working_set SET relevance_score = ? WHERE event_id = ?`,
|
|
1577
1690
|
[score, eventId]
|
|
1578
1691
|
);
|
|
@@ -1584,7 +1697,8 @@ var WorkingSetStore = class {
|
|
|
1584
1697
|
if (eventIds.length === 0)
|
|
1585
1698
|
return;
|
|
1586
1699
|
const placeholders = eventIds.map(() => "?").join(",");
|
|
1587
|
-
await
|
|
1700
|
+
await dbRun(
|
|
1701
|
+
this.db,
|
|
1588
1702
|
`DELETE FROM working_set WHERE event_id IN (${placeholders})`,
|
|
1589
1703
|
eventIds
|
|
1590
1704
|
);
|
|
@@ -1593,7 +1707,8 @@ var WorkingSetStore = class {
|
|
|
1593
1707
|
* Get the count of items in working set
|
|
1594
1708
|
*/
|
|
1595
1709
|
async count() {
|
|
1596
|
-
const result = await
|
|
1710
|
+
const result = await dbAll(
|
|
1711
|
+
this.db,
|
|
1597
1712
|
`SELECT COUNT(*) as count FROM working_set`
|
|
1598
1713
|
);
|
|
1599
1714
|
return result[0]?.count || 0;
|
|
@@ -1602,13 +1717,14 @@ var WorkingSetStore = class {
|
|
|
1602
1717
|
* Clear the entire working set
|
|
1603
1718
|
*/
|
|
1604
1719
|
async clear() {
|
|
1605
|
-
await this.db
|
|
1720
|
+
await dbRun(this.db, `DELETE FROM working_set`);
|
|
1606
1721
|
}
|
|
1607
1722
|
/**
|
|
1608
1723
|
* Check if an event is in the working set
|
|
1609
1724
|
*/
|
|
1610
1725
|
async contains(eventId) {
|
|
1611
|
-
const result = await
|
|
1726
|
+
const result = await dbAll(
|
|
1727
|
+
this.db,
|
|
1612
1728
|
`SELECT COUNT(*) as count FROM working_set WHERE event_id = ?`,
|
|
1613
1729
|
[eventId]
|
|
1614
1730
|
);
|
|
@@ -1621,7 +1737,8 @@ var WorkingSetStore = class {
|
|
|
1621
1737
|
const newExpiresAt = new Date(
|
|
1622
1738
|
Date.now() + this.config.workingSet.timeWindowHours * 60 * 60 * 1e3
|
|
1623
1739
|
);
|
|
1624
|
-
await
|
|
1740
|
+
await dbRun(
|
|
1741
|
+
this.db,
|
|
1625
1742
|
`UPDATE working_set SET expires_at = ? WHERE event_id = ?`,
|
|
1626
1743
|
[newExpiresAt.toISOString(), eventId]
|
|
1627
1744
|
);
|
|
@@ -1630,7 +1747,8 @@ var WorkingSetStore = class {
|
|
|
1630
1747
|
* Clean up expired items
|
|
1631
1748
|
*/
|
|
1632
1749
|
async cleanup() {
|
|
1633
|
-
await
|
|
1750
|
+
await dbRun(
|
|
1751
|
+
this.db,
|
|
1634
1752
|
`DELETE FROM working_set WHERE expires_at < datetime('now')`
|
|
1635
1753
|
);
|
|
1636
1754
|
}
|
|
@@ -1640,7 +1758,8 @@ var WorkingSetStore = class {
|
|
|
1640
1758
|
*/
|
|
1641
1759
|
async enforceLimit() {
|
|
1642
1760
|
const maxEvents = this.config.workingSet.maxEvents;
|
|
1643
|
-
const keepIds = await
|
|
1761
|
+
const keepIds = await dbAll(
|
|
1762
|
+
this.db,
|
|
1644
1763
|
`SELECT id FROM working_set
|
|
1645
1764
|
ORDER BY relevance_score DESC, added_at DESC
|
|
1646
1765
|
LIMIT ?`,
|
|
@@ -1650,7 +1769,8 @@ var WorkingSetStore = class {
|
|
|
1650
1769
|
return;
|
|
1651
1770
|
const keepIdList = keepIds.map((r) => r.id);
|
|
1652
1771
|
const placeholders = keepIdList.map(() => "?").join(",");
|
|
1653
|
-
await
|
|
1772
|
+
await dbRun(
|
|
1773
|
+
this.db,
|
|
1654
1774
|
`DELETE FROM working_set WHERE id NOT IN (${placeholders})`,
|
|
1655
1775
|
keepIdList
|
|
1656
1776
|
);
|
|
@@ -1659,7 +1779,8 @@ var WorkingSetStore = class {
|
|
|
1659
1779
|
* Calculate continuity score based on recent context transitions
|
|
1660
1780
|
*/
|
|
1661
1781
|
async calculateContinuityScore() {
|
|
1662
|
-
const result = await
|
|
1782
|
+
const result = await dbAll(
|
|
1783
|
+
this.db,
|
|
1663
1784
|
`SELECT AVG(continuity_score) as avg_score
|
|
1664
1785
|
FROM continuity_log
|
|
1665
1786
|
WHERE created_at > datetime('now', '-1 hour')`
|
|
@@ -1670,7 +1791,8 @@ var WorkingSetStore = class {
|
|
|
1670
1791
|
* Get topics from current working set for context matching
|
|
1671
1792
|
*/
|
|
1672
1793
|
async getActiveTopics() {
|
|
1673
|
-
const rows = await
|
|
1794
|
+
const rows = await dbAll(
|
|
1795
|
+
this.db,
|
|
1674
1796
|
`SELECT topics FROM working_set WHERE topics IS NOT NULL`
|
|
1675
1797
|
);
|
|
1676
1798
|
const allTopics = /* @__PURE__ */ new Set();
|
|
@@ -1699,7 +1821,8 @@ var ConsolidatedStore = class {
|
|
|
1699
1821
|
*/
|
|
1700
1822
|
async create(input) {
|
|
1701
1823
|
const memoryId = randomUUID3();
|
|
1702
|
-
await
|
|
1824
|
+
await dbRun(
|
|
1825
|
+
this.db,
|
|
1703
1826
|
`INSERT INTO consolidated_memories
|
|
1704
1827
|
(memory_id, summary, topics, source_events, confidence, created_at)
|
|
1705
1828
|
VALUES (?, ?, ?, ?, ?, CURRENT_TIMESTAMP)`,
|
|
@@ -1717,7 +1840,8 @@ var ConsolidatedStore = class {
|
|
|
1717
1840
|
* Get a consolidated memory by ID
|
|
1718
1841
|
*/
|
|
1719
1842
|
async get(memoryId) {
|
|
1720
|
-
const rows = await
|
|
1843
|
+
const rows = await dbAll(
|
|
1844
|
+
this.db,
|
|
1721
1845
|
`SELECT * FROM consolidated_memories WHERE memory_id = ?`,
|
|
1722
1846
|
[memoryId]
|
|
1723
1847
|
);
|
|
@@ -1730,7 +1854,8 @@ var ConsolidatedStore = class {
|
|
|
1730
1854
|
*/
|
|
1731
1855
|
async search(query, options) {
|
|
1732
1856
|
const topK = options?.topK || 5;
|
|
1733
|
-
const rows = await
|
|
1857
|
+
const rows = await dbAll(
|
|
1858
|
+
this.db,
|
|
1734
1859
|
`SELECT * FROM consolidated_memories
|
|
1735
1860
|
WHERE summary LIKE ?
|
|
1736
1861
|
ORDER BY confidence DESC
|
|
@@ -1746,7 +1871,8 @@ var ConsolidatedStore = class {
|
|
|
1746
1871
|
const topK = options?.topK || 5;
|
|
1747
1872
|
const topicConditions = topics.map(() => `topics LIKE ?`).join(" OR ");
|
|
1748
1873
|
const topicParams = topics.map((t) => `%"${t}"%`);
|
|
1749
|
-
const rows = await
|
|
1874
|
+
const rows = await dbAll(
|
|
1875
|
+
this.db,
|
|
1750
1876
|
`SELECT * FROM consolidated_memories
|
|
1751
1877
|
WHERE ${topicConditions}
|
|
1752
1878
|
ORDER BY confidence DESC
|
|
@@ -1760,7 +1886,8 @@ var ConsolidatedStore = class {
|
|
|
1760
1886
|
*/
|
|
1761
1887
|
async getAll(options) {
|
|
1762
1888
|
const limit = options?.limit || 100;
|
|
1763
|
-
const rows = await
|
|
1889
|
+
const rows = await dbAll(
|
|
1890
|
+
this.db,
|
|
1764
1891
|
`SELECT * FROM consolidated_memories
|
|
1765
1892
|
ORDER BY confidence DESC, created_at DESC
|
|
1766
1893
|
LIMIT ?`,
|
|
@@ -1774,7 +1901,8 @@ var ConsolidatedStore = class {
|
|
|
1774
1901
|
async getRecent(options) {
|
|
1775
1902
|
const limit = options?.limit || 10;
|
|
1776
1903
|
const hours = options?.hours || 24;
|
|
1777
|
-
const rows = await
|
|
1904
|
+
const rows = await dbAll(
|
|
1905
|
+
this.db,
|
|
1778
1906
|
`SELECT * FROM consolidated_memories
|
|
1779
1907
|
WHERE created_at > datetime('now', '-${hours} hours')
|
|
1780
1908
|
ORDER BY created_at DESC
|
|
@@ -1787,7 +1915,8 @@ var ConsolidatedStore = class {
|
|
|
1787
1915
|
* Mark a memory as accessed (tracks usage for importance scoring)
|
|
1788
1916
|
*/
|
|
1789
1917
|
async markAccessed(memoryId) {
|
|
1790
|
-
await
|
|
1918
|
+
await dbRun(
|
|
1919
|
+
this.db,
|
|
1791
1920
|
`UPDATE consolidated_memories
|
|
1792
1921
|
SET accessed_at = CURRENT_TIMESTAMP,
|
|
1793
1922
|
access_count = access_count + 1
|
|
@@ -1799,7 +1928,8 @@ var ConsolidatedStore = class {
|
|
|
1799
1928
|
* Update confidence score for a memory
|
|
1800
1929
|
*/
|
|
1801
1930
|
async updateConfidence(memoryId, confidence) {
|
|
1802
|
-
await
|
|
1931
|
+
await dbRun(
|
|
1932
|
+
this.db,
|
|
1803
1933
|
`UPDATE consolidated_memories
|
|
1804
1934
|
SET confidence = ?
|
|
1805
1935
|
WHERE memory_id = ?`,
|
|
@@ -1810,7 +1940,8 @@ var ConsolidatedStore = class {
|
|
|
1810
1940
|
* Delete a consolidated memory
|
|
1811
1941
|
*/
|
|
1812
1942
|
async delete(memoryId) {
|
|
1813
|
-
await
|
|
1943
|
+
await dbRun(
|
|
1944
|
+
this.db,
|
|
1814
1945
|
`DELETE FROM consolidated_memories WHERE memory_id = ?`,
|
|
1815
1946
|
[memoryId]
|
|
1816
1947
|
);
|
|
@@ -1819,7 +1950,8 @@ var ConsolidatedStore = class {
|
|
|
1819
1950
|
* Get count of consolidated memories
|
|
1820
1951
|
*/
|
|
1821
1952
|
async count() {
|
|
1822
|
-
const result = await
|
|
1953
|
+
const result = await dbAll(
|
|
1954
|
+
this.db,
|
|
1823
1955
|
`SELECT COUNT(*) as count FROM consolidated_memories`
|
|
1824
1956
|
);
|
|
1825
1957
|
return result[0]?.count || 0;
|
|
@@ -1828,7 +1960,8 @@ var ConsolidatedStore = class {
|
|
|
1828
1960
|
* Get most accessed memories (for importance scoring)
|
|
1829
1961
|
*/
|
|
1830
1962
|
async getMostAccessed(limit = 10) {
|
|
1831
|
-
const rows = await
|
|
1963
|
+
const rows = await dbAll(
|
|
1964
|
+
this.db,
|
|
1832
1965
|
`SELECT * FROM consolidated_memories
|
|
1833
1966
|
WHERE access_count > 0
|
|
1834
1967
|
ORDER BY access_count DESC
|
|
@@ -1842,11 +1975,13 @@ var ConsolidatedStore = class {
|
|
|
1842
1975
|
*/
|
|
1843
1976
|
async getStats() {
|
|
1844
1977
|
const total = await this.count();
|
|
1845
|
-
const avgResult = await
|
|
1978
|
+
const avgResult = await dbAll(
|
|
1979
|
+
this.db,
|
|
1846
1980
|
`SELECT AVG(confidence) as avg FROM consolidated_memories`
|
|
1847
1981
|
);
|
|
1848
1982
|
const averageConfidence = avgResult[0]?.avg || 0;
|
|
1849
|
-
const recentResult = await
|
|
1983
|
+
const recentResult = await dbAll(
|
|
1984
|
+
this.db,
|
|
1850
1985
|
`SELECT COUNT(*) as count FROM consolidated_memories
|
|
1851
1986
|
WHERE created_at > datetime('now', '-24 hours')`
|
|
1852
1987
|
);
|
|
@@ -1870,7 +2005,8 @@ var ConsolidatedStore = class {
|
|
|
1870
2005
|
*/
|
|
1871
2006
|
async isAlreadyConsolidated(eventIds) {
|
|
1872
2007
|
for (const eventId of eventIds) {
|
|
1873
|
-
const result = await
|
|
2008
|
+
const result = await dbAll(
|
|
2009
|
+
this.db,
|
|
1874
2010
|
`SELECT COUNT(*) as count FROM consolidated_memories
|
|
1875
2011
|
WHERE source_events LIKE ?`,
|
|
1876
2012
|
[`%"${eventId}"%`]
|
|
@@ -1884,7 +2020,8 @@ var ConsolidatedStore = class {
|
|
|
1884
2020
|
* Get the last consolidation time
|
|
1885
2021
|
*/
|
|
1886
2022
|
async getLastConsolidationTime() {
|
|
1887
|
-
const result = await
|
|
2023
|
+
const result = await dbAll(
|
|
2024
|
+
this.db,
|
|
1888
2025
|
`SELECT created_at FROM consolidated_memories
|
|
1889
2026
|
ORDER BY created_at DESC
|
|
1890
2027
|
LIMIT 1`
|
|
@@ -1903,8 +2040,8 @@ var ConsolidatedStore = class {
|
|
|
1903
2040
|
topics: JSON.parse(row.topics || "[]"),
|
|
1904
2041
|
sourceEvents: JSON.parse(row.source_events || "[]"),
|
|
1905
2042
|
confidence: row.confidence,
|
|
1906
|
-
createdAt:
|
|
1907
|
-
accessedAt: row.accessed_at ?
|
|
2043
|
+
createdAt: toDate(row.created_at),
|
|
2044
|
+
accessedAt: row.accessed_at ? toDate(row.accessed_at) : void 0,
|
|
1908
2045
|
accessCount: row.access_count || 0
|
|
1909
2046
|
};
|
|
1910
2047
|
}
|
|
@@ -2270,7 +2407,8 @@ var ContinuityManager = class {
|
|
|
2270
2407
|
* Get recent continuity logs
|
|
2271
2408
|
*/
|
|
2272
2409
|
async getRecentLogs(limit = 10) {
|
|
2273
|
-
const rows = await
|
|
2410
|
+
const rows = await dbAll(
|
|
2411
|
+
this.db,
|
|
2274
2412
|
`SELECT * FROM continuity_log
|
|
2275
2413
|
ORDER BY created_at DESC
|
|
2276
2414
|
LIMIT ?`,
|
|
@@ -2282,14 +2420,15 @@ var ContinuityManager = class {
|
|
|
2282
2420
|
toContextId: row.to_context_id,
|
|
2283
2421
|
continuityScore: row.continuity_score,
|
|
2284
2422
|
transitionType: row.transition_type,
|
|
2285
|
-
createdAt:
|
|
2423
|
+
createdAt: toDate(row.created_at)
|
|
2286
2424
|
}));
|
|
2287
2425
|
}
|
|
2288
2426
|
/**
|
|
2289
2427
|
* Get average continuity score over time period
|
|
2290
2428
|
*/
|
|
2291
2429
|
async getAverageScore(hours = 1) {
|
|
2292
|
-
const result = await
|
|
2430
|
+
const result = await dbAll(
|
|
2431
|
+
this.db,
|
|
2293
2432
|
`SELECT AVG(continuity_score) as avg_score
|
|
2294
2433
|
FROM continuity_log
|
|
2295
2434
|
WHERE created_at > datetime('now', '-${hours} hours')`
|
|
@@ -2300,7 +2439,8 @@ var ContinuityManager = class {
|
|
|
2300
2439
|
* Get transition type distribution
|
|
2301
2440
|
*/
|
|
2302
2441
|
async getTransitionStats(hours = 24) {
|
|
2303
|
-
const rows = await
|
|
2442
|
+
const rows = await dbAll(
|
|
2443
|
+
this.db,
|
|
2304
2444
|
`SELECT transition_type, COUNT(*) as count
|
|
2305
2445
|
FROM continuity_log
|
|
2306
2446
|
WHERE created_at > datetime('now', '-${hours} hours')
|
|
@@ -2320,7 +2460,8 @@ var ContinuityManager = class {
|
|
|
2320
2460
|
* Clear old continuity logs
|
|
2321
2461
|
*/
|
|
2322
2462
|
async cleanup(olderThanDays = 7) {
|
|
2323
|
-
const result = await
|
|
2463
|
+
const result = await dbAll(
|
|
2464
|
+
this.db,
|
|
2324
2465
|
`DELETE FROM continuity_log
|
|
2325
2466
|
WHERE created_at < datetime('now', '-${olderThanDays} days')
|
|
2326
2467
|
RETURNING COUNT(*) as changes`
|
|
@@ -2355,7 +2496,8 @@ var ContinuityManager = class {
|
|
|
2355
2496
|
* Log a context transition
|
|
2356
2497
|
*/
|
|
2357
2498
|
async logTransition(current, previous, score, type) {
|
|
2358
|
-
await
|
|
2499
|
+
await dbRun(
|
|
2500
|
+
this.db,
|
|
2359
2501
|
`INSERT INTO continuity_log
|
|
2360
2502
|
(log_id, from_context_id, to_context_id, continuity_score, transition_type, created_at)
|
|
2361
2503
|
VALUES (?, ?, ?, ?, ?, CURRENT_TIMESTAMP)`,
|
|
@@ -2468,6 +2610,23 @@ function createContinuityManager(eventStore, config) {
|
|
|
2468
2610
|
}
|
|
2469
2611
|
|
|
2470
2612
|
// src/services/memory-service.ts
|
|
2613
|
+
function normalizePath(projectPath) {
|
|
2614
|
+
const expanded = projectPath.startsWith("~") ? path.join(os.homedir(), projectPath.slice(1)) : projectPath;
|
|
2615
|
+
try {
|
|
2616
|
+
return fs.realpathSync(expanded);
|
|
2617
|
+
} catch {
|
|
2618
|
+
return path.resolve(expanded);
|
|
2619
|
+
}
|
|
2620
|
+
}
|
|
2621
|
+
function hashProjectPath(projectPath) {
|
|
2622
|
+
const normalizedPath = normalizePath(projectPath);
|
|
2623
|
+
return crypto2.createHash("sha256").update(normalizedPath).digest("hex").slice(0, 8);
|
|
2624
|
+
}
|
|
2625
|
+
function getProjectStoragePath(projectPath) {
|
|
2626
|
+
const hash = hashProjectPath(projectPath);
|
|
2627
|
+
return path.join(os.homedir(), ".claude-code", "memory", "projects", hash);
|
|
2628
|
+
}
|
|
2629
|
+
var REGISTRY_PATH = path.join(os.homedir(), ".claude-code", "memory", "session-registry.json");
|
|
2471
2630
|
var MemoryService = class {
|
|
2472
2631
|
eventStore;
|
|
2473
2632
|
vectorStore;
|
|
@@ -2915,14 +3074,23 @@ var MemoryService = class {
|
|
|
2915
3074
|
return p;
|
|
2916
3075
|
}
|
|
2917
3076
|
};
|
|
2918
|
-
var
|
|
3077
|
+
var serviceCache = /* @__PURE__ */ new Map();
|
|
3078
|
+
var GLOBAL_KEY = "__global__";
|
|
2919
3079
|
function getDefaultMemoryService() {
|
|
2920
|
-
if (!
|
|
2921
|
-
|
|
3080
|
+
if (!serviceCache.has(GLOBAL_KEY)) {
|
|
3081
|
+
serviceCache.set(GLOBAL_KEY, new MemoryService({
|
|
2922
3082
|
storagePath: "~/.claude-code/memory"
|
|
2923
|
-
});
|
|
3083
|
+
}));
|
|
3084
|
+
}
|
|
3085
|
+
return serviceCache.get(GLOBAL_KEY);
|
|
3086
|
+
}
|
|
3087
|
+
function getMemoryServiceForProject(projectPath) {
|
|
3088
|
+
const hash = hashProjectPath(projectPath);
|
|
3089
|
+
if (!serviceCache.has(hash)) {
|
|
3090
|
+
const storagePath = getProjectStoragePath(projectPath);
|
|
3091
|
+
serviceCache.set(hash, new MemoryService({ storagePath }));
|
|
2924
3092
|
}
|
|
2925
|
-
return
|
|
3093
|
+
return serviceCache.get(hash);
|
|
2926
3094
|
}
|
|
2927
3095
|
|
|
2928
3096
|
// src/services/session-history-importer.ts
|
|
@@ -3166,8 +3334,9 @@ function createSessionHistoryImporter(memoryService) {
|
|
|
3166
3334
|
// src/cli/index.ts
|
|
3167
3335
|
var program = new Command();
|
|
3168
3336
|
program.name("code-memory").description("Claude Code Memory Plugin CLI").version("1.0.0");
|
|
3169
|
-
program.command("search <query>").description("Search memories using semantic search").option("-k, --top-k <number>", "Number of results", "5").option("-s, --min-score <number>", "Minimum similarity score", "0.7").option("--session <id>", "Filter by session ID").action(async (query, options) => {
|
|
3170
|
-
const
|
|
3337
|
+
program.command("search <query>").description("Search memories using semantic search").option("-k, --top-k <number>", "Number of results", "5").option("-s, --min-score <number>", "Minimum similarity score", "0.7").option("--session <id>", "Filter by session ID").option("-p, --project <path>", "Project path (defaults to cwd)").action(async (query, options) => {
|
|
3338
|
+
const projectPath = options.project || process.cwd();
|
|
3339
|
+
const service = getMemoryServiceForProject(projectPath);
|
|
3171
3340
|
try {
|
|
3172
3341
|
const result = await service.retrieveMemories(query, {
|
|
3173
3342
|
topK: parseInt(options.topK),
|
|
@@ -3193,8 +3362,9 @@ program.command("search <query>").description("Search memories using semantic se
|
|
|
3193
3362
|
process.exit(1);
|
|
3194
3363
|
}
|
|
3195
3364
|
});
|
|
3196
|
-
program.command("history").description("View conversation history").option("-l, --limit <number>", "Number of events", "20").option("--session <id>", "Filter by session ID").option("--type <type>", "Filter by event type").action(async (options) => {
|
|
3197
|
-
const
|
|
3365
|
+
program.command("history").description("View conversation history").option("-l, --limit <number>", "Number of events", "20").option("--session <id>", "Filter by session ID").option("--type <type>", "Filter by event type").option("-p, --project <path>", "Project path (defaults to cwd)").action(async (options) => {
|
|
3366
|
+
const projectPath = options.project || process.cwd();
|
|
3367
|
+
const service = getMemoryServiceForProject(projectPath);
|
|
3198
3368
|
try {
|
|
3199
3369
|
let events;
|
|
3200
3370
|
if (options.session) {
|
|
@@ -3222,8 +3392,9 @@ program.command("history").description("View conversation history").option("-l,
|
|
|
3222
3392
|
process.exit(1);
|
|
3223
3393
|
}
|
|
3224
3394
|
});
|
|
3225
|
-
program.command("stats").description("View memory statistics").action(async () => {
|
|
3226
|
-
const
|
|
3395
|
+
program.command("stats").description("View memory statistics").option("-p, --project <path>", "Project path (defaults to cwd)").action(async (options) => {
|
|
3396
|
+
const projectPath = options.project || process.cwd();
|
|
3397
|
+
const service = getMemoryServiceForProject(projectPath);
|
|
3227
3398
|
try {
|
|
3228
3399
|
const stats = await service.getStats();
|
|
3229
3400
|
console.log("\n\u{1F4CA} Memory Statistics\n");
|
|
@@ -3240,8 +3411,9 @@ program.command("stats").description("View memory statistics").action(async () =
|
|
|
3240
3411
|
process.exit(1);
|
|
3241
3412
|
}
|
|
3242
3413
|
});
|
|
3243
|
-
program.command("forget [eventId]").description("Remove memories from storage").option("--session <id>", "Forget all events from a session").option("--before <date>", "Forget events before date (YYYY-MM-DD)").option("--confirm", "Skip confirmation").action(async (eventId, options) => {
|
|
3244
|
-
const
|
|
3414
|
+
program.command("forget [eventId]").description("Remove memories from storage").option("--session <id>", "Forget all events from a session").option("--before <date>", "Forget events before date (YYYY-MM-DD)").option("--confirm", "Skip confirmation").option("-p, --project <path>", "Project path (defaults to cwd)").action(async (eventId, options) => {
|
|
3415
|
+
const projectPath = options.project || process.cwd();
|
|
3416
|
+
const service = getMemoryServiceForProject(projectPath);
|
|
3245
3417
|
try {
|
|
3246
3418
|
if (!eventId && !options.session && !options.before) {
|
|
3247
3419
|
console.error("Please specify an event ID, --session, or --before option");
|
|
@@ -3260,8 +3432,9 @@ program.command("forget [eventId]").description("Remove memories from storage").
|
|
|
3260
3432
|
process.exit(1);
|
|
3261
3433
|
}
|
|
3262
3434
|
});
|
|
3263
|
-
program.command("process").description("Process pending embeddings").action(async () => {
|
|
3264
|
-
const
|
|
3435
|
+
program.command("process").description("Process pending embeddings").option("-p, --project <path>", "Project path (defaults to cwd)").action(async (options) => {
|
|
3436
|
+
const projectPath = options.project || process.cwd();
|
|
3437
|
+
const service = getMemoryServiceForProject(projectPath);
|
|
3265
3438
|
try {
|
|
3266
3439
|
console.log("\u23F3 Processing pending embeddings...");
|
|
3267
3440
|
const count = await service.processPendingEmbeddings();
|
|
@@ -3273,17 +3446,19 @@ program.command("process").description("Process pending embeddings").action(asyn
|
|
|
3273
3446
|
}
|
|
3274
3447
|
});
|
|
3275
3448
|
program.command("import").description("Import existing Claude Code conversation history").option("-p, --project <path>", "Import from specific project path").option("-s, --session <file>", "Import specific session file (JSONL)").option("-a, --all", "Import all sessions from all projects").option("-l, --limit <number>", "Limit messages per session").option("-v, --verbose", "Show detailed progress").action(async (options) => {
|
|
3276
|
-
const
|
|
3449
|
+
const targetProjectPath = options.project || process.cwd();
|
|
3450
|
+
const service = getMemoryServiceForProject(targetProjectPath);
|
|
3277
3451
|
const importer = createSessionHistoryImporter(service);
|
|
3278
3452
|
try {
|
|
3279
3453
|
await service.initialize();
|
|
3280
3454
|
let result;
|
|
3281
3455
|
if (options.session) {
|
|
3282
3456
|
console.log(`
|
|
3283
|
-
\u{1F4E5} Importing session: ${options.session}
|
|
3457
|
+
\u{1F4E5} Importing session: ${options.session}`);
|
|
3458
|
+
console.log(` Target project: ${targetProjectPath}
|
|
3284
3459
|
`);
|
|
3285
3460
|
result = await importer.importSessionFile(options.session, {
|
|
3286
|
-
projectPath:
|
|
3461
|
+
projectPath: targetProjectPath,
|
|
3287
3462
|
limit: options.limit ? parseInt(options.limit) : void 0,
|
|
3288
3463
|
verbose: options.verbose
|
|
3289
3464
|
});
|
|
@@ -3296,11 +3471,36 @@ program.command("import").description("Import existing Claude Code conversation
|
|
|
3296
3471
|
verbose: options.verbose
|
|
3297
3472
|
});
|
|
3298
3473
|
} else if (options.all) {
|
|
3299
|
-
console.log("\n\u{1F4E5} Importing all sessions from all projects
|
|
3300
|
-
|
|
3474
|
+
console.log("\n\u{1F4E5} Importing all sessions from all projects");
|
|
3475
|
+
console.log(" \u26A0\uFE0F Using global storage (use -p for project-specific)\n");
|
|
3476
|
+
const globalService = getDefaultMemoryService();
|
|
3477
|
+
const globalImporter = createSessionHistoryImporter(globalService);
|
|
3478
|
+
await globalService.initialize();
|
|
3479
|
+
result = await globalImporter.importAll({
|
|
3301
3480
|
limit: options.limit ? parseInt(options.limit) : void 0,
|
|
3302
3481
|
verbose: options.verbose
|
|
3303
3482
|
});
|
|
3483
|
+
console.log("\n\u23F3 Processing embeddings...");
|
|
3484
|
+
const embedCount2 = await globalService.processPendingEmbeddings();
|
|
3485
|
+
console.log("\n\u2705 Import Complete\n");
|
|
3486
|
+
console.log(`Sessions processed: ${result.totalSessions}`);
|
|
3487
|
+
console.log(`Total messages: ${result.totalMessages}`);
|
|
3488
|
+
console.log(`Imported prompts: ${result.importedPrompts}`);
|
|
3489
|
+
console.log(`Imported responses: ${result.importedResponses}`);
|
|
3490
|
+
console.log(`Skipped duplicates: ${result.skippedDuplicates}`);
|
|
3491
|
+
console.log(`Embeddings processed: ${embedCount2}`);
|
|
3492
|
+
if (result.errors.length > 0) {
|
|
3493
|
+
console.log(`
|
|
3494
|
+
\u26A0\uFE0F Errors (${result.errors.length}):`);
|
|
3495
|
+
for (const error of result.errors.slice(0, 5)) {
|
|
3496
|
+
console.log(` - ${error}`);
|
|
3497
|
+
}
|
|
3498
|
+
if (result.errors.length > 5) {
|
|
3499
|
+
console.log(` ... and ${result.errors.length - 5} more`);
|
|
3500
|
+
}
|
|
3501
|
+
}
|
|
3502
|
+
await globalService.shutdown();
|
|
3503
|
+
return;
|
|
3304
3504
|
} else {
|
|
3305
3505
|
const cwd = process.cwd();
|
|
3306
3506
|
console.log(`
|
|
@@ -3364,8 +3564,9 @@ program.command("list").description("List available Claude Code sessions").optio
|
|
|
3364
3564
|
}
|
|
3365
3565
|
});
|
|
3366
3566
|
var endlessCmd = program.command("endless").description("Manage Endless Mode (biomimetic continuous memory)");
|
|
3367
|
-
endlessCmd.command("enable").description("Enable Endless Mode").action(async () => {
|
|
3368
|
-
const
|
|
3567
|
+
endlessCmd.command("enable").description("Enable Endless Mode").option("-p, --project <path>", "Project path (defaults to cwd)").action(async (options) => {
|
|
3568
|
+
const projectPath = options.project || process.cwd();
|
|
3569
|
+
const service = getMemoryServiceForProject(projectPath);
|
|
3369
3570
|
try {
|
|
3370
3571
|
await service.initialize();
|
|
3371
3572
|
await service.setMode("endless");
|
|
@@ -3383,8 +3584,9 @@ endlessCmd.command("enable").description("Enable Endless Mode").action(async ()
|
|
|
3383
3584
|
process.exit(1);
|
|
3384
3585
|
}
|
|
3385
3586
|
});
|
|
3386
|
-
endlessCmd.command("disable").description("Disable Endless Mode (return to Session Mode)").action(async () => {
|
|
3387
|
-
const
|
|
3587
|
+
endlessCmd.command("disable").description("Disable Endless Mode (return to Session Mode)").option("-p, --project <path>", "Project path (defaults to cwd)").action(async (options) => {
|
|
3588
|
+
const projectPath = options.project || process.cwd();
|
|
3589
|
+
const service = getMemoryServiceForProject(projectPath);
|
|
3388
3590
|
try {
|
|
3389
3591
|
await service.initialize();
|
|
3390
3592
|
await service.setMode("session");
|
|
@@ -3397,8 +3599,9 @@ endlessCmd.command("disable").description("Disable Endless Mode (return to Sessi
|
|
|
3397
3599
|
process.exit(1);
|
|
3398
3600
|
}
|
|
3399
3601
|
});
|
|
3400
|
-
endlessCmd.command("status").description("Show Endless Mode status").action(async () => {
|
|
3401
|
-
const
|
|
3602
|
+
endlessCmd.command("status").description("Show Endless Mode status").option("-p, --project <path>", "Project path (defaults to cwd)").action(async (options) => {
|
|
3603
|
+
const projectPath = options.project || process.cwd();
|
|
3604
|
+
const service = getMemoryServiceForProject(projectPath);
|
|
3402
3605
|
try {
|
|
3403
3606
|
await service.initialize();
|
|
3404
3607
|
const status = await service.getEndlessModeStatus();
|
|
@@ -3430,8 +3633,9 @@ ${modeIcon} ${modeName}
|
|
|
3430
3633
|
process.exit(1);
|
|
3431
3634
|
}
|
|
3432
3635
|
});
|
|
3433
|
-
endlessCmd.command("consolidate").description("Manually trigger memory consolidation").action(async () => {
|
|
3434
|
-
const
|
|
3636
|
+
endlessCmd.command("consolidate").description("Manually trigger memory consolidation").option("-p, --project <path>", "Project path (defaults to cwd)").action(async (options) => {
|
|
3637
|
+
const projectPath = options.project || process.cwd();
|
|
3638
|
+
const service = getMemoryServiceForProject(projectPath);
|
|
3435
3639
|
try {
|
|
3436
3640
|
await service.initialize();
|
|
3437
3641
|
if (!service.isEndlessModeActive()) {
|
|
@@ -3454,8 +3658,9 @@ endlessCmd.command("consolidate").description("Manually trigger memory consolida
|
|
|
3454
3658
|
process.exit(1);
|
|
3455
3659
|
}
|
|
3456
3660
|
});
|
|
3457
|
-
endlessCmd.command("working-set").alias("ws").description("View current working set").option("-l, --limit <number>", "Number of events to show", "10").action(async (options) => {
|
|
3458
|
-
const
|
|
3661
|
+
endlessCmd.command("working-set").alias("ws").description("View current working set").option("-l, --limit <number>", "Number of events to show", "10").option("-p, --project <path>", "Project path (defaults to cwd)").action(async (options) => {
|
|
3662
|
+
const projectPath = options.project || process.cwd();
|
|
3663
|
+
const service = getMemoryServiceForProject(projectPath);
|
|
3459
3664
|
try {
|
|
3460
3665
|
await service.initialize();
|
|
3461
3666
|
if (!service.isEndlessModeActive()) {
|
|
@@ -3493,8 +3698,9 @@ endlessCmd.command("working-set").alias("ws").description("View current working
|
|
|
3493
3698
|
process.exit(1);
|
|
3494
3699
|
}
|
|
3495
3700
|
});
|
|
3496
|
-
endlessCmd.command("memories").description("View consolidated memories").option("-l, --limit <number>", "Number of memories to show", "10").option("-q, --query <text>", "Search consolidated memories").action(async (options) => {
|
|
3497
|
-
const
|
|
3701
|
+
endlessCmd.command("memories").description("View consolidated memories").option("-l, --limit <number>", "Number of memories to show", "10").option("-q, --query <text>", "Search consolidated memories").option("-p, --project <path>", "Project path (defaults to cwd)").action(async (options) => {
|
|
3702
|
+
const projectPath = options.project || process.cwd();
|
|
3703
|
+
const service = getMemoryServiceForProject(projectPath);
|
|
3498
3704
|
try {
|
|
3499
3705
|
await service.initialize();
|
|
3500
3706
|
let memories;
|