@agentmemory/agentmemory 0.9.17 → 0.9.18
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/.env.example +6 -0
- package/README.md +15 -1
- package/dist/.env.example +6 -0
- package/dist/cli.mjs +12 -6
- package/dist/cli.mjs.map +1 -1
- package/dist/index.mjs +186 -28
- package/dist/index.mjs.map +1 -1
- package/dist/{src-TiNuQ3Ub.mjs → src-C7vygXCj.mjs} +186 -28
- package/dist/src-C7vygXCj.mjs.map +1 -0
- package/dist/{standalone-BIXq6S80.mjs → standalone-kg2TedgD.mjs} +16 -7
- package/dist/standalone-kg2TedgD.mjs.map +1 -0
- package/dist/standalone.mjs +16 -7
- package/dist/standalone.mjs.map +1 -1
- package/dist/viewer/favicon.svg +1 -0
- package/dist/viewer/index.html +190 -60
- package/package.json +2 -2
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/.codex-plugin/plugin.json +1 -1
- package/dist/src-TiNuQ3Ub.mjs.map +0 -1
- package/dist/standalone-BIXq6S80.mjs.map +0 -1
package/dist/viewer/index.html
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
<meta charset="UTF-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
6
|
<title>agentmemory viewer</title>
|
|
7
|
+
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
|
|
7
8
|
<!-- Removed Google Fonts <link> in #323: the viewer CSP is strict
|
|
8
9
|
(default-src 'none', style-src 'unsafe-inline', font-src 'self')
|
|
9
10
|
and external stylesheets from fonts.googleapis.com were blocked,
|
|
@@ -103,12 +104,21 @@
|
|
|
103
104
|
align-items: center;
|
|
104
105
|
justify-content: space-between;
|
|
105
106
|
background: var(--bg);
|
|
107
|
+
flex: 0 0 auto;
|
|
108
|
+
position: relative;
|
|
109
|
+
z-index: 3;
|
|
106
110
|
}
|
|
107
111
|
.app-header .brand {
|
|
108
112
|
display: flex;
|
|
109
113
|
align-items: baseline;
|
|
110
114
|
gap: 10px;
|
|
115
|
+
color: inherit;
|
|
116
|
+
text-decoration: none;
|
|
117
|
+
cursor: pointer;
|
|
111
118
|
}
|
|
119
|
+
.app-header .brand:hover h1,
|
|
120
|
+
.app-header .brand:focus-visible h1 { color: var(--accent); }
|
|
121
|
+
.app-header .brand:focus-visible { outline: 2px solid var(--accent); outline-offset: 4px; }
|
|
112
122
|
.app-header .brand h1 {
|
|
113
123
|
font-size: 22px;
|
|
114
124
|
color: var(--ink);
|
|
@@ -157,6 +167,9 @@
|
|
|
157
167
|
border-bottom: 1px solid var(--border-light);
|
|
158
168
|
background: var(--bg);
|
|
159
169
|
overflow-x: auto;
|
|
170
|
+
flex: 0 0 auto;
|
|
171
|
+
position: relative;
|
|
172
|
+
z-index: 2;
|
|
160
173
|
}
|
|
161
174
|
.tab-bar button {
|
|
162
175
|
background: none;
|
|
@@ -427,22 +440,46 @@
|
|
|
427
440
|
margin-bottom: 12px;
|
|
428
441
|
border-left: 3px solid var(--border-light);
|
|
429
442
|
transition: box-shadow 0.15s;
|
|
443
|
+
min-width: 0;
|
|
444
|
+
max-width: 100%;
|
|
445
|
+
overflow: hidden;
|
|
430
446
|
}
|
|
431
447
|
.obs-card:hover { box-shadow: 3px 3px 0px 0px var(--border-light); }
|
|
432
448
|
.obs-card.imp-high { border-left-color: var(--accent); }
|
|
433
449
|
.obs-card.imp-med { border-left-color: var(--yellow); }
|
|
434
450
|
.obs-card.imp-low { border-left-color: var(--green); }
|
|
435
451
|
.obs-card .obs-head {
|
|
452
|
+
display: grid;
|
|
453
|
+
grid-template-columns: minmax(0, 1fr) auto;
|
|
454
|
+
align-items: start;
|
|
455
|
+
gap: 12px;
|
|
456
|
+
margin-bottom: 6px;
|
|
457
|
+
}
|
|
458
|
+
.obs-card .obs-title-row {
|
|
436
459
|
display: flex;
|
|
437
|
-
justify-content: space-between;
|
|
438
460
|
align-items: center;
|
|
439
|
-
|
|
461
|
+
gap: 6px;
|
|
462
|
+
min-width: 0;
|
|
463
|
+
}
|
|
464
|
+
.obs-card .obs-meta {
|
|
465
|
+
display: flex;
|
|
466
|
+
align-items: center;
|
|
467
|
+
gap: 8px;
|
|
468
|
+
flex: 0 0 auto;
|
|
469
|
+
white-space: nowrap;
|
|
470
|
+
}
|
|
471
|
+
.obs-card .obs-type-icon {
|
|
472
|
+
flex: 0 0 auto;
|
|
440
473
|
}
|
|
441
474
|
.obs-card .obs-title {
|
|
442
475
|
font-size: 14px;
|
|
443
476
|
font-weight: 700;
|
|
444
477
|
color: var(--ink);
|
|
445
478
|
font-family: var(--font-display);
|
|
479
|
+
min-width: 0;
|
|
480
|
+
overflow: hidden;
|
|
481
|
+
text-overflow: ellipsis;
|
|
482
|
+
white-space: nowrap;
|
|
446
483
|
}
|
|
447
484
|
.obs-card .obs-time {
|
|
448
485
|
font-size: 10px;
|
|
@@ -454,6 +491,14 @@
|
|
|
454
491
|
font-size: 13px;
|
|
455
492
|
color: var(--ink-muted);
|
|
456
493
|
margin-bottom: 6px;
|
|
494
|
+
overflow-wrap: anywhere;
|
|
495
|
+
word-break: break-word;
|
|
496
|
+
}
|
|
497
|
+
.obs-card pre {
|
|
498
|
+
max-width: 100%;
|
|
499
|
+
white-space: pre-wrap;
|
|
500
|
+
overflow-wrap: anywhere;
|
|
501
|
+
word-break: break-word;
|
|
457
502
|
}
|
|
458
503
|
.obs-card .obs-facts {
|
|
459
504
|
margin: 6px 0 6px 16px;
|
|
@@ -470,6 +515,9 @@
|
|
|
470
515
|
color: var(--blue);
|
|
471
516
|
font-family: var(--font-mono);
|
|
472
517
|
font-weight: 500;
|
|
518
|
+
max-width: 100%;
|
|
519
|
+
overflow: hidden;
|
|
520
|
+
text-overflow: ellipsis;
|
|
473
521
|
}
|
|
474
522
|
.tag.file-tag { border-color: var(--green); color: var(--green); }
|
|
475
523
|
|
|
@@ -598,7 +646,14 @@
|
|
|
598
646
|
.empty-state .empty-link { color: var(--accent); text-decoration: underline; font-size: 13px; font-style: normal; }
|
|
599
647
|
|
|
600
648
|
/* Feature flag banner system — compact collapsed by default */
|
|
601
|
-
.flag-banners {
|
|
649
|
+
.flag-banners {
|
|
650
|
+
padding: 0 12px 10px 12px;
|
|
651
|
+
background: var(--bg);
|
|
652
|
+
flex: 0 0 auto;
|
|
653
|
+
position: relative;
|
|
654
|
+
z-index: 1;
|
|
655
|
+
}
|
|
656
|
+
.flag-banners:empty { display: none; }
|
|
602
657
|
button.flag-summary {
|
|
603
658
|
display: flex; align-items: center; gap: 12px;
|
|
604
659
|
padding: 8px 14px; border-radius: 4px;
|
|
@@ -609,6 +664,7 @@
|
|
|
609
664
|
cursor: pointer; user-select: none;
|
|
610
665
|
width: 100%; text-align: left;
|
|
611
666
|
appearance: none;
|
|
667
|
+
flex: 1 1 auto;
|
|
612
668
|
}
|
|
613
669
|
button.flag-summary:hover,
|
|
614
670
|
button.flag-summary:focus-visible { background: var(--bg-alt); outline: 2px solid var(--border); outline-offset: 1px; }
|
|
@@ -623,6 +679,8 @@
|
|
|
623
679
|
.flag-list {
|
|
624
680
|
display: none; flex-direction: column; gap: 6px;
|
|
625
681
|
margin-top: 6px;
|
|
682
|
+
max-height: min(30vh, 260px);
|
|
683
|
+
overflow-y: auto;
|
|
626
684
|
}
|
|
627
685
|
.flag-list.open { display: flex; }
|
|
628
686
|
.flag-banner {
|
|
@@ -645,11 +703,13 @@
|
|
|
645
703
|
font-family: var(--font-mono); font-size: 10px; color: var(--ink);
|
|
646
704
|
white-space: pre-wrap; word-break: break-all;
|
|
647
705
|
}
|
|
648
|
-
.flag-
|
|
706
|
+
.flag-close {
|
|
649
707
|
background: none; border: none; color: var(--ink-faint); cursor: pointer;
|
|
650
708
|
font-size: 16px; line-height: 1; padding: 0 4px; font-family: inherit;
|
|
709
|
+
flex: 0 0 auto;
|
|
651
710
|
}
|
|
652
|
-
.flag-
|
|
711
|
+
.flag-close:hover,
|
|
712
|
+
.flag-close:focus-visible { color: var(--ink); outline: 2px solid var(--border); outline-offset: 1px; }
|
|
653
713
|
|
|
654
714
|
/* Viewer footer */
|
|
655
715
|
.viewer-footer {
|
|
@@ -811,7 +871,7 @@
|
|
|
811
871
|
|
|
812
872
|
.timeline-container { position: relative; padding: 20px 0; }
|
|
813
873
|
.timeline-container::before { content: ''; position: absolute; left: 50%; top: 0; bottom: 0; width: 2px; background: var(--border-light); transform: translateX(-50%); }
|
|
814
|
-
.timeline-item { position: relative; width: 45%; margin-bottom: 20px; }
|
|
874
|
+
.timeline-item { position: relative; width: 45%; margin-bottom: 20px; min-width: 0; }
|
|
815
875
|
.timeline-item.tl-left { margin-left: 0; margin-right: auto; text-align: right; padding-right: 30px; }
|
|
816
876
|
.timeline-item.tl-right { margin-left: auto; margin-right: 0; padding-left: 30px; }
|
|
817
877
|
.timeline-dot { position: absolute; width: 12px; height: 12px; border-radius: 50%; top: 16px; z-index: 1; border: 2px solid var(--bg); }
|
|
@@ -874,10 +934,10 @@
|
|
|
874
934
|
</head>
|
|
875
935
|
<body>
|
|
876
936
|
<div class="app-header">
|
|
877
|
-
<
|
|
937
|
+
<a class="brand" href="#dashboard" data-tab-link="dashboard" aria-label="Open dashboard">
|
|
878
938
|
<h1>agentmemory</h1>
|
|
879
939
|
<span class="version">v__AGENTMEMORY_VERSION__</span>
|
|
880
|
-
</
|
|
940
|
+
</a>
|
|
881
941
|
<div class="header-right">
|
|
882
942
|
<span class="dateline" id="dateline"></span>
|
|
883
943
|
<button id="theme-toggle" class="btn" style="font-size:9px;padding:3px 10px;letter-spacing:0.1em;margin-right:8px;" data-action="toggle-theme">DARK</button>
|
|
@@ -886,7 +946,7 @@
|
|
|
886
946
|
</div>
|
|
887
947
|
|
|
888
948
|
<div class="tab-bar" id="tab-bar">
|
|
889
|
-
<button class="active" data-tab="dashboard">Dashboard</button>
|
|
949
|
+
<button class="active" data-tab="dashboard" aria-current="page">Dashboard</button>
|
|
890
950
|
<button data-tab="graph">Graph</button>
|
|
891
951
|
<button data-tab="memories">Memories</button>
|
|
892
952
|
<button data-tab="timeline">Timeline</button>
|
|
@@ -1002,6 +1062,7 @@
|
|
|
1002
1062
|
task: '☑', other: '📄'
|
|
1003
1063
|
};
|
|
1004
1064
|
var CB_STATE_COLORS = { closed: 'badge-green', open: 'badge-red', 'half-open': 'badge-yellow' };
|
|
1065
|
+
var TAB_IDS = ['dashboard', 'graph', 'memories', 'timeline', 'sessions', 'lessons', 'actions', 'crystals', 'audit', 'activity', 'profile', 'replay'];
|
|
1005
1066
|
|
|
1006
1067
|
var state = {
|
|
1007
1068
|
activeTab: 'dashboard',
|
|
@@ -1018,6 +1079,7 @@
|
|
|
1018
1079
|
profile: { loaded: false, projects: [], selectedProject: '', data: null },
|
|
1019
1080
|
replay: { loaded: false, sessions: [], selectedId: '', timeline: null, cursor: 0, playing: false, speed: 1, timer: null, startAt: 0, offsetAt: 0 },
|
|
1020
1081
|
flagsConfig: null,
|
|
1082
|
+
flagsDismissed: {},
|
|
1021
1083
|
ws: null
|
|
1022
1084
|
};
|
|
1023
1085
|
|
|
@@ -1039,6 +1101,23 @@
|
|
|
1039
1101
|
if (!s) return '';
|
|
1040
1102
|
return s.length > n ? s.slice(0, n) + '...' : s;
|
|
1041
1103
|
}
|
|
1104
|
+
function sessionId(s) {
|
|
1105
|
+
return s && s.id !== undefined && s.id !== null ? String(s.id) : '';
|
|
1106
|
+
}
|
|
1107
|
+
function shortSessionId(s, n) {
|
|
1108
|
+
var id = sessionId(s);
|
|
1109
|
+
return id ? id.slice(0, n || 8) : '';
|
|
1110
|
+
}
|
|
1111
|
+
function sessionDisplayName(s) {
|
|
1112
|
+
var project = s && s.project ? String(s.project).split('/').pop() : '';
|
|
1113
|
+
if (project) return project;
|
|
1114
|
+
return shortSessionId(s, 8) || 'Unknown session';
|
|
1115
|
+
}
|
|
1116
|
+
function sessionLabel(s) {
|
|
1117
|
+
var id = shortSessionId(s, 8);
|
|
1118
|
+
var name = sessionDisplayName(s);
|
|
1119
|
+
return id ? name + ' (' + id + ')' : name + ' (missing id)';
|
|
1120
|
+
}
|
|
1042
1121
|
function debounce(fn, ms) {
|
|
1043
1122
|
var t;
|
|
1044
1123
|
return function() {
|
|
@@ -1080,17 +1159,52 @@
|
|
|
1080
1159
|
});
|
|
1081
1160
|
}
|
|
1082
1161
|
|
|
1083
|
-
function
|
|
1162
|
+
function normalizeTab(tab) {
|
|
1163
|
+
var normalized = String(tab || '').replace(/^#/, '').toLowerCase();
|
|
1164
|
+
return TAB_IDS.indexOf(normalized) >= 0 ? normalized : 'dashboard';
|
|
1165
|
+
}
|
|
1166
|
+
|
|
1167
|
+
function tabFromRoute() {
|
|
1168
|
+
try {
|
|
1169
|
+
return normalizeTab(decodeURIComponent(window.location.hash.slice(1)));
|
|
1170
|
+
} catch (_) {
|
|
1171
|
+
return 'dashboard';
|
|
1172
|
+
}
|
|
1173
|
+
}
|
|
1174
|
+
|
|
1175
|
+
function updateTabRoute(tab, replace) {
|
|
1176
|
+
var target = '#' + tab;
|
|
1177
|
+
if (window.location.hash === target) return;
|
|
1178
|
+
if (replace) {
|
|
1179
|
+
history.replaceState(null, '', target);
|
|
1180
|
+
} else {
|
|
1181
|
+
history.pushState(null, '', target);
|
|
1182
|
+
}
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
function switchTab(tab, opts) {
|
|
1186
|
+
opts = opts || {};
|
|
1187
|
+
tab = normalizeTab(tab);
|
|
1084
1188
|
if (state.activeTab === 'replay' && tab !== 'replay' && typeof stopReplayTimer === 'function') {
|
|
1085
1189
|
stopReplayTimer();
|
|
1086
1190
|
}
|
|
1191
|
+
if (!opts.skipRoute) {
|
|
1192
|
+
updateTabRoute(tab, !!opts.replaceRoute);
|
|
1193
|
+
}
|
|
1087
1194
|
state.activeTab = tab;
|
|
1088
1195
|
document.querySelectorAll('.tab-bar button').forEach(function(b) {
|
|
1089
|
-
|
|
1196
|
+
var isActive = b.dataset.tab === tab;
|
|
1197
|
+
b.classList.toggle('active', isActive);
|
|
1198
|
+
if (isActive) {
|
|
1199
|
+
b.setAttribute('aria-current', 'page');
|
|
1200
|
+
} else {
|
|
1201
|
+
b.removeAttribute('aria-current');
|
|
1202
|
+
}
|
|
1090
1203
|
});
|
|
1091
1204
|
document.querySelectorAll('.view').forEach(function(v) {
|
|
1092
1205
|
v.classList.toggle('active', v.id === 'view-' + tab);
|
|
1093
1206
|
});
|
|
1207
|
+
if (state.flagsConfig) renderFlagBanners(state.flagsConfig);
|
|
1094
1208
|
loadTab(tab);
|
|
1095
1209
|
}
|
|
1096
1210
|
|
|
@@ -1278,7 +1392,7 @@
|
|
|
1278
1392
|
html += '<table><tr><th>Project</th><th>Status</th><th>Obs</th><th>Started</th></tr>';
|
|
1279
1393
|
recent.forEach(function(s) {
|
|
1280
1394
|
var statusBadge = s.status === 'active' ? 'badge-green' : s.status === 'completed' ? 'badge-blue' : 'badge-muted';
|
|
1281
|
-
html += '<tr><td style="color:var(--ink);font-weight:500;">' + esc(
|
|
1395
|
+
html += '<tr><td style="color:var(--ink);font-weight:500;">' + esc(sessionDisplayName(s)) + '</td>';
|
|
1282
1396
|
html += '<td><span class="badge ' + statusBadge + '">' + esc(s.status) + '</span></td>';
|
|
1283
1397
|
html += '<td style="color:var(--ink-muted);font-family:var(--font-mono);font-size:12px;">' + (s.observationCount || 0) + '</td>';
|
|
1284
1398
|
html += '<td style="font-family:var(--font-mono);font-size:11px;color:var(--ink-faint);">' + esc(shortTime(s.startedAt)) + '</td></tr>';
|
|
@@ -2192,7 +2306,8 @@
|
|
|
2192
2306
|
|
|
2193
2307
|
if (sessions.length > 0 && !state.timeline.sessionId) {
|
|
2194
2308
|
var sorted = sessions.slice().sort(function(a, b) { return (b.startedAt || '').localeCompare(a.startedAt || ''); });
|
|
2195
|
-
|
|
2309
|
+
var firstSelectable = sorted.find(function(s) { return sessionId(s); });
|
|
2310
|
+
state.timeline.sessionId = firstSelectable ? sessionId(firstSelectable) : '';
|
|
2196
2311
|
}
|
|
2197
2312
|
|
|
2198
2313
|
renderTimelineToolbar(sessions);
|
|
@@ -2204,8 +2319,9 @@
|
|
|
2204
2319
|
var html = '<div class="toolbar">';
|
|
2205
2320
|
html += '<select id="tl-session"><option value="">Select session</option>';
|
|
2206
2321
|
sessions.sort(function(a, b) { return (b.startedAt || '').localeCompare(a.startedAt || ''); }).forEach(function(s) {
|
|
2207
|
-
var
|
|
2208
|
-
|
|
2322
|
+
var id = sessionId(s);
|
|
2323
|
+
var disabled = id ? '' : ' disabled';
|
|
2324
|
+
html += '<option value="' + esc(id) + '"' + (id && state.timeline.sessionId === id ? ' selected' : '') + disabled + '>' + esc(sessionLabel(s)) + '</option>';
|
|
2209
2325
|
});
|
|
2210
2326
|
html += '</select>';
|
|
2211
2327
|
html += '<select id="tl-importance"><option value="0">All importance</option>';
|
|
@@ -2319,12 +2435,12 @@
|
|
|
2319
2435
|
|
|
2320
2436
|
html += '<div class="obs-card imp-' + impClass + '" style="border-left-color:' + typeColor + ';text-align:left;">';
|
|
2321
2437
|
html += '<div class="obs-head">';
|
|
2322
|
-
html += '<div
|
|
2438
|
+
html += '<div class="obs-title-row">';
|
|
2323
2439
|
html += '<span class="obs-type-icon">' + icon + '</span>';
|
|
2324
|
-
html += '<span class="obs-title">' + esc(title) + '</span>';
|
|
2440
|
+
html += '<span class="obs-title" title="' + esc(title) + '">' + esc(title) + '</span>';
|
|
2325
2441
|
if (isRaw) html += '<span class="badge badge-muted" style="font-size:8px;margin-left:4px;">raw</span>';
|
|
2326
2442
|
html += '</div>';
|
|
2327
|
-
html += '<div
|
|
2443
|
+
html += '<div class="obs-meta">';
|
|
2328
2444
|
if (isCompressed) html += '<span class="obs-importance imp-' + impVal + '" title="Importance: ' + impVal + '/10">' + impVal + '</span>';
|
|
2329
2445
|
html += '<span class="obs-time">' + esc(shortTime(o.timestamp)) + '</span>';
|
|
2330
2446
|
html += '</div></div>';
|
|
@@ -2421,8 +2537,8 @@
|
|
|
2421
2537
|
var sorted = sessions.slice().sort(function(a, b) { return (b.startedAt || '').localeCompare(a.startedAt || ''); });
|
|
2422
2538
|
var recentSessions = sorted.slice(0, 5);
|
|
2423
2539
|
|
|
2424
|
-
var obsResults = await Promise.all(recentSessions.map(function(s) {
|
|
2425
|
-
return apiGet('observations?sessionId=' + encodeURIComponent(s
|
|
2540
|
+
var obsResults = await Promise.all(recentSessions.filter(function(s) { return sessionId(s); }).map(function(s) {
|
|
2541
|
+
return apiGet('observations?sessionId=' + encodeURIComponent(sessionId(s)));
|
|
2426
2542
|
}));
|
|
2427
2543
|
obsResults.forEach(function(r) {
|
|
2428
2544
|
if (r && r.observations) allObs = allObs.concat(r.observations);
|
|
@@ -2565,15 +2681,16 @@
|
|
|
2565
2681
|
} else {
|
|
2566
2682
|
items.forEach(function(s) {
|
|
2567
2683
|
var statusBadge = s.status === 'active' ? 'badge-green' : s.status === 'completed' ? 'badge-blue' : 'badge-muted';
|
|
2568
|
-
var
|
|
2569
|
-
|
|
2570
|
-
html += '<div class="session-
|
|
2684
|
+
var id = sessionId(s);
|
|
2685
|
+
var selected = id && state.sessions.selectedId === id;
|
|
2686
|
+
html += '<div class="session-item' + (selected ? ' selected' : '') + '"' + (id ? ' data-action="select-session" data-session-id="' + esc(id) + '"' : '') + '>';
|
|
2687
|
+
html += '<div class="session-top"><span class="session-project">' + esc(sessionDisplayName(s)) + '</span>';
|
|
2571
2688
|
html += '<span class="badge ' + statusBadge + '">' + esc(s.status) + '</span></div>';
|
|
2572
2689
|
var preview = s.firstPrompt || s.summary || '';
|
|
2573
2690
|
if (preview) {
|
|
2574
2691
|
html += '<div class="session-preview" style="font-size:13px;color:var(--ink);margin:4px 0;line-height:1.4;">' + esc(truncate(preview, 140)) + '</div>';
|
|
2575
2692
|
}
|
|
2576
|
-
html += '<div class="session-meta">' + esc(s
|
|
2693
|
+
html += '<div class="session-meta">' + esc(shortSessionId(s, 12) || 'missing id') + ' · ' + esc(formatTime(s.startedAt));
|
|
2577
2694
|
html += ' · ' + (s.observationCount || 0) + ' obs';
|
|
2578
2695
|
if (s.model) html += ' · ' + esc(s.model);
|
|
2579
2696
|
html += '</div></div>';
|
|
@@ -2594,12 +2711,13 @@
|
|
|
2594
2711
|
async function renderSessionDetail() {
|
|
2595
2712
|
var panel = document.getElementById('session-detail');
|
|
2596
2713
|
if (!panel) return;
|
|
2597
|
-
var s = state.sessions.items.find(function(x) { return x
|
|
2598
|
-
|
|
2714
|
+
var s = state.sessions.items.find(function(x) { return sessionId(x) === state.sessions.selectedId; });
|
|
2715
|
+
var id = sessionId(s);
|
|
2716
|
+
if (!s || !id) { panel.innerHTML = ''; return; }
|
|
2599
2717
|
|
|
2600
2718
|
panel.innerHTML = '<div class="detail-panel"><h3>Loading session details…</h3></div>';
|
|
2601
2719
|
|
|
2602
|
-
var obsRes = await apiGet('observations?sessionId=' + encodeURIComponent(
|
|
2720
|
+
var obsRes = await apiGet('observations?sessionId=' + encodeURIComponent(id));
|
|
2603
2721
|
var obs = (obsRes && obsRes.observations) || [];
|
|
2604
2722
|
|
|
2605
2723
|
var typeCounts = {};
|
|
@@ -2672,7 +2790,8 @@
|
|
|
2672
2790
|
|
|
2673
2791
|
html += '<div class="card" style="margin-bottom:12px;"><div class="card-title">Metadata</div>';
|
|
2674
2792
|
html += '<div style="font-size:12px;font-family:var(--font-mono);margin-top:8px;line-height:1.7;">';
|
|
2675
|
-
|
|
2793
|
+
var detailId = sessionId(s);
|
|
2794
|
+
html += '<div><span style="color:var(--ink-muted);">id:</span> ' + esc(detailId || 'missing id') + '</div>';
|
|
2676
2795
|
html += '<div><span style="color:var(--ink-muted);">cwd:</span> ' + esc(s.cwd || '-') + '</div>';
|
|
2677
2796
|
html += '<div><span style="color:var(--ink-muted);">started:</span> ' + esc(formatTime(s.startedAt)) + '</div>';
|
|
2678
2797
|
if (s.endedAt) html += '<div><span style="color:var(--ink-muted);">ended:</span> ' + esc(formatTime(s.endedAt)) + '</div>';
|
|
@@ -2681,10 +2800,14 @@
|
|
|
2681
2800
|
html += '</div></div>';
|
|
2682
2801
|
|
|
2683
2802
|
html += '<div style="display:flex;gap:8px;">';
|
|
2684
|
-
if (s.status === 'active') {
|
|
2685
|
-
html += '<button class="btn btn-danger" data-action="end-session" data-session-id="' + esc(
|
|
2803
|
+
if (detailId && s.status === 'active') {
|
|
2804
|
+
html += '<button class="btn btn-danger" data-action="end-session" data-session-id="' + esc(detailId) + '">End Session</button>';
|
|
2805
|
+
}
|
|
2806
|
+
if (detailId) {
|
|
2807
|
+
html += '<button class="btn btn-primary" data-action="summarize-session" data-session-id="' + esc(detailId) + '">Summarize</button>';
|
|
2808
|
+
} else {
|
|
2809
|
+
html += '<button class="btn btn-primary" disabled>Summarize unavailable</button>';
|
|
2686
2810
|
}
|
|
2687
|
-
html += '<button class="btn btn-primary" data-action="summarize-session" data-session-id="' + esc(s.id) + '">Summarize</button>';
|
|
2688
2811
|
html += '</div></div>';
|
|
2689
2812
|
panel.innerHTML = html;
|
|
2690
2813
|
}
|
|
@@ -3320,26 +3443,39 @@
|
|
|
3320
3443
|
}
|
|
3321
3444
|
|
|
3322
3445
|
document.getElementById('tab-bar').addEventListener('click', function(e) {
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
}
|
|
3446
|
+
var btn = e.target instanceof Element ? e.target.closest('button[data-tab]') : null;
|
|
3447
|
+
if (btn) switchTab(btn.dataset.tab);
|
|
3326
3448
|
});
|
|
3327
3449
|
|
|
3328
|
-
|
|
3329
|
-
|
|
3330
|
-
|
|
3331
|
-
|
|
3332
|
-
|
|
3333
|
-
|
|
3334
|
-
|
|
3450
|
+
document.querySelectorAll('[data-tab-link]').forEach(function(link) {
|
|
3451
|
+
link.addEventListener('click', function(e) {
|
|
3452
|
+
if (e.defaultPrevented || e.button !== 0 || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) return;
|
|
3453
|
+
e.preventDefault();
|
|
3454
|
+
switchTab(link.getAttribute('data-tab-link'));
|
|
3455
|
+
});
|
|
3456
|
+
});
|
|
3457
|
+
|
|
3458
|
+
function syncTabFromRoute() {
|
|
3459
|
+
switchTab(tabFromRoute(), { replaceRoute: true });
|
|
3335
3460
|
}
|
|
3336
|
-
|
|
3337
|
-
|
|
3461
|
+
window.addEventListener('hashchange', syncTabFromRoute);
|
|
3462
|
+
window.addEventListener('popstate', syncTabFromRoute);
|
|
3463
|
+
|
|
3464
|
+
// --- Feature flag banners ---------------------------------------------
|
|
3465
|
+
function getDismissedFlags() {
|
|
3466
|
+
if (!state.flagsDismissed) state.flagsDismissed = {};
|
|
3467
|
+
return state.flagsDismissed;
|
|
3468
|
+
}
|
|
3469
|
+
function dismissFlags(keys) {
|
|
3470
|
+
var dismissed = getDismissedFlags();
|
|
3471
|
+
keys.forEach(function(key) {
|
|
3472
|
+
if (key) dismissed[key] = true;
|
|
3473
|
+
});
|
|
3338
3474
|
}
|
|
3339
3475
|
function renderFlagBanners(cfg) {
|
|
3340
3476
|
var host = document.getElementById('flag-banners');
|
|
3341
3477
|
if (!host) return;
|
|
3342
|
-
var dismissed =
|
|
3478
|
+
var dismissed = getDismissedFlags();
|
|
3343
3479
|
var banners = [];
|
|
3344
3480
|
// Per-flag banner (only for off flags, affecting current tab or dashboard)
|
|
3345
3481
|
(cfg.flags || []).forEach(function(f) {
|
|
@@ -3395,15 +3531,15 @@
|
|
|
3395
3531
|
});
|
|
3396
3532
|
};
|
|
3397
3533
|
var listHtml = banners.map(function(b) {
|
|
3398
|
-
return '<div class="flag-banner ' + b.kind + '" data-flag="' + b.dismissKey + '">' +
|
|
3534
|
+
return '<div class="flag-banner ' + b.kind + '" data-flag="' + escHtml(b.dismissKey) + '">' +
|
|
3399
3535
|
'<span class="flag-icon">' + b.icon + '</span>' +
|
|
3400
3536
|
'<div class="flag-body">' +
|
|
3401
|
-
'<div class="flag-title">' + b.title + ' <code>' + b.keyLabel + '</code></div>' +
|
|
3537
|
+
'<div class="flag-title">' + escHtml(b.title) + ' <code>' + escHtml(b.keyLabel) + '</code></div>' +
|
|
3402
3538
|
'<div class="flag-desc">' + escHtml(b.desc) + '</div>' +
|
|
3403
3539
|
'<code class="flag-enable">' + escHtml(b.enable) + '</code>' +
|
|
3404
|
-
(b.docs ? ' <a class="empty-link" href="' + b.docs + '" target="_blank" rel="noopener">Learn more →</a>' : '') +
|
|
3540
|
+
(b.docs ? ' <a class="empty-link" href="' + escHtml(b.docs) + '" target="_blank" rel="noopener">Learn more →</a>' : '') +
|
|
3405
3541
|
'</div>' +
|
|
3406
|
-
'<button class="flag-close" data-dismiss-flag="' + b.dismissKey + '" aria-label="Dismiss">×</button>' +
|
|
3542
|
+
'<button type="button" class="flag-close" data-dismiss-flag="' + escHtml(b.dismissKey) + '" aria-label="Dismiss">×</button>' +
|
|
3407
3543
|
'</div>';
|
|
3408
3544
|
}).join('');
|
|
3409
3545
|
host.innerHTML = '<button type="button" class="flag-summary" data-action="toggle-flags" aria-expanded="' + (expanded ? 'true' : 'false') + '" aria-controls="flag-list">' +
|
|
@@ -3446,11 +3582,10 @@
|
|
|
3446
3582
|
if (!(e.target instanceof Element)) return;
|
|
3447
3583
|
var btn = e.target.closest('[data-dismiss-flag]');
|
|
3448
3584
|
if (btn) {
|
|
3585
|
+
e.preventDefault();
|
|
3449
3586
|
e.stopPropagation();
|
|
3450
3587
|
var key = btn.getAttribute('data-dismiss-flag');
|
|
3451
|
-
|
|
3452
|
-
d[key] = true;
|
|
3453
|
-
saveDismissedFlags(d);
|
|
3588
|
+
dismissFlags([key]);
|
|
3454
3589
|
if (state.flagsConfig) renderFlagBanners(state.flagsConfig);
|
|
3455
3590
|
return;
|
|
3456
3591
|
}
|
|
@@ -3462,12 +3597,6 @@
|
|
|
3462
3597
|
if (state.flagsConfig) renderFlagBanners(state.flagsConfig);
|
|
3463
3598
|
}
|
|
3464
3599
|
});
|
|
3465
|
-
// Re-render banners when switching tabs so tab-specific banners appear
|
|
3466
|
-
var _origSwitchTab = switchTab;
|
|
3467
|
-
switchTab = function(tab) {
|
|
3468
|
-
_origSwitchTab(tab);
|
|
3469
|
-
if (state.flagsConfig) renderFlagBanners(state.flagsConfig);
|
|
3470
|
-
};
|
|
3471
3600
|
fetchFlags();
|
|
3472
3601
|
document.addEventListener('click', function(e) {
|
|
3473
3602
|
if (!(e.target instanceof Element)) return;
|
|
@@ -3587,8 +3716,9 @@
|
|
|
3587
3716
|
var el = document.getElementById('view-replay');
|
|
3588
3717
|
var sessions = state.replay.sessions || [];
|
|
3589
3718
|
var options = '<option value="">— pick a session —</option>' + sessions.map(function(s) {
|
|
3590
|
-
var
|
|
3591
|
-
|
|
3719
|
+
var id = sessionId(s);
|
|
3720
|
+
var label = sessionDisplayName(s) + ' · ' + (shortSessionId(s, 8) || 'missing id') + ' · ' + (s.observationCount || 0) + ' obs';
|
|
3721
|
+
return '<option value="' + esc(id) + '"' + (id && id === state.replay.selectedId ? ' selected' : '') + (id ? '' : ' disabled') + '>' + esc(label) + '</option>';
|
|
3592
3722
|
}).join('');
|
|
3593
3723
|
|
|
3594
3724
|
var tl = state.replay.timeline;
|
|
@@ -3778,7 +3908,7 @@
|
|
|
3778
3908
|
else if (e.key === 'ArrowRight') { e.preventDefault(); stepReplay(1); }
|
|
3779
3909
|
});
|
|
3780
3910
|
|
|
3781
|
-
|
|
3911
|
+
switchTab(tabFromRoute(), { replaceRoute: true });
|
|
3782
3912
|
connectWs();
|
|
3783
3913
|
startDashboardAutoRefresh();
|
|
3784
3914
|
</script>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agentmemory/agentmemory",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.18",
|
|
4
4
|
"description": "Persistent memory for AI coding agents, powered by iii-engine's three primitives",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.mjs",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"agentmemory": "dist/cli.mjs"
|
|
18
18
|
},
|
|
19
19
|
"scripts": {
|
|
20
|
-
"build": "tsdown && (cp iii-config.yaml dist/ 2>/dev/null || true) && (cp iii-config.docker.yaml dist/ 2>/dev/null || true) && (cp docker-compose.yml dist/ 2>/dev/null || true) && (cp .env.example dist/ 2>/dev/null || true) && mkdir -p dist/viewer && cp src/viewer/index.html dist/viewer/",
|
|
20
|
+
"build": "tsdown && (cp iii-config.yaml dist/ 2>/dev/null || true) && (cp iii-config.docker.yaml dist/ 2>/dev/null || true) && (cp docker-compose.yml dist/ 2>/dev/null || true) && (cp .env.example dist/ 2>/dev/null || true) && mkdir -p dist/viewer && cp src/viewer/index.html dist/viewer/ && cp src/viewer/favicon.svg dist/viewer/",
|
|
21
21
|
"dev": "tsx src/index.ts",
|
|
22
22
|
"start": "node dist/cli.mjs",
|
|
23
23
|
"migrate": "node dist/functions/migrate.js",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agentmemory",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.18",
|
|
4
4
|
"description": "Persistent memory for AI coding agents -- captures tool usage, compresses via LLM, injects context into future sessions. 12 hooks, 51 MCP tools, 4 skills, real-time viewer.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Rohit Ghumare",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agentmemory",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.18",
|
|
4
4
|
"description": "Persistent memory for AI coding agents -- captures tool usage, compresses via LLM, injects context into future sessions. 6 hooks, 51 MCP tools, 4 skills, real-time viewer.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Rohit Ghumare",
|