claude-memory-layer 1.0.14 → 1.0.16
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/.npm-cache/_cacache/content-v2/sha512/04/76/c098f88dfe584a2b80870bff7421b05d17d3d9ee1027f77772332a22d3f93a9a57101a2855107f6ad82077a818bba912b2bc317f2361b5ddb09ad284d9ce +0 -0
- package/.npm-cache/_cacache/content-v2/sha512/60/25/d2ecd39cfc7cab58351162814be77f935c6d6491c10c3745d456da7ddb2117ffd90c10e53fe3c0f1ed16b403307841543634504398b16ee4e6b6dd8e0c45 +0 -0
- package/.npm-cache/_cacache/index-v5/2b/9a/7f8f40206ed8a2e0a84efaa953ccaed1f5d001e14b931083f2e7a0738007 +2 -0
- package/.npm-cache/_cacache/index-v5/2e/d9/fcfa5c6a6abdc2a3644ab84a95936047298c465a2f47ee03db8f7fe1e946 +3 -0
- package/.npm-cache/_cacache/index-v5/a9/42/e519633356d12d3d2f19da66a8301016d496c8f5c3e0554124aaa62dc043 +2 -0
- package/.npm-cache/_logs/2026-02-26T12_04_52_729Z-debug-0.log +256 -0
- package/.npm-cache/_logs/2026-02-26T12_05_36_835Z-debug-0.log +18 -0
- package/.npm-cache/_logs/2026-02-26T12_05_45_982Z-debug-0.log +32 -0
- package/.npm-cache/_logs/2026-02-26T12_05_48_515Z-debug-0.log +260 -0
- package/.npm-cache/_logs/2026-02-26T12_05_53_567Z-debug-0.log +69 -0
- package/.npm-cache/_update-notifier-last-checked +0 -0
- package/README.md +3 -0
- package/claude-memory-layer-1.0.14.tgz +0 -0
- package/dist/cli/index.js +63 -48
- package/dist/cli/index.js.map +2 -2
- package/dist/core/index.js +53 -40
- package/dist/core/index.js.map +2 -2
- package/dist/hooks/post-tool-use.js +53 -40
- package/dist/hooks/post-tool-use.js.map +2 -2
- package/dist/hooks/session-end.js +53 -40
- package/dist/hooks/session-end.js.map +2 -2
- package/dist/hooks/session-start.js +53 -40
- package/dist/hooks/session-start.js.map +2 -2
- package/dist/hooks/stop.js +53 -40
- package/dist/hooks/stop.js.map +2 -2
- package/dist/hooks/user-prompt-submit.js +72 -43
- package/dist/hooks/user-prompt-submit.js.map +2 -2
- package/dist/server/api/index.js +53 -40
- package/dist/server/api/index.js.map +2 -2
- package/dist/server/index.js +53 -40
- package/dist/server/index.js.map +2 -2
- package/dist/services/memory-service.js +53 -40
- package/dist/services/memory-service.js.map +2 -2
- package/memory/_index.md +2 -0
- package/memory/tool_observation/uncategorized/2026-02-26.md +201 -0
- package/memory/user_prompt/uncategorized/2026-02-26.md +10 -0
- package/package.json +1 -1
- package/src/core/sqlite-event-store.ts +52 -40
- package/src/hooks/user-prompt-submit.ts +22 -3
- package/src/services/session-history-importer.ts +15 -7
|
@@ -1446,28 +1446,33 @@ export class SQLiteEventStore {
|
|
|
1446
1446
|
}>> {
|
|
1447
1447
|
await this.initialize();
|
|
1448
1448
|
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1449
|
+
try {
|
|
1450
|
+
const rows = sqliteAll<Record<string, unknown>>(
|
|
1451
|
+
this.db,
|
|
1452
|
+
`SELECT * FROM retrieval_traces ORDER BY created_at DESC LIMIT ?`,
|
|
1453
|
+
[limit]
|
|
1454
|
+
);
|
|
1454
1455
|
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1456
|
+
return rows.map((row) => ({
|
|
1457
|
+
traceId: row.trace_id as string,
|
|
1458
|
+
sessionId: (row.session_id as string) || undefined,
|
|
1459
|
+
projectHash: (row.project_hash as string) || undefined,
|
|
1460
|
+
queryText: row.query_text as string,
|
|
1461
|
+
strategy: (row.strategy as string) || undefined,
|
|
1462
|
+
candidateEventIds: row.candidate_event_ids ? JSON.parse(row.candidate_event_ids as string) : [],
|
|
1463
|
+
selectedEventIds: row.selected_event_ids ? JSON.parse(row.selected_event_ids as string) : [],
|
|
1464
|
+
candidateDetails: row.candidate_details_json ? JSON.parse(row.candidate_details_json as string) : [],
|
|
1465
|
+
selectedDetails: row.selected_details_json ? JSON.parse(row.selected_details_json as string) : [],
|
|
1466
|
+
candidateCount: Number(row.candidate_count || 0),
|
|
1467
|
+
selectedCount: Number(row.selected_count || 0),
|
|
1468
|
+
confidence: (row.confidence as string) || undefined,
|
|
1469
|
+
fallbackTrace: row.fallback_trace ? JSON.parse(row.fallback_trace as string) : [],
|
|
1470
|
+
createdAt: toDateFromSQLite(row.created_at),
|
|
1471
|
+
}));
|
|
1472
|
+
} catch (err: any) {
|
|
1473
|
+
if (err?.message?.includes('no such table')) return [];
|
|
1474
|
+
throw err;
|
|
1475
|
+
}
|
|
1471
1476
|
}
|
|
1472
1477
|
|
|
1473
1478
|
async getRetrievalTraceStats(): Promise<{
|
|
@@ -1478,26 +1483,33 @@ export class SQLiteEventStore {
|
|
|
1478
1483
|
}> {
|
|
1479
1484
|
await this.initialize();
|
|
1480
1485
|
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1486
|
+
try {
|
|
1487
|
+
const row = sqliteGet<Record<string, unknown>>(
|
|
1488
|
+
this.db,
|
|
1489
|
+
`SELECT
|
|
1490
|
+
COUNT(*) as total_queries,
|
|
1491
|
+
AVG(candidate_count) as avg_candidate_count,
|
|
1492
|
+
AVG(selected_count) as avg_selected_count,
|
|
1493
|
+
CASE
|
|
1494
|
+
WHEN SUM(candidate_count) > 0 THEN (SUM(selected_count) * 1.0 / SUM(candidate_count))
|
|
1495
|
+
ELSE 0
|
|
1496
|
+
END as selection_rate
|
|
1497
|
+
FROM retrieval_traces`,
|
|
1498
|
+
[]
|
|
1499
|
+
);
|
|
1494
1500
|
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
+
return {
|
|
1502
|
+
totalQueries: Number(row?.total_queries || 0),
|
|
1503
|
+
avgCandidateCount: Number(row?.avg_candidate_count || 0),
|
|
1504
|
+
avgSelectedCount: Number(row?.avg_selected_count || 0),
|
|
1505
|
+
selectionRate: Number(row?.selection_rate || 0),
|
|
1506
|
+
};
|
|
1507
|
+
} catch (err: any) {
|
|
1508
|
+
if (err?.message?.includes('no such table')) {
|
|
1509
|
+
return { totalQueries: 0, avgCandidateCount: 0, avgSelectedCount: 0, selectionRate: 0 };
|
|
1510
|
+
}
|
|
1511
|
+
throw err;
|
|
1512
|
+
}
|
|
1501
1513
|
}
|
|
1502
1514
|
|
|
1503
1515
|
/**
|
|
@@ -17,7 +17,9 @@ import type { UserPromptSubmitInput, UserPromptSubmitOutput } from '../core/type
|
|
|
17
17
|
|
|
18
18
|
// Configuration
|
|
19
19
|
const MAX_MEMORIES = parseInt(process.env.CLAUDE_MEMORY_MAX_COUNT || '5');
|
|
20
|
-
|
|
20
|
+
// Tuned default for noise/recall balance on shopping_assistant-like corpus
|
|
21
|
+
const BASE_MIN_SCORE = parseFloat(process.env.CLAUDE_MEMORY_MIN_SCORE || '0.4');
|
|
22
|
+
const FALLBACK_MIN_SCORE = parseFloat(process.env.CLAUDE_MEMORY_FALLBACK_MIN_SCORE || '0.3');
|
|
21
23
|
const ENABLE_SEARCH = process.env.CLAUDE_MEMORY_SEARCH !== 'false';
|
|
22
24
|
|
|
23
25
|
/**
|
|
@@ -32,6 +34,14 @@ function shouldStorePrompt(prompt: string): boolean {
|
|
|
32
34
|
return true;
|
|
33
35
|
}
|
|
34
36
|
|
|
37
|
+
|
|
38
|
+
function getDynamicMinScore(prompt: string): number {
|
|
39
|
+
const len = prompt.trim().length;
|
|
40
|
+
if (len <= 20) return Math.min(0.55, BASE_MIN_SCORE + 0.1); // short query → stricter
|
|
41
|
+
if (len >= 80) return Math.max(0.3, BASE_MIN_SCORE - 0.05); // long query → slightly looser
|
|
42
|
+
return BASE_MIN_SCORE;
|
|
43
|
+
}
|
|
44
|
+
|
|
35
45
|
async function main(): Promise<void> {
|
|
36
46
|
// Read input from stdin
|
|
37
47
|
const inputData = await readStdin();
|
|
@@ -61,11 +71,20 @@ async function main(): Promise<void> {
|
|
|
61
71
|
|
|
62
72
|
// Fast keyword search if enabled
|
|
63
73
|
if (ENABLE_SEARCH && input.prompt.length > 10) {
|
|
64
|
-
const
|
|
74
|
+
const minScore = getDynamicMinScore(input.prompt);
|
|
75
|
+
let results = await memoryService.keywordSearch(input.prompt, {
|
|
65
76
|
topK: MAX_MEMORIES,
|
|
66
|
-
minScore
|
|
77
|
+
minScore
|
|
67
78
|
});
|
|
68
79
|
|
|
80
|
+
// recall rescue: if nothing found at tuned threshold, retry with fallback floor
|
|
81
|
+
if (results.length === 0 && FALLBACK_MIN_SCORE < minScore) {
|
|
82
|
+
results = await memoryService.keywordSearch(input.prompt, {
|
|
83
|
+
topK: MAX_MEMORIES,
|
|
84
|
+
minScore: FALLBACK_MIN_SCORE
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
|
|
69
88
|
if (results.length > 0) {
|
|
70
89
|
// Increment access count for found memories
|
|
71
90
|
const eventIds = results.map(r => r.event.id);
|
|
@@ -426,24 +426,32 @@ export class SessionHistoryImporter {
|
|
|
426
426
|
.map(name => path.join(projectsDir, name))
|
|
427
427
|
.filter(p => fs.statSync(p).isDirectory());
|
|
428
428
|
|
|
429
|
-
const normalizedPath = projectPath.replace(
|
|
430
|
-
const
|
|
431
|
-
|
|
429
|
+
const normalizedPath = projectPath.replace(/\+/g, '/').replace(/\/$/, '');
|
|
430
|
+
const normalizeToken = (value: string) => value
|
|
431
|
+
.toLowerCase()
|
|
432
|
+
.replace(/[\s_]+/g, '-')
|
|
433
|
+
.replace(/\/+/g, '-')
|
|
434
|
+
.replace(/-+/g, '-')
|
|
435
|
+
.replace(/^-|-$/g, '');
|
|
436
|
+
|
|
437
|
+
const normalizedDashed = normalizeToken(normalizedPath);
|
|
438
|
+
const baseName = normalizeToken(path.basename(normalizedPath));
|
|
432
439
|
|
|
433
440
|
const scored = projectDirs.map((dir) => {
|
|
434
441
|
const dirName = path.basename(dir);
|
|
442
|
+
const normalizedDirName = dirName.toLowerCase().replace(/[\s_]+/g, '-');
|
|
435
443
|
let score = 0;
|
|
436
444
|
|
|
437
445
|
// strong matches
|
|
438
|
-
if (
|
|
439
|
-
if (normalizedDashed.includes(
|
|
446
|
+
if (normalizedDirName.includes(normalizedDashed)) score += 100;
|
|
447
|
+
if (normalizedDashed.includes(normalizedDirName)) score += 80;
|
|
440
448
|
|
|
441
449
|
// basename signal (handles wrappers adding extra suffix)
|
|
442
|
-
if (baseName &&
|
|
450
|
+
if (baseName && normalizedDirName.includes(baseName)) score += 30;
|
|
443
451
|
|
|
444
452
|
// token overlap signal
|
|
445
453
|
const pathTokens = normalizedDashed.split('-').filter(Boolean);
|
|
446
|
-
const tokenHits = pathTokens.filter(t => t.length >= 3 &&
|
|
454
|
+
const tokenHits = pathTokens.filter(t => t.length >= 3 && normalizedDirName.includes(t)).length;
|
|
447
455
|
score += Math.min(tokenHits, 20);
|
|
448
456
|
|
|
449
457
|
return { dir, score, dirName };
|