claude-usage-dashboard 1.3.9 → 1.3.11

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.cjs ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+ const { join } = require('path');
4
+ const { pathToFileURL } = require('url');
5
+
6
+ const serverPath = join(__dirname, '..', 'server', 'index.js');
7
+ import(pathToFileURL(serverPath).href);
package/bin/cli.js CHANGED
@@ -1,2 +1,2 @@
1
- #!/usr/bin/env node
2
- import '../server/index.js';
1
+ #!/usr/bin/env node
2
+ import '../server/index.js';
package/bin/cli.sh CHANGED
@@ -1,11 +1,11 @@
1
- #!/bin/sh
2
- # Resolve symlinks to find the real script location
3
- SCRIPT="$0"
4
- while [ -L "$SCRIPT" ]; do
5
- DIR="$(cd -P "$(dirname "$SCRIPT")" && pwd)"
6
- SCRIPT="$(readlink "$SCRIPT")"
7
- case "$SCRIPT" in /*) ;; *) SCRIPT="$DIR/$SCRIPT" ;; esac
8
- done
9
- DIR="$(cd -P "$(dirname "$SCRIPT")" && pwd)"
10
-
11
- exec node "$DIR/../server/index.js" "$@"
1
+ #!/bin/sh
2
+ # Resolve symlinks to find the real script location
3
+ SCRIPT="$0"
4
+ while [ -L "$SCRIPT" ]; do
5
+ DIR="$(cd -P "$(dirname "$SCRIPT")" && pwd)"
6
+ SCRIPT="$(readlink "$SCRIPT")"
7
+ case "$SCRIPT" in /*) ;; *) SCRIPT="$DIR/$SCRIPT" ;; esac
8
+ done
9
+ DIR="$(cd -P "$(dirname "$SCRIPT")" && pwd)"
10
+
11
+ exec node "$DIR/../server/index.js" "$@"
package/package.json CHANGED
@@ -1,40 +1,40 @@
1
- {
2
- "name": "claude-usage-dashboard",
3
- "version": "1.3.9",
4
- "description": "Dashboard that visualizes Claude Code usage from local session logs",
5
- "main": "server/index.js",
6
- "bin": {
7
- "claude-usage-dashboard": "bin/cli.sh"
8
- },
9
- "files": [
10
- "bin/",
11
- "server/",
12
- "public/"
13
- ],
14
- "scripts": {
15
- "start": "node server/index.js",
16
- "test": "mocha test/**/*.test.js --timeout 5000"
17
- },
18
- "keywords": [
19
- "claude",
20
- "usage",
21
- "dashboard",
22
- "token",
23
- "cost"
24
- ],
25
- "author": "",
26
- "license": "ISC",
27
- "repository": {
28
- "type": "git",
29
- "url": "https://github.com/ludengz/claude-usage-dashboard.git"
30
- },
31
- "type": "module",
32
- "dependencies": {
33
- "d3": "^7.9.0",
34
- "express": "^5.2.1"
35
- },
36
- "devDependencies": {
37
- "chai": "^6.2.2",
38
- "mocha": "^11.7.5"
39
- }
40
- }
1
+ {
2
+ "name": "claude-usage-dashboard",
3
+ "version": "1.3.11",
4
+ "description": "Dashboard that visualizes Claude Code usage from local session logs",
5
+ "main": "server/index.js",
6
+ "bin": {
7
+ "claude-usage-dashboard": "bin/cli.cjs"
8
+ },
9
+ "files": [
10
+ "bin/",
11
+ "server/",
12
+ "public/"
13
+ ],
14
+ "scripts": {
15
+ "start": "node server/index.js",
16
+ "test": "mocha test/**/*.test.js --timeout 5000"
17
+ },
18
+ "keywords": [
19
+ "claude",
20
+ "usage",
21
+ "dashboard",
22
+ "token",
23
+ "cost"
24
+ ],
25
+ "author": "",
26
+ "license": "ISC",
27
+ "repository": {
28
+ "type": "git",
29
+ "url": "https://github.com/ludengz/claude-usage-dashboard.git"
30
+ },
31
+ "type": "module",
32
+ "dependencies": {
33
+ "d3": "^7.9.0",
34
+ "express": "^5.2.1"
35
+ },
36
+ "devDependencies": {
37
+ "chai": "^6.2.2",
38
+ "mocha": "^11.7.5"
39
+ }
40
+ }
@@ -1,265 +1,265 @@
1
- * { margin: 0; padding: 0; box-sizing: border-box; }
2
-
3
- :root {
4
- --bg-primary: #0f172a;
5
- --bg-card: #1e293b;
6
- --bg-input: #334155;
7
- --border: #475569;
8
- --text-primary: #f8fafc;
9
- --text-secondary: #94a3b8;
10
- --text-muted: #64748b;
11
- --blue: #3b82f6;
12
- --blue-light: #60a5fa;
13
- --purple: #8b5cf6;
14
- --orange: #f97316;
15
- --amber: #f59e0b;
16
- --green: #4ade80;
17
- --red: #ef4444;
18
- }
19
-
20
- body {
21
- background: var(--bg-primary);
22
- color: var(--text-primary);
23
- font-family: system-ui, -apple-system, sans-serif;
24
- padding: 0 24px 40px;
25
- }
26
-
27
- .top-bar {
28
- display: flex;
29
- justify-content: space-between;
30
- align-items: center;
31
- padding: 16px 0;
32
- border-bottom: 1px solid var(--bg-card);
33
- margin-bottom: 20px;
34
- }
35
- .logo { font-size: 18px; font-weight: 700; display: flex; align-items: center; gap: 8px; }
36
- .claude-icon { width: 22px; height: 22px; flex-shrink: 0; }
37
- .controls { display: flex; gap: 12px; align-items: center; }
38
-
39
- .summary-cards {
40
- display: grid;
41
- grid-template-columns: repeat(3, 1fr);
42
- gap: 12px;
43
- margin-bottom: 20px;
44
- }
45
- .card {
46
- background: var(--bg-card);
47
- border-radius: 8px;
48
- padding: 16px;
49
- }
50
- .card-label {
51
- font-size: 11px;
52
- color: var(--text-muted);
53
- text-transform: uppercase;
54
- letter-spacing: 1px;
55
- }
56
- .card-value {
57
- font-size: 24px;
58
- font-weight: 700;
59
- margin-top: 4px;
60
- }
61
- .card-sub {
62
- font-size: 11px;
63
- color: var(--text-secondary);
64
- margin-top: 2px;
65
- }
66
- #val-api-cost { color: var(--amber); }
67
- #val-savings { color: var(--green); }
68
- #val-cache-rate { color: var(--blue-light); }
69
-
70
- .chart-section {
71
- background: var(--bg-card);
72
- border-radius: 8px;
73
- padding: 20px;
74
- margin-bottom: 12px;
75
- }
76
- .chart-section h2 {
77
- font-size: 14px;
78
- font-weight: 600;
79
- margin-bottom: 16px;
80
- }
81
- .chart-header {
82
- display: flex;
83
- justify-content: space-between;
84
- align-items: center;
85
- margin-bottom: 16px;
86
- }
87
- .chart-header h2 { margin-bottom: 0; }
88
- .chart-container { min-height: 200px; }
89
-
90
- .chart-row-3 {
91
- display: grid;
92
- grid-template-columns: repeat(3, 1fr);
93
- gap: 12px;
94
- margin-bottom: 12px;
95
- }
96
-
97
- .granularity-toggle { display: flex; gap: 4px; }
98
- .granularity-toggle button {
99
- padding: 4px 12px;
100
- background: var(--bg-input);
101
- border: none;
102
- border-radius: 4px;
103
- color: var(--text-secondary);
104
- font-size: 12px;
105
- cursor: pointer;
106
- }
107
- .granularity-toggle button.active {
108
- background: var(--blue);
109
- color: white;
110
- box-shadow: 0 0 0 1px rgba(59,130,246,0.5);
111
- }
112
- .granularity-toggle button:disabled {
113
- opacity: 0.35;
114
- cursor: not-allowed;
115
- }
116
-
117
- .table-controls { display: flex; gap: 8px; }
118
- .filter-input, .sort-select {
119
- padding: 6px 10px;
120
- background: var(--bg-input);
121
- border: 1px solid var(--border);
122
- border-radius: 6px;
123
- color: var(--text-primary);
124
- font-size: 12px;
125
- }
126
- .filter-input { width: 180px; }
127
-
128
- .table-container { overflow-x: auto; }
129
- .table-container table {
130
- width: 100%;
131
- border-collapse: collapse;
132
- font-size: 12px;
133
- }
134
- .table-container th {
135
- text-align: left;
136
- padding: 10px 8px;
137
- border-bottom: 2px solid var(--bg-input);
138
- color: var(--text-muted);
139
- text-transform: uppercase;
140
- font-size: 10px;
141
- letter-spacing: 1px;
142
- cursor: pointer;
143
- }
144
- .table-container th.align-right,
145
- .table-container td.align-right { text-align: right; }
146
- .table-container td {
147
- padding: 10px 8px;
148
- border-bottom: 1px solid var(--bg-primary);
149
- color: var(--text-secondary);
150
- }
151
- .table-container tfoot td {
152
- border-top: 2px solid var(--bg-input);
153
- font-weight: 600;
154
- color: var(--text-primary);
155
- }
156
-
157
- .tag {
158
- display: inline-block;
159
- padding: 2px 8px;
160
- border-radius: 4px;
161
- font-size: 11px;
162
- }
163
- .tag-project { background: #1e3a5f; color: var(--blue-light); }
164
- .tag-model-sonnet { background: #1e3a5f; color: var(--blue-light); }
165
- .tag-model-opus { background: #3b1764; color: #c084fc; }
166
- .tag-model-haiku { background: #1a2e1a; color: var(--green); }
167
-
168
- .pagination {
169
- display: flex;
170
- justify-content: center;
171
- gap: 4px;
172
- margin-top: 12px;
173
- }
174
- .pagination button {
175
- padding: 4px 10px;
176
- background: var(--bg-input);
177
- border: none;
178
- border-radius: 4px;
179
- font-size: 11px;
180
- color: var(--text-secondary);
181
- cursor: pointer;
182
- }
183
- .pagination button.active {
184
- background: var(--blue);
185
- color: white;
186
- }
187
-
188
- .date-picker {
189
- display: flex;
190
- align-items: center;
191
- gap: 8px;
192
- }
193
- .date-picker input {
194
- padding: 6px 10px;
195
- background: var(--bg-input);
196
- border: 1px solid var(--border);
197
- border-radius: 6px;
198
- color: var(--text-primary);
199
- font-size: 12px;
200
- }
201
- .date-picker span { color: var(--text-secondary); font-size: 12px; }
202
-
203
- .refresh-controls {
204
- display: flex;
205
- align-items: center;
206
- gap: 8px;
207
- }
208
- .btn-refresh {
209
- padding: 4px 10px;
210
- background: var(--bg-input);
211
- border: 1px solid var(--border);
212
- border-radius: 6px;
213
- color: var(--text-primary);
214
- font-size: 16px;
215
- cursor: pointer;
216
- line-height: 1;
217
- }
218
- .btn-refresh:hover { background: var(--blue); }
219
- .auto-refresh-label {
220
- display: flex;
221
- align-items: center;
222
- gap: 4px;
223
- font-size: 12px;
224
- color: var(--text-secondary);
225
- cursor: pointer;
226
- }
227
- .last-updated {
228
- font-size: 11px;
229
- color: var(--text-muted);
230
- white-space: nowrap;
231
- }
232
-
233
- .plan-selector select, .plan-selector input {
234
- padding: 6px 10px;
235
- background: var(--bg-input);
236
- border: 1px solid var(--border);
237
- border-radius: 6px;
238
- color: var(--text-primary);
239
- font-size: 12px;
240
- }
241
-
242
- .d3-tooltip {
243
- position: absolute;
244
- padding: 8px 12px;
245
- background: rgba(15, 23, 42, 0.95);
246
- border: 1px solid var(--border);
247
- border-radius: 6px;
248
- font-size: 12px;
249
- color: var(--text-primary);
250
- pointer-events: none;
251
- z-index: 100;
252
- }
253
-
254
- .quota-unavailable {
255
- color: var(--text-muted);
256
- font-size: 13px;
257
- padding: 20px;
258
- text-align: center;
259
- }
260
- #quota-section .chart-container { min-height: auto; }
261
-
262
- @media (max-width: 768px) {
263
- .summary-cards { grid-template-columns: repeat(2, 1fr); }
264
- .chart-row-3 { grid-template-columns: 1fr; }
265
- }
1
+ * { margin: 0; padding: 0; box-sizing: border-box; }
2
+
3
+ :root {
4
+ --bg-primary: #0f172a;
5
+ --bg-card: #1e293b;
6
+ --bg-input: #334155;
7
+ --border: #475569;
8
+ --text-primary: #f8fafc;
9
+ --text-secondary: #94a3b8;
10
+ --text-muted: #64748b;
11
+ --blue: #3b82f6;
12
+ --blue-light: #60a5fa;
13
+ --purple: #8b5cf6;
14
+ --orange: #f97316;
15
+ --amber: #f59e0b;
16
+ --green: #4ade80;
17
+ --red: #ef4444;
18
+ }
19
+
20
+ body {
21
+ background: var(--bg-primary);
22
+ color: var(--text-primary);
23
+ font-family: system-ui, -apple-system, sans-serif;
24
+ padding: 0 24px 40px;
25
+ }
26
+
27
+ .top-bar {
28
+ display: flex;
29
+ justify-content: space-between;
30
+ align-items: center;
31
+ padding: 16px 0;
32
+ border-bottom: 1px solid var(--bg-card);
33
+ margin-bottom: 20px;
34
+ }
35
+ .logo { font-size: 18px; font-weight: 700; display: flex; align-items: center; gap: 8px; }
36
+ .claude-icon { width: 22px; height: 22px; flex-shrink: 0; }
37
+ .controls { display: flex; gap: 12px; align-items: center; }
38
+
39
+ .summary-cards {
40
+ display: grid;
41
+ grid-template-columns: repeat(3, 1fr);
42
+ gap: 12px;
43
+ margin-bottom: 20px;
44
+ }
45
+ .card {
46
+ background: var(--bg-card);
47
+ border-radius: 8px;
48
+ padding: 16px;
49
+ }
50
+ .card-label {
51
+ font-size: 11px;
52
+ color: var(--text-muted);
53
+ text-transform: uppercase;
54
+ letter-spacing: 1px;
55
+ }
56
+ .card-value {
57
+ font-size: 24px;
58
+ font-weight: 700;
59
+ margin-top: 4px;
60
+ }
61
+ .card-sub {
62
+ font-size: 11px;
63
+ color: var(--text-secondary);
64
+ margin-top: 2px;
65
+ }
66
+ #val-api-cost { color: var(--amber); }
67
+ #val-savings { color: var(--green); }
68
+ #val-cache-rate { color: var(--blue-light); }
69
+
70
+ .chart-section {
71
+ background: var(--bg-card);
72
+ border-radius: 8px;
73
+ padding: 20px;
74
+ margin-bottom: 12px;
75
+ }
76
+ .chart-section h2 {
77
+ font-size: 14px;
78
+ font-weight: 600;
79
+ margin-bottom: 16px;
80
+ }
81
+ .chart-header {
82
+ display: flex;
83
+ justify-content: space-between;
84
+ align-items: center;
85
+ margin-bottom: 16px;
86
+ }
87
+ .chart-header h2 { margin-bottom: 0; }
88
+ .chart-container { min-height: 200px; }
89
+
90
+ .chart-row-3 {
91
+ display: grid;
92
+ grid-template-columns: repeat(3, 1fr);
93
+ gap: 12px;
94
+ margin-bottom: 12px;
95
+ }
96
+
97
+ .granularity-toggle { display: flex; gap: 4px; }
98
+ .granularity-toggle button {
99
+ padding: 4px 12px;
100
+ background: var(--bg-input);
101
+ border: none;
102
+ border-radius: 4px;
103
+ color: var(--text-secondary);
104
+ font-size: 12px;
105
+ cursor: pointer;
106
+ }
107
+ .granularity-toggle button.active {
108
+ background: var(--blue);
109
+ color: white;
110
+ box-shadow: 0 0 0 1px rgba(59,130,246,0.5);
111
+ }
112
+ .granularity-toggle button:disabled {
113
+ opacity: 0.35;
114
+ cursor: not-allowed;
115
+ }
116
+
117
+ .table-controls { display: flex; gap: 8px; }
118
+ .filter-input, .sort-select {
119
+ padding: 6px 10px;
120
+ background: var(--bg-input);
121
+ border: 1px solid var(--border);
122
+ border-radius: 6px;
123
+ color: var(--text-primary);
124
+ font-size: 12px;
125
+ }
126
+ .filter-input { width: 180px; }
127
+
128
+ .table-container { overflow-x: auto; }
129
+ .table-container table {
130
+ width: 100%;
131
+ border-collapse: collapse;
132
+ font-size: 12px;
133
+ }
134
+ .table-container th {
135
+ text-align: left;
136
+ padding: 10px 8px;
137
+ border-bottom: 2px solid var(--bg-input);
138
+ color: var(--text-muted);
139
+ text-transform: uppercase;
140
+ font-size: 10px;
141
+ letter-spacing: 1px;
142
+ cursor: pointer;
143
+ }
144
+ .table-container th.align-right,
145
+ .table-container td.align-right { text-align: right; }
146
+ .table-container td {
147
+ padding: 10px 8px;
148
+ border-bottom: 1px solid var(--bg-primary);
149
+ color: var(--text-secondary);
150
+ }
151
+ .table-container tfoot td {
152
+ border-top: 2px solid var(--bg-input);
153
+ font-weight: 600;
154
+ color: var(--text-primary);
155
+ }
156
+
157
+ .tag {
158
+ display: inline-block;
159
+ padding: 2px 8px;
160
+ border-radius: 4px;
161
+ font-size: 11px;
162
+ }
163
+ .tag-project { background: #1e3a5f; color: var(--blue-light); }
164
+ .tag-model-sonnet { background: #1e3a5f; color: var(--blue-light); }
165
+ .tag-model-opus { background: #3b1764; color: #c084fc; }
166
+ .tag-model-haiku { background: #1a2e1a; color: var(--green); }
167
+
168
+ .pagination {
169
+ display: flex;
170
+ justify-content: center;
171
+ gap: 4px;
172
+ margin-top: 12px;
173
+ }
174
+ .pagination button {
175
+ padding: 4px 10px;
176
+ background: var(--bg-input);
177
+ border: none;
178
+ border-radius: 4px;
179
+ font-size: 11px;
180
+ color: var(--text-secondary);
181
+ cursor: pointer;
182
+ }
183
+ .pagination button.active {
184
+ background: var(--blue);
185
+ color: white;
186
+ }
187
+
188
+ .date-picker {
189
+ display: flex;
190
+ align-items: center;
191
+ gap: 8px;
192
+ }
193
+ .date-picker input {
194
+ padding: 6px 10px;
195
+ background: var(--bg-input);
196
+ border: 1px solid var(--border);
197
+ border-radius: 6px;
198
+ color: var(--text-primary);
199
+ font-size: 12px;
200
+ }
201
+ .date-picker span { color: var(--text-secondary); font-size: 12px; }
202
+
203
+ .refresh-controls {
204
+ display: flex;
205
+ align-items: center;
206
+ gap: 8px;
207
+ }
208
+ .btn-refresh {
209
+ padding: 4px 10px;
210
+ background: var(--bg-input);
211
+ border: 1px solid var(--border);
212
+ border-radius: 6px;
213
+ color: var(--text-primary);
214
+ font-size: 16px;
215
+ cursor: pointer;
216
+ line-height: 1;
217
+ }
218
+ .btn-refresh:hover { background: var(--blue); }
219
+ .auto-refresh-label {
220
+ display: flex;
221
+ align-items: center;
222
+ gap: 4px;
223
+ font-size: 12px;
224
+ color: var(--text-secondary);
225
+ cursor: pointer;
226
+ }
227
+ .last-updated {
228
+ font-size: 11px;
229
+ color: var(--text-muted);
230
+ white-space: nowrap;
231
+ }
232
+
233
+ .plan-selector select, .plan-selector input {
234
+ padding: 6px 10px;
235
+ background: var(--bg-input);
236
+ border: 1px solid var(--border);
237
+ border-radius: 6px;
238
+ color: var(--text-primary);
239
+ font-size: 12px;
240
+ }
241
+
242
+ .d3-tooltip {
243
+ position: absolute;
244
+ padding: 8px 12px;
245
+ background: rgba(15, 23, 42, 0.95);
246
+ border: 1px solid var(--border);
247
+ border-radius: 6px;
248
+ font-size: 12px;
249
+ color: var(--text-primary);
250
+ pointer-events: none;
251
+ z-index: 100;
252
+ }
253
+
254
+ .quota-unavailable {
255
+ color: var(--text-muted);
256
+ font-size: 13px;
257
+ padding: 20px;
258
+ text-align: center;
259
+ }
260
+ #quota-section .chart-container { min-height: auto; }
261
+
262
+ @media (max-width: 768px) {
263
+ .summary-cards { grid-template-columns: repeat(2, 1fr); }
264
+ .chart-row-3 { grid-template-columns: 1fr; }
265
+ }