@ipv9/tokentracker-cli 0.39.50 → 0.39.52

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.
Files changed (43) hide show
  1. package/README.md +7 -14
  2. package/dashboard/dist/assets/{Card-G3yjiaQ3.js → Card-CEz9362Q.js} +1 -1
  3. package/dashboard/dist/assets/DashboardPage-BEzDx9x_.js +60 -0
  4. package/dashboard/dist/assets/{IpCheckPage-DsTJ2UMw.js → IpCheckPage-COYl0L0c.js} +1 -1
  5. package/dashboard/dist/assets/LimitsPage-CxKP9yCf.js +2 -0
  6. package/dashboard/dist/assets/LocalOnlyNotice-mkvVeaxU.js +1 -0
  7. package/dashboard/dist/assets/PopoverPopup-CcXnjekJ.js +1 -0
  8. package/dashboard/dist/assets/Select-DfLcXuzD.js +1 -0
  9. package/dashboard/dist/assets/SettingsPage-BKATdxHm.js +1 -0
  10. package/dashboard/dist/assets/SkillsPage-BCS1cw7N.js +1 -0
  11. package/dashboard/dist/assets/{WrappedPage-D1BDK0Ph.js → WrappedPage-BZMXgdYx.js} +1 -1
  12. package/dashboard/dist/assets/{format-C3ekCmoV.js → format-DXnZAXRS.js} +1 -1
  13. package/dashboard/dist/assets/limitDisplay-Dkfaklpc.js +1 -0
  14. package/dashboard/dist/assets/main-C7rJ1TVR.css +1 -0
  15. package/dashboard/dist/assets/main-Dft1sGV7.js +610 -0
  16. package/dashboard/dist/assets/{mock-data-C1NPjE59.js → mock-data-u9UDfqcX.js} +1 -1
  17. package/dashboard/dist/assets/use-limits-display-prefs-Nj1Nil2m.js +1 -0
  18. package/dashboard/dist/assets/useCurrency-BxAIQJRl.js +12 -0
  19. package/dashboard/dist/index.html +2 -18
  20. package/package.json +4 -6
  21. package/src/cli.js +1 -1
  22. package/src/commands/sync.js +4 -0
  23. package/src/lib/local-api.js +35 -10
  24. package/src/lib/pricing/seed-snapshot.json +1 -1
  25. package/src/lib/rollout.js +429 -27
  26. package/dashboard/dist/assets/DashboardPage-p9US1mNh.js +0 -60
  27. package/dashboard/dist/assets/FadeIn-Bcqp5CE1.js +0 -1
  28. package/dashboard/dist/assets/LimitsPage-Dh7MA0MN.js +0 -2
  29. package/dashboard/dist/assets/LocalOnlyNotice-TF43yZEk.js +0 -1
  30. package/dashboard/dist/assets/PopoverPopup-BTJTO2ZT.js +0 -1
  31. package/dashboard/dist/assets/Select-_DHMSUO0.js +0 -1
  32. package/dashboard/dist/assets/SelectItemText-CFGxP_cw.js +0 -12
  33. package/dashboard/dist/assets/SettingsPage-CbHgbVTV.js +0 -1
  34. package/dashboard/dist/assets/SkillsPage-Pbf_dSEd.js +0 -1
  35. package/dashboard/dist/assets/WidgetsPage-DdncxT2a.js +0 -1
  36. package/dashboard/dist/assets/arrow-up-right-BAE7-yZI.js +0 -1
  37. package/dashboard/dist/assets/download-CwfCmvh_.js +0 -1
  38. package/dashboard/dist/assets/limitDisplay-DhC8fM_W.js +0 -1
  39. package/dashboard/dist/assets/main-rZD26_5f.js +0 -700
  40. package/dashboard/dist/assets/main-t7dbBL4x.css +0 -1
  41. package/dashboard/dist/assets/use-limits-display-prefs-vLrVb6Bn.js +0 -1
  42. package/dashboard/dist/assets/use-native-settings-B8qCQ9aO.js +0 -1
  43. package/dashboard/dist/assets/useCurrency-MOYNpGd7.js +0 -1
@@ -201,6 +201,20 @@ function normalizeQueueRow(row) {
201
201
  return normalized;
202
202
  }
203
203
 
204
+ function hasHermesAuthoritativeCost(row) {
205
+ const cost = Number(row?.actual_cost_usd);
206
+ return (
207
+ String(row?.source || "").toLowerCase() === "hermes" &&
208
+ row?.cost_provenance === "hermes-actual" &&
209
+ Number.isFinite(cost) &&
210
+ cost >= 0
211
+ );
212
+ }
213
+
214
+ function resolveQueueRowCost(row) {
215
+ return hasHermesAuthoritativeCost(row) ? Number(row.actual_cost_usd) : computeRowCost(row);
216
+ }
217
+
204
218
  function readQueueData(queuePath) {
205
219
  let raw;
206
220
  try {
@@ -278,7 +292,7 @@ function aggregateByDay(rows, timeZoneContext = null) {
278
292
  const a = byDay.get(day);
279
293
  a.total_tokens += row.total_tokens || 0;
280
294
  a.billable_total_tokens += row.billable_total_tokens ?? row.total_tokens ?? 0;
281
- a.total_cost_usd += computeRowCost(row);
295
+ a.total_cost_usd += resolveQueueRowCost(row);
282
296
  a.input_tokens += row.input_tokens || 0;
283
297
  a.output_tokens += row.output_tokens || 0;
284
298
  a.cached_input_tokens += row.cached_input_tokens || 0;
@@ -502,7 +516,7 @@ function aggregateHourlyByDay(rows, dayKey, timeZoneContext) {
502
516
  const bucket = byHour.get(hourKey);
503
517
  bucket.total_tokens += row.total_tokens || 0;
504
518
  bucket.billable_total_tokens += row.total_tokens || 0;
505
- bucket.total_cost_usd += computeRowCost(row);
519
+ bucket.total_cost_usd += resolveQueueRowCost(row);
506
520
  bucket.input_tokens += row.input_tokens || 0;
507
521
  bucket.output_tokens += row.output_tokens || 0;
508
522
  bucket.cached_input_tokens += row.cached_input_tokens || 0;
@@ -1418,8 +1432,10 @@ function createLocalApiHandler({ queuePath }) {
1418
1432
  for (const row of rows) {
1419
1433
  const src = row.source || "unknown";
1420
1434
  const mdl = row.model || "unknown";
1435
+ const rowCost = resolveQueueRowCost(row);
1436
+ const rowUsesAuthoritativeCost = hasHermesAuthoritativeCost(row);
1421
1437
  if (!bySource.has(src))
1422
- bySource.set(src, { source: src, source_scope: getSourceScope(src), totals: { total_tokens: 0, billable_total_tokens: 0, input_tokens: 0, output_tokens: 0, cached_input_tokens: 0, cache_creation_input_tokens: 0, reasoning_output_tokens: 0, total_cost_usd: "0" }, models: new Map() });
1438
+ bySource.set(src, { source: src, source_scope: getSourceScope(src), totals: { total_tokens: 0, billable_total_tokens: 0, input_tokens: 0, output_tokens: 0, cached_input_tokens: 0, cache_creation_input_tokens: 0, reasoning_output_tokens: 0, total_cost_usd: 0 }, models: new Map() });
1423
1439
  const sa = bySource.get(src);
1424
1440
  sa.totals.total_tokens += row.total_tokens || 0;
1425
1441
  sa.totals.billable_total_tokens += row.billable_total_tokens ?? row.total_tokens ?? 0;
@@ -1428,8 +1444,9 @@ function createLocalApiHandler({ queuePath }) {
1428
1444
  sa.totals.cached_input_tokens += row.cached_input_tokens || 0;
1429
1445
  sa.totals.cache_creation_input_tokens += row.cache_creation_input_tokens || 0;
1430
1446
  sa.totals.reasoning_output_tokens += row.reasoning_output_tokens || 0;
1447
+ sa.totals.total_cost_usd += rowCost;
1431
1448
  if (!sa.models.has(mdl))
1432
- sa.models.set(mdl, { model: mdl, model_id: mdl, totals: { total_tokens: 0, billable_total_tokens: 0, input_tokens: 0, output_tokens: 0, cached_input_tokens: 0, cache_creation_input_tokens: 0, reasoning_output_tokens: 0, total_cost_usd: "0" } });
1449
+ sa.models.set(mdl, { model: mdl, model_id: mdl, authoritative_cost_rows: 0, estimated_cost_rows: 0, totals: { total_tokens: 0, billable_total_tokens: 0, input_tokens: 0, output_tokens: 0, cached_input_tokens: 0, cache_creation_input_tokens: 0, reasoning_output_tokens: 0, total_cost_usd: 0 } });
1433
1450
  const ma = sa.models.get(mdl);
1434
1451
  ma.totals.total_tokens += row.total_tokens || 0;
1435
1452
  ma.totals.billable_total_tokens += row.billable_total_tokens ?? row.total_tokens ?? 0;
@@ -1438,22 +1455,30 @@ function createLocalApiHandler({ queuePath }) {
1438
1455
  ma.totals.cached_input_tokens += row.cached_input_tokens || 0;
1439
1456
  ma.totals.cache_creation_input_tokens += row.cache_creation_input_tokens || 0;
1440
1457
  ma.totals.reasoning_output_tokens += row.reasoning_output_tokens || 0;
1458
+ ma.totals.total_cost_usd += rowCost;
1459
+ if (rowUsesAuthoritativeCost) ma.authoritative_cost_rows += 1;
1460
+ else ma.estimated_cost_rows += 1;
1441
1461
  }
1442
1462
 
1443
1463
  const sources = Array.from(bySource.values()).map((s) => {
1444
1464
  s.models = Array.from(s.models.values())
1445
1465
  .map((m) => {
1446
- const cost = computeRowCost({
1447
- ...m.totals,
1448
- model: m.model,
1449
- source: s.source,
1450
- });
1466
+ const cost = Number(m.totals.total_cost_usd || 0);
1467
+ const costProvenance =
1468
+ m.authoritative_cost_rows > 0 && m.estimated_cost_rows === 0
1469
+ ? "hermes-actual"
1470
+ : m.authoritative_cost_rows > 0
1471
+ ? "mixed"
1472
+ : "estimated";
1451
1473
  // How the price was resolved, so the dashboard can say "unpriced"
1452
1474
  // or "matched by substring" instead of inferring it from a $0 cost
1453
1475
  // — a genuinely free model and an unknown one both cost $0.
1454
- const { tier } = getModelPricingMeta(m.model, { source: s.source });
1476
+ const tier = costProvenance === "hermes-actual"
1477
+ ? "hermes:actual"
1478
+ : getModelPricingMeta(m.model, { source: s.source }).tier;
1455
1479
  return {
1456
1480
  ...m,
1481
+ cost_provenance: costProvenance,
1457
1482
  pricing_tier: tier,
1458
1483
  totals: { ...m.totals, total_cost_usd: cost.toFixed(6) },
1459
1484
  };