claude-memory-layer 1.0.19 → 1.0.21
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/dist/cli/index.js +182 -12
- package/dist/cli/index.js.map +2 -2
- package/dist/core/index.js +70 -10
- package/dist/core/index.js.map +2 -2
- package/dist/hooks/post-tool-use.js +155 -9
- package/dist/hooks/post-tool-use.js.map +2 -2
- package/dist/hooks/session-end.js +155 -9
- package/dist/hooks/session-end.js.map +2 -2
- package/dist/hooks/session-start.js +155 -9
- package/dist/hooks/session-start.js.map +2 -2
- package/dist/hooks/stop.js +155 -9
- package/dist/hooks/stop.js.map +2 -2
- package/dist/hooks/user-prompt-submit.js +155 -9
- package/dist/hooks/user-prompt-submit.js.map +2 -2
- package/dist/server/api/index.js +159 -9
- package/dist/server/api/index.js.map +2 -2
- package/dist/server/index.js +159 -9
- package/dist/server/index.js.map +2 -2
- package/dist/services/memory-service.js +155 -9
- package/dist/services/memory-service.js.map +2 -2
- package/dist/ui/app.js +126 -0
- package/dist/ui/index.html +39 -0
- package/dist/ui/style.css +7 -0
- package/package.json +2 -2
- package/scripts/build.ts +1 -0
- package/src/cli/index.ts +23 -1
- package/src/core/embedder.ts +25 -8
- package/src/core/sqlite-event-store.ts +32 -0
- package/src/core/types.ts +2 -2
- package/src/core/vector-store.ts +20 -0
- package/src/server/api/events.ts +6 -0
- package/src/services/memory-service.ts +112 -2
- package/src/ui/app.js +126 -0
- package/src/ui/index.html +39 -0
- package/src/ui/style.css +7 -0
package/src/ui/app.js
CHANGED
|
@@ -14,6 +14,10 @@ const state = {
|
|
|
14
14
|
retrievalTraces: null,
|
|
15
15
|
adherenceSummary: null,
|
|
16
16
|
adherenceWindow: '24h',
|
|
17
|
+
userPromptSearchQuery: '',
|
|
18
|
+
userPromptItems: [],
|
|
19
|
+
userPromptPage: 1,
|
|
20
|
+
userPromptPageSize: 30,
|
|
17
21
|
currentLevel: 'L0',
|
|
18
22
|
currentSort: 'recent',
|
|
19
23
|
currentView: 'overview',
|
|
@@ -149,6 +153,39 @@ function setupEventListeners() {
|
|
|
149
153
|
searchInput.addEventListener('input', debounce((e) => handleSearch(e.target.value), 300));
|
|
150
154
|
}
|
|
151
155
|
|
|
156
|
+
// User prompt search
|
|
157
|
+
const userPromptSearch = document.getElementById('user-prompt-search');
|
|
158
|
+
if (userPromptSearch) {
|
|
159
|
+
userPromptSearch.addEventListener('input', debounce(async (e) => {
|
|
160
|
+
state.userPromptSearchQuery = e.target.value || '';
|
|
161
|
+
state.userPromptPage = 1;
|
|
162
|
+
await loadUserPromptsView();
|
|
163
|
+
}, 250));
|
|
164
|
+
}
|
|
165
|
+
const userPromptRefresh = document.getElementById('user-prompt-refresh');
|
|
166
|
+
if (userPromptRefresh) {
|
|
167
|
+
userPromptRefresh.addEventListener('click', async () => {
|
|
168
|
+
await loadUserPromptsView();
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
const userPromptPrev = document.getElementById('user-prompt-prev');
|
|
172
|
+
if (userPromptPrev) {
|
|
173
|
+
userPromptPrev.addEventListener('click', async () => {
|
|
174
|
+
if (state.userPromptPage <= 1) return;
|
|
175
|
+
state.userPromptPage -= 1;
|
|
176
|
+
await renderUserPromptList();
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
const userPromptNext = document.getElementById('user-prompt-next');
|
|
180
|
+
if (userPromptNext) {
|
|
181
|
+
userPromptNext.addEventListener('click', async () => {
|
|
182
|
+
const totalPages = Math.max(1, Math.ceil((state.userPromptItems?.length || 0) / state.userPromptPageSize));
|
|
183
|
+
if (state.userPromptPage >= totalPages) return;
|
|
184
|
+
state.userPromptPage += 1;
|
|
185
|
+
await renderUserPromptList();
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
|
|
152
189
|
// Project selector
|
|
153
190
|
const projectSelect = document.getElementById('project-select');
|
|
154
191
|
if (projectSelect) {
|
|
@@ -1197,6 +1234,7 @@ function switchView(viewName) {
|
|
|
1197
1234
|
switch (viewName) {
|
|
1198
1235
|
case 'knowledge-graph': loadKnowledgeGraphView(); break;
|
|
1199
1236
|
case 'memory-banks': loadMemoryBanksView(); break;
|
|
1237
|
+
case 'user-prompts': loadUserPromptsView(); break;
|
|
1200
1238
|
case 'configuration': loadConfigurationView(); break;
|
|
1201
1239
|
}
|
|
1202
1240
|
}
|
|
@@ -1430,6 +1468,94 @@ async function loadMemoryBankLevel(level) {
|
|
|
1430
1468
|
}
|
|
1431
1469
|
}
|
|
1432
1470
|
|
|
1471
|
+
// --- User Prompts View ---
|
|
1472
|
+
|
|
1473
|
+
async function renderUserPromptList() {
|
|
1474
|
+
const listEl = document.getElementById('user-prompt-list');
|
|
1475
|
+
const pageEl = document.getElementById('user-prompt-page');
|
|
1476
|
+
const prevBtn = document.getElementById('user-prompt-prev');
|
|
1477
|
+
const nextBtn = document.getElementById('user-prompt-next');
|
|
1478
|
+
const metaEl = document.getElementById('user-prompt-meta');
|
|
1479
|
+
if (!listEl) return;
|
|
1480
|
+
|
|
1481
|
+
const items = state.userPromptItems || [];
|
|
1482
|
+
const pageSize = state.userPromptPageSize;
|
|
1483
|
+
const totalPages = Math.max(1, Math.ceil(items.length / pageSize));
|
|
1484
|
+
if (state.userPromptPage > totalPages) state.userPromptPage = totalPages;
|
|
1485
|
+
|
|
1486
|
+
const start = (state.userPromptPage - 1) * pageSize;
|
|
1487
|
+
const paged = items.slice(start, start + pageSize);
|
|
1488
|
+
|
|
1489
|
+
if (pageEl) pageEl.textContent = `${state.userPromptPage} / ${totalPages}`;
|
|
1490
|
+
if (prevBtn) prevBtn.disabled = state.userPromptPage <= 1;
|
|
1491
|
+
if (nextBtn) nextBtn.disabled = state.userPromptPage >= totalPages;
|
|
1492
|
+
|
|
1493
|
+
if (metaEl) {
|
|
1494
|
+
const sessionCount = new Set(items.map(i => i.sessionId)).size;
|
|
1495
|
+
metaEl.textContent = `${items.length} prompts · ${sessionCount} sessions${state.userPromptSearchQuery ? ` · query: "${state.userPromptSearchQuery}"` : ''}`;
|
|
1496
|
+
}
|
|
1497
|
+
|
|
1498
|
+
if (paged.length === 0) {
|
|
1499
|
+
listEl.innerHTML = '<div style="padding:20px; text-align:center; color:var(--text-muted);">No user prompts found.</div>';
|
|
1500
|
+
return;
|
|
1501
|
+
}
|
|
1502
|
+
|
|
1503
|
+
// Group current page by session
|
|
1504
|
+
const groups = new Map();
|
|
1505
|
+
for (const e of paged) {
|
|
1506
|
+
const key = e.sessionId || 'unknown';
|
|
1507
|
+
const arr = groups.get(key) || [];
|
|
1508
|
+
arr.push(e);
|
|
1509
|
+
groups.set(key, arr);
|
|
1510
|
+
}
|
|
1511
|
+
|
|
1512
|
+
const html = Array.from(groups.entries()).map(([sessionId, sessionItems]) => {
|
|
1513
|
+
const heading = `
|
|
1514
|
+
<div style="margin:10px 0 6px; font-size:12px; color:var(--text-muted); font-weight:600;">
|
|
1515
|
+
<i class="ri-chat-1-line"></i> Session ${escapeHtml((sessionId || '').slice(0, 16))}... · ${sessionItems.length} prompts
|
|
1516
|
+
</div>
|
|
1517
|
+
`;
|
|
1518
|
+
|
|
1519
|
+
const cards = sessionItems.map((e) => `
|
|
1520
|
+
<div class="event-item" style="cursor:pointer;" onclick="openDetailModal('${e.id}')">
|
|
1521
|
+
<div class="event-header">
|
|
1522
|
+
<span class="event-type-badge type-user-prompt">user_prompt</span>
|
|
1523
|
+
<span class="event-time">${new Date(e.timestamp).toLocaleString()}</span>
|
|
1524
|
+
</div>
|
|
1525
|
+
<div class="event-content" style="-webkit-line-clamp:4;">${escapeHtml(e.preview || '')}</div>
|
|
1526
|
+
</div>
|
|
1527
|
+
`).join('');
|
|
1528
|
+
|
|
1529
|
+
return heading + cards;
|
|
1530
|
+
}).join('');
|
|
1531
|
+
|
|
1532
|
+
listEl.innerHTML = html;
|
|
1533
|
+
}
|
|
1534
|
+
|
|
1535
|
+
async function loadUserPromptsView() {
|
|
1536
|
+
const listEl = document.getElementById('user-prompt-list');
|
|
1537
|
+
if (!listEl) return;
|
|
1538
|
+
|
|
1539
|
+
listEl.innerHTML = '<div style="padding:20px; text-align:center; color:var(--text-muted);">Loading user prompts...</div>';
|
|
1540
|
+
|
|
1541
|
+
try {
|
|
1542
|
+
const params = {
|
|
1543
|
+
type: 'user_prompt',
|
|
1544
|
+
sort: 'recent',
|
|
1545
|
+
limit: 500,
|
|
1546
|
+
q: state.userPromptSearchQuery || undefined
|
|
1547
|
+
};
|
|
1548
|
+
const res = await fetch(apiUrl(`${API_BASE}/events`, params));
|
|
1549
|
+
const data = await res.json();
|
|
1550
|
+
const items = data.events || [];
|
|
1551
|
+
state.userPromptItems = items;
|
|
1552
|
+
|
|
1553
|
+
await renderUserPromptList();
|
|
1554
|
+
} catch (error) {
|
|
1555
|
+
listEl.innerHTML = `<div style="padding:20px; text-align:center; color:var(--error);">Failed to load user prompts: ${escapeHtml(error.message)}</div>`;
|
|
1556
|
+
}
|
|
1557
|
+
}
|
|
1558
|
+
|
|
1433
1559
|
// --- Configuration View ---
|
|
1434
1560
|
|
|
1435
1561
|
async function loadConfigurationView() {
|
package/src/ui/index.html
CHANGED
|
@@ -51,6 +51,10 @@
|
|
|
51
51
|
<i class="ri-brain-line"></i>
|
|
52
52
|
<span>Memory Banks</span>
|
|
53
53
|
</li>
|
|
54
|
+
<li class="nav-item" data-nav="user-prompts">
|
|
55
|
+
<i class="ri-message-2-line"></i>
|
|
56
|
+
<span>User Prompts</span>
|
|
57
|
+
</li>
|
|
54
58
|
<li class="nav-item" data-nav="configuration">
|
|
55
59
|
<i class="ri-settings-4-line"></i>
|
|
56
60
|
<span>Configuration</span>
|
|
@@ -363,6 +367,41 @@
|
|
|
363
367
|
</div>
|
|
364
368
|
</div>
|
|
365
369
|
|
|
370
|
+
<!-- ========== VIEW: User Prompts ========== -->
|
|
371
|
+
<div id="view-user-prompts" class="page-view">
|
|
372
|
+
<header class="top-header">
|
|
373
|
+
<div class="page-title">
|
|
374
|
+
<h1>User Prompts</h1>
|
|
375
|
+
<p>Search and browse recent user prompts</p>
|
|
376
|
+
</div>
|
|
377
|
+
</header>
|
|
378
|
+
<div class="card" style="margin-bottom:16px;">
|
|
379
|
+
<div style="display:flex; gap:10px; align-items:center;">
|
|
380
|
+
<div class="search-wrapper" style="width:420px; max-width:100%;">
|
|
381
|
+
<i class="ri-search-line"></i>
|
|
382
|
+
<input type="text" id="user-prompt-search" class="search-input" placeholder="Search user prompts...">
|
|
383
|
+
</div>
|
|
384
|
+
<button id="user-prompt-refresh" class="btn btn-secondary"><i class="ri-refresh-line"></i><span>Refresh</span></button>
|
|
385
|
+
</div>
|
|
386
|
+
</div>
|
|
387
|
+
<div class="card">
|
|
388
|
+
<div class="card-header" style="align-items:flex-end;">
|
|
389
|
+
<div>
|
|
390
|
+
<div class="card-title"><i class="ri-history-line"></i><span>Latest User Prompt History</span></div>
|
|
391
|
+
<div id="user-prompt-meta" style="font-size:12px; color:var(--text-muted); margin-top:6px;"></div>
|
|
392
|
+
</div>
|
|
393
|
+
<div style="display:flex; gap:8px; align-items:center;">
|
|
394
|
+
<button id="user-prompt-prev" class="sort-btn">Prev</button>
|
|
395
|
+
<span id="user-prompt-page" style="font-size:12px; color:var(--text-muted);">1 / 1</span>
|
|
396
|
+
<button id="user-prompt-next" class="sort-btn">Next</button>
|
|
397
|
+
</div>
|
|
398
|
+
</div>
|
|
399
|
+
<div id="user-prompt-list" class="event-list">
|
|
400
|
+
<div style="padding:20px; text-align:center; color:var(--text-muted);">Loading...</div>
|
|
401
|
+
</div>
|
|
402
|
+
</div>
|
|
403
|
+
</div>
|
|
404
|
+
|
|
366
405
|
<!-- ========== VIEW: Configuration ========== -->
|
|
367
406
|
<div id="view-configuration" class="page-view">
|
|
368
407
|
<header class="top-header">
|
package/src/ui/style.css
CHANGED
|
@@ -502,8 +502,11 @@ body {
|
|
|
502
502
|
}
|
|
503
503
|
|
|
504
504
|
.type-user { background: rgba(59, 130, 246, 0.2); color: #60A5FA; }
|
|
505
|
+
.type-user-prompt { background: rgba(59, 130, 246, 0.2); color: #60A5FA; }
|
|
505
506
|
.type-agent { background: rgba(16, 185, 129, 0.2); color: #34D399; }
|
|
507
|
+
.type-agent-response { background: rgba(16, 185, 129, 0.2); color: #34D399; }
|
|
506
508
|
.type-tool { background: rgba(245, 158, 11, 0.2); color: #FBBF24; }
|
|
509
|
+
.type-tool-observation { background: rgba(245, 158, 11, 0.2); color: #FBBF24; }
|
|
507
510
|
.type-system { background: rgba(139, 92, 246, 0.2); color: #A78BFA; }
|
|
508
511
|
|
|
509
512
|
.event-time {
|
|
@@ -597,6 +600,10 @@ body {
|
|
|
597
600
|
color: var(--accent-primary);
|
|
598
601
|
font-weight: 600;
|
|
599
602
|
}
|
|
603
|
+
.sort-btn:disabled {
|
|
604
|
+
opacity: 0.35;
|
|
605
|
+
cursor: not-allowed;
|
|
606
|
+
}
|
|
600
607
|
|
|
601
608
|
/* Access Badge */
|
|
602
609
|
.access-badge {
|