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
@@ -3,7 +3,6 @@
3
3
  * Principles: Append-only, Single Source of Truth, Idempotency
4
4
  */
5
5
 
6
- import { Database } from 'duckdb';
7
6
  import { randomUUID } from 'crypto';
8
7
  import {
9
8
  MemoryEvent,
@@ -13,13 +12,14 @@ import {
13
12
  OutboxItem
14
13
  } from './types.js';
15
14
  import { makeCanonicalKey, makeDedupeKey } from './canonical-key.js';
15
+ import { createDatabase, dbRun, dbAll, dbClose, toDate, type Database } from './db-wrapper.js';
16
16
 
17
17
  export class EventStore {
18
18
  private db: Database;
19
19
  private initialized = false;
20
20
 
21
21
  constructor(private dbPath: string) {
22
- this.db = new Database(dbPath);
22
+ this.db = createDatabase(dbPath);
23
23
  }
24
24
 
25
25
  /**
@@ -29,7 +29,7 @@ export class EventStore {
29
29
  if (this.initialized) return;
30
30
 
31
31
  // L0 EventStore: Single Source of Truth (immutable, append-only)
32
- await this.db.run(`
32
+ await dbRun(this.db, `
33
33
  CREATE TABLE IF NOT EXISTS events (
34
34
  id VARCHAR PRIMARY KEY,
35
35
  event_type VARCHAR NOT NULL,
@@ -43,7 +43,7 @@ export class EventStore {
43
43
  `);
44
44
 
45
45
  // Dedup table for idempotency
46
- await this.db.run(`
46
+ await dbRun(this.db, `
47
47
  CREATE TABLE IF NOT EXISTS event_dedup (
48
48
  dedupe_key VARCHAR PRIMARY KEY,
49
49
  event_id VARCHAR NOT NULL,
@@ -52,7 +52,7 @@ export class EventStore {
52
52
  `);
53
53
 
54
54
  // Session metadata
55
- await this.db.run(`
55
+ await dbRun(this.db, `
56
56
  CREATE TABLE IF NOT EXISTS sessions (
57
57
  id VARCHAR PRIMARY KEY,
58
58
  started_at TIMESTAMP NOT NULL,
@@ -64,7 +64,7 @@ export class EventStore {
64
64
  `);
65
65
 
66
66
  // Insights (derived data, rebuildable)
67
- await this.db.run(`
67
+ await dbRun(this.db, `
68
68
  CREATE TABLE IF NOT EXISTS insights (
69
69
  id VARCHAR PRIMARY KEY,
70
70
  insight_type VARCHAR NOT NULL,
@@ -78,7 +78,7 @@ export class EventStore {
78
78
  `);
79
79
 
80
80
  // Embedding Outbox (Single-Writer Pattern)
81
- await this.db.run(`
81
+ await dbRun(this.db, `
82
82
  CREATE TABLE IF NOT EXISTS embedding_outbox (
83
83
  id VARCHAR PRIMARY KEY,
84
84
  event_id VARCHAR NOT NULL,
@@ -92,7 +92,7 @@ export class EventStore {
92
92
  `);
93
93
 
94
94
  // Projection offset tracking
95
- await this.db.run(`
95
+ await dbRun(this.db, `
96
96
  CREATE TABLE IF NOT EXISTS projection_offsets (
97
97
  projection_name VARCHAR PRIMARY KEY,
98
98
  last_event_id VARCHAR,
@@ -102,7 +102,7 @@ export class EventStore {
102
102
  `);
103
103
 
104
104
  // Memory level tracking
105
- await this.db.run(`
105
+ await dbRun(this.db, `
106
106
  CREATE TABLE IF NOT EXISTS memory_levels (
107
107
  event_id VARCHAR PRIMARY KEY,
108
108
  level VARCHAR NOT NULL DEFAULT 'L0',
@@ -115,7 +115,7 @@ export class EventStore {
115
115
  // ============================================================
116
116
 
117
117
  // Entries (immutable memory units)
118
- await this.db.run(`
118
+ await dbRun(this.db, `
119
119
  CREATE TABLE IF NOT EXISTS entries (
120
120
  entry_id VARCHAR PRIMARY KEY,
121
121
  created_ts TIMESTAMP NOT NULL,
@@ -133,7 +133,7 @@ export class EventStore {
133
133
  `);
134
134
 
135
135
  // Entities (task/condition/artifact)
136
- await this.db.run(`
136
+ await dbRun(this.db, `
137
137
  CREATE TABLE IF NOT EXISTS entities (
138
138
  entity_id VARCHAR PRIMARY KEY,
139
139
  entity_type VARCHAR NOT NULL,
@@ -150,7 +150,7 @@ export class EventStore {
150
150
  `);
151
151
 
152
152
  // Entity aliases for canonical key lookup
153
- await this.db.run(`
153
+ await dbRun(this.db, `
154
154
  CREATE TABLE IF NOT EXISTS entity_aliases (
155
155
  entity_type VARCHAR NOT NULL,
156
156
  canonical_key VARCHAR NOT NULL,
@@ -162,7 +162,7 @@ export class EventStore {
162
162
  `);
163
163
 
164
164
  // Edges (relationships between entries/entities)
165
- await this.db.run(`
165
+ await dbRun(this.db, `
166
166
  CREATE TABLE IF NOT EXISTS edges (
167
167
  edge_id VARCHAR PRIMARY KEY,
168
168
  src_type VARCHAR NOT NULL,
@@ -179,7 +179,7 @@ export class EventStore {
179
179
  // Vector Outbox V2 Table
180
180
  // ============================================================
181
181
 
182
- await this.db.run(`
182
+ await dbRun(this.db, `
183
183
  CREATE TABLE IF NOT EXISTS vector_outbox (
184
184
  job_id VARCHAR PRIMARY KEY,
185
185
  item_kind VARCHAR NOT NULL,
@@ -198,7 +198,7 @@ export class EventStore {
198
198
  // Build Runs & Metrics Tables
199
199
  // ============================================================
200
200
 
201
- await this.db.run(`
201
+ await dbRun(this.db, `
202
202
  CREATE TABLE IF NOT EXISTS build_runs (
203
203
  build_id VARCHAR PRIMARY KEY,
204
204
  started_at TIMESTAMP NOT NULL,
@@ -214,7 +214,7 @@ export class EventStore {
214
214
  )
215
215
  `);
216
216
 
217
- await this.db.run(`
217
+ await dbRun(this.db, `
218
218
  CREATE TABLE IF NOT EXISTS pipeline_metrics (
219
219
  id VARCHAR PRIMARY KEY,
220
220
  ts TIMESTAMP NOT NULL,
@@ -231,7 +231,7 @@ export class EventStore {
231
231
  // ============================================================
232
232
 
233
233
  // Working Set table (active memory window)
234
- await this.db.run(`
234
+ await dbRun(this.db, `
235
235
  CREATE TABLE IF NOT EXISTS working_set (
236
236
  id VARCHAR PRIMARY KEY,
237
237
  event_id VARCHAR NOT NULL,
@@ -243,7 +243,7 @@ export class EventStore {
243
243
  `);
244
244
 
245
245
  // Consolidated Memories table (long-term integrated memories)
246
- await this.db.run(`
246
+ await dbRun(this.db, `
247
247
  CREATE TABLE IF NOT EXISTS consolidated_memories (
248
248
  memory_id VARCHAR PRIMARY KEY,
249
249
  summary TEXT NOT NULL,
@@ -257,7 +257,7 @@ export class EventStore {
257
257
  `);
258
258
 
259
259
  // Continuity Log table (tracks context transitions)
260
- await this.db.run(`
260
+ await dbRun(this.db, `
261
261
  CREATE TABLE IF NOT EXISTS continuity_log (
262
262
  log_id VARCHAR PRIMARY KEY,
263
263
  from_context_id VARCHAR,
@@ -269,7 +269,7 @@ export class EventStore {
269
269
  `);
270
270
 
271
271
  // Endless Mode Config table
272
- await this.db.run(`
272
+ await dbRun(this.db, `
273
273
  CREATE TABLE IF NOT EXISTS endless_config (
274
274
  key VARCHAR PRIMARY KEY,
275
275
  value JSON,
@@ -282,27 +282,27 @@ export class EventStore {
282
282
  // ============================================================
283
283
 
284
284
  // Entry indexes
285
- await this.db.run(`CREATE INDEX IF NOT EXISTS idx_entries_type ON entries(entry_type)`);
286
- await this.db.run(`CREATE INDEX IF NOT EXISTS idx_entries_stage ON entries(stage)`);
287
- await this.db.run(`CREATE INDEX IF NOT EXISTS idx_entries_canonical ON entries(canonical_key)`);
285
+ await dbRun(this.db, `CREATE INDEX IF NOT EXISTS idx_entries_type ON entries(entry_type)`);
286
+ await dbRun(this.db, `CREATE INDEX IF NOT EXISTS idx_entries_stage ON entries(stage)`);
287
+ await dbRun(this.db, `CREATE INDEX IF NOT EXISTS idx_entries_canonical ON entries(canonical_key)`);
288
288
 
289
289
  // Entity indexes
290
- await this.db.run(`CREATE INDEX IF NOT EXISTS idx_entities_type_key ON entities(entity_type, canonical_key)`);
291
- await this.db.run(`CREATE INDEX IF NOT EXISTS idx_entities_status ON entities(status)`);
290
+ await dbRun(this.db, `CREATE INDEX IF NOT EXISTS idx_entities_type_key ON entities(entity_type, canonical_key)`);
291
+ await dbRun(this.db, `CREATE INDEX IF NOT EXISTS idx_entities_status ON entities(status)`);
292
292
 
293
293
  // Edge indexes
294
- await this.db.run(`CREATE INDEX IF NOT EXISTS idx_edges_src ON edges(src_id, rel_type)`);
295
- await this.db.run(`CREATE INDEX IF NOT EXISTS idx_edges_dst ON edges(dst_id, rel_type)`);
296
- await this.db.run(`CREATE INDEX IF NOT EXISTS idx_edges_rel ON edges(rel_type)`);
294
+ await dbRun(this.db, `CREATE INDEX IF NOT EXISTS idx_edges_src ON edges(src_id, rel_type)`);
295
+ await dbRun(this.db, `CREATE INDEX IF NOT EXISTS idx_edges_dst ON edges(dst_id, rel_type)`);
296
+ await dbRun(this.db, `CREATE INDEX IF NOT EXISTS idx_edges_rel ON edges(rel_type)`);
297
297
 
298
298
  // Outbox indexes
299
- await this.db.run(`CREATE INDEX IF NOT EXISTS idx_outbox_status ON vector_outbox(status)`);
299
+ await dbRun(this.db, `CREATE INDEX IF NOT EXISTS idx_outbox_status ON vector_outbox(status)`);
300
300
 
301
301
  // Endless Mode indexes
302
- await this.db.run(`CREATE INDEX IF NOT EXISTS idx_working_set_expires ON working_set(expires_at)`);
303
- await this.db.run(`CREATE INDEX IF NOT EXISTS idx_working_set_relevance ON working_set(relevance_score DESC)`);
304
- await this.db.run(`CREATE INDEX IF NOT EXISTS idx_consolidated_confidence ON consolidated_memories(confidence DESC)`);
305
- await this.db.run(`CREATE INDEX IF NOT EXISTS idx_continuity_created ON continuity_log(created_at)`);
302
+ await dbRun(this.db, `CREATE INDEX IF NOT EXISTS idx_working_set_expires ON working_set(expires_at)`);
303
+ await dbRun(this.db, `CREATE INDEX IF NOT EXISTS idx_working_set_relevance ON working_set(relevance_score DESC)`);
304
+ await dbRun(this.db, `CREATE INDEX IF NOT EXISTS idx_consolidated_confidence ON consolidated_memories(confidence DESC)`);
305
+ await dbRun(this.db, `CREATE INDEX IF NOT EXISTS idx_continuity_created ON continuity_log(created_at)`);
306
306
 
307
307
  this.initialized = true;
308
308
  }
@@ -318,7 +318,8 @@ export class EventStore {
318
318
  const dedupeKey = makeDedupeKey(input.content, input.sessionId);
319
319
 
320
320
  // Check for duplicate
321
- const existing = await this.db.all<{ event_id: string }[]>(
321
+ const existing = await dbAll<{ event_id: string }>(
322
+ this.db,
322
323
  `SELECT event_id FROM event_dedup WHERE dedupe_key = ?`,
323
324
  [dedupeKey]
324
325
  );
@@ -335,7 +336,8 @@ export class EventStore {
335
336
  const timestamp = input.timestamp.toISOString();
336
337
 
337
338
  try {
338
- await this.db.run(
339
+ await dbRun(
340
+ this.db,
339
341
  `INSERT INTO events (id, event_type, session_id, timestamp, content, canonical_key, dedupe_key, metadata)
340
342
  VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
341
343
  [
@@ -350,13 +352,15 @@ export class EventStore {
350
352
  ]
351
353
  );
352
354
 
353
- await this.db.run(
355
+ await dbRun(
356
+ this.db,
354
357
  `INSERT INTO event_dedup (dedupe_key, event_id) VALUES (?, ?)`,
355
358
  [dedupeKey, id]
356
359
  );
357
360
 
358
361
  // Initialize at L0
359
- await this.db.run(
362
+ await dbRun(
363
+ this.db,
360
364
  `INSERT INTO memory_levels (event_id, level) VALUES (?, 'L0')`,
361
365
  [id]
362
366
  );
@@ -376,7 +380,8 @@ export class EventStore {
376
380
  async getSessionEvents(sessionId: string): Promise<MemoryEvent[]> {
377
381
  await this.initialize();
378
382
 
379
- const rows = await this.db.all<Array<Record<string, unknown>>>(
383
+ const rows = await dbAll<Record<string, unknown>>(
384
+ this.db,
380
385
  `SELECT * FROM events WHERE session_id = ? ORDER BY timestamp ASC`,
381
386
  [sessionId]
382
387
  );
@@ -390,7 +395,8 @@ export class EventStore {
390
395
  async getRecentEvents(limit: number = 100): Promise<MemoryEvent[]> {
391
396
  await this.initialize();
392
397
 
393
- const rows = await this.db.all<Array<Record<string, unknown>>>(
398
+ const rows = await dbAll<Record<string, unknown>>(
399
+ this.db,
394
400
  `SELECT * FROM events ORDER BY timestamp DESC LIMIT ?`,
395
401
  [limit]
396
402
  );
@@ -404,7 +410,8 @@ export class EventStore {
404
410
  async getEvent(id: string): Promise<MemoryEvent | null> {
405
411
  await this.initialize();
406
412
 
407
- const rows = await this.db.all<Array<Record<string, unknown>>>(
413
+ const rows = await dbAll<Record<string, unknown>>(
414
+ this.db,
408
415
  `SELECT * FROM events WHERE id = ?`,
409
416
  [id]
410
417
  );
@@ -419,13 +426,15 @@ export class EventStore {
419
426
  async upsertSession(session: Partial<Session> & { id: string }): Promise<void> {
420
427
  await this.initialize();
421
428
 
422
- const existing = await this.db.all<Array<{ id: string }>>(
429
+ const existing = await dbAll<{ id: string }>(
430
+ this.db,
423
431
  `SELECT id FROM sessions WHERE id = ?`,
424
432
  [session.id]
425
433
  );
426
434
 
427
435
  if (existing.length === 0) {
428
- await this.db.run(
436
+ await dbRun(
437
+ this.db,
429
438
  `INSERT INTO sessions (id, started_at, project_path, tags)
430
439
  VALUES (?, ?, ?, ?)`,
431
440
  [
@@ -454,7 +463,8 @@ export class EventStore {
454
463
 
455
464
  if (updates.length > 0) {
456
465
  values.push(session.id);
457
- await this.db.run(
466
+ await dbRun(
467
+ this.db,
458
468
  `UPDATE sessions SET ${updates.join(', ')} WHERE id = ?`,
459
469
  values
460
470
  );
@@ -468,7 +478,8 @@ export class EventStore {
468
478
  async getSession(id: string): Promise<Session | null> {
469
479
  await this.initialize();
470
480
 
471
- const rows = await this.db.all<Array<Record<string, unknown>>>(
481
+ const rows = await dbAll<Record<string, unknown>>(
482
+ this.db,
472
483
  `SELECT * FROM sessions WHERE id = ?`,
473
484
  [id]
474
485
  );
@@ -478,8 +489,8 @@ export class EventStore {
478
489
  const row = rows[0];
479
490
  return {
480
491
  id: row.id as string,
481
- startedAt: new Date(row.started_at as string),
482
- endedAt: row.ended_at ? new Date(row.ended_at as string) : undefined,
492
+ startedAt: toDate(row.started_at),
493
+ endedAt: row.ended_at ? toDate(row.ended_at) : undefined,
483
494
  projectPath: row.project_path as string | undefined,
484
495
  summary: row.summary as string | undefined,
485
496
  tags: row.tags ? JSON.parse(row.tags as string) : undefined
@@ -493,7 +504,8 @@ export class EventStore {
493
504
  await this.initialize();
494
505
 
495
506
  const id = randomUUID();
496
- await this.db.run(
507
+ await dbRun(
508
+ this.db,
497
509
  `INSERT INTO embedding_outbox (id, event_id, content, status, retry_count)
498
510
  VALUES (?, ?, ?, 'pending', 0)`,
499
511
  [id, eventId, content]
@@ -508,27 +520,34 @@ export class EventStore {
508
520
  async getPendingOutboxItems(limit: number = 32): Promise<OutboxItem[]> {
509
521
  await this.initialize();
510
522
 
511
- // Atomic update to claim items
512
- const rows = await this.db.all<Array<Record<string, unknown>>>(
513
- `UPDATE embedding_outbox
514
- SET status = 'processing'
515
- WHERE id IN (
516
- SELECT id FROM embedding_outbox
517
- WHERE status = 'pending'
518
- ORDER BY created_at
519
- LIMIT ?
520
- )
521
- RETURNING *`,
523
+ // First, get pending items
524
+ const pending = await dbAll<Record<string, unknown>>(
525
+ this.db,
526
+ `SELECT * FROM embedding_outbox
527
+ WHERE status = 'pending'
528
+ ORDER BY created_at
529
+ LIMIT ?`,
522
530
  [limit]
523
531
  );
524
532
 
525
- return rows.map(row => ({
533
+ if (pending.length === 0) return [];
534
+
535
+ // Update status to processing
536
+ const ids = pending.map(r => r.id as string);
537
+ const placeholders = ids.map(() => '?').join(',');
538
+ await dbRun(
539
+ this.db,
540
+ `UPDATE embedding_outbox SET status = 'processing' WHERE id IN (${placeholders})`,
541
+ ids
542
+ );
543
+
544
+ return pending.map(row => ({
526
545
  id: row.id as string,
527
546
  eventId: row.event_id as string,
528
547
  content: row.content as string,
529
- status: row.status as 'pending' | 'processing' | 'done' | 'failed',
548
+ status: 'processing' as const,
530
549
  retryCount: row.retry_count as number,
531
- createdAt: new Date(row.created_at as string),
550
+ createdAt: toDate(row.created_at),
532
551
  errorMessage: row.error_message as string | undefined
533
552
  }));
534
553
  }
@@ -540,7 +559,8 @@ export class EventStore {
540
559
  if (ids.length === 0) return;
541
560
 
542
561
  const placeholders = ids.map(() => '?').join(',');
543
- await this.db.run(
562
+ await dbRun(
563
+ this.db,
544
564
  `DELETE FROM embedding_outbox WHERE id IN (${placeholders})`,
545
565
  ids
546
566
  );
@@ -553,7 +573,8 @@ export class EventStore {
553
573
  if (ids.length === 0) return;
554
574
 
555
575
  const placeholders = ids.map(() => '?').join(',');
556
- await this.db.run(
576
+ await dbRun(
577
+ this.db,
557
578
  `UPDATE embedding_outbox
558
579
  SET status = CASE WHEN retry_count >= 3 THEN 'failed' ELSE 'pending' END,
559
580
  retry_count = retry_count + 1,
@@ -569,7 +590,8 @@ export class EventStore {
569
590
  async updateMemoryLevel(eventId: string, level: string): Promise<void> {
570
591
  await this.initialize();
571
592
 
572
- await this.db.run(
593
+ await dbRun(
594
+ this.db,
573
595
  `UPDATE memory_levels SET level = ?, promoted_at = CURRENT_TIMESTAMP WHERE event_id = ?`,
574
596
  [level, eventId]
575
597
  );
@@ -581,7 +603,8 @@ export class EventStore {
581
603
  async getLevelStats(): Promise<Array<{ level: string; count: number }>> {
582
604
  await this.initialize();
583
605
 
584
- const rows = await this.db.all<Array<{ level: string; count: number }>>(
606
+ const rows = await dbAll<{ level: string; count: number }>(
607
+ this.db,
585
608
  `SELECT level, COUNT(*) as count FROM memory_levels GROUP BY level`
586
609
  );
587
610
 
@@ -605,7 +628,8 @@ export class EventStore {
605
628
  async getEndlessConfig(key: string): Promise<unknown | null> {
606
629
  await this.initialize();
607
630
 
608
- const rows = await this.db.all<Array<{ value: string }>>(
631
+ const rows = await dbAll<{ value: string }>(
632
+ this.db,
609
633
  `SELECT value FROM endless_config WHERE key = ?`,
610
634
  [key]
611
635
  );
@@ -620,7 +644,8 @@ export class EventStore {
620
644
  async setEndlessConfig(key: string, value: unknown): Promise<void> {
621
645
  await this.initialize();
622
646
 
623
- await this.db.run(
647
+ await dbRun(
648
+ this.db,
624
649
  `INSERT OR REPLACE INTO endless_config (key, value, updated_at)
625
650
  VALUES (?, ?, CURRENT_TIMESTAMP)`,
626
651
  [key, JSON.stringify(value)]
@@ -633,14 +658,15 @@ export class EventStore {
633
658
  async getAllSessions(): Promise<Session[]> {
634
659
  await this.initialize();
635
660
 
636
- const rows = await this.db.all<Array<Record<string, unknown>>>(
661
+ const rows = await dbAll<Record<string, unknown>>(
662
+ this.db,
637
663
  `SELECT * FROM sessions ORDER BY started_at DESC`
638
664
  );
639
665
 
640
666
  return rows.map(row => ({
641
667
  id: row.id as string,
642
- startedAt: new Date(row.started_at as string),
643
- endedAt: row.ended_at ? new Date(row.ended_at as string) : undefined,
668
+ startedAt: toDate(row.started_at),
669
+ endedAt: row.ended_at ? toDate(row.ended_at) : undefined,
644
670
  projectPath: row.project_path as string | undefined,
645
671
  summary: row.summary as string | undefined,
646
672
  tags: row.tags ? JSON.parse(row.tags as string) : undefined
@@ -651,7 +677,7 @@ export class EventStore {
651
677
  * Close database connection
652
678
  */
653
679
  async close(): Promise<void> {
654
- await this.db.close();
680
+ await dbClose(this.db);
655
681
  }
656
682
 
657
683
  /**
@@ -662,7 +688,7 @@ export class EventStore {
662
688
  id: row.id as string,
663
689
  eventType: row.event_type as 'user_prompt' | 'agent_response' | 'session_summary',
664
690
  sessionId: row.session_id as string,
665
- timestamp: new Date(row.timestamp as string),
691
+ timestamp: toDate(row.timestamp),
666
692
  content: row.content as string,
667
693
  canonicalKey: row.canonical_key as string,
668
694
  dedupeKey: row.dedupe_key as string,
@@ -3,7 +3,7 @@
3
3
  * AXIOMMIND: No stub task creation, fallback to condition
4
4
  */
5
5
 
6
- import { Database } from 'duckdb';
6
+ import { dbRun, dbAll, type Database } from '../db-wrapper.js';
7
7
  import { randomUUID } from 'crypto';
8
8
  import type { BlockerRef, BlockerKind, Entity } from '../types.js';
9
9
  import { makeEntityCanonicalKey, makeArtifactKey } from '../canonical-key.js';
@@ -110,7 +110,8 @@ export class BlockerResolver {
110
110
  const canonicalKey = makeArtifactKey(text);
111
111
 
112
112
  // Find or create artifact
113
- const existing = await this.db.all<Array<Record<string, unknown>>>(
113
+ const existing = await dbAll<Record<string, unknown>>(
114
+ this.db,
114
115
  `SELECT entity_id FROM entities
115
116
  WHERE entity_type = 'artifact' AND canonical_key = ?`,
116
117
  [canonicalKey]
@@ -138,7 +139,8 @@ export class BlockerResolver {
138
139
  */
139
140
  private async tryResolveAsTaskId(taskId: string): Promise<BlockerRef | null> {
140
141
  // taskId format: task:project:identifier
141
- const rows = await this.db.all<Array<Record<string, unknown>>>(
142
+ const rows = await dbAll<Record<string, unknown>>(
143
+ this.db,
142
144
  `SELECT entity_id FROM entities
143
145
  WHERE entity_type = 'task' AND canonical_key = ?
144
146
  AND status = 'active'`,
@@ -169,7 +171,8 @@ export class BlockerResolver {
169
171
  });
170
172
 
171
173
  // Find existing condition
172
- const existing = await this.db.all<Array<Record<string, unknown>>>(
174
+ const existing = await dbAll<Record<string, unknown>>(
175
+ this.db,
173
176
  `SELECT entity_id FROM entities
174
177
  WHERE entity_type = 'condition' AND canonical_key = ?`,
175
178
  [canonicalKey]
@@ -213,7 +216,8 @@ export class BlockerResolver {
213
216
  }))
214
217
  };
215
218
 
216
- await this.db.run(
219
+ await dbRun(
220
+ this.db,
217
221
  `INSERT INTO entities (
218
222
  entity_id, entity_type, canonical_key, title, stage, status,
219
223
  current_json, title_norm, search_text, created_at, updated_at
@@ -234,7 +238,8 @@ export class BlockerResolver {
234
238
  );
235
239
 
236
240
  // Create alias
237
- await this.db.run(
241
+ await dbRun(
242
+ this.db,
238
243
  `INSERT INTO entity_aliases (entity_type, canonical_key, entity_id, is_primary)
239
244
  VALUES (?, ?, ?, TRUE)
240
245
  ON CONFLICT (entity_type, canonical_key) DO NOTHING`,
@@ -269,7 +274,8 @@ export class BlockerResolver {
269
274
  artifactType
270
275
  };
271
276
 
272
- await this.db.run(
277
+ await dbRun(
278
+ this.db,
273
279
  `INSERT INTO entities (
274
280
  entity_id, entity_type, canonical_key, title, stage, status,
275
281
  current_json, title_norm, search_text, created_at, updated_at
@@ -290,7 +296,8 @@ export class BlockerResolver {
290
296
  );
291
297
 
292
298
  // Create alias
293
- await this.db.run(
299
+ await dbRun(
300
+ this.db,
294
301
  `INSERT INTO entity_aliases (entity_type, canonical_key, entity_id, is_primary)
295
302
  VALUES (?, ?, ?, TRUE)
296
303
  ON CONFLICT (entity_type, canonical_key) DO NOTHING`,
@@ -310,7 +317,8 @@ export class BlockerResolver {
310
317
  const ref = await this.createConditionBlocker(text);
311
318
 
312
319
  // Mark as auto placeholder
313
- await this.db.run(
320
+ await dbRun(
321
+ this.db,
314
322
  `UPDATE entities
315
323
  SET current_json = json_set(current_json, '$.auto_placeholder', true)
316
324
  WHERE entity_id = ?`,
@@ -3,7 +3,7 @@
3
3
  * AXIOMMIND: strict matching (≥0.92, gap≥0.03)
4
4
  */
5
5
 
6
- import { Database } from 'duckdb';
6
+ import { dbAll, toDate, type Database } from '../db-wrapper.js';
7
7
  import type { Entity, MatchConfidence } from '../types.js';
8
8
  import { makeEntityCanonicalKey } from '../canonical-key.js';
9
9
  import { MATCH_THRESHOLDS } from '../types.js';
@@ -46,7 +46,8 @@ export class TaskMatcher {
46
46
  async findExact(title: string, project?: string): Promise<Entity | null> {
47
47
  const canonicalKey = makeEntityCanonicalKey('task', title, { project });
48
48
 
49
- const rows = await this.db.all<Array<Record<string, unknown>>>(
49
+ const rows = await dbAll<Record<string, unknown>>(
50
+ this.db,
50
51
  `SELECT * FROM entities
51
52
  WHERE entity_type = 'task' AND canonical_key = ?
52
53
  AND status = 'active'`,
@@ -63,7 +64,8 @@ export class TaskMatcher {
63
64
  async findByAlias(title: string, project?: string): Promise<Entity | null> {
64
65
  const canonicalKey = makeEntityCanonicalKey('task', title, { project });
65
66
 
66
- const rows = await this.db.all<Array<Record<string, unknown>>>(
67
+ const rows = await dbAll<Record<string, unknown>>(
68
+ this.db,
67
69
  `SELECT e.* FROM entities e
68
70
  JOIN entity_aliases a ON e.entity_id = a.entity_id
69
71
  WHERE a.entity_type = 'task' AND a.canonical_key = ?
@@ -105,7 +107,7 @@ export class TaskMatcher {
105
107
  sql += ` ORDER BY match_score DESC, updated_at DESC LIMIT ?`;
106
108
  params.push(this.config.maxCandidates);
107
109
 
108
- const rows = await this.db.all<Array<Record<string, unknown>>>(sql, params);
110
+ const rows = await dbAll<Record<string, unknown>>(this.db, sql, params);
109
111
 
110
112
  return rows.map(row => ({
111
113
  entity: this.rowToEntity(row),
@@ -231,8 +233,8 @@ export class TaskMatcher {
231
233
  : row.current_json as Record<string, unknown>,
232
234
  titleNorm: row.title_norm as string | undefined,
233
235
  searchText: row.search_text as string | undefined,
234
- createdAt: new Date(row.created_at as string),
235
- updatedAt: new Date(row.updated_at as string)
236
+ createdAt: toDate(row.created_at),
237
+ updatedAt: toDate(row.updated_at)
236
238
  };
237
239
  }
238
240
  }