tokmon 0.17.0 → 0.18.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.
@@ -5,7 +5,7 @@ import {
5
5
  cacheDir,
6
6
  detectProviders,
7
7
  resolveTimezone
8
- } from "./chunk-TLE24LIH.js";
8
+ } from "./chunk-UAPL47GL.js";
9
9
 
10
10
  // src/web/server.ts
11
11
  import { createServer } from "http";
@@ -52,9 +52,6 @@ async function resolveAccounts(config) {
52
52
  const p = PROVIDERS[a.providerId];
53
53
  return {
54
54
  account: a,
55
- // Web-only: a provider with a usage table (e.g. Cursor's local composer history)
56
- // shows in the dashboard's leaderboard/calendar/explore even when its TUI flag is
57
- // false. The TUI reads PROVIDERS[id].hasUsage directly, so it is unaffected.
58
55
  hasUsage: p.hasUsage || !!p.fetchTable,
59
56
  hasBilling: p.hasBilling,
60
57
  color: colorHex(a.color, PROVIDERS[a.providerId].color)
@@ -1524,11 +1524,9 @@ async function cursorApiUsage(tz, homeDir) {
1524
1524
  const endMs = Date.now();
1525
1525
  const startMs = endMs - WINDOW_DAYS * 864e5;
1526
1526
  const events = [];
1527
- let total = Infinity;
1528
- for (let page = 1; page <= MAX_PAGES && events.length < total; page++) {
1527
+ for (let page = 1; page <= MAX_PAGES; page++) {
1529
1528
  const resp = await fetchPage(token, startMs, endMs, page);
1530
1529
  if (!resp) return page === 1 ? null : finalizeTable(events, tz);
1531
- total = resp.totalUsageEventsCount ?? 0;
1532
1530
  const batch = resp.usageEventsDisplay ?? [];
1533
1531
  events.push(...batch);
1534
1532
  if (batch.length < PAGE_SIZE) break;
@@ -1566,10 +1564,11 @@ function finalizeTable(events, tz) {
1566
1564
  const ts = Number(e.timestamp);
1567
1565
  if (!Number.isFinite(ts) || ts <= 0) continue;
1568
1566
  const tu = e.tokenUsage ?? {};
1569
- const input = Number(tu.inputTokens) || 0;
1570
- const output = Number(tu.outputTokens) || 0;
1571
- const cacheRead = Number(tu.cacheReadTokens) || 0;
1572
- const usd = (Number(e.chargedCents) || 0) / 100;
1567
+ const input = safeNum(tu.inputTokens);
1568
+ const output = safeNum(tu.outputTokens);
1569
+ const cacheRead = safeNum(tu.cacheReadTokens);
1570
+ const cents = Number(e.chargedCents);
1571
+ const usd = Number.isFinite(cents) && cents > 0 ? cents / 100 : 0;
1573
1572
  if (usd <= 0 && input + output + cacheRead === 0) continue;
1574
1573
  const model = String(e.model ?? "unknown");
1575
1574
  put(buckets.daily, dayKey(ts, tz), model, usd, input, output, cacheRead);
@@ -1587,16 +1586,62 @@ function finalizeTable(events, tz) {
1587
1586
 
1588
1587
  // src/providers/cursor/index.ts
1589
1588
  var EMPTY = { daily: [], weekly: [], monthly: [] };
1589
+ var overlayDaily = (lo, hi) => {
1590
+ const m = new Map(lo.map((r) => [r.label, r]));
1591
+ for (const r of hi) m.set(r.label, r);
1592
+ return [...m.values()].sort((a, b) => a.label.localeCompare(b.label));
1593
+ };
1594
+ function reBucket(daily, tz, keyOf) {
1595
+ const out = /* @__PURE__ */ new Map();
1596
+ for (const day of daily) {
1597
+ const [y, mo, d] = day.label.split("-").map(Number);
1598
+ const label = keyOf(Date.UTC(y, mo - 1, d, 12), tz);
1599
+ let row = out.get(label);
1600
+ if (!row) {
1601
+ row = { label, models: [], input: 0, output: 0, cacheCreate: 0, cacheRead: 0, cacheSavings: 0, total: 0, cost: 0, count: 0, breakdown: [] };
1602
+ out.set(label, row);
1603
+ }
1604
+ row.input += day.input;
1605
+ row.output += day.output;
1606
+ row.cacheCreate += day.cacheCreate;
1607
+ row.cacheRead += day.cacheRead;
1608
+ row.cacheSavings += day.cacheSavings;
1609
+ row.total += day.total;
1610
+ row.cost += day.cost;
1611
+ row.count += day.count;
1612
+ for (const b of day.breakdown) {
1613
+ let md = row.breakdown.find((x) => x.name === b.name);
1614
+ if (!md) {
1615
+ md = { name: b.name, input: 0, output: 0, cacheCreate: 0, cacheRead: 0, cacheSavings: 0, cost: 0, count: 0 };
1616
+ row.breakdown.push(md);
1617
+ }
1618
+ md.input += b.input;
1619
+ md.output += b.output;
1620
+ md.cacheCreate += b.cacheCreate;
1621
+ md.cacheRead += b.cacheRead;
1622
+ md.cacheSavings += b.cacheSavings;
1623
+ md.cost += b.cost;
1624
+ md.count += b.count;
1625
+ }
1626
+ }
1627
+ return [...out.values()].map((r) => {
1628
+ r.breakdown.sort((a, b) => b.cost - a.cost);
1629
+ r.models = r.breakdown.map((b) => b.name);
1630
+ return r;
1631
+ }).sort((a, b) => a.label.localeCompare(b.label));
1632
+ }
1590
1633
  async function cursorTable(tz, homeDir) {
1591
- return await cursorApiUsage(tz, homeDir) ?? await cursorUsageTable(tz, homeDir) ?? EMPTY;
1634
+ const [api, local] = await Promise.all([cursorApiUsage(tz, homeDir), cursorUsageTable(tz, homeDir)]);
1635
+ if (!api && !local) return EMPTY;
1636
+ const daily = overlayDaily(local?.daily ?? [], api?.daily ?? []);
1637
+ if (daily.length === 0) return EMPTY;
1638
+ return { daily, weekly: reBucket(daily, tz, weekKey), monthly: reBucket(daily, tz, monthKey) };
1592
1639
  }
1593
1640
  var cursorProvider = {
1594
1641
  id: "cursor",
1595
1642
  name: "Cursor",
1596
1643
  color: "magenta",
1597
- // hasUsage stays false: the TUI keys its dedicated Cursor spend-table off this flag.
1598
- // The web surfaces the usage table via fetchTable (resolveAccounts promotes any
1599
- // provider with a fetchTable to hasUsage for the dashboard only).
1644
+ // hasUsage: false TUI keys its dedicated Cursor spend-table off this flag directly.
1600
1645
  hasUsage: false,
1601
1646
  hasBilling: true,
1602
1647
  detect: (homeDir) => detectCursor(homeDir),
package/dist/cli.js CHANGED
@@ -23,7 +23,7 @@ import {
23
23
  systemTimezone,
24
24
  time,
25
25
  tokens
26
- } from "./chunk-TLE24LIH.js";
26
+ } from "./chunk-UAPL47GL.js";
27
27
 
28
28
  // src/cli.tsx
29
29
  import { EventEmitter } from "events";
@@ -1606,11 +1606,7 @@ function App({ interval: cliInterval, initialConfig }) {
1606
1606
  const hasStrip = slots.length > 1;
1607
1607
  const stripChipW = (s) => 2 + 2 + truncateName(s.name, 16).length + 2;
1608
1608
  const stripChars = slots.reduce((sum, s) => sum + stripChipW(s), 0);
1609
- const stripLines = hasStrip ? Math.max(1, Math.ceil(stripChars / Math.max(
1610
- 1,
1611
- cols - 4 - 7
1612
- /*"focus "*/
1613
- ))) : 0;
1609
+ const stripLines = hasStrip ? Math.max(1, Math.ceil(stripChars / Math.max(1, cols - 4 - 7))) : 0;
1614
1610
  const headerRows = cols < 70 ? 2 : 1;
1615
1611
  const CHROME = 2 + headerRows + 3 + (hasStrip ? 1 + stripLines : 0) + 2 + 2;
1616
1612
  const gridBudget = Math.max(1, rows - CHROME);
@@ -1856,7 +1852,6 @@ function App({ interval: cliInterval, initialConfig }) {
1856
1852
  function toggleProvider(pid) {
1857
1853
  updateConfig((c) => ({
1858
1854
  ...c,
1859
- // Toggling in settings is also an explicit decision → mark it known.
1860
1855
  knownProviders: c.knownProviders.includes(pid) ? c.knownProviders : [...c.knownProviders, pid],
1861
1856
  disabledProviders: c.disabledProviders.includes(pid) ? c.disabledProviders.filter((p) => p !== pid) : [...c.disabledProviders, pid]
1862
1857
  }));
@@ -1996,7 +1991,7 @@ function App({ interval: cliInterval, initialConfig }) {
1996
1991
  setWebStatus("off");
1997
1992
  } else {
1998
1993
  setWebStatus("starting");
1999
- const { startWebServer } = await import("./server-UPX3ANBP.js");
1994
+ const { startWebServer } = await import("./server-VMB5ZLZC.js");
2000
1995
  const ctrl = await startWebServer({ config: cfg, log: false });
2001
1996
  webRef.current = ctrl;
2002
1997
  setWebUrl(ctrl.url);
@@ -2674,7 +2669,7 @@ process.emitWarning = ((warning, ...rest) => {
2674
2669
  var args = process.argv.slice(2);
2675
2670
  var subcommand = args[0]?.toLowerCase();
2676
2671
  if (subcommand === "serve" || subcommand === "web") {
2677
- const { startWeb } = await import("./web-23FJCFDS.js");
2672
+ const { startWeb } = await import("./web-DYAEMCAE.js");
2678
2673
  await startWeb(args.slice(1));
2679
2674
  process.exit(typeof process.exitCode === "number" ? process.exitCode : 0);
2680
2675
  }
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  startWebServer
4
- } from "./chunk-ZZ7DIK3O.js";
5
- import "./chunk-TLE24LIH.js";
4
+ } from "./chunk-STCMWCFW.js";
5
+ import "./chunk-UAPL47GL.js";
6
6
  export {
7
7
  startWebServer
8
8
  };