claude-memory-layer 1.0.53 → 1.0.54

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.
@@ -1269,11 +1269,12 @@ function updateRetrievalReviewQueueUI() {
1269
1269
  const selectedIds = (item.selectedEventIds || []).slice(0, 3)
1270
1270
  .map((id) => `<span class="event-type-badge">${escapeHtml((id || '').slice(0, 8))}...</span>`)
1271
1271
  .join(' ');
1272
+ const strategy = normalizeRetrievalTraceStrategyLabel(item.strategy);
1272
1273
  return `
1273
1274
  <div class="shared-item" style="align-items:flex-start; border-left:2px solid ${severityColor};">
1274
1275
  <div class="shared-info" style="align-items:flex-start; flex-direction:column; gap:4px;">
1275
1276
  <span style="font-size:12px; color:var(--text-secondary);"><strong>${escapeHtml(item.title || 'Retrieval trace needs review')}</strong></span>
1276
- <span style="font-size:11px; color:var(--text-muted);">Trace ${escapeHtml((item.traceId || '').slice(0, 18))} · ${ts} · reason=${escapeHtml(item.reason || 'unknown')} · strategy=${escapeHtml(item.strategy || 'auto')} ${rewriteBadge}</span>
1277
+ <span style="font-size:11px; color:var(--text-muted);">Trace ${escapeHtml((item.traceId || '').slice(0, 18))} · ${ts} · reason=${escapeHtml(item.reason || 'unknown')} · strategy=${escapeHtml(strategy)} ${rewriteBadge}</span>
1277
1278
  <span style="font-size:11px; color:var(--text-muted);">${escapeHtml(item.detail || '')}</span>
1278
1279
  <span style="font-size:11px; color:var(--text-secondary);"><strong>Action:</strong> ${escapeHtml(item.action || '')}</span>
1279
1280
  <span style="font-size:11px; color:var(--text-muted);">candidates: ${candidateIds || '-'} · selected: ${selectedIds || '-'}</span>
@@ -1287,6 +1288,23 @@ function updateRetrievalReviewQueueUI() {
1287
1288
  }).join('');
1288
1289
  }
1289
1290
 
1291
+ const SAFE_RETRIEVAL_TRACE_STRATEGIES = new Set([
1292
+ 'auto',
1293
+ 'deep',
1294
+ 'fast',
1295
+ 'hybrid',
1296
+ 'keyword',
1297
+ 'semantic',
1298
+ 'mcp-context-pack',
1299
+ 'session-start-hook',
1300
+ 'unknown'
1301
+ ]);
1302
+
1303
+ function normalizeRetrievalTraceStrategyLabel(value) {
1304
+ const normalized = String(value || 'unknown').trim().toLowerCase();
1305
+ return SAFE_RETRIEVAL_TRACE_STRATEGIES.has(normalized) ? normalized : 'unknown';
1306
+ }
1307
+
1290
1308
  function updateRetrievalTraceUI() {
1291
1309
  updateRetrievalReviewQueueUI();
1292
1310
  const summaryEl = document.getElementById('retrieval-trace-summary');
@@ -1305,6 +1323,18 @@ function updateRetrievalTraceUI() {
1305
1323
 
1306
1324
  const selectionRate = ((stats.selectionRate || 0) * 100).toFixed(1);
1307
1325
  const rewriteRate = ((stats.rewriteRate || 0) * 100).toFixed(1);
1326
+ const strategyBreakdown = Array.isArray(stats.strategyBreakdown) ? stats.strategyBreakdown.slice(0, 4) : [];
1327
+ const strategyBreakdownHtml = strategyBreakdown.length > 0
1328
+ ? `<div style="display:flex; gap:8px; flex-wrap:wrap; font-size:11px; margin-top:8px; color:var(--text-muted);">
1329
+ ${strategyBreakdown.map((row) => {
1330
+ const strategy = normalizeRetrievalTraceStrategyLabel(row.strategy);
1331
+ const queries = Number(row.totalQueries || 0);
1332
+ const yieldRate = (Number(row.queryYieldRate || 0) * 100).toFixed(1);
1333
+ const selRate = (Number(row.selectionRate || 0) * 100).toFixed(1);
1334
+ return `<span class="event-type-badge" title="${escapeHtml(selRate)}% selected memories/candidates">${escapeHtml(strategy)} · ${formatNumber(queries)} queries · ${escapeHtml(yieldRate)}% yield</span>`;
1335
+ }).join('')}
1336
+ </div>`
1337
+ : '';
1308
1338
  summaryEl.innerHTML = `
1309
1339
  <div style="display:flex; gap:14px; flex-wrap:wrap; font-size:12px;">
1310
1340
  <span><strong>${formatNumber(stats.totalQueries)}</strong> queries</span>
@@ -1313,11 +1343,13 @@ function updateRetrievalTraceUI() {
1313
1343
  <span><strong>${selectionRate}%</strong> selection rate</span>
1314
1344
  <span title="Share of retrieval queries enriched with previous prompt/assistant context"><strong>${rewriteRate}%</strong> rewrite rate</span>
1315
1345
  </div>
1346
+ ${strategyBreakdownHtml}
1316
1347
  `;
1317
1348
 
1318
1349
  listEl.innerHTML = traces.slice(0, 8).map((t) => {
1319
1350
  const ts = t.createdAt ? new Date(t.createdAt).toLocaleString() : '-';
1320
1351
  const confidence = t.confidence || 'n/a';
1352
+ const strategy = normalizeRetrievalTraceStrategyLabel(t.strategy);
1321
1353
  const selected = Number(t.selectedCount || 0);
1322
1354
  const candidates = Number(t.candidateCount || 0);
1323
1355
  const rewriteKind = t.queryRewriteKind || (t.rewritten ? 'rewritten' : 'none');
@@ -1341,7 +1373,7 @@ function updateRetrievalTraceUI() {
1341
1373
  <div class="shared-item" style="align-items:flex-start;">
1342
1374
  <div class="shared-info" style="align-items:flex-start; flex-direction:column; gap:4px;">
1343
1375
  <span style="font-size:12px; color:var(--text-secondary);"><strong>Trace:</strong> ${escapeHtml((t.traceId || '').slice(0, 12)) || '-'}</span>
1344
- <span style="font-size:11px; color:var(--text-muted);">${ts} · strategy=${escapeHtml(t.strategy || 'auto')} · conf=${escapeHtml(confidence)} ${rewriteBadge}</span>
1376
+ <span style="font-size:11px; color:var(--text-muted);">${ts} · strategy=${escapeHtml(strategy)} · conf=${escapeHtml(confidence)} ${rewriteBadge}</span>
1345
1377
  <span style="font-size:11px; color:var(--text-muted);">selected IDs: ${selectedIdsHtml}</span>
1346
1378
  <span style="font-size:11px; color:var(--text-muted);">candidates: ${candidateDetails.map((d) => `<span class=\"event-type-badge\" style=\"cursor:pointer;\" onclick=\"openDetailModal(${jsAttrArg(d.eventId || '')})\">${escapeHtml((d.eventId || '').slice(0, 8))}...</span>`).join(' ') || '-'}</span>
1347
1379
  ${scoreBreakdownHtml}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-memory-layer",
3
- "version": "1.0.53",
3
+ "version": "1.0.54",
4
4
  "description": "Project-scoped memory layer for Claude Code, Codex, Hermes, MCP, and dashboards",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -19,9 +19,12 @@
19
19
  "build": "tsx scripts/build.ts",
20
20
  "dev": "tsx src/apps/cli/index.ts",
21
21
  "test": "vitest",
22
+ "test:run": "vitest run",
22
23
  "test:coverage": "vitest --coverage",
23
- "lint": "eslint src/**/*.ts",
24
+ "lint": "eslint \"src/**/*.ts\"",
24
25
  "typecheck": "tsc --noEmit",
26
+ "verify": "npm run typecheck && npm run lint && npm run test:run",
27
+ "prepublishOnly": "npm run typecheck && npm run lint && npm run test:run && npm run build",
25
28
  "smoke:dashboard": "tsx scripts/dashboard-smoke.ts",
26
29
  "check:architecture": "node scripts/check-import-boundaries.mjs",
27
30
  "ops:sync-gap:report": "node scripts/report-sync-gap.js",