tokmon 0.12.3 → 0.12.5

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 (2) hide show
  1. package/dist/cli.js +89 -90
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -484,8 +484,9 @@ async function fetchUsage(token) {
484
484
  resetsAt: formatReset(data.seven_day_sonnet.resets_at)
485
485
  } : null,
486
486
  extraUsage: data.extra_usage?.is_enabled ? {
487
- limit: data.extra_usage.monthly_limit / 100,
488
- used: data.extra_usage.used_credits / 100
487
+ limit: data.extra_usage.monthly_limit != null ? data.extra_usage.monthly_limit / 100 : null,
488
+ used: (data.extra_usage.used_credits ?? 0) / 100,
489
+ currency: data.extra_usage.currency ?? "USD"
489
490
  } : null
490
491
  }
491
492
  };
@@ -641,13 +642,15 @@ function App({ interval: cliInterval }) {
641
642
  });
642
643
  }, []);
643
644
  const billingMs = cfg.billingInterval * 6e4;
644
- const slotIdsKey = (activeSlot.id === null && cfg.accounts.length > 0 ? slots.slice(1) : [activeSlot]).map((s) => s.id ?? "__default__").join(",");
645
+ const configReady = config2 !== null;
646
+ const accountsKey = cfg.accounts.map((a) => `${a.id}:${a.homeDir}`).join("|");
647
+ const dataSlotsRef = useRef([]);
648
+ dataSlotsRef.current = cfg.accounts.length > 0 ? slots.slice(1) : slots;
645
649
  useEffect(() => {
646
- if (!config2) return;
650
+ if (!configReady) return;
647
651
  let active = true;
648
- const slotsToLoad = activeSlot.id === null && cfg.accounts.length > 0 ? slots.slice(1) : [activeSlot];
649
652
  const load = async () => {
650
- await Promise.all(slotsToLoad.map(async (slot) => {
653
+ await Promise.all(dataSlotsRef.current.map(async (slot) => {
651
654
  try {
652
655
  const dashboard = await fetchDashboard(tz, slot.homeDir);
653
656
  if (!active) return;
@@ -672,13 +675,12 @@ function App({ interval: cliInterval }) {
672
675
  active = false;
673
676
  clearInterval(id);
674
677
  };
675
- }, [interval2, tz, config2, slotIdsKey]);
678
+ }, [interval2, tz, configReady, accountsKey]);
676
679
  useEffect(() => {
677
- if (!config2) return;
680
+ if (!configReady) return;
678
681
  let active = true;
679
- const slotsToLoad = activeSlot.id === null && cfg.accounts.length > 0 ? slots.slice(1) : [activeSlot];
680
682
  const load = async () => {
681
- await Promise.all(slotsToLoad.map(async (slot) => {
683
+ await Promise.all(dataSlotsRef.current.map(async (slot) => {
682
684
  try {
683
685
  const billing = await fetchBilling(slot.homeDir);
684
686
  if (!active) return;
@@ -698,7 +700,7 @@ function App({ interval: cliInterval }) {
698
700
  active = false;
699
701
  clearInterval(id);
700
702
  };
701
- }, [billingMs, config2, slotIdsKey]);
703
+ }, [billingMs, configReady, accountsKey]);
702
704
  useEffect(() => {
703
705
  tableLoadedOnce.current = false;
704
706
  setTable(null);
@@ -1155,34 +1157,38 @@ function App({ interval: cliInterval }) {
1155
1157
  activeAccountId: cfg.activeAccountId
1156
1158
  }
1157
1159
  ) : /* @__PURE__ */ jsxs(Fragment, { children: [
1158
- slots.length > 1 && /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(
1159
- AccountStrip,
1160
- {
1161
- slots,
1162
- activeIdx: activeSlotIdx,
1163
- onSelect: (i) => {
1164
- const id = slots[i].id;
1165
- updateConfig((c) => ({ ...c, activeAccountId: id }));
1166
- resetView();
1167
- }
1168
- }
1169
- ) }),
1170
- /* @__PURE__ */ jsxs(Box, { marginTop: slots.length > 1 ? 0 : 1, children: [
1160
+ /* @__PURE__ */ jsxs(Box, { marginTop: 1, marginBottom: 1, children: [
1171
1161
  /* @__PURE__ */ jsx(TabBar, { tabs: TABS, active: tab, onSelect: (i) => {
1172
1162
  setTab(i);
1173
1163
  resetView();
1174
1164
  } }),
1175
1165
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: " Tab/\u2190\u2192" })
1176
1166
  ] }),
1177
- /* @__PURE__ */ jsx(Box, { height: 1 }),
1178
- tab === 0 && /* @__PURE__ */ jsx(
1179
- DashboardView,
1180
- {
1181
- slots: visibleSlots,
1182
- stats,
1183
- compact: visibleSlots.length > 1
1184
- }
1185
- ),
1167
+ tab === 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
1168
+ /* @__PURE__ */ jsx(
1169
+ DashboardView,
1170
+ {
1171
+ slots: visibleSlots,
1172
+ stats,
1173
+ compact: visibleSlots.length > 1
1174
+ }
1175
+ ),
1176
+ slots.length > 1 && /* @__PURE__ */ jsxs(Box, { marginTop: 1, children: [
1177
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "focus " }),
1178
+ /* @__PURE__ */ jsx(
1179
+ AccountStrip,
1180
+ {
1181
+ slots,
1182
+ activeIdx: activeSlotIdx,
1183
+ onSelect: (i) => {
1184
+ const id = slots[i].id;
1185
+ updateConfig((c) => ({ ...c, activeAccountId: id }));
1186
+ resetView();
1187
+ }
1188
+ }
1189
+ )
1190
+ ] })
1191
+ ] }),
1186
1192
  tab === 1 && /* @__PURE__ */ jsxs(Fragment, { children: [
1187
1193
  /* @__PURE__ */ jsx(ViewBar, { views: VIEWS, active: view, sort: SORTS[sort], onSelect: (i) => {
1188
1194
  setView(i);
@@ -1234,12 +1240,13 @@ function AccountStrip({ slots, activeIdx, onSelect }) {
1234
1240
  return /* @__PURE__ */ jsx(Box, { flexWrap: "wrap", children: slots.map((s, i) => {
1235
1241
  const active = i === activeIdx;
1236
1242
  const dot = s.id === null ? "\u2726" : "\u25CF";
1243
+ const label = truncateName(s.name, 16);
1237
1244
  return /* @__PURE__ */ jsxs(ClickableBox, { onClick: () => onSelect(i), marginRight: 2, children: [
1238
1245
  /* @__PURE__ */ jsx(Text, { dimColor: !active, children: i }),
1239
1246
  /* @__PURE__ */ jsx(Text, { children: " " }),
1240
1247
  /* @__PURE__ */ jsx(Text, { color: s.color, bold: active, dimColor: !active, children: dot }),
1241
1248
  /* @__PURE__ */ jsx(Text, { children: " " }),
1242
- active ? /* @__PURE__ */ jsx(Text, { bold: true, color: s.color, children: s.name }) : /* @__PURE__ */ jsx(Text, { dimColor: true, children: s.name })
1249
+ active ? /* @__PURE__ */ jsx(Text, { bold: true, color: s.color, children: label }) : /* @__PURE__ */ jsx(Text, { dimColor: true, children: label })
1243
1250
  ] }, s.id ?? "__all__");
1244
1251
  }) });
1245
1252
  }
@@ -1384,9 +1391,11 @@ function SettingsView({
1384
1391
  isActive ? "\u25CF" : "\u25CB",
1385
1392
  " "
1386
1393
  ] }),
1387
- /* @__PURE__ */ jsx(Box, { width: 16, children: /* @__PURE__ */ jsx(Text, { bold: true, children: acc.name }) }),
1388
- /* @__PURE__ */ jsx(Box, { width: 14, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: acc.id }) }),
1389
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: acc.homeDir })
1394
+ /* @__PURE__ */ jsx(Text, { bold: true, children: truncateName(acc.name, 24) }),
1395
+ /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
1396
+ " ",
1397
+ truncateName(acc.homeDir, 28)
1398
+ ] })
1390
1399
  ] }, acc.id);
1391
1400
  }),
1392
1401
  /* @__PURE__ */ jsxs(Box, { children: [
@@ -1595,35 +1604,18 @@ function DashboardView({ slots, stats, compact: _compact }) {
1595
1604
  borderTop: false,
1596
1605
  borderBottom: false,
1597
1606
  children: [
1598
- /* @__PURE__ */ jsxs(Box, { children: [
1599
- /* @__PURE__ */ jsx(Text, { bold: true, children: "Claude" }),
1600
- isMulti && /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
1601
- " all accounts (",
1602
- items.length,
1603
- ")"
1604
- ] }),
1605
- !isMulti && items[0].slot.id && /* @__PURE__ */ jsxs(Fragment, { children: [
1606
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: " " }),
1607
- /* @__PURE__ */ jsx(Text, { color: items[0].slot.color, children: "\u25CF " }),
1608
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: items[0].slot.name })
1609
- ] })
1610
- ] }),
1611
- /* @__PURE__ */ jsx(Box, { height: 1 }),
1607
+ /* @__PURE__ */ jsx(Text, { bold: true, children: "Claude" }),
1612
1608
  /* @__PURE__ */ jsx(SummaryRow, { label: "Today", summary: agg.today }),
1613
1609
  /* @__PURE__ */ jsx(SummaryRow, { label: "This Week", summary: agg.week }),
1614
1610
  /* @__PURE__ */ jsx(SummaryRow, { label: "This Month", summary: agg.month }),
1615
- agg.burnRate > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
1616
- /* @__PURE__ */ jsx(Box, { height: 1 }),
1617
- /* @__PURE__ */ jsxs(Box, { children: [
1618
- /* @__PURE__ */ jsx(Box, { width: 14, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Burn rate" }) }),
1619
- /* @__PURE__ */ jsx(Box, { width: 12, justifyContent: "flex-end", children: /* @__PURE__ */ jsx(Text, { color: "red", children: currency(agg.burnRate) }) }),
1620
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: "/hr" })
1621
- ] })
1611
+ agg.burnRate > 0 && /* @__PURE__ */ jsxs(Box, { children: [
1612
+ /* @__PURE__ */ jsx(Box, { width: 14, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Burn rate" }) }),
1613
+ /* @__PURE__ */ jsx(Box, { width: 12, justifyContent: "flex-end", children: /* @__PURE__ */ jsx(Text, { color: "red", children: currency(agg.burnRate) }) }),
1614
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "/hr" })
1622
1615
  ] })
1623
1616
  ]
1624
1617
  }
1625
1618
  ),
1626
- /* @__PURE__ */ jsx(Box, { height: 1 }),
1627
1619
  /* @__PURE__ */ jsx(RateLimitsCard, { items })
1628
1620
  ] });
1629
1621
  }
@@ -1671,31 +1663,32 @@ function RateLimitsCard({ items }) {
1671
1663
  borderBottom: false,
1672
1664
  children: [
1673
1665
  /* @__PURE__ */ jsx(Text, { bold: true, children: "Rate Limits" }),
1674
- /* @__PURE__ */ jsx(Box, { height: 1 }),
1675
1666
  !anyData ? anyError ? /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: items.map(({ slot, s }) => s.billing?.error && /* @__PURE__ */ jsxs(Box, { children: [
1676
1667
  /* @__PURE__ */ jsx(Text, { color: slot.color, children: "\u25CF " }),
1677
1668
  /* @__PURE__ */ jsx(Box, { width: 22, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: truncateName(slot.name, 20) }) }),
1678
1669
  /* @__PURE__ */ jsx(Text, { color: "red", children: s.billing.error })
1679
1670
  ] }, slot.id ?? "__default__")) }) : /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Fetching..." }) : /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
1680
- /* @__PURE__ */ jsx(MetricBlock, { label: "Total Usage", sublabel: "5h session", pick: (b) => b?.session, items, showResets: true }),
1681
- /* @__PURE__ */ jsx(MetricBlock, { label: "This Week", sublabel: "7-day", pick: (b) => b?.weekly, items, showResets: true }),
1682
- /* @__PURE__ */ jsx(MetricBlock, { label: "Sonnet", sublabel: "7-day sonnet", pick: (b) => b?.sonnet, items }),
1683
- items.some((i) => i.s.billing?.extraUsage) && /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
1684
- /* @__PURE__ */ jsx(Text, { bold: true, dimColor: true, children: "Extra Usage" }),
1671
+ /* @__PURE__ */ jsx(MetricBlock, { label: "5h", pick: (b) => b?.session, items, showResets: true }),
1672
+ /* @__PURE__ */ jsx(MetricBlock, { label: "Week", pick: (b) => b?.weekly, items, showResets: true }),
1673
+ /* @__PURE__ */ jsx(MetricBlock, { label: "Sonnet", pick: (b) => b?.sonnet, items }),
1674
+ items.some((i) => i.s.billing?.extraUsage) && /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
1675
+ /* @__PURE__ */ jsx(Text, { bold: true, dimColor: true, children: "Extra" }),
1685
1676
  items.map(({ slot, s }) => {
1686
1677
  const e = s.billing?.extraUsage;
1687
1678
  if (!e) return null;
1679
+ const sym = e.currency === "EUR" ? "\u20AC" : "$";
1688
1680
  return /* @__PURE__ */ jsxs(Box, { children: [
1689
1681
  /* @__PURE__ */ jsx(Text, { color: slot.color, children: "\u25CF " }),
1690
1682
  /* @__PURE__ */ jsx(Box, { width: 22, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: truncateName(slot.name, 20) }) }),
1691
1683
  /* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
1692
- "$",
1684
+ sym,
1693
1685
  e.used.toFixed(2)
1694
1686
  ] }),
1695
- /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
1696
- " / $",
1687
+ e.limit != null ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
1688
+ " / ",
1689
+ sym,
1697
1690
  e.limit.toFixed(2)
1698
- ] })
1691
+ ] }) : /* @__PURE__ */ jsx(Text, { dimColor: true, children: " used" })
1699
1692
  ] }, slot.id ?? "__default__");
1700
1693
  })
1701
1694
  ] })
@@ -1706,31 +1699,37 @@ function RateLimitsCard({ items }) {
1706
1699
  }
1707
1700
  function MetricBlock({
1708
1701
  label,
1709
- sublabel,
1710
1702
  pick,
1711
1703
  items,
1712
1704
  showResets
1713
1705
  }) {
1714
- const rows = items.map((i) => ({ slot: i.slot, lim: pick(i.s.billing) ?? null })).filter((r) => r.lim !== null);
1715
- if (rows.length === 0) return null;
1716
- return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [
1717
- /* @__PURE__ */ jsxs(Box, { children: [
1718
- /* @__PURE__ */ jsx(Text, { bold: true, children: label }),
1719
- /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
1720
- " ",
1721
- sublabel
1722
- ] })
1723
- ] }),
1724
- rows.map(({ slot, lim }) => /* @__PURE__ */ jsx(
1725
- AccountLimitBar,
1726
- {
1727
- slot,
1728
- pct: lim.utilization,
1729
- resets: showResets ? lim.resetsAt : null,
1730
- showName: items.length > 1
1731
- },
1732
- slot.id ?? "__default__"
1733
- ))
1706
+ const rows = items.map((i) => ({
1707
+ slot: i.slot,
1708
+ lim: pick(i.s.billing) ?? null,
1709
+ error: i.s.billing?.error ?? null
1710
+ }));
1711
+ if (rows.every((r) => r.lim === null && !r.error)) return null;
1712
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
1713
+ /* @__PURE__ */ jsx(Text, { bold: true, children: label }),
1714
+ rows.map(({ slot, lim, error }) => {
1715
+ if (lim) {
1716
+ return /* @__PURE__ */ jsx(
1717
+ AccountLimitBar,
1718
+ {
1719
+ slot,
1720
+ pct: lim.utilization,
1721
+ resets: showResets ? lim.resetsAt : null,
1722
+ showName: items.length > 1
1723
+ },
1724
+ slot.id ?? "__default__"
1725
+ );
1726
+ }
1727
+ return /* @__PURE__ */ jsxs(Box, { children: [
1728
+ /* @__PURE__ */ jsx(Text, { color: slot.color, children: "\u25CF " }),
1729
+ /* @__PURE__ */ jsx(Box, { width: 22, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: truncateName(slot.name, 20) }) }),
1730
+ /* @__PURE__ */ jsx(Text, { color: error ? "red" : void 0, dimColor: !error, children: error ?? "no data" })
1731
+ ] }, slot.id ?? "__default__");
1732
+ })
1734
1733
  ] });
1735
1734
  }
1736
1735
  function AccountLimitBar({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tokmon",
3
- "version": "0.12.3",
3
+ "version": "0.12.5",
4
4
  "description": "Terminal dashboard for Claude Code usage and costs",
5
5
  "type": "module",
6
6
  "bin": {