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.
Files changed (37) hide show
  1. package/.claude/settings.local.json +14 -0
  2. package/.history/package_20260201114632.json +46 -0
  3. package/dist/cli/index.js +360 -154
  4. package/dist/cli/index.js.map +4 -4
  5. package/dist/core/index.js +337 -161
  6. package/dist/core/index.js.map +3 -3
  7. package/dist/hooks/session-end.js +320 -130
  8. package/dist/hooks/session-end.js.map +4 -4
  9. package/dist/hooks/session-start.js +331 -138
  10. package/dist/hooks/session-start.js.map +4 -4
  11. package/dist/hooks/stop.js +320 -130
  12. package/dist/hooks/stop.js.map +4 -4
  13. package/dist/hooks/user-prompt-submit.js +320 -130
  14. package/dist/hooks/user-prompt-submit.js.map +4 -4
  15. package/dist/services/memory-service.js +349 -128
  16. package/dist/services/memory-service.js.map +4 -4
  17. package/package.json +2 -1
  18. package/src/cli/index.ts +84 -23
  19. package/src/core/consolidated-store.ts +33 -18
  20. package/src/core/continuity-manager.ts +12 -7
  21. package/src/core/db-wrapper.ts +112 -0
  22. package/src/core/edge-repo.ts +22 -13
  23. package/src/core/entity-repo.ts +23 -14
  24. package/src/core/event-store.ts +98 -72
  25. package/src/core/task/blocker-resolver.ts +17 -9
  26. package/src/core/task/task-matcher.ts +8 -6
  27. package/src/core/task/task-projector.ts +29 -16
  28. package/src/core/task/task-resolver.ts +17 -9
  29. package/src/core/vector-outbox.ts +29 -16
  30. package/src/core/vector-store.ts +23 -12
  31. package/src/core/vector-worker.ts +7 -4
  32. package/src/core/working-set-store.ts +31 -18
  33. package/src/hooks/session-end.ts +3 -2
  34. package/src/hooks/session-start.ts +12 -8
  35. package/src/hooks/stop.ts +3 -2
  36. package/src/hooks/user-prompt-submit.ts +3 -2
  37. 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 = new Database(dbPath);
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.run(`
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.run(`
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.run(`
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.run(`
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.run(`
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.run(`
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.run(`
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.run(`
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.run(`
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.run(`
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.run(`
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.run(`
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.run(`
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.run(`
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.run(`
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.run(`
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.run(`
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.run(`
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.run(`CREATE INDEX IF NOT EXISTS idx_entries_type ON entries(entry_type)`);
260
- await this.db.run(`CREATE INDEX IF NOT EXISTS idx_entries_stage ON entries(stage)`);
261
- await this.db.run(`CREATE INDEX IF NOT EXISTS idx_entries_canonical ON entries(canonical_key)`);
262
- await this.db.run(`CREATE INDEX IF NOT EXISTS idx_entities_type_key ON entities(entity_type, canonical_key)`);
263
- await this.db.run(`CREATE INDEX IF NOT EXISTS idx_entities_status ON entities(status)`);
264
- await this.db.run(`CREATE INDEX IF NOT EXISTS idx_edges_src ON edges(src_id, rel_type)`);
265
- await this.db.run(`CREATE INDEX IF NOT EXISTS idx_edges_dst ON edges(dst_id, rel_type)`);
266
- await this.db.run(`CREATE INDEX IF NOT EXISTS idx_edges_rel ON edges(rel_type)`);
267
- await this.db.run(`CREATE INDEX IF NOT EXISTS idx_outbox_status ON vector_outbox(status)`);
268
- await this.db.run(`CREATE INDEX IF NOT EXISTS idx_working_set_expires ON working_set(expires_at)`);
269
- await this.db.run(`CREATE INDEX IF NOT EXISTS idx_working_set_relevance ON working_set(relevance_score DESC)`);
270
- await this.db.run(`CREATE INDEX IF NOT EXISTS idx_consolidated_confidence ON consolidated_memories(confidence DESC)`);
271
- await this.db.run(`CREATE INDEX IF NOT EXISTS idx_continuity_created ON continuity_log(created_at)`);
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 this.db.all(
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 this.db.run(
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 this.db.run(
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 this.db.run(
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 this.db.all(
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 this.db.all(
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 this.db.all(
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 this.db.all(
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 this.db.run(
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 this.db.run(
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 this.db.all(
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: new Date(row.started_at),
420
- endedAt: row.ended_at ? new Date(row.ended_at) : void 0,
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 this.db.run(
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 rows = await this.db.all(
445
- `UPDATE embedding_outbox
446
- SET status = 'processing'
447
- WHERE id IN (
448
- SELECT id FROM embedding_outbox
449
- WHERE status = 'pending'
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
- return rows.map((row) => ({
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: row.status,
557
+ status: "processing",
461
558
  retryCount: row.retry_count,
462
- createdAt: new Date(row.created_at),
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 this.db.run(
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 this.db.run(
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 this.db.run(
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 this.db.all(
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 this.db.all(
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 this.db.run(
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 this.db.all(
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: new Date(row.started_at),
558
- endedAt: row.ended_at ? new Date(row.ended_at) : void 0,
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.close();
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: new Date(row.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 score = 1 - (r._distance || 0);
781
+ const distance = r._distance || 0;
782
+ const score = 1 - distance / 2;
678
783
  return score >= minScore;
679
- }).slice(0, limit).map((r) => ({
680
- id: r.id,
681
- eventId: r.eventId,
682
- content: r.content,
683
- score: 1 - (r._distance || 0),
684
- sessionId: r.sessionId,
685
- eventType: r.eventType,
686
- timestamp: r.timestamp
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 this.db.run(
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 this.db.all(
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: new Date(row.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 this.db.all(
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: new Date(row.added_at),
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: new Date(row.expires_at)
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 this.db.run(
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 this.db.run(
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 this.db.all(
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.run(`DELETE FROM working_set`);
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 this.db.all(
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 this.db.run(
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 this.db.run(
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 this.db.all(
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 this.db.run(
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 this.db.all(
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 this.db.all(
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 this.db.run(
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 this.db.all(
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 this.db.all(
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 this.db.all(
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 this.db.all(
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 this.db.all(
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 this.db.run(
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 this.db.run(
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 this.db.run(
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 this.db.all(
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 this.db.all(
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 this.db.all(
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 this.db.all(
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 this.db.all(
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 this.db.all(
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: new Date(row.created_at),
1907
- accessedAt: row.accessed_at ? new Date(row.accessed_at) : void 0,
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 this.db.all(
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: new Date(row.created_at)
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 this.db.all(
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 this.db.all(
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 this.db.all(
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 this.db.run(
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 defaultService = null;
3077
+ var serviceCache = /* @__PURE__ */ new Map();
3078
+ var GLOBAL_KEY = "__global__";
2919
3079
  function getDefaultMemoryService() {
2920
- if (!defaultService) {
2921
- defaultService = new MemoryService({
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 defaultService;
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 service = getDefaultMemoryService();
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 service = getDefaultMemoryService();
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 service = getDefaultMemoryService();
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 service = getDefaultMemoryService();
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 service = getDefaultMemoryService();
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 service = getDefaultMemoryService();
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: options.project,
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\n");
3300
- result = await importer.importAll({
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 service = getDefaultMemoryService();
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 service = getDefaultMemoryService();
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 service = getDefaultMemoryService();
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 service = getDefaultMemoryService();
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 service = getDefaultMemoryService();
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 service = getDefaultMemoryService();
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;