@zhangferry-dev/tokendash 1.5.0 → 1.6.0
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/dist/client/assets/{index-BPWY9q0y.js → index-CY4G_b0x.js} +47 -47
- package/dist/client/assets/index-_yA9tOzZ.css +1 -0
- package/dist/client/index.html +2 -2
- package/dist/client/popover.html +822 -396
- package/dist/electron-server.cjs +91 -51
- package/dist/electron-server.cjs.map +2 -2
- package/dist/server/claudeBlocksParser.js +2 -2
- package/dist/server/claudeJsonlParser.d.ts +1 -1
- package/dist/server/claudeJsonlParser.js +22 -19
- package/dist/server/codexParser.js +72 -32
- package/electron/main.cjs +35 -50
- package/electron/preload.cjs +11 -0
- package/electron/updateService.cjs +148 -0
- package/package.json +1 -1
- package/dist/client/assets/index-iYDpTV63.css +0 -1
package/dist/electron-server.cjs
CHANGED
|
@@ -255,20 +255,24 @@ var TokenUsageSchema = import_zod2.z.object({
|
|
|
255
255
|
}).default({ input_tokens: 0, cached_input_tokens: 0, output_tokens: 0, reasoning_output_tokens: 0, total_tokens: 0 });
|
|
256
256
|
var TokenCountInfoSchema = import_zod2.z.object({
|
|
257
257
|
total_token_usage: TokenUsageSchema,
|
|
258
|
-
last_token_usage: TokenUsageSchema
|
|
258
|
+
last_token_usage: TokenUsageSchema.optional()
|
|
259
259
|
}).nullable().default(null);
|
|
260
260
|
var TokenCountPayloadSchema = import_zod2.z.object({
|
|
261
261
|
type: import_zod2.z.literal("token_count"),
|
|
262
262
|
info: TokenCountInfoSchema
|
|
263
263
|
});
|
|
264
|
-
function
|
|
265
|
-
return
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
264
|
+
function subtractTokenUsage(current, previous) {
|
|
265
|
+
return {
|
|
266
|
+
timestamp: "",
|
|
267
|
+
inputTokens: Math.max(0, current.input_tokens - (previous?.input_tokens ?? 0)),
|
|
268
|
+
cachedInputTokens: Math.max(0, current.cached_input_tokens - (previous?.cached_input_tokens ?? 0)),
|
|
269
|
+
outputTokens: Math.max(0, current.output_tokens - (previous?.output_tokens ?? 0)),
|
|
270
|
+
reasoningOutputTokens: Math.max(0, current.reasoning_output_tokens - (previous?.reasoning_output_tokens ?? 0)),
|
|
271
|
+
totalTokens: Math.max(0, current.total_tokens - (previous?.total_tokens ?? 0))
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
function displayInputTokens(inputTokens, cachedInputTokens) {
|
|
275
|
+
return Math.max(0, inputTokens - cachedInputTokens);
|
|
272
276
|
}
|
|
273
277
|
function getSessionsDir() {
|
|
274
278
|
return (0, import_node_path2.join)((0, import_node_os2.homedir)(), ".codex", "sessions");
|
|
@@ -314,7 +318,9 @@ function parseCodexSession(filepath) {
|
|
|
314
318
|
let model = "";
|
|
315
319
|
let createdAt = "";
|
|
316
320
|
const tokenEvents = [];
|
|
321
|
+
let previousTotalUsage = null;
|
|
317
322
|
const seenTotalUsageSnapshots = /* @__PURE__ */ new Set();
|
|
323
|
+
const seenUsageEvents = /* @__PURE__ */ new Set();
|
|
318
324
|
for (const line of lines) {
|
|
319
325
|
const trimmed = line.trim();
|
|
320
326
|
if (!trimmed) continue;
|
|
@@ -348,18 +354,40 @@ function parseCodexSession(filepath) {
|
|
|
348
354
|
}
|
|
349
355
|
const info = parseResult.data.info;
|
|
350
356
|
if (!info) continue;
|
|
351
|
-
const totalUsageKey =
|
|
357
|
+
const totalUsageKey = [
|
|
358
|
+
info.total_token_usage.input_tokens,
|
|
359
|
+
info.total_token_usage.cached_input_tokens,
|
|
360
|
+
info.total_token_usage.output_tokens,
|
|
361
|
+
info.total_token_usage.reasoning_output_tokens,
|
|
362
|
+
info.total_token_usage.total_tokens
|
|
363
|
+
].join(":");
|
|
352
364
|
if (seenTotalUsageSnapshots.has(totalUsageKey)) continue;
|
|
353
365
|
seenTotalUsageSnapshots.add(totalUsageKey);
|
|
354
|
-
const last = info.last_token_usage;
|
|
355
|
-
|
|
366
|
+
const last = info.last_token_usage ?? info.total_token_usage;
|
|
367
|
+
const rawEvent = info.last_token_usage ? subtractTokenUsage(last, null) : subtractTokenUsage(last, previousTotalUsage);
|
|
368
|
+
previousTotalUsage = info.total_token_usage;
|
|
369
|
+
if (rawEvent.inputTokens === 0 && rawEvent.cachedInputTokens === 0 && rawEvent.outputTokens === 0 && rawEvent.reasoningOutputTokens === 0) {
|
|
370
|
+
continue;
|
|
371
|
+
}
|
|
372
|
+
const event = {
|
|
373
|
+
...rawEvent,
|
|
356
374
|
timestamp,
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
375
|
+
cachedInputTokens: Math.min(rawEvent.cachedInputTokens, rawEvent.inputTokens)
|
|
376
|
+
};
|
|
377
|
+
const eventKey = [
|
|
378
|
+
timestamp,
|
|
379
|
+
model,
|
|
380
|
+
event.inputTokens,
|
|
381
|
+
event.cachedInputTokens,
|
|
382
|
+
event.outputTokens,
|
|
383
|
+
event.reasoningOutputTokens,
|
|
384
|
+
event.totalTokens
|
|
385
|
+
].join(":");
|
|
386
|
+
if (seenUsageEvents.has(eventKey)) {
|
|
387
|
+
continue;
|
|
388
|
+
}
|
|
389
|
+
seenUsageEvents.add(eventKey);
|
|
390
|
+
tokenEvents.push(event);
|
|
363
391
|
}
|
|
364
392
|
}
|
|
365
393
|
}
|
|
@@ -409,6 +437,12 @@ function addAcc(a, ev) {
|
|
|
409
437
|
a.reasoningOutputTokens += ev.reasoningOutputTokens;
|
|
410
438
|
a.totalTokens += ev.totalTokens;
|
|
411
439
|
}
|
|
440
|
+
function displayAcc(acc) {
|
|
441
|
+
return {
|
|
442
|
+
...acc,
|
|
443
|
+
inputTokens: displayInputTokens(acc.inputTokens, acc.cachedInputTokens)
|
|
444
|
+
};
|
|
445
|
+
}
|
|
412
446
|
function mergeAcc(a, b) {
|
|
413
447
|
a.inputTokens += b.inputTokens;
|
|
414
448
|
a.cachedInputTokens += b.cachedInputTokens;
|
|
@@ -423,30 +457,34 @@ function addAccToBucket(bucket, ev, model) {
|
|
|
423
457
|
addAcc(bucket.models.get(model), ev);
|
|
424
458
|
}
|
|
425
459
|
function accToEntry(date, acc, modelAccs) {
|
|
460
|
+
const display = displayAcc(acc);
|
|
426
461
|
const modelNames = [...modelAccs.keys()];
|
|
427
462
|
const modelBreakdowns = buildModelBreakdowns(modelAccs);
|
|
428
463
|
const totalCost = modelBreakdowns.reduce((sum, model) => sum + model.cost, 0);
|
|
429
464
|
return {
|
|
430
465
|
date,
|
|
431
|
-
inputTokens:
|
|
432
|
-
outputTokens:
|
|
466
|
+
inputTokens: display.inputTokens,
|
|
467
|
+
outputTokens: display.outputTokens,
|
|
433
468
|
cacheCreationTokens: 0,
|
|
434
|
-
cacheReadTokens:
|
|
435
|
-
totalTokens:
|
|
469
|
+
cacheReadTokens: display.cachedInputTokens,
|
|
470
|
+
totalTokens: display.totalTokens,
|
|
436
471
|
totalCost,
|
|
437
472
|
modelsUsed: modelNames,
|
|
438
473
|
modelBreakdowns
|
|
439
474
|
};
|
|
440
475
|
}
|
|
441
476
|
function buildModelBreakdowns(modelAccs) {
|
|
442
|
-
return [...modelAccs.entries()].map(([modelName, acc]) =>
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
477
|
+
return [...modelAccs.entries()].map(([modelName, acc]) => {
|
|
478
|
+
const display = displayAcc(acc);
|
|
479
|
+
return {
|
|
480
|
+
modelName,
|
|
481
|
+
inputTokens: display.inputTokens,
|
|
482
|
+
outputTokens: display.outputTokens,
|
|
483
|
+
cacheCreationTokens: 0,
|
|
484
|
+
cacheReadTokens: display.cachedInputTokens,
|
|
485
|
+
cost: calculateCost(acc, /* @__PURE__ */ new Set([modelName]))
|
|
486
|
+
};
|
|
487
|
+
});
|
|
450
488
|
}
|
|
451
489
|
function groupSessions(sessions, options) {
|
|
452
490
|
const tz = options.timezone || "Asia/Shanghai";
|
|
@@ -501,7 +539,7 @@ function buildDailyResponse(sessions, options) {
|
|
|
501
539
|
return {
|
|
502
540
|
daily,
|
|
503
541
|
totals: {
|
|
504
|
-
inputTokens: totalsAcc.inputTokens,
|
|
542
|
+
inputTokens: displayInputTokens(totalsAcc.inputTokens, totalsAcc.cachedInputTokens),
|
|
505
543
|
outputTokens: totalsAcc.outputTokens,
|
|
506
544
|
cacheCreationTokens: 0,
|
|
507
545
|
cacheReadTokens: totalsAcc.cachedInputTokens,
|
|
@@ -552,7 +590,7 @@ function buildBlocksResponse(sessions, options) {
|
|
|
552
590
|
isGap: false,
|
|
553
591
|
entries: acc.totalTokens > 0 ? 1 : 0,
|
|
554
592
|
tokenCounts: {
|
|
555
|
-
inputTokens: acc.inputTokens,
|
|
593
|
+
inputTokens: displayInputTokens(acc.inputTokens, acc.cachedInputTokens),
|
|
556
594
|
outputTokens: acc.outputTokens,
|
|
557
595
|
cacheCreationInputTokens: 0,
|
|
558
596
|
cacheReadInputTokens: acc.cachedInputTokens
|
|
@@ -1165,18 +1203,18 @@ var import_node_path5 = require("node:path");
|
|
|
1165
1203
|
var import_node_os5 = require("node:os");
|
|
1166
1204
|
var MODEL_PRICING2 = {
|
|
1167
1205
|
// Claude 4.6
|
|
1168
|
-
"claude-opus-4-6": { inputPer1M: 15, cacheReadPer1M: 1.5, outputPer1M: 75 },
|
|
1169
|
-
"claude-sonnet-4-6": { inputPer1M: 3, cacheReadPer1M: 0.3, outputPer1M: 15 },
|
|
1206
|
+
"claude-opus-4-6": { inputPer1M: 15, cacheCreationPer1M: 18.75, cacheReadPer1M: 1.5, outputPer1M: 75 },
|
|
1207
|
+
"claude-sonnet-4-6": { inputPer1M: 3, cacheCreationPer1M: 3.75, cacheReadPer1M: 0.3, outputPer1M: 15 },
|
|
1170
1208
|
// Claude 4.5
|
|
1171
|
-
"claude-sonnet-4-5-20250514": { inputPer1M: 3, cacheReadPer1M: 0.3, outputPer1M: 15 },
|
|
1172
|
-
"claude-haiku-4-5-20251001": { inputPer1M: 0.8, cacheReadPer1M: 0.08, outputPer1M: 4 },
|
|
1209
|
+
"claude-sonnet-4-5-20250514": { inputPer1M: 3, cacheCreationPer1M: 3.75, cacheReadPer1M: 0.3, outputPer1M: 15 },
|
|
1210
|
+
"claude-haiku-4-5-20251001": { inputPer1M: 0.8, cacheCreationPer1M: 1, cacheReadPer1M: 0.08, outputPer1M: 4 },
|
|
1173
1211
|
// Older Claude models
|
|
1174
|
-
"claude-3-5-sonnet-20241022": { inputPer1M: 3, cacheReadPer1M: 0.3, outputPer1M: 15 },
|
|
1175
|
-
"claude-3-5-haiku-20241022": { inputPer1M: 0.8, cacheReadPer1M: 0.08, outputPer1M: 4 },
|
|
1176
|
-
"claude-3-opus-20240229": { inputPer1M: 15, cacheReadPer1M: 1.5, outputPer1M: 75 },
|
|
1177
|
-
"claude-3-haiku-20240307": { inputPer1M: 0.25, cacheReadPer1M: 0.03, outputPer1M: 1.25 }
|
|
1212
|
+
"claude-3-5-sonnet-20241022": { inputPer1M: 3, cacheCreationPer1M: 3.75, cacheReadPer1M: 0.3, outputPer1M: 15 },
|
|
1213
|
+
"claude-3-5-haiku-20241022": { inputPer1M: 0.8, cacheCreationPer1M: 1, cacheReadPer1M: 0.08, outputPer1M: 4 },
|
|
1214
|
+
"claude-3-opus-20240229": { inputPer1M: 15, cacheCreationPer1M: 18.75, cacheReadPer1M: 1.5, outputPer1M: 75 },
|
|
1215
|
+
"claude-3-haiku-20240307": { inputPer1M: 0.25, cacheCreationPer1M: 0.3, cacheReadPer1M: 0.03, outputPer1M: 1.25 }
|
|
1178
1216
|
};
|
|
1179
|
-
var DEFAULT_PRICING2 = { inputPer1M: 3, cacheReadPer1M: 0.3, outputPer1M: 15 };
|
|
1217
|
+
var DEFAULT_PRICING2 = { inputPer1M: 3, cacheCreationPer1M: 3.75, cacheReadPer1M: 0.3, outputPer1M: 15 };
|
|
1180
1218
|
function getPricing(model) {
|
|
1181
1219
|
if (MODEL_PRICING2[model]) return MODEL_PRICING2[model];
|
|
1182
1220
|
const lower = model.toLowerCase();
|
|
@@ -1185,10 +1223,12 @@ function getPricing(model) {
|
|
|
1185
1223
|
}
|
|
1186
1224
|
return DEFAULT_PRICING2;
|
|
1187
1225
|
}
|
|
1188
|
-
function calculateCost2(inputTokens, cacheReadTokens, outputTokens, model) {
|
|
1226
|
+
function calculateCost2(inputTokens, cacheReadTokens, outputTokens, model, cacheCreationTokens = 0) {
|
|
1189
1227
|
const p = getPricing(model);
|
|
1190
|
-
|
|
1191
|
-
|
|
1228
|
+
return inputTokens / 1e6 * p.inputPer1M + cacheCreationTokens / 1e6 * p.cacheCreationPer1M + cacheReadTokens / 1e6 * p.cacheReadPer1M + outputTokens / 1e6 * p.outputPer1M;
|
|
1229
|
+
}
|
|
1230
|
+
function totalClaudeTokens(inputTokens, outputTokens, cacheCreationTokens, cacheReadTokens) {
|
|
1231
|
+
return inputTokens + outputTokens + cacheCreationTokens + cacheReadTokens;
|
|
1192
1232
|
}
|
|
1193
1233
|
var CLAUDE_PROJECTS_DIR = (0, import_node_path5.join)((0, import_node_os5.homedir)(), ".claude", "projects");
|
|
1194
1234
|
var fileCache = /* @__PURE__ */ new Map();
|
|
@@ -1293,7 +1333,7 @@ function parseAllSessions2(project) {
|
|
|
1293
1333
|
const outputTokens = usage.output_tokens || 0;
|
|
1294
1334
|
const cacheCreationTokens = usage.cache_creation_input_tokens || 0;
|
|
1295
1335
|
const cacheReadTokens = usage.cache_read_input_tokens || 0;
|
|
1296
|
-
const totalTokens = inputTokens
|
|
1336
|
+
const totalTokens = totalClaudeTokens(inputTokens, outputTokens, cacheCreationTokens, cacheReadTokens);
|
|
1297
1337
|
if (totalTokens === 0) continue;
|
|
1298
1338
|
entries.push({
|
|
1299
1339
|
timestamp: obj.timestamp,
|
|
@@ -1377,8 +1417,8 @@ function getDailyResponse4(project, tz = DEFAULT_TZ) {
|
|
|
1377
1417
|
agg.outputTokens += e.outputTokens;
|
|
1378
1418
|
agg.cacheCreationTokens += e.cacheCreationTokens;
|
|
1379
1419
|
agg.cacheReadTokens += e.cacheReadTokens;
|
|
1380
|
-
agg.totalTokens += e.inputTokens
|
|
1381
|
-
const cost = calculateCost2(e.inputTokens, e.cacheReadTokens, e.outputTokens, e.model);
|
|
1420
|
+
agg.totalTokens += totalClaudeTokens(e.inputTokens, e.outputTokens, e.cacheCreationTokens, e.cacheReadTokens);
|
|
1421
|
+
const cost = calculateCost2(e.inputTokens, e.cacheReadTokens, e.outputTokens, e.model, e.cacheCreationTokens);
|
|
1382
1422
|
agg.totalCost += cost;
|
|
1383
1423
|
if (!agg.models.has(e.model)) {
|
|
1384
1424
|
agg.models.set(e.model, { input: 0, output: 0, cacheCreation: 0, cacheRead: 0, cost: 0 });
|
|
@@ -1428,8 +1468,8 @@ function getProjectsResponse4(tz = DEFAULT_TZ) {
|
|
|
1428
1468
|
agg.outputTokens += e.outputTokens;
|
|
1429
1469
|
agg.cacheCreationTokens += e.cacheCreationTokens;
|
|
1430
1470
|
agg.cacheReadTokens += e.cacheReadTokens;
|
|
1431
|
-
agg.totalTokens += e.inputTokens
|
|
1432
|
-
const cost = calculateCost2(e.inputTokens, e.cacheReadTokens, e.outputTokens, e.model);
|
|
1471
|
+
agg.totalTokens += totalClaudeTokens(e.inputTokens, e.outputTokens, e.cacheCreationTokens, e.cacheReadTokens);
|
|
1472
|
+
const cost = calculateCost2(e.inputTokens, e.cacheReadTokens, e.outputTokens, e.model, e.cacheCreationTokens);
|
|
1433
1473
|
agg.totalCost += cost;
|
|
1434
1474
|
if (!agg.models.has(e.model)) {
|
|
1435
1475
|
agg.models.set(e.model, { input: 0, output: 0, cacheCreation: 0, cacheRead: 0, cost: 0 });
|
|
@@ -1467,13 +1507,13 @@ function getBlocksResponse4(project, tz = DEFAULT_TZ) {
|
|
|
1467
1507
|
bucket.outputTokens += e.outputTokens;
|
|
1468
1508
|
bucket.cacheCreationTokens += e.cacheCreationTokens;
|
|
1469
1509
|
bucket.cacheReadTokens += e.cacheReadTokens;
|
|
1470
|
-
bucket.costUSD += calculateCost2(e.inputTokens, e.cacheReadTokens, e.outputTokens, e.model);
|
|
1510
|
+
bucket.costUSD += calculateCost2(e.inputTokens, e.cacheReadTokens, e.outputTokens, e.model, e.cacheCreationTokens);
|
|
1471
1511
|
bucket.models.add(e.model);
|
|
1472
1512
|
}
|
|
1473
1513
|
const blocks = [];
|
|
1474
1514
|
let idx = 0;
|
|
1475
1515
|
for (const [hourKey, bucket] of hourMap) {
|
|
1476
|
-
const totalTokens = bucket.inputTokens
|
|
1516
|
+
const totalTokens = totalClaudeTokens(bucket.inputTokens, bucket.outputTokens, bucket.cacheCreationTokens, bucket.cacheReadTokens);
|
|
1477
1517
|
blocks.push({
|
|
1478
1518
|
id: `claude-${idx}`,
|
|
1479
1519
|
startTime: `${hourKey}:00:00`,
|