tokmon 0.12.2 → 0.12.4
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/cli.js +141 -69
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -434,16 +434,15 @@ async function readMacKeychain() {
|
|
|
434
434
|
}
|
|
435
435
|
}
|
|
436
436
|
async function getAccessToken(homeDir) {
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
if (
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
if (token) return token;
|
|
437
|
+
const isDefault = !homeDir || homeDir === homedir3();
|
|
438
|
+
if (isDefault) {
|
|
439
|
+
if (process.platform === "darwin") {
|
|
440
|
+
const token = await readMacKeychain();
|
|
441
|
+
if (token) return token;
|
|
442
|
+
}
|
|
443
|
+
return readCredentialsFile(homeDir);
|
|
445
444
|
}
|
|
446
|
-
return readCredentialsFile();
|
|
445
|
+
return readCredentialsFile(homeDir);
|
|
447
446
|
}
|
|
448
447
|
var EMPTY = { session: null, weekly: null, sonnet: null, extraUsage: null, peak: null, error: null };
|
|
449
448
|
async function fetchBilling(homeDir) {
|
|
@@ -485,8 +484,9 @@ async function fetchUsage(token) {
|
|
|
485
484
|
resetsAt: formatReset(data.seven_day_sonnet.resets_at)
|
|
486
485
|
} : null,
|
|
487
486
|
extraUsage: data.extra_usage?.is_enabled ? {
|
|
488
|
-
limit: data.extra_usage.monthly_limit / 100,
|
|
489
|
-
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"
|
|
490
490
|
} : null
|
|
491
491
|
}
|
|
492
492
|
};
|
|
@@ -580,6 +580,9 @@ var DEFAULT_CONFIG = {
|
|
|
580
580
|
};
|
|
581
581
|
var GENERAL_ROWS = 4;
|
|
582
582
|
var IS_TTY = process.stdin.isTTY === true;
|
|
583
|
+
function truncateName(s, n) {
|
|
584
|
+
return s.length > n ? s.slice(0, n - 1) + "\u2026" : s;
|
|
585
|
+
}
|
|
583
586
|
function buildSlots(config2) {
|
|
584
587
|
const slots = [];
|
|
585
588
|
if (config2.accounts.length === 0) {
|
|
@@ -638,27 +641,30 @@ function App({ interval: cliInterval }) {
|
|
|
638
641
|
setConfig(c);
|
|
639
642
|
});
|
|
640
643
|
}, []);
|
|
644
|
+
const billingMs = cfg.billingInterval * 6e4;
|
|
645
|
+
const dataSlots = cfg.accounts.length > 0 ? slots.slice(1) : slots;
|
|
646
|
+
const dataSlotsKey = dataSlots.map((s) => s.id ?? "__default__").join(",");
|
|
641
647
|
useEffect(() => {
|
|
642
648
|
if (!config2) return;
|
|
643
649
|
let active = true;
|
|
644
|
-
const slotsToLoad = activeSlot.id === null && cfg.accounts.length > 0 ? slots.slice(1) : [activeSlot];
|
|
645
650
|
const load = async () => {
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
setError(
|
|
658
|
-
setUpdated(/* @__PURE__ */ new Date());
|
|
651
|
+
await Promise.all(dataSlots.map(async (slot) => {
|
|
652
|
+
try {
|
|
653
|
+
const dashboard = await fetchDashboard(tz, slot.homeDir);
|
|
654
|
+
if (!active) return;
|
|
655
|
+
setStats((prev) => {
|
|
656
|
+
const next = new Map(prev);
|
|
657
|
+
const cur = next.get(slotKey(slot)) ?? { slot, dashboard: null, billing: null };
|
|
658
|
+
next.set(slotKey(slot), { ...cur, slot, dashboard });
|
|
659
|
+
return next;
|
|
660
|
+
});
|
|
661
|
+
} catch (e) {
|
|
662
|
+
if (active) setError(e instanceof Error ? e.message : String(e));
|
|
659
663
|
}
|
|
660
|
-
}
|
|
661
|
-
|
|
664
|
+
}));
|
|
665
|
+
if (active) {
|
|
666
|
+
setError(null);
|
|
667
|
+
setUpdated(/* @__PURE__ */ new Date());
|
|
662
668
|
}
|
|
663
669
|
};
|
|
664
670
|
load();
|
|
@@ -667,7 +673,32 @@ function App({ interval: cliInterval }) {
|
|
|
667
673
|
active = false;
|
|
668
674
|
clearInterval(id);
|
|
669
675
|
};
|
|
670
|
-
}, [interval2, tz, config2,
|
|
676
|
+
}, [interval2, tz, config2, dataSlotsKey]);
|
|
677
|
+
useEffect(() => {
|
|
678
|
+
if (!config2) return;
|
|
679
|
+
let active = true;
|
|
680
|
+
const load = async () => {
|
|
681
|
+
await Promise.all(dataSlots.map(async (slot) => {
|
|
682
|
+
try {
|
|
683
|
+
const billing = await fetchBilling(slot.homeDir);
|
|
684
|
+
if (!active) return;
|
|
685
|
+
setStats((prev) => {
|
|
686
|
+
const next = new Map(prev);
|
|
687
|
+
const cur = next.get(slotKey(slot)) ?? { slot, dashboard: null, billing: null };
|
|
688
|
+
next.set(slotKey(slot), { ...cur, slot, billing });
|
|
689
|
+
return next;
|
|
690
|
+
});
|
|
691
|
+
} catch {
|
|
692
|
+
}
|
|
693
|
+
}));
|
|
694
|
+
};
|
|
695
|
+
load();
|
|
696
|
+
const id = setInterval(load, billingMs);
|
|
697
|
+
return () => {
|
|
698
|
+
active = false;
|
|
699
|
+
clearInterval(id);
|
|
700
|
+
};
|
|
701
|
+
}, [billingMs, config2, dataSlotsKey]);
|
|
671
702
|
useEffect(() => {
|
|
672
703
|
tableLoadedOnce.current = false;
|
|
673
704
|
setTable(null);
|
|
@@ -813,6 +844,21 @@ function App({ interval: cliInterval }) {
|
|
|
813
844
|
activeAccountId: c.activeAccountId === id ? null : c.activeAccountId
|
|
814
845
|
}));
|
|
815
846
|
}
|
|
847
|
+
function moveAccount(idx, dir) {
|
|
848
|
+
updateConfig((c) => {
|
|
849
|
+
const next = [...c.accounts];
|
|
850
|
+
const target = idx + dir;
|
|
851
|
+
if (target < 0 || target >= next.length) return c;
|
|
852
|
+
[next[idx], next[target]] = [next[target], next[idx]];
|
|
853
|
+
return { ...c, accounts: next };
|
|
854
|
+
});
|
|
855
|
+
setSettingsCursor((c) => {
|
|
856
|
+
const target = c + dir;
|
|
857
|
+
const min = accountRowsStart;
|
|
858
|
+
const max = accountRowsStart + cfg.accounts.length - 1;
|
|
859
|
+
return Math.max(min, Math.min(max, target));
|
|
860
|
+
});
|
|
861
|
+
}
|
|
816
862
|
const accountRowsStart = GENERAL_ROWS;
|
|
817
863
|
const totalSettingsRows = GENERAL_ROWS + cfg.accounts.length + 1;
|
|
818
864
|
useInput((input, key) => {
|
|
@@ -915,6 +961,12 @@ function App({ interval: cliInterval }) {
|
|
|
915
961
|
setShowSettings(false);
|
|
916
962
|
return;
|
|
917
963
|
}
|
|
964
|
+
const accIdxNav = settingsCursor - accountRowsStart;
|
|
965
|
+
const onAccountRow = accIdxNav >= 0 && accIdxNav < cfg.accounts.length;
|
|
966
|
+
if (onAccountRow && key.shift && (key.upArrow || key.downArrow)) {
|
|
967
|
+
moveAccount(accIdxNav, key.upArrow ? -1 : 1);
|
|
968
|
+
return;
|
|
969
|
+
}
|
|
918
970
|
if (key.upArrow) {
|
|
919
971
|
setSettingsCursor((c) => Math.max(0, c - 1));
|
|
920
972
|
return;
|
|
@@ -1103,19 +1155,7 @@ function App({ interval: cliInterval }) {
|
|
|
1103
1155
|
activeAccountId: cfg.activeAccountId
|
|
1104
1156
|
}
|
|
1105
1157
|
) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1106
|
-
|
|
1107
|
-
AccountStrip,
|
|
1108
|
-
{
|
|
1109
|
-
slots,
|
|
1110
|
-
activeIdx: activeSlotIdx,
|
|
1111
|
-
onSelect: (i) => {
|
|
1112
|
-
const id = slots[i].id;
|
|
1113
|
-
updateConfig((c) => ({ ...c, activeAccountId: id }));
|
|
1114
|
-
resetView();
|
|
1115
|
-
}
|
|
1116
|
-
}
|
|
1117
|
-
) }),
|
|
1118
|
-
/* @__PURE__ */ jsxs(Box, { marginTop: slots.length > 1 ? 0 : 1, children: [
|
|
1158
|
+
/* @__PURE__ */ jsxs(Box, { marginTop: 1, children: [
|
|
1119
1159
|
/* @__PURE__ */ jsx(TabBar, { tabs: TABS, active: tab, onSelect: (i) => {
|
|
1120
1160
|
setTab(i);
|
|
1121
1161
|
resetView();
|
|
@@ -1123,14 +1163,31 @@ function App({ interval: cliInterval }) {
|
|
|
1123
1163
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: " Tab/\u2190\u2192" })
|
|
1124
1164
|
] }),
|
|
1125
1165
|
/* @__PURE__ */ jsx(Box, { height: 1 }),
|
|
1126
|
-
tab === 0 && /* @__PURE__ */
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1166
|
+
tab === 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1167
|
+
/* @__PURE__ */ jsx(
|
|
1168
|
+
DashboardView,
|
|
1169
|
+
{
|
|
1170
|
+
slots: visibleSlots,
|
|
1171
|
+
stats,
|
|
1172
|
+
compact: visibleSlots.length > 1
|
|
1173
|
+
}
|
|
1174
|
+
),
|
|
1175
|
+
slots.length > 1 && /* @__PURE__ */ jsxs(Box, { marginTop: 1, flexDirection: "column", children: [
|
|
1176
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: "Accounts" }),
|
|
1177
|
+
/* @__PURE__ */ jsx(Box, { marginTop: 0, children: /* @__PURE__ */ jsx(
|
|
1178
|
+
AccountStrip,
|
|
1179
|
+
{
|
|
1180
|
+
slots,
|
|
1181
|
+
activeIdx: activeSlotIdx,
|
|
1182
|
+
onSelect: (i) => {
|
|
1183
|
+
const id = slots[i].id;
|
|
1184
|
+
updateConfig((c) => ({ ...c, activeAccountId: id }));
|
|
1185
|
+
resetView();
|
|
1186
|
+
}
|
|
1187
|
+
}
|
|
1188
|
+
) })
|
|
1189
|
+
] })
|
|
1190
|
+
] }),
|
|
1134
1191
|
tab === 1 && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1135
1192
|
/* @__PURE__ */ jsx(ViewBar, { views: VIEWS, active: view, sort: SORTS[sort], onSelect: (i) => {
|
|
1136
1193
|
setView(i);
|
|
@@ -1346,7 +1403,7 @@ function SettingsView({
|
|
|
1346
1403
|
/* @__PURE__ */ jsx(Text, { children: "Add account" })
|
|
1347
1404
|
] }),
|
|
1348
1405
|
/* @__PURE__ */ jsx(Box, { height: 1 }),
|
|
1349
|
-
editingTz ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "type IANA name (e.g. Europe/London) \xB7 empty = System \xB7 Enter save \xB7 Esc cancel" }) : cursor >= accountRowsStart && cursor < accountRowsStart + config2.accounts.length ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2191\u2193 select \xB7 Enter edit \xB7 space activate \xB7 d delete \xB7 s/Esc close" }) : cursor === accountRowsStart + config2.accounts.length ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2191\u2193 select \xB7 Enter add account \xB7 s/Esc close" }) : /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2191\u2193 select \u2190\u2192 adjust Enter edit s/Esc close" })
|
|
1406
|
+
editingTz ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "type IANA name (e.g. Europe/London) \xB7 empty = System \xB7 Enter save \xB7 Esc cancel" }) : cursor >= accountRowsStart && cursor < accountRowsStart + config2.accounts.length ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2191\u2193 select \xB7 \u21E7\u2191\u2193 reorder \xB7 Enter edit \xB7 space activate \xB7 d delete \xB7 s/Esc close" }) : cursor === accountRowsStart + config2.accounts.length ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2191\u2193 select \xB7 Enter add account \xB7 s/Esc close" }) : /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2191\u2193 select \u2190\u2192 adjust Enter edit s/Esc close" })
|
|
1350
1407
|
] });
|
|
1351
1408
|
}
|
|
1352
1409
|
function AccountFormView({ form, accounts }) {
|
|
@@ -1622,7 +1679,7 @@ function RateLimitsCard({ items }) {
|
|
|
1622
1679
|
/* @__PURE__ */ jsx(Box, { height: 1 }),
|
|
1623
1680
|
!anyData ? anyError ? /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: items.map(({ slot, s }) => s.billing?.error && /* @__PURE__ */ jsxs(Box, { children: [
|
|
1624
1681
|
/* @__PURE__ */ jsx(Text, { color: slot.color, children: "\u25CF " }),
|
|
1625
|
-
/* @__PURE__ */ jsx(Box, { width:
|
|
1682
|
+
/* @__PURE__ */ jsx(Box, { width: 22, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: truncateName(slot.name, 20) }) }),
|
|
1626
1683
|
/* @__PURE__ */ jsx(Text, { color: "red", children: s.billing.error })
|
|
1627
1684
|
] }, slot.id ?? "__default__")) }) : /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Fetching..." }) : /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
1628
1685
|
/* @__PURE__ */ jsx(MetricBlock, { label: "Total Usage", sublabel: "5h session", pick: (b) => b?.session, items, showResets: true }),
|
|
@@ -1633,17 +1690,19 @@ function RateLimitsCard({ items }) {
|
|
|
1633
1690
|
items.map(({ slot, s }) => {
|
|
1634
1691
|
const e = s.billing?.extraUsage;
|
|
1635
1692
|
if (!e) return null;
|
|
1693
|
+
const sym = e.currency === "EUR" ? "\u20AC" : "$";
|
|
1636
1694
|
return /* @__PURE__ */ jsxs(Box, { children: [
|
|
1637
1695
|
/* @__PURE__ */ jsx(Text, { color: slot.color, children: "\u25CF " }),
|
|
1638
|
-
/* @__PURE__ */ jsx(Box, { width:
|
|
1696
|
+
/* @__PURE__ */ jsx(Box, { width: 22, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: truncateName(slot.name, 20) }) }),
|
|
1639
1697
|
/* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
|
|
1640
|
-
|
|
1698
|
+
sym,
|
|
1641
1699
|
e.used.toFixed(2)
|
|
1642
1700
|
] }),
|
|
1643
|
-
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
1644
|
-
" /
|
|
1701
|
+
e.limit != null ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
1702
|
+
" / ",
|
|
1703
|
+
sym,
|
|
1645
1704
|
e.limit.toFixed(2)
|
|
1646
|
-
] })
|
|
1705
|
+
] }) : /* @__PURE__ */ jsx(Text, { dimColor: true, children: " used" })
|
|
1647
1706
|
] }, slot.id ?? "__default__");
|
|
1648
1707
|
})
|
|
1649
1708
|
] })
|
|
@@ -1659,8 +1718,12 @@ function MetricBlock({
|
|
|
1659
1718
|
items,
|
|
1660
1719
|
showResets
|
|
1661
1720
|
}) {
|
|
1662
|
-
const rows = items.map((i) => ({
|
|
1663
|
-
|
|
1721
|
+
const rows = items.map((i) => ({
|
|
1722
|
+
slot: i.slot,
|
|
1723
|
+
lim: pick(i.s.billing) ?? null,
|
|
1724
|
+
error: i.s.billing?.error ?? null
|
|
1725
|
+
}));
|
|
1726
|
+
if (rows.every((r) => r.lim === null && !r.error)) return null;
|
|
1664
1727
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [
|
|
1665
1728
|
/* @__PURE__ */ jsxs(Box, { children: [
|
|
1666
1729
|
/* @__PURE__ */ jsx(Text, { bold: true, children: label }),
|
|
@@ -1669,16 +1732,25 @@ function MetricBlock({
|
|
|
1669
1732
|
sublabel
|
|
1670
1733
|
] })
|
|
1671
1734
|
] }),
|
|
1672
|
-
rows.map(({ slot, lim }) =>
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1735
|
+
rows.map(({ slot, lim, error }) => {
|
|
1736
|
+
if (lim) {
|
|
1737
|
+
return /* @__PURE__ */ jsx(
|
|
1738
|
+
AccountLimitBar,
|
|
1739
|
+
{
|
|
1740
|
+
slot,
|
|
1741
|
+
pct: lim.utilization,
|
|
1742
|
+
resets: showResets ? lim.resetsAt : null,
|
|
1743
|
+
showName: items.length > 1
|
|
1744
|
+
},
|
|
1745
|
+
slot.id ?? "__default__"
|
|
1746
|
+
);
|
|
1747
|
+
}
|
|
1748
|
+
return /* @__PURE__ */ jsxs(Box, { children: [
|
|
1749
|
+
/* @__PURE__ */ jsx(Text, { color: slot.color, children: "\u25CF " }),
|
|
1750
|
+
/* @__PURE__ */ jsx(Box, { width: 22, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: truncateName(slot.name, 20) }) }),
|
|
1751
|
+
/* @__PURE__ */ jsx(Text, { color: error ? "red" : void 0, dimColor: !error, children: error ?? "no data" })
|
|
1752
|
+
] }, slot.id ?? "__default__");
|
|
1753
|
+
})
|
|
1682
1754
|
] });
|
|
1683
1755
|
}
|
|
1684
1756
|
function AccountLimitBar({
|
|
@@ -1691,7 +1763,7 @@ function AccountLimitBar({
|
|
|
1691
1763
|
const filled = Math.max(0, Math.min(width, Math.round(pct / 100 * width)));
|
|
1692
1764
|
return /* @__PURE__ */ jsxs(Box, { children: [
|
|
1693
1765
|
/* @__PURE__ */ jsx(Text, { color: slot.color, children: "\u25CF " }),
|
|
1694
|
-
showName ? /* @__PURE__ */ jsx(Box, { width:
|
|
1766
|
+
showName ? /* @__PURE__ */ jsx(Box, { width: 22, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: truncateName(slot.name, 20) }) }) : /* @__PURE__ */ jsx(Box, { width: 2, children: /* @__PURE__ */ jsx(Text, { children: " " }) }),
|
|
1695
1767
|
/* @__PURE__ */ jsx(Text, { color: slot.color, children: "\u2501".repeat(filled) }),
|
|
1696
1768
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2500".repeat(width - filled) }),
|
|
1697
1769
|
/* @__PURE__ */ jsx(Text, { children: " " }),
|