vibestats 1.3.9 → 1.3.10
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 +4 -0
- package/dist/index.js +319 -191
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -18,6 +18,8 @@ vibestats # Daily usage table
|
|
|
18
18
|
vibestats --monthly # Monthly aggregation
|
|
19
19
|
vibestats --model # Aggregate by model
|
|
20
20
|
vibestats --total # Show only totals
|
|
21
|
+
vibestats --kimi # Kimi family stats only
|
|
22
|
+
vibestats --minimax # MiniMax family stats only
|
|
21
23
|
|
|
22
24
|
# Wrapped summary
|
|
23
25
|
vibestats --wrapped # Annual wrapped summary
|
|
@@ -37,6 +39,8 @@ vibestats --claude-limits
|
|
|
37
39
|
| `--model` | Aggregate by model |
|
|
38
40
|
| `--sessions` | Aggregate by session |
|
|
39
41
|
| `--total` | Show only totals |
|
|
42
|
+
| `--kimi` | Show only Kimi family stats |
|
|
43
|
+
| `--minimax` | Show only MiniMax family stats |
|
|
40
44
|
| `--since YYYY-MM-DD` | Filter from date |
|
|
41
45
|
| `--until YYYY-MM-DD` | Filter to date |
|
|
42
46
|
| `--last N` | Last N days (shorthand: `--last7`, `--last30`, etc.) |
|
package/dist/index.js
CHANGED
|
@@ -280,6 +280,195 @@ function calculateCodexCost(modelName, inputTokens, outputTokens, cachedInputTok
|
|
|
280
280
|
return inputCost + cachedCost + outputCost;
|
|
281
281
|
}
|
|
282
282
|
|
|
283
|
+
// src/pricing.ts
|
|
284
|
+
var MODEL_PRICING = {
|
|
285
|
+
// Fireworks router pricing as of 2026-03-30:
|
|
286
|
+
// https://fireworks.ai/pricing
|
|
287
|
+
// Fireworks exposes a single "cached input" rate, so cache creation
|
|
288
|
+
// tokens are treated as regular input and cache reads use the discounted rate.
|
|
289
|
+
"accounts/fireworks/routers/kimi-k2p5-turbo": {
|
|
290
|
+
input: 0.99,
|
|
291
|
+
output: 4.94,
|
|
292
|
+
cacheWrite: 0.99,
|
|
293
|
+
cacheRead: 0.16
|
|
294
|
+
},
|
|
295
|
+
// Fireworks prices the MiniMax M2 family at one rate. We apply that
|
|
296
|
+
// official family pricing to MiniMax-M2.7 because Fireworks does not
|
|
297
|
+
// publish a distinct M2.7 per-token row.
|
|
298
|
+
"MiniMax-M2.7": {
|
|
299
|
+
input: 0.3,
|
|
300
|
+
output: 1.2,
|
|
301
|
+
cacheWrite: 0.3,
|
|
302
|
+
cacheRead: 0.03
|
|
303
|
+
},
|
|
304
|
+
// Opus 4.6 (same pricing as Opus 4.5)
|
|
305
|
+
"claude-opus-4-6-20260101": {
|
|
306
|
+
input: 5,
|
|
307
|
+
output: 25,
|
|
308
|
+
cacheWrite: 6.25,
|
|
309
|
+
cacheRead: 0.5
|
|
310
|
+
},
|
|
311
|
+
// Opus 4.5 (cheaper than Opus 4.1)
|
|
312
|
+
"claude-opus-4-5-20251101": {
|
|
313
|
+
input: 5,
|
|
314
|
+
output: 25,
|
|
315
|
+
cacheWrite: 6.25,
|
|
316
|
+
cacheRead: 0.5
|
|
317
|
+
},
|
|
318
|
+
// Sonnet 4.6 (same pricing as Sonnet 4.5)
|
|
319
|
+
"claude-sonnet-4-6-20260101": {
|
|
320
|
+
input: 3,
|
|
321
|
+
output: 15,
|
|
322
|
+
cacheWrite: 3.75,
|
|
323
|
+
cacheRead: 0.3
|
|
324
|
+
},
|
|
325
|
+
// Sonnet 4.5
|
|
326
|
+
"claude-sonnet-4-5-20250929": {
|
|
327
|
+
input: 3,
|
|
328
|
+
output: 15,
|
|
329
|
+
cacheWrite: 3.75,
|
|
330
|
+
cacheRead: 0.3
|
|
331
|
+
},
|
|
332
|
+
// Opus 4.1 (MORE expensive than Opus 4.5)
|
|
333
|
+
"claude-opus-4-1-20250805": {
|
|
334
|
+
input: 15,
|
|
335
|
+
output: 75,
|
|
336
|
+
cacheWrite: 18.75,
|
|
337
|
+
cacheRead: 1.5
|
|
338
|
+
},
|
|
339
|
+
// Haiku 4.5
|
|
340
|
+
"claude-haiku-4-5-20251001": {
|
|
341
|
+
input: 1,
|
|
342
|
+
output: 5,
|
|
343
|
+
cacheWrite: 1.25,
|
|
344
|
+
cacheRead: 0.1
|
|
345
|
+
},
|
|
346
|
+
// Sonnet 3.5 (legacy - same as Sonnet 4.5)
|
|
347
|
+
"claude-3-5-sonnet-20241022": {
|
|
348
|
+
input: 3,
|
|
349
|
+
output: 15,
|
|
350
|
+
cacheWrite: 3.75,
|
|
351
|
+
cacheRead: 0.3
|
|
352
|
+
},
|
|
353
|
+
"claude-3-5-sonnet-20240620": {
|
|
354
|
+
input: 3,
|
|
355
|
+
output: 15,
|
|
356
|
+
cacheWrite: 3.75,
|
|
357
|
+
cacheRead: 0.3
|
|
358
|
+
},
|
|
359
|
+
// Haiku 3.5 (legacy - same as Haiku 4.5)
|
|
360
|
+
"claude-3-5-haiku-20241022": {
|
|
361
|
+
input: 1,
|
|
362
|
+
output: 5,
|
|
363
|
+
cacheWrite: 1.25,
|
|
364
|
+
cacheRead: 0.1
|
|
365
|
+
}
|
|
366
|
+
};
|
|
367
|
+
function normalizeModelName(modelName) {
|
|
368
|
+
return modelName.trim().toLowerCase();
|
|
369
|
+
}
|
|
370
|
+
function hasModelVersion(normalized, family, version) {
|
|
371
|
+
const versionPattern = version.replace(/\./g, "[\\s._-]*");
|
|
372
|
+
const familyPattern = family.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
373
|
+
const boundary = "(?:^|[^a-z0-9])";
|
|
374
|
+
const tailBoundary = "(?:[^a-z0-9]|$)";
|
|
375
|
+
return new RegExp(`${boundary}${familyPattern}(?:[^a-z0-9]+)?${versionPattern}${tailBoundary}`).test(normalized) || new RegExp(`${boundary}${versionPattern}(?:[^a-z0-9]+)?${familyPattern}${tailBoundary}`).test(normalized);
|
|
376
|
+
}
|
|
377
|
+
function isKimiK25Turbo(normalized) {
|
|
378
|
+
return normalized.includes("kimi-code") || normalized.includes("accounts/fireworks/routers/kimi-k2p5-turbo") || normalized.includes("accounts/fireworks/models/kimi-k2p5-turbo") || normalized.includes("custom:kimi-k2.5-turbo") || normalized.includes("custom:kimi-k2p5-turbo") || normalized.includes("kimi") && (normalized.includes("k2.5") || normalized.includes("k2p5")) && normalized.includes("turbo");
|
|
379
|
+
}
|
|
380
|
+
function isMiniMaxM27(normalized) {
|
|
381
|
+
return normalized.includes("minimax-code") || normalized.includes("custom:minimax-m2.7") || normalized.includes("custom:minimax-m2-7") || normalized.includes("minimax-m2.7") || normalized.includes("minimax-m2-7");
|
|
382
|
+
}
|
|
383
|
+
function isKimiFamilyModel(modelName) {
|
|
384
|
+
const normalized = normalizeModelName(modelName);
|
|
385
|
+
return isKimiK25Turbo(normalized) || normalized.includes("kimi");
|
|
386
|
+
}
|
|
387
|
+
function isMiniMaxFamilyModel(modelName) {
|
|
388
|
+
const normalized = normalizeModelName(modelName);
|
|
389
|
+
return isMiniMaxM27(normalized) || normalized.includes("minimax");
|
|
390
|
+
}
|
|
391
|
+
function matchesModelFamilies(modelName, families) {
|
|
392
|
+
if (!families || families.length === 0) return true;
|
|
393
|
+
return families.some((family) => {
|
|
394
|
+
if (family === "kimi") return isKimiFamilyModel(modelName);
|
|
395
|
+
if (family === "minimax") return isMiniMaxFamilyModel(modelName);
|
|
396
|
+
return false;
|
|
397
|
+
});
|
|
398
|
+
}
|
|
399
|
+
function formatModelFamilyLabel(families) {
|
|
400
|
+
if (!families || families.length === 0) return void 0;
|
|
401
|
+
const unique = Array.from(new Set(families));
|
|
402
|
+
const labels = unique.map((family) => family === "kimi" ? "Kimi" : "MiniMax");
|
|
403
|
+
if (labels.length === 0) return void 0;
|
|
404
|
+
if (labels.length === 1) return labels[0];
|
|
405
|
+
return labels.join(" + ");
|
|
406
|
+
}
|
|
407
|
+
function tryGetModelPricing(modelName) {
|
|
408
|
+
if (MODEL_PRICING[modelName]) {
|
|
409
|
+
return MODEL_PRICING[modelName];
|
|
410
|
+
}
|
|
411
|
+
const normalized = normalizeModelName(modelName);
|
|
412
|
+
if (isKimiK25Turbo(normalized)) {
|
|
413
|
+
return MODEL_PRICING["accounts/fireworks/routers/kimi-k2p5-turbo"];
|
|
414
|
+
}
|
|
415
|
+
if (isMiniMaxM27(normalized)) {
|
|
416
|
+
return MODEL_PRICING["MiniMax-M2.7"];
|
|
417
|
+
}
|
|
418
|
+
if (hasModelVersion(normalized, "opus", "4.6")) {
|
|
419
|
+
return MODEL_PRICING["claude-opus-4-6-20260101"];
|
|
420
|
+
}
|
|
421
|
+
if (hasModelVersion(normalized, "opus", "4.5")) {
|
|
422
|
+
return MODEL_PRICING["claude-opus-4-5-20251101"];
|
|
423
|
+
}
|
|
424
|
+
if (hasModelVersion(normalized, "opus", "4.1") || normalized.includes("opus-4")) {
|
|
425
|
+
return MODEL_PRICING["claude-opus-4-1-20250805"];
|
|
426
|
+
}
|
|
427
|
+
if (hasModelVersion(normalized, "sonnet", "4.6")) {
|
|
428
|
+
return MODEL_PRICING["claude-sonnet-4-6-20260101"];
|
|
429
|
+
}
|
|
430
|
+
if (hasModelVersion(normalized, "sonnet", "4.5")) {
|
|
431
|
+
return MODEL_PRICING["claude-sonnet-4-5-20250929"];
|
|
432
|
+
}
|
|
433
|
+
if (hasModelVersion(normalized, "sonnet", "3.5") || normalized.includes("sonnet")) {
|
|
434
|
+
return MODEL_PRICING["claude-3-5-sonnet-20241022"];
|
|
435
|
+
}
|
|
436
|
+
if (hasModelVersion(normalized, "haiku", "4.5")) {
|
|
437
|
+
return MODEL_PRICING["claude-haiku-4-5-20251001"];
|
|
438
|
+
}
|
|
439
|
+
if (hasModelVersion(normalized, "haiku", "3.5") || normalized.includes("haiku")) {
|
|
440
|
+
return MODEL_PRICING["claude-3-5-haiku-20241022"];
|
|
441
|
+
}
|
|
442
|
+
return null;
|
|
443
|
+
}
|
|
444
|
+
function getModelDisplayName(modelName) {
|
|
445
|
+
const normalized = normalizeModelName(modelName);
|
|
446
|
+
if (normalized.includes("kimi-code")) {
|
|
447
|
+
return "Kimi K2.5 Turbo";
|
|
448
|
+
}
|
|
449
|
+
if (normalized.includes("minimax-code")) {
|
|
450
|
+
return "MiniMax-M2.7";
|
|
451
|
+
}
|
|
452
|
+
if (isKimiK25Turbo(normalized)) {
|
|
453
|
+
return "Kimi K2.5 Turbo";
|
|
454
|
+
}
|
|
455
|
+
if (isMiniMaxM27(normalized)) {
|
|
456
|
+
return "MiniMax-M2.7";
|
|
457
|
+
}
|
|
458
|
+
if (hasModelVersion(normalized, "opus", "4.6")) return "Opus 4.6";
|
|
459
|
+
if (hasModelVersion(normalized, "opus", "4.5")) return "Opus 4.5";
|
|
460
|
+
if (hasModelVersion(normalized, "opus", "4.1")) return "Opus 4.1";
|
|
461
|
+
if (normalized.includes("opus")) return "Opus";
|
|
462
|
+
if (hasModelVersion(normalized, "sonnet", "4.6")) return "Sonnet 4.6";
|
|
463
|
+
if (hasModelVersion(normalized, "sonnet", "4.5")) return "Sonnet 4.5";
|
|
464
|
+
if (hasModelVersion(normalized, "sonnet", "3.5")) return "Sonnet 3.5";
|
|
465
|
+
if (normalized.includes("sonnet")) return "Sonnet";
|
|
466
|
+
if (hasModelVersion(normalized, "haiku", "4.5")) return "Haiku 4.5";
|
|
467
|
+
if (hasModelVersion(normalized, "haiku", "3.5")) return "Haiku 3.5";
|
|
468
|
+
if (normalized.includes("haiku")) return "Haiku";
|
|
469
|
+
return modelName;
|
|
470
|
+
}
|
|
471
|
+
|
|
283
472
|
// src/url-encoder.ts
|
|
284
473
|
function formatCompactNumber(num) {
|
|
285
474
|
if (num >= 1e9) {
|
|
@@ -634,14 +823,14 @@ function buildActivityGraph(stats, metric, requestedDays = 365) {
|
|
|
634
823
|
}
|
|
635
824
|
};
|
|
636
825
|
}
|
|
637
|
-
function buildActivityTitle(
|
|
638
|
-
const sourceLabel = source === "codex" ? "Codex" : source === "combined" ? "AI Coding" : "Local AI";
|
|
826
|
+
function buildActivityTitle(stats, metric) {
|
|
827
|
+
const sourceLabel = stats.scopeLabel ? stats.scopeLabel : stats.source === "codex" ? "Codex" : stats.source === "combined" ? "AI Coding" : "Local AI";
|
|
639
828
|
const metricLabel = metric === "tokens" ? "Activity" : metric === "sessions" ? "Session Activity" : "Message Activity";
|
|
640
829
|
return `${sourceLabel} ${metricLabel}`;
|
|
641
830
|
}
|
|
642
831
|
function buildActivityArtifactPayload(stats, metric, requestedDays = 365) {
|
|
643
832
|
return {
|
|
644
|
-
title: buildActivityTitle(stats
|
|
833
|
+
title: buildActivityTitle(stats, metric),
|
|
645
834
|
source: stats.source,
|
|
646
835
|
activity: buildActivityGraph(stats, metric, requestedDays)
|
|
647
836
|
};
|
|
@@ -671,151 +860,6 @@ import { promises as fs } from "fs";
|
|
|
671
860
|
import { homedir } from "os";
|
|
672
861
|
import { basename, join } from "path";
|
|
673
862
|
import { promisify } from "util";
|
|
674
|
-
|
|
675
|
-
// src/pricing.ts
|
|
676
|
-
var MODEL_PRICING = {
|
|
677
|
-
// Fireworks router pricing as of 2026-03-30:
|
|
678
|
-
// https://fireworks.ai/pricing
|
|
679
|
-
// Fireworks exposes a single "cached input" rate, so cache creation
|
|
680
|
-
// tokens are treated as regular input and cache reads use the discounted rate.
|
|
681
|
-
"accounts/fireworks/routers/kimi-k2p5-turbo": {
|
|
682
|
-
input: 0.99,
|
|
683
|
-
output: 4.94,
|
|
684
|
-
cacheWrite: 0.99,
|
|
685
|
-
cacheRead: 0.16
|
|
686
|
-
},
|
|
687
|
-
// Fireworks prices the MiniMax M2 family at one rate. We apply that
|
|
688
|
-
// official family pricing to MiniMax-M2.7 because Fireworks does not
|
|
689
|
-
// publish a distinct M2.7 per-token row.
|
|
690
|
-
"MiniMax-M2.7": {
|
|
691
|
-
input: 0.3,
|
|
692
|
-
output: 1.2,
|
|
693
|
-
cacheWrite: 0.3,
|
|
694
|
-
cacheRead: 0.03
|
|
695
|
-
},
|
|
696
|
-
// Opus 4.6 (same pricing as Opus 4.5)
|
|
697
|
-
"claude-opus-4-6-20260101": {
|
|
698
|
-
input: 5,
|
|
699
|
-
output: 25,
|
|
700
|
-
cacheWrite: 6.25,
|
|
701
|
-
cacheRead: 0.5
|
|
702
|
-
},
|
|
703
|
-
// Opus 4.5 (cheaper than Opus 4.1)
|
|
704
|
-
"claude-opus-4-5-20251101": {
|
|
705
|
-
input: 5,
|
|
706
|
-
output: 25,
|
|
707
|
-
cacheWrite: 6.25,
|
|
708
|
-
cacheRead: 0.5
|
|
709
|
-
},
|
|
710
|
-
// Sonnet 4.6 (same pricing as Sonnet 4.5)
|
|
711
|
-
"claude-sonnet-4-6-20260101": {
|
|
712
|
-
input: 3,
|
|
713
|
-
output: 15,
|
|
714
|
-
cacheWrite: 3.75,
|
|
715
|
-
cacheRead: 0.3
|
|
716
|
-
},
|
|
717
|
-
// Sonnet 4.5
|
|
718
|
-
"claude-sonnet-4-5-20250929": {
|
|
719
|
-
input: 3,
|
|
720
|
-
output: 15,
|
|
721
|
-
cacheWrite: 3.75,
|
|
722
|
-
cacheRead: 0.3
|
|
723
|
-
},
|
|
724
|
-
// Opus 4.1 (MORE expensive than Opus 4.5)
|
|
725
|
-
"claude-opus-4-1-20250805": {
|
|
726
|
-
input: 15,
|
|
727
|
-
output: 75,
|
|
728
|
-
cacheWrite: 18.75,
|
|
729
|
-
cacheRead: 1.5
|
|
730
|
-
},
|
|
731
|
-
// Haiku 4.5
|
|
732
|
-
"claude-haiku-4-5-20251001": {
|
|
733
|
-
input: 1,
|
|
734
|
-
output: 5,
|
|
735
|
-
cacheWrite: 1.25,
|
|
736
|
-
cacheRead: 0.1
|
|
737
|
-
},
|
|
738
|
-
// Sonnet 3.5 (legacy - same as Sonnet 4.5)
|
|
739
|
-
"claude-3-5-sonnet-20241022": {
|
|
740
|
-
input: 3,
|
|
741
|
-
output: 15,
|
|
742
|
-
cacheWrite: 3.75,
|
|
743
|
-
cacheRead: 0.3
|
|
744
|
-
},
|
|
745
|
-
"claude-3-5-sonnet-20240620": {
|
|
746
|
-
input: 3,
|
|
747
|
-
output: 15,
|
|
748
|
-
cacheWrite: 3.75,
|
|
749
|
-
cacheRead: 0.3
|
|
750
|
-
},
|
|
751
|
-
// Haiku 3.5 (legacy - same as Haiku 4.5)
|
|
752
|
-
"claude-3-5-haiku-20241022": {
|
|
753
|
-
input: 1,
|
|
754
|
-
output: 5,
|
|
755
|
-
cacheWrite: 1.25,
|
|
756
|
-
cacheRead: 0.1
|
|
757
|
-
}
|
|
758
|
-
};
|
|
759
|
-
function tryGetModelPricing(modelName) {
|
|
760
|
-
if (MODEL_PRICING[modelName]) {
|
|
761
|
-
return MODEL_PRICING[modelName];
|
|
762
|
-
}
|
|
763
|
-
const normalized = modelName.toLowerCase();
|
|
764
|
-
if (normalized.includes("kimi-k2p5-turbo")) {
|
|
765
|
-
return MODEL_PRICING["accounts/fireworks/routers/kimi-k2p5-turbo"];
|
|
766
|
-
}
|
|
767
|
-
if (normalized.includes("minimax-m2.7")) {
|
|
768
|
-
return MODEL_PRICING["MiniMax-M2.7"];
|
|
769
|
-
}
|
|
770
|
-
if (modelName.includes("opus-4-6") || modelName.includes("opus-4.6")) {
|
|
771
|
-
return MODEL_PRICING["claude-opus-4-6-20260101"];
|
|
772
|
-
}
|
|
773
|
-
if (modelName.includes("opus-4-5") || modelName.includes("opus-4.5")) {
|
|
774
|
-
return MODEL_PRICING["claude-opus-4-5-20251101"];
|
|
775
|
-
}
|
|
776
|
-
if (modelName.includes("opus-4-1") || modelName.includes("opus-4.1") || modelName.includes("opus-4")) {
|
|
777
|
-
return MODEL_PRICING["claude-opus-4-1-20250805"];
|
|
778
|
-
}
|
|
779
|
-
if (modelName.includes("sonnet-4-6") || modelName.includes("sonnet-4.6")) {
|
|
780
|
-
return MODEL_PRICING["claude-sonnet-4-6-20260101"];
|
|
781
|
-
}
|
|
782
|
-
if (modelName.includes("sonnet-4-5") || modelName.includes("sonnet-4.5")) {
|
|
783
|
-
return MODEL_PRICING["claude-sonnet-4-5-20250929"];
|
|
784
|
-
}
|
|
785
|
-
if (modelName.includes("sonnet")) {
|
|
786
|
-
return MODEL_PRICING["claude-3-5-sonnet-20241022"];
|
|
787
|
-
}
|
|
788
|
-
if (modelName.includes("haiku-4-5") || modelName.includes("haiku-4.5")) {
|
|
789
|
-
return MODEL_PRICING["claude-haiku-4-5-20251001"];
|
|
790
|
-
}
|
|
791
|
-
if (modelName.includes("haiku")) {
|
|
792
|
-
return MODEL_PRICING["claude-3-5-haiku-20241022"];
|
|
793
|
-
}
|
|
794
|
-
return null;
|
|
795
|
-
}
|
|
796
|
-
function getModelDisplayName(modelName) {
|
|
797
|
-
const normalized = modelName.toLowerCase();
|
|
798
|
-
if (normalized.includes("accounts/fireworks/routers/kimi-k2p5-turbo") || normalized.includes("custom:kimi-k2.5-turbo")) {
|
|
799
|
-
return "Kimi K2.5 Turbo";
|
|
800
|
-
}
|
|
801
|
-
if (normalized.includes("minimax-m2.7") || normalized.includes("custom:minimax-m2.7")) {
|
|
802
|
-
return "MiniMax-M2.7";
|
|
803
|
-
}
|
|
804
|
-
if (modelName.includes("opus-4-6") || modelName.includes("opus-4.6")) return "Opus 4.6";
|
|
805
|
-
if (modelName.includes("opus-4-5") || modelName.includes("opus-4.5")) return "Opus 4.5";
|
|
806
|
-
if (modelName.includes("opus-4-1") || modelName.includes("opus-4.1")) return "Opus 4.1";
|
|
807
|
-
if (modelName.includes("opus")) return "Opus";
|
|
808
|
-
if (modelName.includes("sonnet-4-6") || modelName.includes("sonnet-4.6")) return "Sonnet 4.6";
|
|
809
|
-
if (modelName.includes("sonnet-4-5") || modelName.includes("sonnet-4.5")) return "Sonnet 4.5";
|
|
810
|
-
if (modelName.includes("sonnet-3-5") || modelName.includes("sonnet-3.5")) return "Sonnet 3.5";
|
|
811
|
-
if (modelName.includes("sonnet")) return "Sonnet";
|
|
812
|
-
if (modelName.includes("haiku-4-5") || modelName.includes("haiku-4.5")) return "Haiku 4.5";
|
|
813
|
-
if (modelName.includes("haiku-3-5") || modelName.includes("haiku-3.5")) return "Haiku 3.5";
|
|
814
|
-
if (modelName.includes("haiku")) return "Haiku";
|
|
815
|
-
return modelName;
|
|
816
|
-
}
|
|
817
|
-
|
|
818
|
-
// src/anthropic-sources.ts
|
|
819
863
|
var execFileAsync = promisify(execFile);
|
|
820
864
|
var SQLITE_SEPARATOR = "";
|
|
821
865
|
var SQLITE_MAX_BUFFER = 64 * 1024 * 1024;
|
|
@@ -871,10 +915,16 @@ async function findFiles(dir, matcher, visited = /* @__PURE__ */ new Set(), resu
|
|
|
871
915
|
function normalizeAnthropicModelName(modelName) {
|
|
872
916
|
const trimmed = modelName.trim();
|
|
873
917
|
const normalized = trimmed.toLowerCase();
|
|
874
|
-
if (
|
|
918
|
+
if (normalized.includes("kimi-code")) {
|
|
919
|
+
return "accounts/fireworks/routers/kimi-k2p5-turbo";
|
|
920
|
+
}
|
|
921
|
+
if (normalized.includes("minimax-code")) {
|
|
922
|
+
return "MiniMax-M2.7";
|
|
923
|
+
}
|
|
924
|
+
if (/^custom:minimax-m2(?:\.|-)?7(?:-\d+)?$/.test(normalized)) {
|
|
875
925
|
return "MiniMax-M2.7";
|
|
876
926
|
}
|
|
877
|
-
if (/^custom:kimi-k2
|
|
927
|
+
if (/^custom:kimi-k2(?:\.|p)?5-turbo(?:-\d+)?$/.test(normalized) || /^accounts\/fireworks\/models\/kimi-k2p5-turbo$/.test(normalized) || /^accounts\/fireworks\/routers\/kimi-k2p5-turbo$/.test(normalized)) {
|
|
878
928
|
return "accounts/fireworks/routers/kimi-k2p5-turbo";
|
|
879
929
|
}
|
|
880
930
|
return trimmed;
|
|
@@ -1152,10 +1202,14 @@ async function collectAnthropicUsageEntries(options = {}) {
|
|
|
1152
1202
|
parseOpenCodeEntries(),
|
|
1153
1203
|
parseFactoryEntries()
|
|
1154
1204
|
]);
|
|
1155
|
-
|
|
1205
|
+
const entries = [...claudeEntries, ...opencodeEntries, ...factoryEntries];
|
|
1206
|
+
if (!options.families || options.families.length === 0) {
|
|
1207
|
+
return entries;
|
|
1208
|
+
}
|
|
1209
|
+
return entries.filter((entry) => matchesModelFamilies(entry.rawModel, options.families));
|
|
1156
1210
|
}
|
|
1157
|
-
async function loadClaudeStatsFromJsonl() {
|
|
1158
|
-
const entries = await collectAnthropicUsageEntries();
|
|
1211
|
+
async function loadClaudeStatsFromJsonl(options = {}) {
|
|
1212
|
+
const entries = await collectAnthropicUsageEntries(options);
|
|
1159
1213
|
if (entries.length === 0) {
|
|
1160
1214
|
return null;
|
|
1161
1215
|
}
|
|
@@ -1233,6 +1287,15 @@ async function loadClaudeStatsFromJsonl() {
|
|
|
1233
1287
|
|
|
1234
1288
|
// src/usage/loader.ts
|
|
1235
1289
|
var MAX_RECURSION_DEPTH = 10;
|
|
1290
|
+
function normalizePresentableModelName(modelName) {
|
|
1291
|
+
return getModelDisplayName(modelName).trim();
|
|
1292
|
+
}
|
|
1293
|
+
function normalizeEntryModels(entries) {
|
|
1294
|
+
return entries.map((entry) => ({
|
|
1295
|
+
...entry,
|
|
1296
|
+
model: normalizePresentableModelName(entry.model)
|
|
1297
|
+
}));
|
|
1298
|
+
}
|
|
1236
1299
|
function toLocalDateString2(isoTimestamp) {
|
|
1237
1300
|
const date = new Date(isoTimestamp);
|
|
1238
1301
|
const year = date.getFullYear();
|
|
@@ -1286,8 +1349,8 @@ async function findJsonlFiles(dir, visited = /* @__PURE__ */ new Set(), depth =
|
|
|
1286
1349
|
}
|
|
1287
1350
|
return result;
|
|
1288
1351
|
}
|
|
1289
|
-
async function parseClaudeJsonl(projectFilter) {
|
|
1290
|
-
const entries = await collectAnthropicUsageEntries({ projectFilter });
|
|
1352
|
+
async function parseClaudeJsonl(projectFilter, families) {
|
|
1353
|
+
const entries = await collectAnthropicUsageEntries({ projectFilter, families });
|
|
1291
1354
|
return entries.map((entry) => ({
|
|
1292
1355
|
date: entry.date,
|
|
1293
1356
|
model: entry.model,
|
|
@@ -1357,6 +1420,7 @@ async function parseCodexJsonl() {
|
|
|
1357
1420
|
entries.push({
|
|
1358
1421
|
date,
|
|
1359
1422
|
model: getCodexModelDisplayName(currentModel),
|
|
1423
|
+
rawModel: currentModel,
|
|
1360
1424
|
inputTokens: inputTokens - cachedInputTokens,
|
|
1361
1425
|
outputTokens,
|
|
1362
1426
|
cacheWriteTokens: 0,
|
|
@@ -1490,6 +1554,7 @@ function aggregateByModel(entries) {
|
|
|
1490
1554
|
const modelMap = /* @__PURE__ */ new Map();
|
|
1491
1555
|
for (const e of entries) {
|
|
1492
1556
|
const entryTotal = e.inputTokens + e.outputTokens + e.cacheWriteTokens + e.cacheReadTokens;
|
|
1557
|
+
if (entryTotal <= 0) continue;
|
|
1493
1558
|
const existing = modelMap.get(e.model);
|
|
1494
1559
|
if (existing) {
|
|
1495
1560
|
existing.inputTokens += e.inputTokens;
|
|
@@ -1576,6 +1641,7 @@ function computeModelBreakdown(entries) {
|
|
|
1576
1641
|
const modelMap = /* @__PURE__ */ new Map();
|
|
1577
1642
|
for (const e of entries) {
|
|
1578
1643
|
const total = e.inputTokens + e.outputTokens + e.cacheWriteTokens + e.cacheReadTokens;
|
|
1644
|
+
if (total <= 0) continue;
|
|
1579
1645
|
const existing = modelMap.get(e.model);
|
|
1580
1646
|
if (existing) {
|
|
1581
1647
|
existing.tokens += total;
|
|
@@ -1661,10 +1727,10 @@ function computeActivityStats(entries, source) {
|
|
|
1661
1727
|
};
|
|
1662
1728
|
}
|
|
1663
1729
|
async function loadUsageStats(options) {
|
|
1664
|
-
const { aggregation, since, until, codexOnly, combined, projectFilter } = options;
|
|
1730
|
+
const { aggregation, since, until, codexOnly, combined, projectFilter, families } = options;
|
|
1665
1731
|
let entries = [];
|
|
1666
1732
|
if (!codexOnly) {
|
|
1667
|
-
entries = entries.concat(await parseClaudeJsonl(projectFilter));
|
|
1733
|
+
entries = entries.concat(await parseClaudeJsonl(projectFilter, families));
|
|
1668
1734
|
}
|
|
1669
1735
|
if (codexOnly || combined) {
|
|
1670
1736
|
entries = entries.concat(await parseCodexJsonl());
|
|
@@ -1672,6 +1738,10 @@ async function loadUsageStats(options) {
|
|
|
1672
1738
|
if (entries.length === 0) {
|
|
1673
1739
|
return null;
|
|
1674
1740
|
}
|
|
1741
|
+
entries = normalizeEntryModels(entries);
|
|
1742
|
+
if (families && families.length > 0) {
|
|
1743
|
+
entries = entries.filter((entry) => matchesModelFamilies(entry.rawModel || entry.model, families));
|
|
1744
|
+
}
|
|
1675
1745
|
entries = filterByDateRange(entries, since, until);
|
|
1676
1746
|
entries = entries.filter((e) => !e.model.toLowerCase().includes("synthetic"));
|
|
1677
1747
|
if (entries.length === 0) {
|
|
@@ -1711,6 +1781,7 @@ async function loadUsageStats(options) {
|
|
|
1711
1781
|
rows,
|
|
1712
1782
|
totals,
|
|
1713
1783
|
source,
|
|
1784
|
+
scopeLabel: formatModelFamilyLabel(families),
|
|
1714
1785
|
aggregation,
|
|
1715
1786
|
dateRange,
|
|
1716
1787
|
modelBreakdown,
|
|
@@ -1718,10 +1789,10 @@ async function loadUsageStats(options) {
|
|
|
1718
1789
|
};
|
|
1719
1790
|
}
|
|
1720
1791
|
async function loadActivityStats(options) {
|
|
1721
|
-
const { since, until, codexOnly, combined, projectFilter } = options;
|
|
1792
|
+
const { since, until, codexOnly, combined, projectFilter, families } = options;
|
|
1722
1793
|
let entries = [];
|
|
1723
1794
|
if (!codexOnly) {
|
|
1724
|
-
entries = entries.concat(await parseClaudeJsonl(projectFilter));
|
|
1795
|
+
entries = entries.concat(await parseClaudeJsonl(projectFilter, families));
|
|
1725
1796
|
}
|
|
1726
1797
|
if (codexOnly || combined) {
|
|
1727
1798
|
entries = entries.concat(await parseCodexJsonl());
|
|
@@ -1729,6 +1800,10 @@ async function loadActivityStats(options) {
|
|
|
1729
1800
|
if (entries.length === 0) {
|
|
1730
1801
|
return null;
|
|
1731
1802
|
}
|
|
1803
|
+
entries = normalizeEntryModels(entries);
|
|
1804
|
+
if (families && families.length > 0) {
|
|
1805
|
+
entries = entries.filter((entry) => matchesModelFamilies(entry.rawModel || entry.model, families));
|
|
1806
|
+
}
|
|
1732
1807
|
entries = filterByDateRange(entries, since, until);
|
|
1733
1808
|
entries = entries.filter((entry) => !entry.model.toLowerCase().includes("synthetic"));
|
|
1734
1809
|
if (entries.length === 0) {
|
|
@@ -1737,7 +1812,9 @@ async function loadActivityStats(options) {
|
|
|
1737
1812
|
let source = "claude";
|
|
1738
1813
|
if (codexOnly) source = "codex";
|
|
1739
1814
|
else if (combined) source = "combined";
|
|
1740
|
-
|
|
1815
|
+
const stats = computeActivityStats(entries, source);
|
|
1816
|
+
stats.scopeLabel = formatModelFamilyLabel(families);
|
|
1817
|
+
return stats;
|
|
1741
1818
|
}
|
|
1742
1819
|
|
|
1743
1820
|
// src/usage/table.ts
|
|
@@ -1785,9 +1862,11 @@ function displayUsageTable(stats, options = {}) {
|
|
|
1785
1862
|
const termWidth = process.stdout.columns || 140;
|
|
1786
1863
|
const useCompact = compact || termWidth < 120;
|
|
1787
1864
|
console.log();
|
|
1788
|
-
let title = "Claude Code Usage";
|
|
1789
|
-
if (stats.
|
|
1790
|
-
|
|
1865
|
+
let title = stats.scopeLabel ? `${stats.scopeLabel} Usage` : "Claude Code Usage";
|
|
1866
|
+
if (!stats.scopeLabel) {
|
|
1867
|
+
if (stats.source === "codex") title = "Codex CLI Usage";
|
|
1868
|
+
else if (stats.source === "combined") title = "AI Coding Usage (Claude + Codex)";
|
|
1869
|
+
}
|
|
1791
1870
|
const aggLabel = stats.aggregation === "daily" ? "Daily" : stats.aggregation === "monthly" ? "Monthly" : stats.aggregation === "model" ? "By Model" : stats.aggregation === "session" ? "By Session" : "Total";
|
|
1792
1871
|
console.log(`${c.orange}${c.bold}${title} - ${aggLabel} Report${c.reset}`);
|
|
1793
1872
|
console.log(`${c.gray}Date range: ${stats.dateRange.start} to ${stats.dateRange.end}${c.reset}`);
|
|
@@ -1868,9 +1947,11 @@ function displayTotalOnly(stats, options = {}) {
|
|
|
1868
1947
|
const c = getColors(options.showColors);
|
|
1869
1948
|
const { hideCost } = options;
|
|
1870
1949
|
console.log();
|
|
1871
|
-
let title = "Claude Code Usage";
|
|
1872
|
-
if (stats.
|
|
1873
|
-
|
|
1950
|
+
let title = stats.scopeLabel ? `${stats.scopeLabel} Usage` : "Claude Code Usage";
|
|
1951
|
+
if (!stats.scopeLabel) {
|
|
1952
|
+
if (stats.source === "codex") title = "Codex CLI Usage";
|
|
1953
|
+
else if (stats.source === "combined") title = "AI Coding Usage (Claude + Codex)";
|
|
1954
|
+
}
|
|
1874
1955
|
console.log(`${c.orange}${c.bold}${title} - Summary${c.reset}`);
|
|
1875
1956
|
console.log(`${c.gray}Date range: ${stats.dateRange.start} to ${stats.dateRange.end}${c.reset}`);
|
|
1876
1957
|
if (stats.sessionCounts) {
|
|
@@ -1959,7 +2040,7 @@ async function findJsonlFiles2(dir) {
|
|
|
1959
2040
|
}
|
|
1960
2041
|
return files;
|
|
1961
2042
|
}
|
|
1962
|
-
async function parseSessionFile(filePath) {
|
|
2043
|
+
async function parseSessionFile(filePath, families) {
|
|
1963
2044
|
try {
|
|
1964
2045
|
const content = await fs3.readFile(filePath, "utf-8");
|
|
1965
2046
|
const lines = content.trim().split("\n");
|
|
@@ -2014,7 +2095,12 @@ async function parseSessionFile(filePath) {
|
|
|
2014
2095
|
};
|
|
2015
2096
|
let primaryModel = "gpt-5";
|
|
2016
2097
|
let maxTokens = 0;
|
|
2098
|
+
let matchedModel = false;
|
|
2017
2099
|
for (const [model, usage] of Object.entries(perModelUsage)) {
|
|
2100
|
+
if (!matchesModelFamilies(model, families)) {
|
|
2101
|
+
continue;
|
|
2102
|
+
}
|
|
2103
|
+
matchedModel = true;
|
|
2018
2104
|
summedUsage.input_tokens += usage.input_tokens;
|
|
2019
2105
|
summedUsage.cached_input_tokens += usage.cached_input_tokens;
|
|
2020
2106
|
summedUsage.output_tokens += usage.output_tokens;
|
|
@@ -2025,6 +2111,9 @@ async function parseSessionFile(filePath) {
|
|
|
2025
2111
|
primaryModel = model;
|
|
2026
2112
|
}
|
|
2027
2113
|
}
|
|
2114
|
+
if (families && families.length > 0 && !matchedModel) {
|
|
2115
|
+
return null;
|
|
2116
|
+
}
|
|
2028
2117
|
return {
|
|
2029
2118
|
id: sessionMeta.id,
|
|
2030
2119
|
canonicalId: canonicalId || sessionMeta.id,
|
|
@@ -2039,7 +2128,7 @@ async function parseSessionFile(filePath) {
|
|
|
2039
2128
|
return null;
|
|
2040
2129
|
}
|
|
2041
2130
|
}
|
|
2042
|
-
async function loadCodexStats() {
|
|
2131
|
+
async function loadCodexStats(options = {}) {
|
|
2043
2132
|
const codexDir = getCodexDir2();
|
|
2044
2133
|
if (!await codexDataExists()) {
|
|
2045
2134
|
return null;
|
|
@@ -2056,7 +2145,7 @@ async function loadCodexStats() {
|
|
|
2056
2145
|
}
|
|
2057
2146
|
const sessions = [];
|
|
2058
2147
|
for (const file of jsonlFiles) {
|
|
2059
|
-
const session = await parseSessionFile(file);
|
|
2148
|
+
const session = await parseSessionFile(file, options.families);
|
|
2060
2149
|
if (session) {
|
|
2061
2150
|
sessions.push(session);
|
|
2062
2151
|
}
|
|
@@ -2141,17 +2230,17 @@ async function loadCodexStats() {
|
|
|
2141
2230
|
|
|
2142
2231
|
// src/shared/data-loader.ts
|
|
2143
2232
|
async function loadData(options) {
|
|
2144
|
-
const { codexOnly, combined } = options;
|
|
2233
|
+
const { codexOnly, combined, families } = options;
|
|
2145
2234
|
let claude = null;
|
|
2146
2235
|
let codex = null;
|
|
2147
2236
|
if (!codexOnly) {
|
|
2148
2237
|
if (await claudeCompatibleDataExists()) {
|
|
2149
|
-
claude = await loadClaudeStatsFromJsonl();
|
|
2238
|
+
claude = await loadClaudeStatsFromJsonl({ families });
|
|
2150
2239
|
}
|
|
2151
2240
|
}
|
|
2152
2241
|
if (codexOnly || combined) {
|
|
2153
2242
|
if (await codexDataExists()) {
|
|
2154
|
-
codex = await loadCodexStats();
|
|
2243
|
+
codex = await loadCodexStats({ families });
|
|
2155
2244
|
}
|
|
2156
2245
|
}
|
|
2157
2246
|
let source = "claude";
|
|
@@ -2161,14 +2250,15 @@ async function loadData(options) {
|
|
|
2161
2250
|
}
|
|
2162
2251
|
function validateData(data, options) {
|
|
2163
2252
|
if (!data.claude && !data.codex) {
|
|
2253
|
+
const familyPrefix = options.scopeLabel ? `${options.scopeLabel} ` : "";
|
|
2164
2254
|
if (options.codexOnly) {
|
|
2165
2255
|
console.error("Error: OpenAI Codex data not found at ~/.codex");
|
|
2166
2256
|
console.error("Make sure you have used the Codex CLI at least once.");
|
|
2167
2257
|
} else if (options.combined) {
|
|
2168
|
-
console.error(
|
|
2258
|
+
console.error(`Error: No ${familyPrefix}usage data found`);
|
|
2169
2259
|
console.error("Make sure you have used a supported local CLI source such as Claude Code, OpenCode, Droid, or Codex at least once.");
|
|
2170
2260
|
} else {
|
|
2171
|
-
console.error(
|
|
2261
|
+
console.error(`Error: No ${familyPrefix}usage data found`);
|
|
2172
2262
|
console.error("Checked ~/.claude, ~/.local/share/opencode/opencode.db, and ~/.factory/sessions.");
|
|
2173
2263
|
}
|
|
2174
2264
|
process.exit(1);
|
|
@@ -2299,6 +2389,7 @@ function getDisplayModelTokens(modelUsage) {
|
|
|
2299
2389
|
if (shouldExcludeModel(modelName)) continue;
|
|
2300
2390
|
const displayName = getModelDisplayName(modelName);
|
|
2301
2391
|
const modelTokens = getUsageTokens(usage);
|
|
2392
|
+
if (modelTokens <= 0) continue;
|
|
2302
2393
|
aggregated.set(displayName, (aggregated.get(displayName) || 0) + modelTokens);
|
|
2303
2394
|
}
|
|
2304
2395
|
return Array.from(aggregated.entries()).map(([model, tokens]) => ({ model, tokens })).sort((a, b) => b.tokens - a.tokens);
|
|
@@ -2320,6 +2411,7 @@ function getCodexDisplayModelTokens(modelUsage) {
|
|
|
2320
2411
|
for (const [modelName, usage] of Object.entries(modelUsage)) {
|
|
2321
2412
|
const displayName = getCodexModelDisplayName(modelName);
|
|
2322
2413
|
const modelTokens = usage.inputTokens + usage.outputTokens;
|
|
2414
|
+
if (modelTokens <= 0) continue;
|
|
2323
2415
|
aggregated.set(displayName, (aggregated.get(displayName) || 0) + modelTokens);
|
|
2324
2416
|
}
|
|
2325
2417
|
return Array.from(aggregated.entries()).map(([model, tokens]) => ({ model, tokens })).sort((a, b) => b.tokens - a.tokens);
|
|
@@ -2533,14 +2625,16 @@ function formatCount2(n) {
|
|
|
2533
2625
|
function displayWrappedStats(stats, url, options) {
|
|
2534
2626
|
const c = getColors2(options?.theme);
|
|
2535
2627
|
console.log();
|
|
2536
|
-
let title = "\u2728 Claude Code Wrapped 2025 \u2728";
|
|
2628
|
+
let title = stats.scopeLabel ? `\u2728 ${stats.scopeLabel} Wrapped 2025 \u2728` : "\u2728 Claude Code Wrapped 2025 \u2728";
|
|
2537
2629
|
let sourceLabel = "";
|
|
2538
|
-
if (stats.
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
|
|
2630
|
+
if (!stats.scopeLabel) {
|
|
2631
|
+
if (stats.source === "codex") {
|
|
2632
|
+
title = "\u2728 Codex CLI Wrapped 2025 \u2728";
|
|
2633
|
+
sourceLabel = " (Codex)";
|
|
2634
|
+
} else if (stats.source === "combined") {
|
|
2635
|
+
title = "\u2728 AI Coding Wrapped 2025 \u2728";
|
|
2636
|
+
sourceLabel = " (Claude + Codex)";
|
|
2637
|
+
}
|
|
2544
2638
|
}
|
|
2545
2639
|
console.log(`${c.orange}${c.bold}\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557${c.reset}`);
|
|
2546
2640
|
console.log(`${c.orange}${c.bold}\u2551${c.reset} ${c.orange}${c.bold}\u2551${c.reset}`);
|
|
@@ -2928,6 +3022,26 @@ function resolveOptions(cliArgs, config) {
|
|
|
2928
3022
|
};
|
|
2929
3023
|
}
|
|
2930
3024
|
|
|
3025
|
+
// src/shared/args.ts
|
|
3026
|
+
var modelFamilyArgs = {
|
|
3027
|
+
kimi: {
|
|
3028
|
+
type: "boolean",
|
|
3029
|
+
description: "Show only Kimi family stats across local usage sources",
|
|
3030
|
+
default: false
|
|
3031
|
+
},
|
|
3032
|
+
minimax: {
|
|
3033
|
+
type: "boolean",
|
|
3034
|
+
description: "Show only MiniMax family stats across local usage sources",
|
|
3035
|
+
default: false
|
|
3036
|
+
}
|
|
3037
|
+
};
|
|
3038
|
+
function getSelectedModelFamilies(args) {
|
|
3039
|
+
const families = [];
|
|
3040
|
+
if (args.kimi === true) families.push("kimi");
|
|
3041
|
+
if (args.minimax === true) families.push("minimax");
|
|
3042
|
+
return families;
|
|
3043
|
+
}
|
|
3044
|
+
|
|
2931
3045
|
// src/index.ts
|
|
2932
3046
|
function createSpinner(label = "Loading vibestats...") {
|
|
2933
3047
|
const spinnerFrames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
@@ -3071,7 +3185,7 @@ async function publishArtifactWithFallback(artifact, baseUrl, fallbackUrl, prefe
|
|
|
3071
3185
|
var main = defineCommand({
|
|
3072
3186
|
meta: {
|
|
3073
3187
|
name: "vibestats",
|
|
3074
|
-
version: "1.3.
|
|
3188
|
+
version: "1.3.10",
|
|
3075
3189
|
description: "AI coding stats - usage tracking and annual wrapped for Claude Code & Codex"
|
|
3076
3190
|
},
|
|
3077
3191
|
args: {
|
|
@@ -3098,6 +3212,7 @@ var main = defineCommand({
|
|
|
3098
3212
|
description: "Show combined Claude Code + Codex stats",
|
|
3099
3213
|
default: false
|
|
3100
3214
|
},
|
|
3215
|
+
...modelFamilyArgs,
|
|
3101
3216
|
// Output format
|
|
3102
3217
|
json: {
|
|
3103
3218
|
type: "boolean",
|
|
@@ -3241,6 +3356,8 @@ var main = defineCommand({
|
|
|
3241
3356
|
}
|
|
3242
3357
|
});
|
|
3243
3358
|
async function runUsage(args, config) {
|
|
3359
|
+
const families = getSelectedModelFamilies(args);
|
|
3360
|
+
const scopeLabel = formatModelFamilyLabel(families);
|
|
3244
3361
|
const requestedSince = args.since;
|
|
3245
3362
|
const requestedUntil = args.until;
|
|
3246
3363
|
const requestedLastDays = parseLastDaysFlag(args);
|
|
@@ -3271,13 +3388,15 @@ async function runUsage(args, config) {
|
|
|
3271
3388
|
until,
|
|
3272
3389
|
codexOnly: args.codex,
|
|
3273
3390
|
combined: args.combined,
|
|
3274
|
-
projectFilter: args.project ? process.cwd() : void 0
|
|
3391
|
+
projectFilter: args.project ? process.cwd() : void 0,
|
|
3392
|
+
families,
|
|
3393
|
+
scopeLabel
|
|
3275
3394
|
})
|
|
3276
3395
|
);
|
|
3277
3396
|
if (!stats) {
|
|
3278
3397
|
if (requestedSince || requestedUntil || requestedLastDays) {
|
|
3279
3398
|
const rangeStr = `${since || "(start)"} to ${until || "(end)"}`;
|
|
3280
|
-
console.error(`Error: No usage data found for date range ${rangeStr}.`);
|
|
3399
|
+
console.error(`Error: No ${scopeLabel ? `${scopeLabel} ` : ""}usage data found for date range ${rangeStr}.`);
|
|
3281
3400
|
if (args.codex) {
|
|
3282
3401
|
console.error("Checked: ~/.codex/sessions and ~/.codex/archived_sessions");
|
|
3283
3402
|
} else if (args.combined) {
|
|
@@ -3292,10 +3411,10 @@ async function runUsage(args, config) {
|
|
|
3292
3411
|
console.error("Error: OpenAI Codex data not found at ~/.codex");
|
|
3293
3412
|
console.error("Make sure you have used the Codex CLI at least once.");
|
|
3294
3413
|
} else if (args.combined) {
|
|
3295
|
-
console.error(
|
|
3414
|
+
console.error(`Error: No ${scopeLabel ? `${scopeLabel} ` : ""}usage data found`);
|
|
3296
3415
|
console.error("Make sure you have used a supported local CLI source such as Claude Code, OpenCode, Droid, or Codex at least once.");
|
|
3297
3416
|
} else {
|
|
3298
|
-
console.error(
|
|
3417
|
+
console.error(`Error: No ${scopeLabel ? `${scopeLabel} ` : ""}usage data found`);
|
|
3299
3418
|
console.error("Checked ~/.claude, ~/.local/share/opencode/opencode.db, and ~/.factory/sessions.");
|
|
3300
3419
|
}
|
|
3301
3420
|
process.exit(1);
|
|
@@ -3343,16 +3462,18 @@ async function runUsage(args, config) {
|
|
|
3343
3462
|
}
|
|
3344
3463
|
async function runWrapped(args, config) {
|
|
3345
3464
|
const options = resolveOptions(args, config);
|
|
3465
|
+
const families = getSelectedModelFamilies(args);
|
|
3466
|
+
const scopeLabel = formatModelFamilyLabel(families);
|
|
3346
3467
|
const metric = parseActivityMetric(args.metric);
|
|
3347
3468
|
const days = parseActivityDays(args.days);
|
|
3348
3469
|
const spinner = createSpinner("Preparing wrapped...");
|
|
3349
3470
|
const [data, activityStats] = await spinner.whilePromise(
|
|
3350
3471
|
Promise.all([
|
|
3351
|
-
loadData({ codexOnly: args.codex, combined: args.combined }),
|
|
3352
|
-
loadActivityStats({ codexOnly: args.codex, combined: args.combined })
|
|
3472
|
+
loadData({ codexOnly: args.codex, combined: args.combined, families, scopeLabel }),
|
|
3473
|
+
loadActivityStats({ codexOnly: args.codex, combined: args.combined, families, scopeLabel })
|
|
3353
3474
|
])
|
|
3354
3475
|
);
|
|
3355
|
-
validateData(data, { codexOnly: args.codex, combined: args.combined });
|
|
3476
|
+
validateData(data, { codexOnly: args.codex, combined: args.combined, families, scopeLabel });
|
|
3356
3477
|
let claudeStats = null;
|
|
3357
3478
|
let codexStats = null;
|
|
3358
3479
|
if (data.claude) {
|
|
@@ -3369,6 +3490,9 @@ async function runWrapped(args, config) {
|
|
|
3369
3490
|
} else {
|
|
3370
3491
|
stats = claudeStats;
|
|
3371
3492
|
}
|
|
3493
|
+
if (scopeLabel) {
|
|
3494
|
+
stats.scopeLabel = scopeLabel;
|
|
3495
|
+
}
|
|
3372
3496
|
if (activityStats) {
|
|
3373
3497
|
stats.activity = buildActivityGraph(activityStats, metric, days);
|
|
3374
3498
|
}
|
|
@@ -3404,6 +3528,8 @@ async function runWrapped(args, config) {
|
|
|
3404
3528
|
}
|
|
3405
3529
|
}
|
|
3406
3530
|
async function runActivity(args, config) {
|
|
3531
|
+
const families = getSelectedModelFamilies(args);
|
|
3532
|
+
const scopeLabel = formatModelFamilyLabel(families);
|
|
3407
3533
|
const metric = parseActivityMetric(args.metric);
|
|
3408
3534
|
const days = parseActivityDays(args.days);
|
|
3409
3535
|
const spinner = createSpinner("Preparing activity graph...");
|
|
@@ -3413,11 +3539,13 @@ async function runActivity(args, config) {
|
|
|
3413
3539
|
combined: args.combined,
|
|
3414
3540
|
projectFilter: args.project ? process.cwd() : void 0,
|
|
3415
3541
|
since: args.since,
|
|
3416
|
-
until: args.until
|
|
3542
|
+
until: args.until,
|
|
3543
|
+
families,
|
|
3544
|
+
scopeLabel
|
|
3417
3545
|
})
|
|
3418
3546
|
);
|
|
3419
3547
|
if (!stats) {
|
|
3420
|
-
console.error(
|
|
3548
|
+
console.error(`Error: No ${scopeLabel ? `${scopeLabel} ` : ""}activity data found.`);
|
|
3421
3549
|
process.exit(1);
|
|
3422
3550
|
}
|
|
3423
3551
|
const artifact = buildActivityArtifact(stats, metric, days);
|