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
|
@@ -1033,6 +1033,28 @@ var SQLiteEventStore = class {
|
|
|
1033
1033
|
CREATE INDEX IF NOT EXISTS idx_consolidated_confidence ON consolidated_memories(confidence);
|
|
1034
1034
|
CREATE INDEX IF NOT EXISTS idx_continuity_created ON continuity_log(created_at);
|
|
1035
1035
|
CREATE INDEX IF NOT EXISTS idx_embedding_outbox_status ON embedding_outbox(status);
|
|
1036
|
+
|
|
1037
|
+
-- FTS5 Full-Text Search for fast keyword search
|
|
1038
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS events_fts USING fts5(
|
|
1039
|
+
content,
|
|
1040
|
+
event_id UNINDEXED,
|
|
1041
|
+
content='events',
|
|
1042
|
+
content_rowid='rowid'
|
|
1043
|
+
);
|
|
1044
|
+
|
|
1045
|
+
-- Triggers to keep FTS in sync with events table
|
|
1046
|
+
CREATE TRIGGER IF NOT EXISTS events_fts_insert AFTER INSERT ON events BEGIN
|
|
1047
|
+
INSERT INTO events_fts(rowid, content, event_id) VALUES (NEW.rowid, NEW.content, NEW.id);
|
|
1048
|
+
END;
|
|
1049
|
+
|
|
1050
|
+
CREATE TRIGGER IF NOT EXISTS events_fts_delete AFTER DELETE ON events BEGIN
|
|
1051
|
+
INSERT INTO events_fts(events_fts, rowid, content, event_id) VALUES('delete', OLD.rowid, OLD.content, OLD.id);
|
|
1052
|
+
END;
|
|
1053
|
+
|
|
1054
|
+
CREATE TRIGGER IF NOT EXISTS events_fts_update AFTER UPDATE ON events BEGIN
|
|
1055
|
+
INSERT INTO events_fts(events_fts, rowid, content, event_id) VALUES('delete', OLD.rowid, OLD.content, OLD.id);
|
|
1056
|
+
INSERT INTO events_fts(rowid, content, event_id) VALUES (NEW.rowid, NEW.content, NEW.id);
|
|
1057
|
+
END;
|
|
1036
1058
|
`);
|
|
1037
1059
|
const tableInfo = sqliteAll(this.db, "PRAGMA table_info(events)", []);
|
|
1038
1060
|
const columnNames = tableInfo.map((col) => col.name);
|
|
@@ -1473,6 +1495,62 @@ var SQLiteEventStore = class {
|
|
|
1473
1495
|
);
|
|
1474
1496
|
return rows.map((row) => this.rowToEvent(row));
|
|
1475
1497
|
}
|
|
1498
|
+
/**
|
|
1499
|
+
* Fast keyword search using FTS5
|
|
1500
|
+
* Returns events matching the search query, ranked by relevance
|
|
1501
|
+
*/
|
|
1502
|
+
async keywordSearch(query, limit = 10) {
|
|
1503
|
+
await this.initialize();
|
|
1504
|
+
const searchTerms = query.replace(/['"(){}[\]^~*?:\\/-]/g, " ").split(/\s+/).filter((term) => term.length > 1).map((term) => `"${term}"*`).join(" OR ");
|
|
1505
|
+
if (!searchTerms) {
|
|
1506
|
+
return [];
|
|
1507
|
+
}
|
|
1508
|
+
try {
|
|
1509
|
+
const rows = sqliteAll(
|
|
1510
|
+
this.db,
|
|
1511
|
+
`SELECT e.*, fts.rank
|
|
1512
|
+
FROM events_fts fts
|
|
1513
|
+
JOIN events e ON e.id = fts.event_id
|
|
1514
|
+
WHERE events_fts MATCH ?
|
|
1515
|
+
ORDER BY fts.rank
|
|
1516
|
+
LIMIT ?`,
|
|
1517
|
+
[searchTerms, limit]
|
|
1518
|
+
);
|
|
1519
|
+
return rows.map((row) => ({
|
|
1520
|
+
event: this.rowToEvent(row),
|
|
1521
|
+
rank: row.rank
|
|
1522
|
+
}));
|
|
1523
|
+
} catch (error) {
|
|
1524
|
+
const likePattern = `%${query}%`;
|
|
1525
|
+
const rows = sqliteAll(
|
|
1526
|
+
this.db,
|
|
1527
|
+
`SELECT *, 0 as rank FROM events
|
|
1528
|
+
WHERE content LIKE ?
|
|
1529
|
+
ORDER BY timestamp DESC
|
|
1530
|
+
LIMIT ?`,
|
|
1531
|
+
[likePattern, limit]
|
|
1532
|
+
);
|
|
1533
|
+
return rows.map((row) => ({
|
|
1534
|
+
event: this.rowToEvent(row),
|
|
1535
|
+
rank: 0
|
|
1536
|
+
}));
|
|
1537
|
+
}
|
|
1538
|
+
}
|
|
1539
|
+
/**
|
|
1540
|
+
* Rebuild FTS index from existing events
|
|
1541
|
+
* Call this once after upgrading to FTS5
|
|
1542
|
+
*/
|
|
1543
|
+
async rebuildFtsIndex() {
|
|
1544
|
+
await this.initialize();
|
|
1545
|
+
const countRow = sqliteGet(this.db, "SELECT COUNT(*) as count FROM events", []);
|
|
1546
|
+
const totalEvents = countRow?.count ?? 0;
|
|
1547
|
+
sqliteExec(this.db, `
|
|
1548
|
+
DELETE FROM events_fts;
|
|
1549
|
+
INSERT INTO events_fts(rowid, content, event_id)
|
|
1550
|
+
SELECT rowid, content, id FROM events;
|
|
1551
|
+
`);
|
|
1552
|
+
return totalEvents;
|
|
1553
|
+
}
|
|
1476
1554
|
/**
|
|
1477
1555
|
* Get database instance for direct access
|
|
1478
1556
|
*/
|
|
@@ -4571,9 +4649,11 @@ var MemoryService = class {
|
|
|
4571
4649
|
sharedStoreConfig = null;
|
|
4572
4650
|
projectHash = null;
|
|
4573
4651
|
readOnly;
|
|
4652
|
+
lightweightMode;
|
|
4574
4653
|
constructor(config) {
|
|
4575
4654
|
const storagePath = this.expandPath(config.storagePath);
|
|
4576
4655
|
this.readOnly = config.readOnly ?? false;
|
|
4656
|
+
this.lightweightMode = config.lightweightMode ?? false;
|
|
4577
4657
|
if (!this.readOnly && !fs.existsSync(storagePath)) {
|
|
4578
4658
|
fs.mkdirSync(storagePath, { recursive: true });
|
|
4579
4659
|
}
|
|
@@ -4620,6 +4700,10 @@ var MemoryService = class {
|
|
|
4620
4700
|
if (this.initialized)
|
|
4621
4701
|
return;
|
|
4622
4702
|
await this.sqliteStore.initialize();
|
|
4703
|
+
if (this.lightweightMode) {
|
|
4704
|
+
this.initialized = true;
|
|
4705
|
+
return;
|
|
4706
|
+
}
|
|
4623
4707
|
if (this.analyticsStore) {
|
|
4624
4708
|
try {
|
|
4625
4709
|
await this.analyticsStore.initialize();
|
|
@@ -4789,9 +4873,6 @@ var MemoryService = class {
|
|
|
4789
4873
|
*/
|
|
4790
4874
|
async retrieveMemories(query, options) {
|
|
4791
4875
|
await this.initialize();
|
|
4792
|
-
if (this.vectorWorker) {
|
|
4793
|
-
await this.vectorWorker.processAll();
|
|
4794
|
-
}
|
|
4795
4876
|
if (options?.includeShared && this.sharedStore) {
|
|
4796
4877
|
return this.retriever.retrieveUnified(query, {
|
|
4797
4878
|
...options,
|
|
@@ -4801,6 +4882,29 @@ var MemoryService = class {
|
|
|
4801
4882
|
}
|
|
4802
4883
|
return this.retriever.retrieve(query, options);
|
|
4803
4884
|
}
|
|
4885
|
+
/**
|
|
4886
|
+
* Fast keyword search using SQLite FTS5
|
|
4887
|
+
* Much faster than vector search - no embedding model needed
|
|
4888
|
+
*/
|
|
4889
|
+
async keywordSearch(query, options) {
|
|
4890
|
+
await this.initialize();
|
|
4891
|
+
const results = await this.sqliteStore.keywordSearch(query, options?.topK ?? 10);
|
|
4892
|
+
const maxRank = Math.min(...results.map((r) => r.rank), -1e-3);
|
|
4893
|
+
const minRank = Math.max(...results.map((r) => r.rank), -1e3);
|
|
4894
|
+
const rankRange = maxRank - minRank || 1;
|
|
4895
|
+
return results.map((r) => ({
|
|
4896
|
+
event: r.event,
|
|
4897
|
+
score: 1 - (r.rank - minRank) / rankRange
|
|
4898
|
+
// Normalize to 0-1
|
|
4899
|
+
})).filter((r) => !options?.minScore || r.score >= options.minScore);
|
|
4900
|
+
}
|
|
4901
|
+
/**
|
|
4902
|
+
* Rebuild FTS index (call after database upgrade)
|
|
4903
|
+
*/
|
|
4904
|
+
async rebuildFtsIndex() {
|
|
4905
|
+
await this.initialize();
|
|
4906
|
+
return this.sqliteStore.rebuildFtsIndex();
|
|
4907
|
+
}
|
|
4804
4908
|
/**
|
|
4805
4909
|
* Get session history
|
|
4806
4910
|
*/
|
|
@@ -5269,6 +5373,22 @@ function getMemoryServiceForSession(sessionId) {
|
|
|
5269
5373
|
}
|
|
5270
5374
|
return getDefaultMemoryService();
|
|
5271
5375
|
}
|
|
5376
|
+
function getLightweightMemoryService(sessionId) {
|
|
5377
|
+
const projectInfo = getSessionProject(sessionId);
|
|
5378
|
+
const key = projectInfo ? `lightweight_${projectInfo.projectHash}` : "lightweight_global";
|
|
5379
|
+
if (!serviceCache.has(key)) {
|
|
5380
|
+
const storagePath = projectInfo ? getProjectStoragePath(projectInfo.projectPath) : path.join(os.homedir(), ".claude-code", "memory");
|
|
5381
|
+
serviceCache.set(key, new MemoryService({
|
|
5382
|
+
storagePath,
|
|
5383
|
+
projectHash: projectInfo?.projectHash,
|
|
5384
|
+
lightweightMode: true,
|
|
5385
|
+
// Skip embedder/vector/workers
|
|
5386
|
+
analyticsEnabled: false,
|
|
5387
|
+
sharedStoreConfig: { enabled: false }
|
|
5388
|
+
}));
|
|
5389
|
+
}
|
|
5390
|
+
return serviceCache.get(key);
|
|
5391
|
+
}
|
|
5272
5392
|
function createMemoryService(config) {
|
|
5273
5393
|
return new MemoryService(config);
|
|
5274
5394
|
}
|
|
@@ -5276,6 +5396,7 @@ export {
|
|
|
5276
5396
|
MemoryService,
|
|
5277
5397
|
createMemoryService,
|
|
5278
5398
|
getDefaultMemoryService,
|
|
5399
|
+
getLightweightMemoryService,
|
|
5279
5400
|
getMemoryServiceForProject,
|
|
5280
5401
|
getMemoryServiceForSession,
|
|
5281
5402
|
getProjectStoragePath,
|