claude-session-insights 0.3.1 → 0.3.2
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/README.md +6 -0
- package/package.json +1 -1
- package/public/index.html +69 -7
package/README.md
CHANGED
|
@@ -18,6 +18,12 @@ Think "Spotify Wrapped" for your Claude Code usage — scores, summaries, badges
|
|
|
18
18
|
- **Auto-Refresh** — optional 15-second polling to keep the dashboard current while you work
|
|
19
19
|
- **Account Info** — displays your subscription type, org, and email from `claude auth status`
|
|
20
20
|
|
|
21
|
+
## Screenshots
|
|
22
|
+
<img width="1080" height="880" alt="image" src="https://github.com/user-attachments/assets/d9914527-4ea5-49ed-aa8a-09a2896b1c67" />
|
|
23
|
+
<img width="1080" height="845" alt="image" src="https://github.com/user-attachments/assets/20799313-617c-4bc6-a999-76a0d95e2d8e" />
|
|
24
|
+
<img width="1080" height="823" alt="image" src="https://github.com/user-attachments/assets/249b4c78-8849-4db6-91bf-5ac87b4defbc" />
|
|
25
|
+
|
|
26
|
+
|
|
21
27
|
## Quick Start
|
|
22
28
|
|
|
23
29
|
```bash
|
package/package.json
CHANGED
package/public/index.html
CHANGED
|
@@ -698,10 +698,43 @@
|
|
|
698
698
|
color: var(--text3); cursor: pointer; font-size: 18px; line-height: 1; padding: 4px;
|
|
699
699
|
}
|
|
700
700
|
.share-close:hover { color: var(--text); }
|
|
701
|
+
|
|
702
|
+
/* Session drawer */
|
|
703
|
+
.session-drawer-overlay {
|
|
704
|
+
position: fixed; inset: 0; z-index: 500;
|
|
705
|
+
background: rgba(0,0,0,0.4); backdrop-filter: blur(2px);
|
|
706
|
+
opacity: 0; pointer-events: none; transition: opacity 0.25s;
|
|
707
|
+
}
|
|
708
|
+
.session-drawer-overlay.open { opacity: 1; pointer-events: auto; }
|
|
709
|
+
.session-drawer {
|
|
710
|
+
position: absolute; top: 0; right: 0; bottom: 0;
|
|
711
|
+
width: min(840px, 92vw);
|
|
712
|
+
background: var(--bg); overflow-y: auto;
|
|
713
|
+
padding: 24px 32px;
|
|
714
|
+
transform: translateX(100%);
|
|
715
|
+
transition: transform 0.28s cubic-bezier(0.4, 0, 0.2, 1);
|
|
716
|
+
box-shadow: -4px 0 40px rgba(0,0,0,0.18);
|
|
717
|
+
}
|
|
718
|
+
.session-drawer-overlay.open .session-drawer { transform: translateX(0); }
|
|
719
|
+
.drawer-topbar {
|
|
720
|
+
display: flex; justify-content: space-between; align-items: center;
|
|
721
|
+
margin-bottom: 20px; padding-bottom: 14px; border-bottom: 1px solid var(--border);
|
|
722
|
+
}
|
|
723
|
+
.drawer-topbar-label { font-size: 11px; color: var(--text3); font-weight: 500; }
|
|
724
|
+
.drawer-close-btn {
|
|
725
|
+
background: var(--surface2); border: 1px solid var(--border); color: var(--text2);
|
|
726
|
+
width: 30px; height: 30px; border-radius: 7px; cursor: pointer;
|
|
727
|
+
display: flex; align-items: center; justify-content: center;
|
|
728
|
+
font-size: 17px; line-height: 1; padding: 0; transition: all 0.15s; flex-shrink: 0;
|
|
729
|
+
}
|
|
730
|
+
.drawer-close-btn:hover { background: var(--surface3); color: var(--text); border-color: var(--border-hover); }
|
|
701
731
|
</style>
|
|
702
732
|
</head>
|
|
703
733
|
<body>
|
|
704
734
|
<div id="app" class="loading">Loading sessions...</div>
|
|
735
|
+
<div class="session-drawer-overlay" id="session-drawer-overlay" onclick="if(event.target===this)closeSessionDrawer()">
|
|
736
|
+
<div class="session-drawer" id="session-drawer"></div>
|
|
737
|
+
</div>
|
|
705
738
|
|
|
706
739
|
<script>
|
|
707
740
|
const $ = (s) => document.querySelector(s);
|
|
@@ -1202,7 +1235,12 @@ function renderDashboard(data) {
|
|
|
1202
1235
|
|
|
1203
1236
|
async function openSession(id) {
|
|
1204
1237
|
currentView = 'session';
|
|
1205
|
-
|
|
1238
|
+
const overlay = document.getElementById('session-drawer-overlay');
|
|
1239
|
+
const drawer = document.getElementById('session-drawer');
|
|
1240
|
+
drawer.innerHTML = '<div class="loading">Loading session...</div>';
|
|
1241
|
+
overlay.classList.add('open');
|
|
1242
|
+
document.body.style.overflow = 'hidden';
|
|
1243
|
+
if (autoRefreshActive) pauseAutoRefresh();
|
|
1206
1244
|
const s = await fetchSession(id);
|
|
1207
1245
|
renderSession(s);
|
|
1208
1246
|
}
|
|
@@ -1218,8 +1256,11 @@ function renderSession(s) {
|
|
|
1218
1256
|
|
|
1219
1257
|
let cumCost = 0;
|
|
1220
1258
|
|
|
1221
|
-
|
|
1222
|
-
<
|
|
1259
|
+
document.getElementById('session-drawer').innerHTML = `
|
|
1260
|
+
<div class="drawer-topbar">
|
|
1261
|
+
<span class="drawer-topbar-label">Session Detail</span>
|
|
1262
|
+
<button class="drawer-close-btn" onclick="closeSessionDrawer()" title="Close (Esc)">×</button>
|
|
1263
|
+
</div>
|
|
1223
1264
|
|
|
1224
1265
|
<div class="session-header">
|
|
1225
1266
|
<h2>${escHtml(s.title)}</h2>
|
|
@@ -1300,13 +1341,20 @@ function renderSession(s) {
|
|
|
1300
1341
|
if (costCanvas) drawCostPerTurn(costCanvas, s.turns);
|
|
1301
1342
|
}
|
|
1302
1343
|
|
|
1344
|
+
function closeSessionDrawer() {
|
|
1345
|
+
document.getElementById('session-drawer-overlay').classList.remove('open');
|
|
1346
|
+
document.body.style.overflow = '';
|
|
1347
|
+
currentView = 'dashboard';
|
|
1348
|
+
resumeAutoRefreshIfPaused();
|
|
1349
|
+
}
|
|
1350
|
+
|
|
1303
1351
|
function toggleScoreBreakdown() {
|
|
1304
1352
|
const el = document.getElementById('score-breakdown-overlay');
|
|
1305
1353
|
if (el) el.classList.toggle('open');
|
|
1306
1354
|
}
|
|
1307
1355
|
|
|
1308
1356
|
function goBack() {
|
|
1309
|
-
|
|
1357
|
+
closeSessionDrawer();
|
|
1310
1358
|
}
|
|
1311
1359
|
|
|
1312
1360
|
// --- AI Insights ---
|
|
@@ -1314,6 +1362,7 @@ function goBack() {
|
|
|
1314
1362
|
let aiModels = [];
|
|
1315
1363
|
let aiDefaultModel = null;
|
|
1316
1364
|
let aiDefaultModelLabel = null;
|
|
1365
|
+
let cachedAIRender = null; // persists AI insights across renderDashboard calls
|
|
1317
1366
|
|
|
1318
1367
|
function renderMarkdown(text) {
|
|
1319
1368
|
return text
|
|
@@ -1374,7 +1423,16 @@ document.addEventListener('click', () => {
|
|
|
1374
1423
|
document.querySelectorAll('.ai-model-picker.open').forEach(p => p.classList.remove('open'));
|
|
1375
1424
|
});
|
|
1376
1425
|
|
|
1426
|
+
function applyAIState() {
|
|
1427
|
+
if (cachedAIRender) {
|
|
1428
|
+
renderAIComplete(cachedAIRender.content, cachedAIRender.generatedAt, cachedAIRender.model);
|
|
1429
|
+
} else {
|
|
1430
|
+
renderModelPicker();
|
|
1431
|
+
}
|
|
1432
|
+
}
|
|
1433
|
+
|
|
1377
1434
|
function renderAIComplete(content, generatedAt, model) {
|
|
1435
|
+
cachedAIRender = { content, generatedAt, model };
|
|
1378
1436
|
const body = document.getElementById('ai-insights-body');
|
|
1379
1437
|
if (!body) return;
|
|
1380
1438
|
body.innerHTML = `
|
|
@@ -1393,6 +1451,7 @@ function renderAIComplete(content, generatedAt, model) {
|
|
|
1393
1451
|
}
|
|
1394
1452
|
|
|
1395
1453
|
function clearAIInsights() {
|
|
1454
|
+
cachedAIRender = null;
|
|
1396
1455
|
fetch('/api/ai-analyze', { method: 'DELETE' }).catch(() => {});
|
|
1397
1456
|
const body = document.getElementById('ai-insights-body');
|
|
1398
1457
|
if (!body) return;
|
|
@@ -1871,6 +1930,7 @@ async function doRefresh() {
|
|
|
1871
1930
|
btn.classList.add('spinning');
|
|
1872
1931
|
currentData = await fetchData(true);
|
|
1873
1932
|
renderDashboard(currentData);
|
|
1933
|
+
applyAIState();
|
|
1874
1934
|
btn.classList.remove('spinning');
|
|
1875
1935
|
}
|
|
1876
1936
|
|
|
@@ -1897,6 +1957,7 @@ function startAutoRefresh() {
|
|
|
1897
1957
|
if (btn) btn.classList.add('spinning');
|
|
1898
1958
|
currentData = await fetchData(true);
|
|
1899
1959
|
renderDashboard(currentData);
|
|
1960
|
+
applyAIState();
|
|
1900
1961
|
if (btn) btn.classList.remove('spinning');
|
|
1901
1962
|
updateCountdownLabel();
|
|
1902
1963
|
})();
|
|
@@ -1935,13 +1996,14 @@ function resumeAutoRefreshIfPaused() {
|
|
|
1935
1996
|
}
|
|
1936
1997
|
}
|
|
1937
1998
|
|
|
1938
|
-
|
|
1939
|
-
|
|
1999
|
+
document.addEventListener('keydown', e => {
|
|
2000
|
+
if (e.key === 'Escape' && currentView === 'session') closeSessionDrawer();
|
|
2001
|
+
});
|
|
1940
2002
|
|
|
1941
2003
|
fetchData().then(data => {
|
|
1942
2004
|
currentData = data;
|
|
1943
2005
|
renderDashboard(data);
|
|
1944
|
-
loadCachedAIInsights();
|
|
2006
|
+
loadCachedAIInsights();
|
|
1945
2007
|
if (autoRefreshActive) startAutoRefresh();
|
|
1946
2008
|
});
|
|
1947
2009
|
|