claude-memory-layer 1.0.9 → 1.0.10

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.
@@ -1034,6 +1034,28 @@ var SQLiteEventStore = class {
1034
1034
  CREATE INDEX IF NOT EXISTS idx_consolidated_confidence ON consolidated_memories(confidence);
1035
1035
  CREATE INDEX IF NOT EXISTS idx_continuity_created ON continuity_log(created_at);
1036
1036
  CREATE INDEX IF NOT EXISTS idx_embedding_outbox_status ON embedding_outbox(status);
1037
+
1038
+ -- FTS5 Full-Text Search for fast keyword search
1039
+ CREATE VIRTUAL TABLE IF NOT EXISTS events_fts USING fts5(
1040
+ content,
1041
+ event_id UNINDEXED,
1042
+ content='events',
1043
+ content_rowid='rowid'
1044
+ );
1045
+
1046
+ -- Triggers to keep FTS in sync with events table
1047
+ CREATE TRIGGER IF NOT EXISTS events_fts_insert AFTER INSERT ON events BEGIN
1048
+ INSERT INTO events_fts(rowid, content, event_id) VALUES (NEW.rowid, NEW.content, NEW.id);
1049
+ END;
1050
+
1051
+ CREATE TRIGGER IF NOT EXISTS events_fts_delete AFTER DELETE ON events BEGIN
1052
+ INSERT INTO events_fts(events_fts, rowid, content, event_id) VALUES('delete', OLD.rowid, OLD.content, OLD.id);
1053
+ END;
1054
+
1055
+ CREATE TRIGGER IF NOT EXISTS events_fts_update AFTER UPDATE ON events BEGIN
1056
+ INSERT INTO events_fts(events_fts, rowid, content, event_id) VALUES('delete', OLD.rowid, OLD.content, OLD.id);
1057
+ INSERT INTO events_fts(rowid, content, event_id) VALUES (NEW.rowid, NEW.content, NEW.id);
1058
+ END;
1037
1059
  `);
1038
1060
  const tableInfo = sqliteAll(this.db, "PRAGMA table_info(events)", []);
1039
1061
  const columnNames = tableInfo.map((col) => col.name);
@@ -1474,6 +1496,62 @@ var SQLiteEventStore = class {
1474
1496
  );
1475
1497
  return rows.map((row) => this.rowToEvent(row));
1476
1498
  }
1499
+ /**
1500
+ * Fast keyword search using FTS5
1501
+ * Returns events matching the search query, ranked by relevance
1502
+ */
1503
+ async keywordSearch(query, limit = 10) {
1504
+ await this.initialize();
1505
+ const searchTerms = query.replace(/['"(){}[\]^~*?:\\/-]/g, " ").split(/\s+/).filter((term) => term.length > 1).map((term) => `"${term}"*`).join(" OR ");
1506
+ if (!searchTerms) {
1507
+ return [];
1508
+ }
1509
+ try {
1510
+ const rows = sqliteAll(
1511
+ this.db,
1512
+ `SELECT e.*, fts.rank
1513
+ FROM events_fts fts
1514
+ JOIN events e ON e.id = fts.event_id
1515
+ WHERE events_fts MATCH ?
1516
+ ORDER BY fts.rank
1517
+ LIMIT ?`,
1518
+ [searchTerms, limit]
1519
+ );
1520
+ return rows.map((row) => ({
1521
+ event: this.rowToEvent(row),
1522
+ rank: row.rank
1523
+ }));
1524
+ } catch (error) {
1525
+ const likePattern = `%${query}%`;
1526
+ const rows = sqliteAll(
1527
+ this.db,
1528
+ `SELECT *, 0 as rank FROM events
1529
+ WHERE content LIKE ?
1530
+ ORDER BY timestamp DESC
1531
+ LIMIT ?`,
1532
+ [likePattern, limit]
1533
+ );
1534
+ return rows.map((row) => ({
1535
+ event: this.rowToEvent(row),
1536
+ rank: 0
1537
+ }));
1538
+ }
1539
+ }
1540
+ /**
1541
+ * Rebuild FTS index from existing events
1542
+ * Call this once after upgrading to FTS5
1543
+ */
1544
+ async rebuildFtsIndex() {
1545
+ await this.initialize();
1546
+ const countRow = sqliteGet(this.db, "SELECT COUNT(*) as count FROM events", []);
1547
+ const totalEvents = countRow?.count ?? 0;
1548
+ sqliteExec(this.db, `
1549
+ DELETE FROM events_fts;
1550
+ INSERT INTO events_fts(rowid, content, event_id)
1551
+ SELECT rowid, content, id FROM events;
1552
+ `);
1553
+ return totalEvents;
1554
+ }
1477
1555
  /**
1478
1556
  * Get database instance for direct access
1479
1557
  */
@@ -4568,9 +4646,11 @@ var MemoryService = class {
4568
4646
  sharedStoreConfig = null;
4569
4647
  projectHash = null;
4570
4648
  readOnly;
4649
+ lightweightMode;
4571
4650
  constructor(config) {
4572
4651
  const storagePath = this.expandPath(config.storagePath);
4573
4652
  this.readOnly = config.readOnly ?? false;
4653
+ this.lightweightMode = config.lightweightMode ?? false;
4574
4654
  if (!this.readOnly && !fs.existsSync(storagePath)) {
4575
4655
  fs.mkdirSync(storagePath, { recursive: true });
4576
4656
  }
@@ -4617,6 +4697,10 @@ var MemoryService = class {
4617
4697
  if (this.initialized)
4618
4698
  return;
4619
4699
  await this.sqliteStore.initialize();
4700
+ if (this.lightweightMode) {
4701
+ this.initialized = true;
4702
+ return;
4703
+ }
4620
4704
  if (this.analyticsStore) {
4621
4705
  try {
4622
4706
  await this.analyticsStore.initialize();
@@ -4786,9 +4870,6 @@ var MemoryService = class {
4786
4870
  */
4787
4871
  async retrieveMemories(query, options) {
4788
4872
  await this.initialize();
4789
- if (this.vectorWorker) {
4790
- await this.vectorWorker.processAll();
4791
- }
4792
4873
  if (options?.includeShared && this.sharedStore) {
4793
4874
  return this.retriever.retrieveUnified(query, {
4794
4875
  ...options,
@@ -4798,6 +4879,29 @@ var MemoryService = class {
4798
4879
  }
4799
4880
  return this.retriever.retrieve(query, options);
4800
4881
  }
4882
+ /**
4883
+ * Fast keyword search using SQLite FTS5
4884
+ * Much faster than vector search - no embedding model needed
4885
+ */
4886
+ async keywordSearch(query, options) {
4887
+ await this.initialize();
4888
+ const results = await this.sqliteStore.keywordSearch(query, options?.topK ?? 10);
4889
+ const maxRank = Math.min(...results.map((r) => r.rank), -1e-3);
4890
+ const minRank = Math.max(...results.map((r) => r.rank), -1e3);
4891
+ const rankRange = maxRank - minRank || 1;
4892
+ return results.map((r) => ({
4893
+ event: r.event,
4894
+ score: 1 - (r.rank - minRank) / rankRange
4895
+ // Normalize to 0-1
4896
+ })).filter((r) => !options?.minScore || r.score >= options.minScore);
4897
+ }
4898
+ /**
4899
+ * Rebuild FTS index (call after database upgrade)
4900
+ */
4901
+ async rebuildFtsIndex() {
4902
+ await this.initialize();
4903
+ return this.sqliteStore.rebuildFtsIndex();
4904
+ }
4801
4905
  /**
4802
4906
  * Get session history
4803
4907
  */