memory-lancedb-pro 1.0.25 → 1.0.26

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/src/store.ts CHANGED
@@ -4,7 +4,14 @@
4
4
 
5
5
  import type * as LanceDB from "@lancedb/lancedb";
6
6
  import { randomUUID } from "node:crypto";
7
- import { existsSync, accessSync, constants, mkdirSync, realpathSync, lstatSync } from "node:fs";
7
+ import {
8
+ existsSync,
9
+ accessSync,
10
+ constants,
11
+ mkdirSync,
12
+ realpathSync,
13
+ lstatSync,
14
+ } from "node:fs";
8
15
  import { dirname } from "node:path";
9
16
 
10
17
  // ============================================================================
@@ -36,16 +43,22 @@ export interface StoreConfig {
36
43
  // LanceDB Dynamic Import
37
44
  // ============================================================================
38
45
 
39
- let lancedbImportPromise: Promise<typeof import("@lancedb/lancedb")> | null = null;
46
+ let lancedbImportPromise: Promise<typeof import("@lancedb/lancedb")> | null =
47
+ null;
40
48
 
41
- export const loadLanceDB = async (): Promise<typeof import("@lancedb/lancedb")> => {
49
+ export const loadLanceDB = async (): Promise<
50
+ typeof import("@lancedb/lancedb")
51
+ > => {
42
52
  if (!lancedbImportPromise) {
43
53
  lancedbImportPromise = import("@lancedb/lancedb");
44
54
  }
45
55
  try {
46
56
  return await lancedbImportPromise;
47
57
  } catch (err) {
48
- throw new Error(`memory-lancedb-pro: failed to load LanceDB. ${String(err)}`, { cause: err });
58
+ throw new Error(
59
+ `memory-lancedb-pro: failed to load LanceDB. ${String(err)}`,
60
+ { cause: err },
61
+ );
49
62
  }
50
63
  };
51
64
 
@@ -83,8 +96,8 @@ export function validateStoragePath(dbPath: string): string {
83
96
  } catch (err: any) {
84
97
  throw new Error(
85
98
  `dbPath "${dbPath}" is a symlink whose target does not exist.\n` +
86
- ` Fix: Create the target directory, or update the symlink to point to a valid path.\n` +
87
- ` Details: ${err.code || ""} ${err.message}`
99
+ ` Fix: Create the target directory, or update the symlink to point to a valid path.\n` +
100
+ ` Details: ${err.code || ""} ${err.message}`,
88
101
  );
89
102
  }
90
103
  }
@@ -92,7 +105,10 @@ export function validateStoragePath(dbPath: string): string {
92
105
  // Missing path is OK (it will be created below)
93
106
  if (err?.code === "ENOENT") {
94
107
  // no-op
95
- } else if (typeof err?.message === "string" && err.message.includes("symlink whose target does not exist")) {
108
+ } else if (
109
+ typeof err?.message === "string" &&
110
+ err.message.includes("symlink whose target does not exist")
111
+ ) {
96
112
  throw err;
97
113
  } else {
98
114
  // Other lstat failures — continue with original path
@@ -106,9 +122,9 @@ export function validateStoragePath(dbPath: string): string {
106
122
  } catch (err: any) {
107
123
  throw new Error(
108
124
  `Failed to create dbPath directory "${resolvedPath}".\n` +
109
- ` Fix: Ensure the parent directory "${dirname(resolvedPath)}" exists and is writable,\n` +
110
- ` or create it manually: mkdir -p "${resolvedPath}"\n` +
111
- ` Details: ${err.code || ""} ${err.message}`
125
+ ` Fix: Ensure the parent directory "${dirname(resolvedPath)}" exists and is writable,\n` +
126
+ ` or create it manually: mkdir -p "${resolvedPath}"\n` +
127
+ ` Details: ${err.code || ""} ${err.message}`,
112
128
  );
113
129
  }
114
130
  }
@@ -119,9 +135,9 @@ export function validateStoragePath(dbPath: string): string {
119
135
  } catch (err: any) {
120
136
  throw new Error(
121
137
  `dbPath directory "${resolvedPath}" is not writable.\n` +
122
- ` Fix: Check permissions with: ls -la "${dirname(resolvedPath)}"\n` +
123
- ` Or grant write access: chmod u+w "${resolvedPath}"\n` +
124
- ` Details: ${err.code || ""} ${err.message}`
138
+ ` Fix: Check permissions with: ls -la "${dirname(resolvedPath)}"\n` +
139
+ ` Or grant write access: chmod u+w "${resolvedPath}"\n` +
140
+ ` Details: ${err.code || ""} ${err.message}`,
125
141
  );
126
142
  }
127
143
 
@@ -172,7 +188,7 @@ export class MemoryStore {
172
188
  const message = err.message || String(err);
173
189
  throw new Error(
174
190
  `Failed to open LanceDB at "${this.config.dbPath}": ${code} ${message}\n` +
175
- ` Fix: Verify the path exists and is writable. Check parent directory permissions.`
191
+ ` Fix: Verify the path exists and is writable. Check parent directory permissions.`,
176
192
  );
177
193
  }
178
194
 
@@ -188,7 +204,9 @@ export class MemoryStore {
188
204
  try {
189
205
  const sample = await table.query().limit(1).toArray();
190
206
  if (sample.length > 0 && !("scope" in sample[0])) {
191
- console.warn("Adding scope column for backward compatibility with existing data");
207
+ console.warn(
208
+ "Adding scope column for backward compatibility with existing data",
209
+ );
192
210
  }
193
211
  } catch (err) {
194
212
  console.warn("Could not check table schema:", err);
@@ -198,7 +216,9 @@ export class MemoryStore {
198
216
  const schemaEntry: MemoryEntry = {
199
217
  id: "__schema__",
200
218
  text: "",
201
- vector: Array.from({ length: this.config.vectorDim }).fill(0) as number[],
219
+ vector: Array.from({ length: this.config.vectorDim }).fill(
220
+ 0,
221
+ ) as number[],
202
222
  category: "other",
203
223
  scope: "global",
204
224
  importance: 0,
@@ -228,7 +248,7 @@ export class MemoryStore {
228
248
  const existingDim = sample[0].vector.length;
229
249
  if (existingDim !== this.config.vectorDim) {
230
250
  throw new Error(
231
- `Vector dimension mismatch: table=${existingDim}, config=${this.config.vectorDim}. Create a new table/dbPath or set matching embedding.dimensions.`
251
+ `Vector dimension mismatch: table=${existingDim}, config=${this.config.vectorDim}. Create a new table/dbPath or set matching embedding.dimensions.`,
232
252
  );
233
253
  }
234
254
  }
@@ -238,7 +258,10 @@ export class MemoryStore {
238
258
  await this.createFtsIndex(table);
239
259
  this.ftsIndexCreated = true;
240
260
  } catch (err) {
241
- console.warn("Failed to create FTS index, falling back to vector-only search:", err);
261
+ console.warn(
262
+ "Failed to create FTS index, falling back to vector-only search:",
263
+ err,
264
+ );
242
265
  this.ftsIndexCreated = false;
243
266
  }
244
267
 
@@ -250,8 +273,8 @@ export class MemoryStore {
250
273
  try {
251
274
  // Check if FTS index already exists
252
275
  const indices = await table.listIndices();
253
- const hasFtsIndex = indices?.some((idx: any) =>
254
- idx.indexType === "FTS" || idx.columns?.includes("text")
276
+ const hasFtsIndex = indices?.some(
277
+ (idx: any) => idx.indexType === "FTS" || idx.columns?.includes("text"),
255
278
  );
256
279
 
257
280
  if (!hasFtsIndex) {
@@ -262,11 +285,15 @@ export class MemoryStore {
262
285
  });
263
286
  }
264
287
  } catch (err) {
265
- throw new Error(`FTS index creation failed: ${err instanceof Error ? err.message : String(err)}`);
288
+ throw new Error(
289
+ `FTS index creation failed: ${err instanceof Error ? err.message : String(err)}`,
290
+ );
266
291
  }
267
292
  }
268
293
 
269
- async store(entry: Omit<MemoryEntry, "id" | "timestamp">): Promise<MemoryEntry> {
294
+ async store(
295
+ entry: Omit<MemoryEntry, "id" | "timestamp">,
296
+ ): Promise<MemoryEntry> {
270
297
  await this.ensureInitialized();
271
298
 
272
299
  const fullEntry: MemoryEntry = {
@@ -282,7 +309,7 @@ export class MemoryStore {
282
309
  const code = err.code || "";
283
310
  const message = err.message || String(err);
284
311
  throw new Error(
285
- `Failed to store memory in "${this.config.dbPath}": ${code} ${message}`
312
+ `Failed to store memory in "${this.config.dbPath}": ${code} ${message}`,
286
313
  );
287
314
  }
288
315
  return fullEntry;
@@ -303,7 +330,7 @@ export class MemoryStore {
303
330
  const vector = entry.vector || [];
304
331
  if (!Array.isArray(vector) || vector.length !== this.config.vectorDim) {
305
332
  throw new Error(
306
- `Vector dimension mismatch: expected ${this.config.vectorDim}, got ${Array.isArray(vector) ? vector.length : 'non-array'}`
333
+ `Vector dimension mismatch: expected ${this.config.vectorDim}, got ${Array.isArray(vector) ? vector.length : "non-array"}`,
307
334
  );
308
335
  }
309
336
 
@@ -311,7 +338,9 @@ export class MemoryStore {
311
338
  ...entry,
312
339
  scope: entry.scope || "global",
313
340
  importance: Number.isFinite(entry.importance) ? entry.importance : 0.7,
314
- timestamp: Number.isFinite(entry.timestamp) ? entry.timestamp : Date.now(),
341
+ timestamp: Number.isFinite(entry.timestamp)
342
+ ? entry.timestamp
343
+ : Date.now(),
315
344
  metadata: entry.metadata || "{}",
316
345
  };
317
346
 
@@ -322,11 +351,46 @@ export class MemoryStore {
322
351
  async hasId(id: string): Promise<boolean> {
323
352
  await this.ensureInitialized();
324
353
  const safeId = escapeSqlLiteral(id);
325
- const res = await this.table!.query().select(["id"]).where(`id = '${safeId}'`).limit(1).toArray();
354
+ const res = await this.table!.query()
355
+ .select(["id"])
356
+ .where(`id = '${safeId}'`)
357
+ .limit(1)
358
+ .toArray();
326
359
  return res.length > 0;
327
360
  }
328
361
 
329
- async vectorSearch(vector: number[], limit = 5, minScore = 0.3, scopeFilter?: string[]): Promise<MemorySearchResult[]> {
362
+ /**
363
+ * Read a single memory entry by exact ID without any mutation.
364
+ * Unlike update(id, {}), this performs a pure read (no delete+add cycle).
365
+ */
366
+ async getById(id: string): Promise<MemoryEntry | null> {
367
+ await this.ensureInitialized();
368
+ const safeId = escapeSqlLiteral(id);
369
+ const rows = await this.table!.query()
370
+ .where(`id = '${safeId}'`)
371
+ .limit(1)
372
+ .toArray();
373
+ if (rows.length === 0) return null;
374
+
375
+ const row = rows[0];
376
+ return {
377
+ id: row.id as string,
378
+ text: row.text as string,
379
+ vector: Array.from(row.vector as Iterable<number>),
380
+ category: row.category as MemoryEntry["category"],
381
+ scope: (row.scope as string | undefined) ?? "global",
382
+ importance: Number(row.importance),
383
+ timestamp: Number(row.timestamp),
384
+ metadata: (row.metadata as string) || "{}",
385
+ };
386
+ }
387
+
388
+ async vectorSearch(
389
+ vector: number[],
390
+ limit = 5,
391
+ minScore = 0.3,
392
+ scopeFilter?: string[],
393
+ ): Promise<MemorySearchResult[]> {
330
394
  await this.ensureInitialized();
331
395
 
332
396
  const safeLimit = clampInt(limit, 1, 20);
@@ -337,7 +401,7 @@ export class MemoryStore {
337
401
  // Apply scope filter if provided
338
402
  if (scopeFilter && scopeFilter.length > 0) {
339
403
  const scopeConditions = scopeFilter
340
- .map(scope => `scope = '${escapeSqlLiteral(scope)}'`)
404
+ .map((scope) => `scope = '${escapeSqlLiteral(scope)}'`)
341
405
  .join(" OR ");
342
406
  query = query.where(`(${scopeConditions}) OR scope IS NULL`); // NULL for backward compatibility
343
407
  }
@@ -354,7 +418,11 @@ export class MemoryStore {
354
418
  const rowScope = (row.scope as string | undefined) ?? "global";
355
419
 
356
420
  // Double-check scope filter in application layer
357
- if (scopeFilter && scopeFilter.length > 0 && !scopeFilter.includes(rowScope)) {
421
+ if (
422
+ scopeFilter &&
423
+ scopeFilter.length > 0 &&
424
+ !scopeFilter.includes(rowScope)
425
+ ) {
358
426
  continue;
359
427
  }
360
428
 
@@ -378,7 +446,11 @@ export class MemoryStore {
378
446
  return mapped;
379
447
  }
380
448
 
381
- async bm25Search(query: string, limit = 5, scopeFilter?: string[]): Promise<MemorySearchResult[]> {
449
+ async bm25Search(
450
+ query: string,
451
+ limit = 5,
452
+ scopeFilter?: string[],
453
+ ): Promise<MemorySearchResult[]> {
382
454
  await this.ensureInitialized();
383
455
 
384
456
  if (!this.ftsIndexCreated) {
@@ -394,9 +466,11 @@ export class MemoryStore {
394
466
  // Apply scope filter if provided
395
467
  if (scopeFilter && scopeFilter.length > 0) {
396
468
  const scopeConditions = scopeFilter
397
- .map(scope => `scope = '${escapeSqlLiteral(scope)}'`)
469
+ .map((scope) => `scope = '${escapeSqlLiteral(scope)}'`)
398
470
  .join(" OR ");
399
- searchQuery = searchQuery.where(`(${scopeConditions}) OR scope IS NULL`);
471
+ searchQuery = searchQuery.where(
472
+ `(${scopeConditions}) OR scope IS NULL`,
473
+ );
400
474
  }
401
475
 
402
476
  const results = await searchQuery.toArray();
@@ -406,14 +480,19 @@ export class MemoryStore {
406
480
  const rowScope = (row.scope as string | undefined) ?? "global";
407
481
 
408
482
  // Double-check scope filter in application layer
409
- if (scopeFilter && scopeFilter.length > 0 && !scopeFilter.includes(rowScope)) {
483
+ if (
484
+ scopeFilter &&
485
+ scopeFilter.length > 0 &&
486
+ !scopeFilter.includes(rowScope)
487
+ ) {
410
488
  continue;
411
489
  }
412
490
 
413
491
  // LanceDB FTS _score is raw BM25 (unbounded). Normalize with sigmoid.
414
492
  // LanceDB may return BigInt for numeric columns; coerce safely.
415
- const rawScore = (row._score != null) ? Number(row._score) : 0;
416
- const normalizedScore = rawScore > 0 ? 1 / (1 + Math.exp(-rawScore / 5)) : 0.5;
493
+ const rawScore = row._score != null ? Number(row._score) : 0;
494
+ const normalizedScore =
495
+ rawScore > 0 ? 1 / (1 + Math.exp(-rawScore / 5)) : 0.5;
417
496
 
418
497
  mapped.push({
419
498
  entry: {
@@ -441,7 +520,8 @@ export class MemoryStore {
441
520
  await this.ensureInitialized();
442
521
 
443
522
  // Support both full UUID and short prefix (8+ hex chars)
444
- const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
523
+ const uuidRegex =
524
+ /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
445
525
  const prefixRegex = /^[0-9a-f]{8,}$/i;
446
526
  const isFullId = uuidRegex.test(id);
447
527
  const isPrefix = !isFullId && prefixRegex.test(id);
@@ -452,13 +532,21 @@ export class MemoryStore {
452
532
 
453
533
  let candidates: any[];
454
534
  if (isFullId) {
455
- candidates = await this.table!.query().where(`id = '${id}'`).limit(1).toArray();
535
+ candidates = await this.table!.query()
536
+ .where(`id = '${id}'`)
537
+ .limit(1)
538
+ .toArray();
456
539
  } else {
457
540
  // Prefix match: fetch candidates and filter in app layer
458
- const all = await this.table!.query().select(["id", "scope"]).limit(1000).toArray();
541
+ const all = await this.table!.query()
542
+ .select(["id", "scope"])
543
+ .limit(1000)
544
+ .toArray();
459
545
  candidates = all.filter((r: any) => (r.id as string).startsWith(id));
460
546
  if (candidates.length > 1) {
461
- throw new Error(`Ambiguous prefix "${id}" matches ${candidates.length} memories. Use a longer prefix or full ID.`);
547
+ throw new Error(
548
+ `Ambiguous prefix "${id}" matches ${candidates.length} memories. Use a longer prefix or full ID.`,
549
+ );
462
550
  }
463
551
  }
464
552
  if (candidates.length === 0) {
@@ -469,7 +557,11 @@ export class MemoryStore {
469
557
  const rowScope = (candidates[0].scope as string | undefined) ?? "global";
470
558
 
471
559
  // Check scope permissions
472
- if (scopeFilter && scopeFilter.length > 0 && !scopeFilter.includes(rowScope)) {
560
+ if (
561
+ scopeFilter &&
562
+ scopeFilter.length > 0 &&
563
+ !scopeFilter.includes(rowScope)
564
+ ) {
473
565
  throw new Error(`Memory ${resolvedId} is outside accessible scopes`);
474
566
  }
475
567
 
@@ -477,7 +569,12 @@ export class MemoryStore {
477
569
  return true;
478
570
  }
479
571
 
480
- async list(scopeFilter?: string[], category?: string, limit = 20, offset = 0): Promise<MemoryEntry[]> {
572
+ async list(
573
+ scopeFilter?: string[],
574
+ category?: string,
575
+ limit = 20,
576
+ offset = 0,
577
+ ): Promise<MemoryEntry[]> {
481
578
  await this.ensureInitialized();
482
579
 
483
580
  let query = this.table!.query();
@@ -487,7 +584,7 @@ export class MemoryStore {
487
584
 
488
585
  if (scopeFilter && scopeFilter.length > 0) {
489
586
  const scopeConditions = scopeFilter
490
- .map(scope => `scope = '${escapeSqlLiteral(scope)}'`)
587
+ .map((scope) => `scope = '${escapeSqlLiteral(scope)}'`)
491
588
  .join(" OR ");
492
589
  conditions.push(`((${scopeConditions}) OR scope IS NULL)`);
493
590
  }
@@ -502,20 +599,30 @@ export class MemoryStore {
502
599
 
503
600
  // Fetch all matching rows (no pre-limit) so app-layer sort is correct across full dataset
504
601
  const results = await query
505
- .select(["id", "text", "category", "scope", "importance", "timestamp", "metadata"])
602
+ .select([
603
+ "id",
604
+ "text",
605
+ "category",
606
+ "scope",
607
+ "importance",
608
+ "timestamp",
609
+ "metadata",
610
+ ])
506
611
  .toArray();
507
612
 
508
613
  return results
509
- .map((row): MemoryEntry => ({
510
- id: row.id as string,
511
- text: row.text as string,
512
- vector: [], // Don't include vectors in list results for performance
513
- category: row.category as MemoryEntry["category"],
514
- scope: (row.scope as string | undefined) ?? "global",
515
- importance: Number(row.importance),
516
- timestamp: Number(row.timestamp),
517
- metadata: (row.metadata as string) || "{}",
518
- }))
614
+ .map(
615
+ (row): MemoryEntry => ({
616
+ id: row.id as string,
617
+ text: row.text as string,
618
+ vector: [], // Don't include vectors in list results for performance
619
+ category: row.category as MemoryEntry["category"],
620
+ scope: (row.scope as string | undefined) ?? "global",
621
+ importance: Number(row.importance),
622
+ timestamp: Number(row.timestamp),
623
+ metadata: (row.metadata as string) || "{}",
624
+ }),
625
+ )
519
626
  .sort((a, b) => (b.timestamp || 0) - (a.timestamp || 0))
520
627
  .slice(offset, offset + limit);
521
628
  }
@@ -523,7 +630,7 @@ export class MemoryStore {
523
630
  async stats(scopeFilter?: string[]): Promise<{
524
631
  totalCount: number;
525
632
  scopeCounts: Record<string, number>;
526
- categoryCounts: Record<string, number>
633
+ categoryCounts: Record<string, number>;
527
634
  }> {
528
635
  await this.ensureInitialized();
529
636
 
@@ -531,7 +638,7 @@ export class MemoryStore {
531
638
 
532
639
  if (scopeFilter && scopeFilter.length > 0) {
533
640
  const scopeConditions = scopeFilter
534
- .map(scope => `scope = '${escapeSqlLiteral(scope)}'`)
641
+ .map((scope) => `scope = '${escapeSqlLiteral(scope)}'`)
535
642
  .join(" OR ");
536
643
  query = query.where(`((${scopeConditions}) OR scope IS NULL)`);
537
644
  }
@@ -558,13 +665,20 @@ export class MemoryStore {
558
665
 
559
666
  async update(
560
667
  id: string,
561
- updates: { text?: string; vector?: number[]; importance?: number; category?: MemoryEntry["category"]; metadata?: string },
562
- scopeFilter?: string[]
668
+ updates: {
669
+ text?: string;
670
+ vector?: number[];
671
+ importance?: number;
672
+ category?: MemoryEntry["category"];
673
+ metadata?: string;
674
+ },
675
+ scopeFilter?: string[],
563
676
  ): Promise<MemoryEntry | null> {
564
677
  await this.ensureInitialized();
565
678
 
566
679
  // Support both full UUID and short prefix (8+ hex chars), same as delete()
567
- const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
680
+ const uuidRegex =
681
+ /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
568
682
  const prefixRegex = /^[0-9a-f]{8,}$/i;
569
683
  const isFullId = uuidRegex.test(id);
570
684
  const isPrefix = !isFullId && prefixRegex.test(id);
@@ -576,13 +690,30 @@ export class MemoryStore {
576
690
  let rows: any[];
577
691
  if (isFullId) {
578
692
  const safeId = escapeSqlLiteral(id);
579
- rows = await this.table!.query().where(`id = '${safeId}'`).limit(1).toArray();
693
+ rows = await this.table!.query()
694
+ .where(`id = '${safeId}'`)
695
+ .limit(1)
696
+ .toArray();
580
697
  } else {
581
698
  // Prefix match
582
- const all = await this.table!.query().select(["id", "text", "vector", "category", "scope", "importance", "timestamp", "metadata"]).limit(1000).toArray();
699
+ const all = await this.table!.query()
700
+ .select([
701
+ "id",
702
+ "text",
703
+ "vector",
704
+ "category",
705
+ "scope",
706
+ "importance",
707
+ "timestamp",
708
+ "metadata",
709
+ ])
710
+ .limit(1000)
711
+ .toArray();
583
712
  rows = all.filter((r: any) => (r.id as string).startsWith(id));
584
713
  if (rows.length > 1) {
585
- throw new Error(`Ambiguous prefix "${id}" matches ${rows.length} memories. Use a longer prefix or full ID.`);
714
+ throw new Error(
715
+ `Ambiguous prefix "${id}" matches ${rows.length} memories. Use a longer prefix or full ID.`,
716
+ );
586
717
  }
587
718
  }
588
719
 
@@ -592,7 +723,11 @@ export class MemoryStore {
592
723
  const rowScope = (row.scope as string | undefined) ?? "global";
593
724
 
594
725
  // Check scope permissions
595
- if (scopeFilter && scopeFilter.length > 0 && !scopeFilter.includes(rowScope)) {
726
+ if (
727
+ scopeFilter &&
728
+ scopeFilter.length > 0 &&
729
+ !scopeFilter.includes(rowScope)
730
+ ) {
596
731
  throw new Error(`Memory ${id} is outside accessible scopes`);
597
732
  }
598
733
 
@@ -600,7 +735,7 @@ export class MemoryStore {
600
735
  const updated: MemoryEntry = {
601
736
  id: row.id as string,
602
737
  text: updates.text ?? (row.text as string),
603
- vector: updates.vector ?? (Array.from(row.vector as Iterable<number>)),
738
+ vector: updates.vector ?? Array.from(row.vector as Iterable<number>),
604
739
  category: updates.category ?? (row.category as MemoryEntry["category"]),
605
740
  scope: rowScope,
606
741
  importance: updates.importance ?? Number(row.importance),
@@ -616,14 +751,17 @@ export class MemoryStore {
616
751
  return updated;
617
752
  }
618
753
 
619
- async bulkDelete(scopeFilter: string[], beforeTimestamp?: number): Promise<number> {
754
+ async bulkDelete(
755
+ scopeFilter: string[],
756
+ beforeTimestamp?: number,
757
+ ): Promise<number> {
620
758
  await this.ensureInitialized();
621
759
 
622
760
  const conditions: string[] = [];
623
761
 
624
762
  if (scopeFilter.length > 0) {
625
763
  const scopeConditions = scopeFilter
626
- .map(scope => `scope = '${escapeSqlLiteral(scope)}'`)
764
+ .map((scope) => `scope = '${escapeSqlLiteral(scope)}'`)
627
765
  .join(" OR ");
628
766
  conditions.push(`(${scopeConditions})`);
629
767
  }
@@ -633,7 +771,9 @@ export class MemoryStore {
633
771
  }
634
772
 
635
773
  if (conditions.length === 0) {
636
- throw new Error("Bulk delete requires at least scope or timestamp filter for safety");
774
+ throw new Error(
775
+ "Bulk delete requires at least scope or timestamp filter for safety",
776
+ );
637
777
  }
638
778
 
639
779
  const whereClause = conditions.join(" AND ");
@@ -653,4 +793,4 @@ export class MemoryStore {
653
793
  get hasFtsSupport(): boolean {
654
794
  return this.ftsIndexCreated;
655
795
  }
656
- }
796
+ }