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.
- package/.history/package_20260202121115.json +49 -0
- package/dist/cli/index.js +107 -3
- package/dist/cli/index.js.map +2 -2
- package/dist/core/index.js +78 -0
- package/dist/core/index.js.map +2 -2
- package/dist/hooks/post-tool-use.js +107 -3
- package/dist/hooks/post-tool-use.js.map +2 -2
- package/dist/hooks/session-end.js +107 -3
- package/dist/hooks/session-end.js.map +2 -2
- package/dist/hooks/session-start.js +107 -3
- package/dist/hooks/session-start.js.map +2 -2
- package/dist/hooks/stop.js +107 -3
- package/dist/hooks/stop.js.map +2 -2
- package/dist/hooks/user-prompt-submit.js +140 -70
- package/dist/hooks/user-prompt-submit.js.map +2 -2
- package/dist/server/api/index.js +107 -3
- package/dist/server/api/index.js.map +2 -2
- package/dist/server/index.js +107 -3
- package/dist/server/index.js.map +2 -2
- package/dist/services/memory-service.js +124 -3
- package/dist/services/memory-service.js.map +2 -2
- package/package.json +1 -1
- package/src/core/sqlite-event-store.ts +98 -0
- package/src/hooks/user-prompt-submit.ts +34 -60
- package/src/services/memory-service.ts +71 -4
|
@@ -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
|
*/
|
|
@@ -4635,9 +4713,11 @@ var MemoryService = class {
|
|
|
4635
4713
|
sharedStoreConfig = null;
|
|
4636
4714
|
projectHash = null;
|
|
4637
4715
|
readOnly;
|
|
4716
|
+
lightweightMode;
|
|
4638
4717
|
constructor(config) {
|
|
4639
4718
|
const storagePath = this.expandPath(config.storagePath);
|
|
4640
4719
|
this.readOnly = config.readOnly ?? false;
|
|
4720
|
+
this.lightweightMode = config.lightweightMode ?? false;
|
|
4641
4721
|
if (!this.readOnly && !fs.existsSync(storagePath)) {
|
|
4642
4722
|
fs.mkdirSync(storagePath, { recursive: true });
|
|
4643
4723
|
}
|
|
@@ -4684,6 +4764,10 @@ var MemoryService = class {
|
|
|
4684
4764
|
if (this.initialized)
|
|
4685
4765
|
return;
|
|
4686
4766
|
await this.sqliteStore.initialize();
|
|
4767
|
+
if (this.lightweightMode) {
|
|
4768
|
+
this.initialized = true;
|
|
4769
|
+
return;
|
|
4770
|
+
}
|
|
4687
4771
|
if (this.analyticsStore) {
|
|
4688
4772
|
try {
|
|
4689
4773
|
await this.analyticsStore.initialize();
|
|
@@ -4853,9 +4937,6 @@ var MemoryService = class {
|
|
|
4853
4937
|
*/
|
|
4854
4938
|
async retrieveMemories(query, options) {
|
|
4855
4939
|
await this.initialize();
|
|
4856
|
-
if (this.vectorWorker) {
|
|
4857
|
-
await this.vectorWorker.processAll();
|
|
4858
|
-
}
|
|
4859
4940
|
if (options?.includeShared && this.sharedStore) {
|
|
4860
4941
|
return this.retriever.retrieveUnified(query, {
|
|
4861
4942
|
...options,
|
|
@@ -4865,6 +4946,29 @@ var MemoryService = class {
|
|
|
4865
4946
|
}
|
|
4866
4947
|
return this.retriever.retrieve(query, options);
|
|
4867
4948
|
}
|
|
4949
|
+
/**
|
|
4950
|
+
* Fast keyword search using SQLite FTS5
|
|
4951
|
+
* Much faster than vector search - no embedding model needed
|
|
4952
|
+
*/
|
|
4953
|
+
async keywordSearch(query, options) {
|
|
4954
|
+
await this.initialize();
|
|
4955
|
+
const results = await this.sqliteStore.keywordSearch(query, options?.topK ?? 10);
|
|
4956
|
+
const maxRank = Math.min(...results.map((r) => r.rank), -1e-3);
|
|
4957
|
+
const minRank = Math.max(...results.map((r) => r.rank), -1e3);
|
|
4958
|
+
const rankRange = maxRank - minRank || 1;
|
|
4959
|
+
return results.map((r) => ({
|
|
4960
|
+
event: r.event,
|
|
4961
|
+
score: 1 - (r.rank - minRank) / rankRange
|
|
4962
|
+
// Normalize to 0-1
|
|
4963
|
+
})).filter((r) => !options?.minScore || r.score >= options.minScore);
|
|
4964
|
+
}
|
|
4965
|
+
/**
|
|
4966
|
+
* Rebuild FTS index (call after database upgrade)
|
|
4967
|
+
*/
|
|
4968
|
+
async rebuildFtsIndex() {
|
|
4969
|
+
await this.initialize();
|
|
4970
|
+
return this.sqliteStore.rebuildFtsIndex();
|
|
4971
|
+
}
|
|
4868
4972
|
/**
|
|
4869
4973
|
* Get session history
|
|
4870
4974
|
*/
|