@jeet427/claude-sessions-dashboard 1.0.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/bin/cli.js ADDED
@@ -0,0 +1,96 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { createServer } = require('../src/server');
4
+
5
+ if (process.argv.includes('--digest')) {
6
+ const { analyzeAllSessions } = require('../src/analyzer');
7
+ const data = analyzeAllSessions();
8
+
9
+ // Filter to last 7 days
10
+ const cutoff = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000).toISOString().slice(0, 10);
11
+ const weekSessions = data.sessionDetails.filter(s => s.startTime && s.startTime.slice(0, 10) >= cutoff);
12
+ const weekCost = weekSessions.reduce((s, x) => s + x.cost, 0);
13
+ const weekMessages = weekSessions.reduce((s, x) => s + x.humanMessages + x.assistantMessages, 0);
14
+ const weekTools = weekSessions.reduce((s, x) => s + x.toolCalls, 0);
15
+ const anomalies = weekSessions.filter(s => s.isAnomaly).length;
16
+
17
+ // Top model this week
18
+ const modelCounts = {};
19
+ weekSessions.forEach(s => Object.entries(s.models || {}).forEach(([m, c]) => { modelCounts[m] = (modelCounts[m] || 0) + c; }));
20
+ const topModel = Object.entries(modelCounts).sort((a, b) => b[1] - a[1])[0];
21
+
22
+ // Top project this week
23
+ const projCosts = {};
24
+ weekSessions.forEach(s => { projCosts[s.projectName] = (projCosts[s.projectName] || 0) + s.cost; });
25
+ const topProject = Object.entries(projCosts).sort((a, b) => b[1] - a[1])[0];
26
+
27
+ const line = '═'.repeat(45);
28
+ const monday = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000);
29
+ const today = new Date();
30
+ const dateRange = monday.toLocaleDateString('en-US', { month: 'short', day: 'numeric' }) + ' – ' + today.toLocaleDateString('en-US', { month: 'short', day: 'numeric' });
31
+
32
+ // Cache hit rate for week
33
+ const weekCacheRead = weekSessions.reduce((s, x) => s + (x.cacheReadTokens || 0), 0);
34
+ const weekCacheWrite = weekSessions.reduce((s, x) => s + (x.cacheWriteTokens || 0), 0);
35
+ const weekCacheHit = (weekCacheRead + weekCacheWrite) > 0
36
+ ? ((weekCacheRead / (weekCacheRead + weekCacheWrite)) * 100).toFixed(1) + '%'
37
+ : '—';
38
+
39
+ console.log('\n' + line);
40
+ console.log(' Claude Sessions — Weekly Digest');
41
+ console.log(' Week of ' + dateRange);
42
+ console.log(line);
43
+ console.log(' Sessions this week: ' + weekSessions.length);
44
+ console.log(' Total cost this week: $' + weekCost.toFixed(2));
45
+ console.log(' Avg cost/session: $' + (weekSessions.length > 0 ? (weekCost / weekSessions.length).toFixed(2) : '0.00'));
46
+ console.log(' Total messages: ' + weekMessages);
47
+ console.log(' Total tool calls: ' + weekTools);
48
+ console.log(' Cache hit rate: ' + weekCacheHit);
49
+ console.log(' Top model: ' + (topModel ? topModel[0] + ' (' + topModel[1] + ' responses)' : '—'));
50
+ console.log(' Most used tool: ' + (data.toolUsage[0] ? data.toolUsage[0].name + ' (' + data.toolUsage[0].count + ' calls)' : '—'));
51
+ console.log(' Top project: ' + (topProject ? topProject[0] + ' ($' + topProject[1].toFixed(2) + ')' : '—'));
52
+ console.log(' Anomalous sessions: ' + anomalies + (anomalies > 0 ? ' ⚠ (cost > 3× avg)' : ''));
53
+ console.log(line + '\n');
54
+
55
+ process.exit(0);
56
+ }
57
+
58
+ const args = process.argv.slice(2);
59
+ const portFlag = args.indexOf('--port');
60
+ const port = portFlag !== -1 && args[portFlag + 1] ? parseInt(args[portFlag + 1], 10) : 3141;
61
+ const noBrowser = args.includes('--no-browser');
62
+ const budgetFlag = args.indexOf('--daily-budget');
63
+ const dailyBudget = budgetFlag !== -1 && args[budgetFlag + 1] ? parseFloat(args[budgetFlag + 1]) : null;
64
+
65
+ async function main() {
66
+ console.log('\n Claude Sessions Dashboard');
67
+ console.log(' ─────────────────────────\n');
68
+
69
+ try {
70
+ const { server, port: actualPort } = await createServer(port, { dailyBudget });
71
+ const url = `http://localhost:${actualPort}`;
72
+
73
+ console.log(` Dashboard running at: ${url}`);
74
+ console.log(' Press Ctrl+C to stop\n');
75
+
76
+ if (!noBrowser) {
77
+ try {
78
+ const open = (await import('open')).default;
79
+ await open(url);
80
+ } catch {
81
+ console.log(` Could not open browser automatically. Visit: ${url}\n`);
82
+ }
83
+ }
84
+
85
+ process.on('SIGINT', () => {
86
+ console.log('\n Shutting down...');
87
+ server.close();
88
+ process.exit(0);
89
+ });
90
+ } catch (err) {
91
+ console.error(' Failed to start:', err.message);
92
+ process.exit(1);
93
+ }
94
+ }
95
+
96
+ main();
package/package.json ADDED
@@ -0,0 +1,29 @@
1
+ {
2
+ "name": "@jeet427/claude-sessions-dashboard",
3
+ "version": "1.0.2",
4
+ "description": "A modern dashboard for Claude Code session analytics — tokens, costs, tools, models, and usage patterns",
5
+ "bin": {
6
+ "claude-dashboard": "./bin/cli.js"
7
+ },
8
+ "main": "src/server.js",
9
+ "scripts": {
10
+ "start": "node bin/cli.js",
11
+ "dev": "node bin/cli.js --port 3141"
12
+ },
13
+ "keywords": [
14
+ "claude",
15
+ "claude-code",
16
+ "dashboard",
17
+ "analytics",
18
+ "sessions"
19
+ ],
20
+ "author": "Jitendra Mathur",
21
+ "license": "MIT",
22
+ "dependencies": {
23
+ "express": "^4.21.0",
24
+ "open": "^10.1.0"
25
+ },
26
+ "engines": {
27
+ "node": ">=18.0.0"
28
+ }
29
+ }
@@ -0,0 +1,35 @@
1
+ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap');
2
+ body { font-family: 'Inter', sans-serif; }
3
+ .mono { font-family: 'JetBrains Mono', monospace; }
4
+ .glass { background: rgba(30, 30, 53, 0.8); backdrop-filter: blur(12px); }
5
+ .glow { box-shadow: 0 0 20px rgba(232, 130, 90, 0.15); }
6
+ .fade-in { animation: fadeIn 0.4s ease-out; }
7
+ @keyframes fadeIn { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } }
8
+ ::-webkit-scrollbar { width: 6px; height: 6px; }
9
+ ::-webkit-scrollbar-track { background: #0f0f1a; }
10
+ ::-webkit-scrollbar-thumb { background: #2a2a45; border-radius: 3px; }
11
+ ::-webkit-scrollbar-thumb:hover { background: #3a3a55; }
12
+ /* Hide native details disclosure triangle */
13
+ details > summary { list-style: none; }
14
+ details > summary::-webkit-details-marker { display: none; }
15
+ .tab-active { border-bottom: 2px solid #E8825A; color: #E8825A; }
16
+ .tab-inactive { border-bottom: 2px solid transparent; color: #8888aa; }
17
+ .tab-inactive:hover { color: #bbbbdd; }
18
+ .session-row:hover { background: rgba(42,42,69,0.4); cursor: pointer; }
19
+ #session-modal { display: none; }
20
+ #session-modal.open { display: flex; }
21
+ #shortcuts-overlay { display: none; }
22
+ #shortcuts-overlay.visible { display: block; }
23
+ /* ── Light Mode ─────────────────────── */
24
+ html.light-mode body { background: #f5f5f5; color: #1a1a2e; }
25
+ html.light-mode .bg-claude-darker { background: #f0f0f5 !important; }
26
+ html.light-mode .bg-claude-card, html.light-mode .glass { background: #ffffff !important; border-color: #e0e0f0 !important; }
27
+ html.light-mode .text-white { color: #1a1a2e !important; }
28
+ html.light-mode .text-gray-200 { color: #2a2a3e !important; }
29
+ html.light-mode .text-gray-300 { color: #3a3a4e !important; }
30
+ html.light-mode .text-gray-400 { color: #4a4a5e !important; }
31
+ html.light-mode .border-claude-border { border-color: #d0d0e8 !important; }
32
+ html.light-mode .bg-\[#16213e\], html.light-mode .bg-\[#1e1e35\], html.light-mode .bg-\[#0f0f1a\], html.light-mode .bg-\[#0d0d1a\] { background: #f8f8ff !important; }
33
+ html.light-mode .text-claude-muted { color: #5a5a7a !important; }
34
+ html.light-mode #modal-conv-messages .flex.justify-start > div > div { background: #eef0ff !important; border-color: #d0d0f0 !important; }
35
+ html.light-mode #modal-conv-messages .flex.justify-end > div > div { background: #e0e0f5 !important; }