@zhangferry-dev/tokendash 1.1.4 → 1.2.1
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 +25 -7
- package/dist/client/assets/index-92lvfG3S.css +1 -0
- package/dist/client/assets/index-DohuMiQc.js +121 -0
- package/dist/client/index.html +2 -2
- package/dist/server/agentDetection.d.ts +6 -0
- package/dist/server/agentDetection.js +25 -0
- package/dist/server/analyticsParser.d.ts +13 -0
- package/dist/server/analyticsParser.js +277 -0
- package/dist/server/cache.d.ts +5 -0
- package/dist/server/cache.js +54 -10
- package/dist/server/claudeJsonlParser.d.ts +9 -0
- package/dist/server/claudeJsonlParser.js +314 -0
- package/dist/server/index.js +3 -3
- package/dist/server/routes/analytics.d.ts +2 -0
- package/dist/server/routes/analytics.js +40 -0
- package/dist/server/routes/api.js +5 -3
- package/dist/server/routes/blocks.js +31 -51
- package/dist/server/routes/daily.js +28 -19
- package/dist/server/routes/monthly.d.ts +1 -1
- package/dist/server/routes/monthly.js +26 -9
- package/dist/server/routes/projects.js +28 -19
- package/dist/server/routes/session.d.ts +1 -1
- package/dist/server/routes/session.js +26 -9
- package/dist/shared/schemas.d.ts +53 -31
- package/dist/shared/schemas.js +29 -0
- package/dist/shared/types.d.ts +29 -0
- package/package.json +8 -3
- package/dist/client/assets/index-BJbeEwyn.js +0 -121
- package/dist/client/assets/index-DI_qK8jk.css +0 -1
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { runCcusage } from '../ccusage.js';
|
|
2
1
|
import { cache } from '../cache.js';
|
|
3
2
|
import { validateProjects } from '../../shared/schemas.js';
|
|
4
|
-
import { getProjectsResponse } from '../codexParser.js';
|
|
3
|
+
import { getProjectsResponse as getCodexProjectsResponse } from '../codexParser.js';
|
|
5
4
|
import { getProjectsResponse as getOpenClawProjectsResponse } from '../openclawParser.js';
|
|
5
|
+
import { getProjectsResponse as getClaudeProjectsResponse } from '../claudeJsonlParser.js';
|
|
6
6
|
export async function getProjects(req, res) {
|
|
7
7
|
const agent = req.query.agent || 'claude';
|
|
8
8
|
const cacheKey = `projects:${agent}`;
|
|
@@ -12,24 +12,16 @@ export async function getProjects(req, res) {
|
|
|
12
12
|
res.json(cached);
|
|
13
13
|
return;
|
|
14
14
|
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
const data = getOpenClawProjectsResponse();
|
|
22
|
-
const validated = validateProjects(data);
|
|
23
|
-
cache.set(cacheKey, validated);
|
|
24
|
-
res.json(validated);
|
|
25
|
-
}
|
|
26
|
-
else {
|
|
27
|
-
const stdout = await runCcusage(['daily', '--instances', '--breakdown']);
|
|
28
|
-
const data = JSON.parse(stdout);
|
|
29
|
-
const validated = validateProjects(data);
|
|
30
|
-
cache.set(cacheKey, validated);
|
|
31
|
-
res.json(validated);
|
|
15
|
+
// Stale-while-revalidate
|
|
16
|
+
const stale = cache.getStale(cacheKey);
|
|
17
|
+
if (stale) {
|
|
18
|
+
refreshProjectsCache(agent, cacheKey);
|
|
19
|
+
res.json(stale);
|
|
20
|
+
return;
|
|
32
21
|
}
|
|
22
|
+
const data = fetchProjectsData(agent);
|
|
23
|
+
cache.set(cacheKey, data);
|
|
24
|
+
res.json(data);
|
|
33
25
|
}
|
|
34
26
|
catch (error) {
|
|
35
27
|
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
@@ -40,3 +32,20 @@ export async function getProjects(req, res) {
|
|
|
40
32
|
});
|
|
41
33
|
}
|
|
42
34
|
}
|
|
35
|
+
function fetchProjectsData(agent) {
|
|
36
|
+
if (agent === 'codex') {
|
|
37
|
+
return getCodexProjectsResponse();
|
|
38
|
+
}
|
|
39
|
+
else if (agent === 'openclaw') {
|
|
40
|
+
return validateProjects(getOpenClawProjectsResponse());
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
// Claude Code: parse JSONL directly (fast, no CLI)
|
|
44
|
+
return validateProjects(getClaudeProjectsResponse());
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
function refreshProjectsCache(agent, cacheKey) {
|
|
48
|
+
Promise.resolve()
|
|
49
|
+
.then(() => { const data = fetchProjectsData(agent); cache.set(cacheKey, data); })
|
|
50
|
+
.catch(err => console.error('Background refresh failed (projects):', err));
|
|
51
|
+
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { type Request, type Response } from 'express';
|
|
2
|
-
export declare function getSession(
|
|
2
|
+
export declare function getSession(req: Request, res: Response): Promise<void>;
|
|
@@ -1,24 +1,41 @@
|
|
|
1
|
-
import { runCcusage } from '../ccusage.js';
|
|
2
1
|
import { cache } from '../cache.js';
|
|
3
2
|
import { validateDaily } from '../../shared/schemas.js';
|
|
4
|
-
|
|
3
|
+
import { getDailyResponse as getClaudeDailyResponse } from '../claudeJsonlParser.js';
|
|
4
|
+
import { getDailyResponse as getCodexDailyResponse } from '../codexParser.js';
|
|
5
|
+
import { getDailyResponse as getOpenClawDailyResponse } from '../openclawParser.js';
|
|
6
|
+
export async function getSession(req, res) {
|
|
7
|
+
const agent = req.query.agent || 'claude';
|
|
8
|
+
const cacheKey = `session:${agent}`;
|
|
5
9
|
try {
|
|
6
|
-
const cached = cache.get(
|
|
10
|
+
const cached = cache.get(cacheKey);
|
|
7
11
|
if (cached) {
|
|
8
12
|
res.json(cached);
|
|
9
13
|
return;
|
|
10
14
|
}
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
15
|
+
const stale = cache.getStale(cacheKey);
|
|
16
|
+
if (stale) {
|
|
17
|
+
res.json(stale);
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
// Session data uses same daily aggregation
|
|
21
|
+
let data;
|
|
22
|
+
if (agent === 'codex') {
|
|
23
|
+
data = validateDaily(getCodexDailyResponse());
|
|
24
|
+
}
|
|
25
|
+
else if (agent === 'openclaw') {
|
|
26
|
+
data = validateDaily(getOpenClawDailyResponse());
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
data = validateDaily(getClaudeDailyResponse());
|
|
30
|
+
}
|
|
31
|
+
cache.set(cacheKey, data);
|
|
32
|
+
res.json(data);
|
|
16
33
|
}
|
|
17
34
|
catch (error) {
|
|
18
35
|
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
19
36
|
console.error('Error fetching session data:', error);
|
|
20
37
|
res.status(502).json({
|
|
21
|
-
error: 'Failed to fetch session data
|
|
38
|
+
error: 'Failed to fetch session data',
|
|
22
39
|
hint: message,
|
|
23
40
|
});
|
|
24
41
|
}
|
package/dist/shared/schemas.d.ts
CHANGED
|
@@ -7,19 +7,19 @@ export declare const ModelBreakdownSchema: z.ZodObject<{
|
|
|
7
7
|
cacheReadTokens: z.ZodDefault<z.ZodNumber>;
|
|
8
8
|
cost: z.ZodDefault<z.ZodNumber>;
|
|
9
9
|
}, "strip", z.ZodTypeAny, {
|
|
10
|
+
cost: number;
|
|
10
11
|
modelName: string;
|
|
11
12
|
inputTokens: number;
|
|
12
13
|
outputTokens: number;
|
|
13
14
|
cacheCreationTokens: number;
|
|
14
15
|
cacheReadTokens: number;
|
|
15
|
-
cost: number;
|
|
16
16
|
}, {
|
|
17
17
|
modelName: string;
|
|
18
|
+
cost?: number | undefined;
|
|
18
19
|
inputTokens?: number | undefined;
|
|
19
20
|
outputTokens?: number | undefined;
|
|
20
21
|
cacheCreationTokens?: number | undefined;
|
|
21
22
|
cacheReadTokens?: number | undefined;
|
|
22
|
-
cost?: number | undefined;
|
|
23
23
|
}>;
|
|
24
24
|
export declare const DailyEntrySchema: z.ZodObject<{
|
|
25
25
|
date: z.ZodString;
|
|
@@ -38,19 +38,19 @@ export declare const DailyEntrySchema: z.ZodObject<{
|
|
|
38
38
|
cacheReadTokens: z.ZodDefault<z.ZodNumber>;
|
|
39
39
|
cost: z.ZodDefault<z.ZodNumber>;
|
|
40
40
|
}, "strip", z.ZodTypeAny, {
|
|
41
|
+
cost: number;
|
|
41
42
|
modelName: string;
|
|
42
43
|
inputTokens: number;
|
|
43
44
|
outputTokens: number;
|
|
44
45
|
cacheCreationTokens: number;
|
|
45
46
|
cacheReadTokens: number;
|
|
46
|
-
cost: number;
|
|
47
47
|
}, {
|
|
48
48
|
modelName: string;
|
|
49
|
+
cost?: number | undefined;
|
|
49
50
|
inputTokens?: number | undefined;
|
|
50
51
|
outputTokens?: number | undefined;
|
|
51
52
|
cacheCreationTokens?: number | undefined;
|
|
52
53
|
cacheReadTokens?: number | undefined;
|
|
53
|
-
cost?: number | undefined;
|
|
54
54
|
}>, "many">>;
|
|
55
55
|
}, "strip", z.ZodTypeAny, {
|
|
56
56
|
date: string;
|
|
@@ -62,12 +62,12 @@ export declare const DailyEntrySchema: z.ZodObject<{
|
|
|
62
62
|
totalCost: number;
|
|
63
63
|
modelsUsed: string[];
|
|
64
64
|
modelBreakdowns: {
|
|
65
|
+
cost: number;
|
|
65
66
|
modelName: string;
|
|
66
67
|
inputTokens: number;
|
|
67
68
|
outputTokens: number;
|
|
68
69
|
cacheCreationTokens: number;
|
|
69
70
|
cacheReadTokens: number;
|
|
70
|
-
cost: number;
|
|
71
71
|
}[];
|
|
72
72
|
}, {
|
|
73
73
|
date: string;
|
|
@@ -80,11 +80,11 @@ export declare const DailyEntrySchema: z.ZodObject<{
|
|
|
80
80
|
modelsUsed?: string[] | undefined;
|
|
81
81
|
modelBreakdowns?: {
|
|
82
82
|
modelName: string;
|
|
83
|
+
cost?: number | undefined;
|
|
83
84
|
inputTokens?: number | undefined;
|
|
84
85
|
outputTokens?: number | undefined;
|
|
85
86
|
cacheCreationTokens?: number | undefined;
|
|
86
87
|
cacheReadTokens?: number | undefined;
|
|
87
|
-
cost?: number | undefined;
|
|
88
88
|
}[] | undefined;
|
|
89
89
|
}>;
|
|
90
90
|
export declare const TotalsSchema: z.ZodObject<{
|
|
@@ -127,19 +127,19 @@ export declare const DailyResponseSchema: z.ZodObject<{
|
|
|
127
127
|
cacheReadTokens: z.ZodDefault<z.ZodNumber>;
|
|
128
128
|
cost: z.ZodDefault<z.ZodNumber>;
|
|
129
129
|
}, "strip", z.ZodTypeAny, {
|
|
130
|
+
cost: number;
|
|
130
131
|
modelName: string;
|
|
131
132
|
inputTokens: number;
|
|
132
133
|
outputTokens: number;
|
|
133
134
|
cacheCreationTokens: number;
|
|
134
135
|
cacheReadTokens: number;
|
|
135
|
-
cost: number;
|
|
136
136
|
}, {
|
|
137
137
|
modelName: string;
|
|
138
|
+
cost?: number | undefined;
|
|
138
139
|
inputTokens?: number | undefined;
|
|
139
140
|
outputTokens?: number | undefined;
|
|
140
141
|
cacheCreationTokens?: number | undefined;
|
|
141
142
|
cacheReadTokens?: number | undefined;
|
|
142
|
-
cost?: number | undefined;
|
|
143
143
|
}>, "many">>;
|
|
144
144
|
}, "strip", z.ZodTypeAny, {
|
|
145
145
|
date: string;
|
|
@@ -151,12 +151,12 @@ export declare const DailyResponseSchema: z.ZodObject<{
|
|
|
151
151
|
totalCost: number;
|
|
152
152
|
modelsUsed: string[];
|
|
153
153
|
modelBreakdowns: {
|
|
154
|
+
cost: number;
|
|
154
155
|
modelName: string;
|
|
155
156
|
inputTokens: number;
|
|
156
157
|
outputTokens: number;
|
|
157
158
|
cacheCreationTokens: number;
|
|
158
159
|
cacheReadTokens: number;
|
|
159
|
-
cost: number;
|
|
160
160
|
}[];
|
|
161
161
|
}, {
|
|
162
162
|
date: string;
|
|
@@ -169,11 +169,11 @@ export declare const DailyResponseSchema: z.ZodObject<{
|
|
|
169
169
|
modelsUsed?: string[] | undefined;
|
|
170
170
|
modelBreakdowns?: {
|
|
171
171
|
modelName: string;
|
|
172
|
+
cost?: number | undefined;
|
|
172
173
|
inputTokens?: number | undefined;
|
|
173
174
|
outputTokens?: number | undefined;
|
|
174
175
|
cacheCreationTokens?: number | undefined;
|
|
175
176
|
cacheReadTokens?: number | undefined;
|
|
176
|
-
cost?: number | undefined;
|
|
177
177
|
}[] | undefined;
|
|
178
178
|
}>, "many">>;
|
|
179
179
|
totals: z.ZodObject<{
|
|
@@ -209,12 +209,12 @@ export declare const DailyResponseSchema: z.ZodObject<{
|
|
|
209
209
|
totalCost: number;
|
|
210
210
|
modelsUsed: string[];
|
|
211
211
|
modelBreakdowns: {
|
|
212
|
+
cost: number;
|
|
212
213
|
modelName: string;
|
|
213
214
|
inputTokens: number;
|
|
214
215
|
outputTokens: number;
|
|
215
216
|
cacheCreationTokens: number;
|
|
216
217
|
cacheReadTokens: number;
|
|
217
|
-
cost: number;
|
|
218
218
|
}[];
|
|
219
219
|
}[];
|
|
220
220
|
totals: {
|
|
@@ -245,11 +245,11 @@ export declare const DailyResponseSchema: z.ZodObject<{
|
|
|
245
245
|
modelsUsed?: string[] | undefined;
|
|
246
246
|
modelBreakdowns?: {
|
|
247
247
|
modelName: string;
|
|
248
|
+
cost?: number | undefined;
|
|
248
249
|
inputTokens?: number | undefined;
|
|
249
250
|
outputTokens?: number | undefined;
|
|
250
251
|
cacheCreationTokens?: number | undefined;
|
|
251
252
|
cacheReadTokens?: number | undefined;
|
|
252
|
-
cost?: number | undefined;
|
|
253
253
|
}[] | undefined;
|
|
254
254
|
}[] | undefined;
|
|
255
255
|
}>;
|
|
@@ -272,19 +272,19 @@ export declare const ProjectEntrySchema: z.ZodObject<{
|
|
|
272
272
|
cacheReadTokens: z.ZodDefault<z.ZodNumber>;
|
|
273
273
|
cost: z.ZodDefault<z.ZodNumber>;
|
|
274
274
|
}, "strip", z.ZodTypeAny, {
|
|
275
|
+
cost: number;
|
|
275
276
|
modelName: string;
|
|
276
277
|
inputTokens: number;
|
|
277
278
|
outputTokens: number;
|
|
278
279
|
cacheCreationTokens: number;
|
|
279
280
|
cacheReadTokens: number;
|
|
280
|
-
cost: number;
|
|
281
281
|
}, {
|
|
282
282
|
modelName: string;
|
|
283
|
+
cost?: number | undefined;
|
|
283
284
|
inputTokens?: number | undefined;
|
|
284
285
|
outputTokens?: number | undefined;
|
|
285
286
|
cacheCreationTokens?: number | undefined;
|
|
286
287
|
cacheReadTokens?: number | undefined;
|
|
287
|
-
cost?: number | undefined;
|
|
288
288
|
}>, "many">>;
|
|
289
289
|
}, "strip", z.ZodTypeAny, {
|
|
290
290
|
date: string;
|
|
@@ -296,12 +296,12 @@ export declare const ProjectEntrySchema: z.ZodObject<{
|
|
|
296
296
|
totalCost: number;
|
|
297
297
|
modelsUsed: string[];
|
|
298
298
|
modelBreakdowns: {
|
|
299
|
+
cost: number;
|
|
299
300
|
modelName: string;
|
|
300
301
|
inputTokens: number;
|
|
301
302
|
outputTokens: number;
|
|
302
303
|
cacheCreationTokens: number;
|
|
303
304
|
cacheReadTokens: number;
|
|
304
|
-
cost: number;
|
|
305
305
|
}[];
|
|
306
306
|
}, {
|
|
307
307
|
date: string;
|
|
@@ -314,11 +314,11 @@ export declare const ProjectEntrySchema: z.ZodObject<{
|
|
|
314
314
|
modelsUsed?: string[] | undefined;
|
|
315
315
|
modelBreakdowns?: {
|
|
316
316
|
modelName: string;
|
|
317
|
+
cost?: number | undefined;
|
|
317
318
|
inputTokens?: number | undefined;
|
|
318
319
|
outputTokens?: number | undefined;
|
|
319
320
|
cacheCreationTokens?: number | undefined;
|
|
320
321
|
cacheReadTokens?: number | undefined;
|
|
321
|
-
cost?: number | undefined;
|
|
322
322
|
}[] | undefined;
|
|
323
323
|
}>, "many">>;
|
|
324
324
|
}, "strip", z.ZodTypeAny, {
|
|
@@ -333,12 +333,12 @@ export declare const ProjectEntrySchema: z.ZodObject<{
|
|
|
333
333
|
totalCost: number;
|
|
334
334
|
modelsUsed: string[];
|
|
335
335
|
modelBreakdowns: {
|
|
336
|
+
cost: number;
|
|
336
337
|
modelName: string;
|
|
337
338
|
inputTokens: number;
|
|
338
339
|
outputTokens: number;
|
|
339
340
|
cacheCreationTokens: number;
|
|
340
341
|
cacheReadTokens: number;
|
|
341
|
-
cost: number;
|
|
342
342
|
}[];
|
|
343
343
|
}[];
|
|
344
344
|
}, {
|
|
@@ -354,11 +354,11 @@ export declare const ProjectEntrySchema: z.ZodObject<{
|
|
|
354
354
|
modelsUsed?: string[] | undefined;
|
|
355
355
|
modelBreakdowns?: {
|
|
356
356
|
modelName: string;
|
|
357
|
+
cost?: number | undefined;
|
|
357
358
|
inputTokens?: number | undefined;
|
|
358
359
|
outputTokens?: number | undefined;
|
|
359
360
|
cacheCreationTokens?: number | undefined;
|
|
360
361
|
cacheReadTokens?: number | undefined;
|
|
361
|
-
cost?: number | undefined;
|
|
362
362
|
}[] | undefined;
|
|
363
363
|
}[] | undefined;
|
|
364
364
|
}>;
|
|
@@ -380,19 +380,19 @@ export declare const ProjectsResponseSchema: z.ZodObject<{
|
|
|
380
380
|
cacheReadTokens: z.ZodDefault<z.ZodNumber>;
|
|
381
381
|
cost: z.ZodDefault<z.ZodNumber>;
|
|
382
382
|
}, "strip", z.ZodTypeAny, {
|
|
383
|
+
cost: number;
|
|
383
384
|
modelName: string;
|
|
384
385
|
inputTokens: number;
|
|
385
386
|
outputTokens: number;
|
|
386
387
|
cacheCreationTokens: number;
|
|
387
388
|
cacheReadTokens: number;
|
|
388
|
-
cost: number;
|
|
389
389
|
}, {
|
|
390
390
|
modelName: string;
|
|
391
|
+
cost?: number | undefined;
|
|
391
392
|
inputTokens?: number | undefined;
|
|
392
393
|
outputTokens?: number | undefined;
|
|
393
394
|
cacheCreationTokens?: number | undefined;
|
|
394
395
|
cacheReadTokens?: number | undefined;
|
|
395
|
-
cost?: number | undefined;
|
|
396
396
|
}>, "many">>;
|
|
397
397
|
}, "strip", z.ZodTypeAny, {
|
|
398
398
|
date: string;
|
|
@@ -404,12 +404,12 @@ export declare const ProjectsResponseSchema: z.ZodObject<{
|
|
|
404
404
|
totalCost: number;
|
|
405
405
|
modelsUsed: string[];
|
|
406
406
|
modelBreakdowns: {
|
|
407
|
+
cost: number;
|
|
407
408
|
modelName: string;
|
|
408
409
|
inputTokens: number;
|
|
409
410
|
outputTokens: number;
|
|
410
411
|
cacheCreationTokens: number;
|
|
411
412
|
cacheReadTokens: number;
|
|
412
|
-
cost: number;
|
|
413
413
|
}[];
|
|
414
414
|
}, {
|
|
415
415
|
date: string;
|
|
@@ -422,11 +422,11 @@ export declare const ProjectsResponseSchema: z.ZodObject<{
|
|
|
422
422
|
modelsUsed?: string[] | undefined;
|
|
423
423
|
modelBreakdowns?: {
|
|
424
424
|
modelName: string;
|
|
425
|
+
cost?: number | undefined;
|
|
425
426
|
inputTokens?: number | undefined;
|
|
426
427
|
outputTokens?: number | undefined;
|
|
427
428
|
cacheCreationTokens?: number | undefined;
|
|
428
429
|
cacheReadTokens?: number | undefined;
|
|
429
|
-
cost?: number | undefined;
|
|
430
430
|
}[] | undefined;
|
|
431
431
|
}>, "many">>>>;
|
|
432
432
|
}, "strip", z.ZodTypeAny, {
|
|
@@ -440,12 +440,12 @@ export declare const ProjectsResponseSchema: z.ZodObject<{
|
|
|
440
440
|
totalCost: number;
|
|
441
441
|
modelsUsed: string[];
|
|
442
442
|
modelBreakdowns: {
|
|
443
|
+
cost: number;
|
|
443
444
|
modelName: string;
|
|
444
445
|
inputTokens: number;
|
|
445
446
|
outputTokens: number;
|
|
446
447
|
cacheCreationTokens: number;
|
|
447
448
|
cacheReadTokens: number;
|
|
448
|
-
cost: number;
|
|
449
449
|
}[];
|
|
450
450
|
}[]>;
|
|
451
451
|
}, {
|
|
@@ -460,11 +460,11 @@ export declare const ProjectsResponseSchema: z.ZodObject<{
|
|
|
460
460
|
modelsUsed?: string[] | undefined;
|
|
461
461
|
modelBreakdowns?: {
|
|
462
462
|
modelName: string;
|
|
463
|
+
cost?: number | undefined;
|
|
463
464
|
inputTokens?: number | undefined;
|
|
464
465
|
outputTokens?: number | undefined;
|
|
465
466
|
cacheCreationTokens?: number | undefined;
|
|
466
467
|
cacheReadTokens?: number | undefined;
|
|
467
|
-
cost?: number | undefined;
|
|
468
468
|
}[] | undefined;
|
|
469
469
|
}[] | undefined> | undefined;
|
|
470
470
|
}>;
|
|
@@ -479,12 +479,12 @@ export declare function validateDaily(data: unknown): {
|
|
|
479
479
|
totalCost: number;
|
|
480
480
|
modelsUsed: string[];
|
|
481
481
|
modelBreakdowns: {
|
|
482
|
+
cost: number;
|
|
482
483
|
modelName: string;
|
|
483
484
|
inputTokens: number;
|
|
484
485
|
outputTokens: number;
|
|
485
486
|
cacheCreationTokens: number;
|
|
486
487
|
cacheReadTokens: number;
|
|
487
|
-
cost: number;
|
|
488
488
|
}[];
|
|
489
489
|
}[];
|
|
490
490
|
totals: {
|
|
@@ -507,12 +507,12 @@ export declare function validateProjects(data: unknown): {
|
|
|
507
507
|
totalCost: number;
|
|
508
508
|
modelsUsed: string[];
|
|
509
509
|
modelBreakdowns: {
|
|
510
|
+
cost: number;
|
|
510
511
|
modelName: string;
|
|
511
512
|
inputTokens: number;
|
|
512
513
|
outputTokens: number;
|
|
513
514
|
cacheCreationTokens: number;
|
|
514
515
|
cacheReadTokens: number;
|
|
515
|
-
cost: number;
|
|
516
516
|
}[];
|
|
517
517
|
}[]>;
|
|
518
518
|
};
|
|
@@ -545,9 +545,9 @@ export declare const BlocksResponseSchema: z.ZodObject<{
|
|
|
545
545
|
costUSD: z.ZodDefault<z.ZodNumber>;
|
|
546
546
|
models: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
547
547
|
}, "strip", z.ZodTypeAny, {
|
|
548
|
+
models: string[];
|
|
548
549
|
entries: number;
|
|
549
550
|
id: string;
|
|
550
|
-
models: string[];
|
|
551
551
|
totalTokens: number;
|
|
552
552
|
startTime: string;
|
|
553
553
|
endTime: string;
|
|
@@ -565,8 +565,8 @@ export declare const BlocksResponseSchema: z.ZodObject<{
|
|
|
565
565
|
id: string;
|
|
566
566
|
startTime: string;
|
|
567
567
|
endTime: string;
|
|
568
|
-
entries?: number | undefined;
|
|
569
568
|
models?: string[] | undefined;
|
|
569
|
+
entries?: number | undefined;
|
|
570
570
|
totalTokens?: number | undefined;
|
|
571
571
|
actualEndTime?: string | null | undefined;
|
|
572
572
|
isActive?: boolean | undefined;
|
|
@@ -581,9 +581,9 @@ export declare const BlocksResponseSchema: z.ZodObject<{
|
|
|
581
581
|
}>, "many">>;
|
|
582
582
|
}, "strip", z.ZodTypeAny, {
|
|
583
583
|
blocks: {
|
|
584
|
+
models: string[];
|
|
584
585
|
entries: number;
|
|
585
586
|
id: string;
|
|
586
|
-
models: string[];
|
|
587
587
|
totalTokens: number;
|
|
588
588
|
startTime: string;
|
|
589
589
|
endTime: string;
|
|
@@ -603,8 +603,8 @@ export declare const BlocksResponseSchema: z.ZodObject<{
|
|
|
603
603
|
id: string;
|
|
604
604
|
startTime: string;
|
|
605
605
|
endTime: string;
|
|
606
|
-
entries?: number | undefined;
|
|
607
606
|
models?: string[] | undefined;
|
|
607
|
+
entries?: number | undefined;
|
|
608
608
|
totalTokens?: number | undefined;
|
|
609
609
|
actualEndTime?: string | null | undefined;
|
|
610
610
|
isActive?: boolean | undefined;
|
|
@@ -620,9 +620,9 @@ export declare const BlocksResponseSchema: z.ZodObject<{
|
|
|
620
620
|
}>;
|
|
621
621
|
export declare function validateBlocks(data: unknown): {
|
|
622
622
|
blocks: {
|
|
623
|
+
models: string[];
|
|
623
624
|
entries: number;
|
|
624
625
|
id: string;
|
|
625
|
-
models: string[];
|
|
626
626
|
totalTokens: number;
|
|
627
627
|
startTime: string;
|
|
628
628
|
endTime: string;
|
|
@@ -638,3 +638,25 @@ export declare function validateBlocks(data: unknown): {
|
|
|
638
638
|
costUSD: number;
|
|
639
639
|
}[];
|
|
640
640
|
};
|
|
641
|
+
export declare function validateAnalytics(data: unknown): {
|
|
642
|
+
codeChangeTrend: {
|
|
643
|
+
date: string;
|
|
644
|
+
linesAdded: number;
|
|
645
|
+
linesDeleted: number;
|
|
646
|
+
netChange: number;
|
|
647
|
+
filesModified: number;
|
|
648
|
+
}[];
|
|
649
|
+
toolUsageDistribution: {
|
|
650
|
+
name: string;
|
|
651
|
+
count: number;
|
|
652
|
+
}[];
|
|
653
|
+
productivityKPIs: {
|
|
654
|
+
avgLinesPerEdit: number;
|
|
655
|
+
filesModifiedPerDay: number;
|
|
656
|
+
addDeleteRatio: number;
|
|
657
|
+
totalEdits: number;
|
|
658
|
+
totalFilesModified: number;
|
|
659
|
+
activeDaysWithEdits: number;
|
|
660
|
+
};
|
|
661
|
+
toolCallTrend: Record<string, string | number>[];
|
|
662
|
+
};
|
package/dist/shared/schemas.js
CHANGED
|
@@ -67,3 +67,32 @@ export const BlocksResponseSchema = z.object({
|
|
|
67
67
|
export function validateBlocks(data) {
|
|
68
68
|
return BlocksResponseSchema.parse(data);
|
|
69
69
|
}
|
|
70
|
+
// --- Analytics schemas ---
|
|
71
|
+
const DailyCodeChangeSchema = z.object({
|
|
72
|
+
date: z.string(),
|
|
73
|
+
linesAdded: z.number().default(0),
|
|
74
|
+
linesDeleted: z.number().default(0),
|
|
75
|
+
netChange: z.number().default(0),
|
|
76
|
+
filesModified: z.number().default(0),
|
|
77
|
+
});
|
|
78
|
+
const ToolUsageEntrySchema = z.object({
|
|
79
|
+
name: z.string(),
|
|
80
|
+
count: z.number().default(0),
|
|
81
|
+
});
|
|
82
|
+
const ProductivityKPIsSchema = z.object({
|
|
83
|
+
avgLinesPerEdit: z.number().default(0),
|
|
84
|
+
filesModifiedPerDay: z.number().default(0),
|
|
85
|
+
addDeleteRatio: z.number().default(0),
|
|
86
|
+
totalEdits: z.number().default(0),
|
|
87
|
+
totalFilesModified: z.number().default(0),
|
|
88
|
+
activeDaysWithEdits: z.number().default(0),
|
|
89
|
+
});
|
|
90
|
+
const AnalyticsResponseSchema = z.object({
|
|
91
|
+
codeChangeTrend: z.array(DailyCodeChangeSchema).default([]),
|
|
92
|
+
toolUsageDistribution: z.array(ToolUsageEntrySchema).default([]),
|
|
93
|
+
productivityKPIs: ProductivityKPIsSchema,
|
|
94
|
+
toolCallTrend: z.array(z.record(z.union([z.string(), z.number()]))).default([]),
|
|
95
|
+
});
|
|
96
|
+
export function validateAnalytics(data) {
|
|
97
|
+
return AnalyticsResponseSchema.parse(data);
|
|
98
|
+
}
|
package/dist/shared/types.d.ts
CHANGED
|
@@ -63,3 +63,32 @@ export interface BlocksResponse {
|
|
|
63
63
|
}
|
|
64
64
|
export type MetricMode = 'tokens' | 'usd';
|
|
65
65
|
export type GranularityMode = 'day' | 'hour';
|
|
66
|
+
export interface ToolUsageEntry {
|
|
67
|
+
name: string;
|
|
68
|
+
count: number;
|
|
69
|
+
}
|
|
70
|
+
export interface DailyCodeChange {
|
|
71
|
+
date: string;
|
|
72
|
+
linesAdded: number;
|
|
73
|
+
linesDeleted: number;
|
|
74
|
+
netChange: number;
|
|
75
|
+
filesModified: number;
|
|
76
|
+
}
|
|
77
|
+
export interface DailyToolCall {
|
|
78
|
+
date: string;
|
|
79
|
+
[toolName: string]: string | number;
|
|
80
|
+
}
|
|
81
|
+
export interface ProductivityKPIs {
|
|
82
|
+
avgLinesPerEdit: number;
|
|
83
|
+
filesModifiedPerDay: number;
|
|
84
|
+
addDeleteRatio: number;
|
|
85
|
+
totalEdits: number;
|
|
86
|
+
totalFilesModified: number;
|
|
87
|
+
activeDaysWithEdits: number;
|
|
88
|
+
}
|
|
89
|
+
export interface AnalyticsResponse {
|
|
90
|
+
codeChangeTrend: DailyCodeChange[];
|
|
91
|
+
toolUsageDistribution: ToolUsageEntry[];
|
|
92
|
+
productivityKPIs: ProductivityKPIs;
|
|
93
|
+
toolCallTrend: DailyToolCall[];
|
|
94
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zhangferry-dev/tokendash",
|
|
3
|
-
"version": "1.1
|
|
3
|
+
"version": "1.2.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Token Usage Analytics Dashboard",
|
|
6
6
|
"publishConfig": {
|
|
@@ -22,6 +22,9 @@
|
|
|
22
22
|
"build": "vite build && tsc -p tsconfig.json",
|
|
23
23
|
"start": "node dist/server/index.js",
|
|
24
24
|
"typecheck": "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.frontend.json --noEmit",
|
|
25
|
+
"test": "vitest run",
|
|
26
|
+
"test:watch": "vitest",
|
|
27
|
+
"test:e2e": "playwright test",
|
|
25
28
|
"prepack": "npm run build"
|
|
26
29
|
},
|
|
27
30
|
"dependencies": {
|
|
@@ -33,6 +36,7 @@
|
|
|
33
36
|
"zod": "^3.24.3"
|
|
34
37
|
},
|
|
35
38
|
"devDependencies": {
|
|
39
|
+
"@playwright/test": "^1.59.1",
|
|
36
40
|
"@types/express": "^5.0.2",
|
|
37
41
|
"@types/node": "^22.15.2",
|
|
38
42
|
"@types/react": "^19.1.2",
|
|
@@ -41,6 +45,7 @@
|
|
|
41
45
|
"concurrently": "^9.1.2",
|
|
42
46
|
"tsx": "^4.19.3",
|
|
43
47
|
"typescript": "^5.8.3",
|
|
44
|
-
"vite": "^6.3.3"
|
|
48
|
+
"vite": "^6.3.3",
|
|
49
|
+
"vitest": "^4.1.4"
|
|
45
50
|
}
|
|
46
|
-
}
|
|
51
|
+
}
|