tokmon 0.4.0 → 0.5.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.
- package/dist/cli.js +184 -140
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -46,41 +46,6 @@ import { createReadStream } from "fs";
|
|
|
46
46
|
import { createInterface } from "readline";
|
|
47
47
|
import { join as join2 } from "path";
|
|
48
48
|
import { homedir as homedir2 } from "os";
|
|
49
|
-
|
|
50
|
-
// src/format.ts
|
|
51
|
-
function currency(value) {
|
|
52
|
-
return `$${value.toFixed(2)}`;
|
|
53
|
-
}
|
|
54
|
-
function tokens(value) {
|
|
55
|
-
if (value >= 1e9) return `${(value / 1e9).toFixed(1)}B`;
|
|
56
|
-
if (value >= 1e6) return `${(value / 1e6).toFixed(1)}M`;
|
|
57
|
-
if (value >= 1e3) return `${(value / 1e3).toFixed(1)}K`;
|
|
58
|
-
return String(value);
|
|
59
|
-
}
|
|
60
|
-
function time(date) {
|
|
61
|
-
return date.toLocaleTimeString(void 0, {
|
|
62
|
-
hour: "2-digit",
|
|
63
|
-
minute: "2-digit",
|
|
64
|
-
second: "2-digit"
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
function minutes(mins) {
|
|
68
|
-
const h = Math.floor(mins / 60);
|
|
69
|
-
const m = Math.round(mins % 60);
|
|
70
|
-
return h > 0 ? `${h}h ${m}m` : `${m}m`;
|
|
71
|
-
}
|
|
72
|
-
function shortDate(iso) {
|
|
73
|
-
const [, m, d] = iso.split("-");
|
|
74
|
-
const months = ["", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
|
|
75
|
-
return `${months[Number(m)]} ${Number(d).toString().padStart(2, " ")}`;
|
|
76
|
-
}
|
|
77
|
-
function col(s, w, align = "right") {
|
|
78
|
-
if (s.length > w) return s.slice(0, w - 1) + "~";
|
|
79
|
-
const spaces = " ".repeat(w - s.length);
|
|
80
|
-
return align === "right" ? spaces + s : s + spaces;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// src/data.ts
|
|
84
49
|
var PRICING = {
|
|
85
50
|
"claude-opus-4": { i: 5e-6, o: 25e-6, cc: 625e-8, cr: 5e-7 },
|
|
86
51
|
"claude-sonnet-4": { i: 3e-6, o: 15e-6, cc: 375e-8, cr: 3e-7 },
|
|
@@ -227,47 +192,17 @@ function isoWeekLabel(ts) {
|
|
|
227
192
|
function monthLabel(ts) {
|
|
228
193
|
return new Date(ts).toISOString().slice(0, 7);
|
|
229
194
|
}
|
|
230
|
-
function findBlockStart(entries, now) {
|
|
231
|
-
const recent = entries.filter((e) => e.ts <= now).sort((a, b) => a.ts - b.ts);
|
|
232
|
-
if (recent.length === 0) return 0;
|
|
233
|
-
const GAP = 30 * 6e4;
|
|
234
|
-
let blockStart = recent[0].ts;
|
|
235
|
-
for (let i = 1; i < recent.length; i++) {
|
|
236
|
-
if (recent[i].ts - recent[i - 1].ts > GAP) {
|
|
237
|
-
blockStart = recent[i].ts;
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
if (now - blockStart > 5 * 36e5) return 0;
|
|
241
|
-
return blockStart;
|
|
242
|
-
}
|
|
243
195
|
async function fetchDashboard() {
|
|
244
|
-
const now = Date.now();
|
|
245
196
|
const d = /* @__PURE__ */ new Date();
|
|
246
197
|
const monthStart = new Date(d.getFullYear(), d.getMonth(), 1).getTime();
|
|
247
198
|
const todayStart = new Date(d.getFullYear(), d.getMonth(), d.getDate()).getTime();
|
|
248
199
|
const weekDay = d.getDay();
|
|
249
200
|
const weekStart = new Date(d.getFullYear(), d.getMonth(), d.getDate() - (weekDay === 0 ? 6 : weekDay - 1)).getTime();
|
|
250
201
|
const entries = await loadEntries(monthStart);
|
|
251
|
-
let block = null;
|
|
252
|
-
const blockStart = findBlockStart(entries, now);
|
|
253
|
-
if (blockStart > 0) {
|
|
254
|
-
const blockEnd = blockStart + 5 * 36e5;
|
|
255
|
-
const blockEntries = entries.filter((e) => e.ts >= blockStart && e.ts < blockEnd);
|
|
256
|
-
if (blockEntries.length > 0) {
|
|
257
|
-
const spent = blockEntries.reduce((s, e) => s + e.cost, 0);
|
|
258
|
-
const elapsedMs = now - blockStart;
|
|
259
|
-
const elapsedHrs = elapsedMs / 36e5;
|
|
260
|
-
const burnRate = elapsedHrs > 0 ? spent / elapsedHrs : 0;
|
|
261
|
-
const remainMs = Math.max(0, blockEnd - now);
|
|
262
|
-
const percent = Math.min(100, elapsedMs / (5 * 36e5) * 100);
|
|
263
|
-
block = { spent, projected: burnRate * 5, burnRate, percent, remaining: minutes(remainMs / 6e4) };
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
202
|
return {
|
|
267
203
|
today: sum(entries.filter((e) => e.ts >= todayStart)),
|
|
268
204
|
week: sum(entries.filter((e) => e.ts >= weekStart)),
|
|
269
|
-
month: sum(entries.filter((e) => e.ts >= monthStart))
|
|
270
|
-
block
|
|
205
|
+
month: sum(entries.filter((e) => e.ts >= monthStart))
|
|
271
206
|
};
|
|
272
207
|
}
|
|
273
208
|
async function fetchTable() {
|
|
@@ -281,12 +216,113 @@ async function fetchTable() {
|
|
|
281
216
|
};
|
|
282
217
|
}
|
|
283
218
|
|
|
219
|
+
// src/billing.ts
|
|
220
|
+
import { execFile as execFileCb } from "child_process";
|
|
221
|
+
import { promisify } from "util";
|
|
222
|
+
var execFile = promisify(execFileCb);
|
|
223
|
+
async function getAccessToken() {
|
|
224
|
+
if (process.platform === "darwin") {
|
|
225
|
+
try {
|
|
226
|
+
const { stdout } = await execFile("security", [
|
|
227
|
+
"find-generic-password",
|
|
228
|
+
"-s",
|
|
229
|
+
"Claude Code-credentials",
|
|
230
|
+
"-w"
|
|
231
|
+
], { timeout: 5e3 });
|
|
232
|
+
const creds = JSON.parse(stdout.trim());
|
|
233
|
+
return creds?.claudeAiOauth?.accessToken ?? null;
|
|
234
|
+
} catch {
|
|
235
|
+
return null;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
return null;
|
|
239
|
+
}
|
|
240
|
+
async function fetchBilling() {
|
|
241
|
+
const token = await getAccessToken();
|
|
242
|
+
if (!token) return null;
|
|
243
|
+
try {
|
|
244
|
+
const res = await fetch("https://api.anthropic.com/api/oauth/usage", {
|
|
245
|
+
headers: {
|
|
246
|
+
"Authorization": `Bearer ${token}`,
|
|
247
|
+
"anthropic-beta": "oauth-2025-04-20",
|
|
248
|
+
"User-Agent": "tokmon"
|
|
249
|
+
},
|
|
250
|
+
signal: AbortSignal.timeout(1e4)
|
|
251
|
+
});
|
|
252
|
+
if (!res.ok) return null;
|
|
253
|
+
const data = await res.json();
|
|
254
|
+
return {
|
|
255
|
+
session: data.five_hour ? {
|
|
256
|
+
utilization: data.five_hour.utilization,
|
|
257
|
+
resetsAt: formatReset(data.five_hour.resets_at)
|
|
258
|
+
} : null,
|
|
259
|
+
weekly: data.seven_day ? {
|
|
260
|
+
utilization: data.seven_day.utilization,
|
|
261
|
+
resetsAt: formatReset(data.seven_day.resets_at)
|
|
262
|
+
} : null,
|
|
263
|
+
sonnet: data.seven_day_sonnet ? {
|
|
264
|
+
utilization: data.seven_day_sonnet.utilization,
|
|
265
|
+
resetsAt: formatReset(data.seven_day_sonnet.resets_at)
|
|
266
|
+
} : null,
|
|
267
|
+
extraUsage: data.extra_usage?.is_enabled ? {
|
|
268
|
+
limit: data.extra_usage.monthly_limit / 100,
|
|
269
|
+
used: data.extra_usage.used_credits / 100
|
|
270
|
+
} : null
|
|
271
|
+
};
|
|
272
|
+
} catch {
|
|
273
|
+
return null;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
function formatReset(iso) {
|
|
277
|
+
const d = new Date(iso);
|
|
278
|
+
const now = /* @__PURE__ */ new Date();
|
|
279
|
+
const diff = d.getTime() - now.getTime();
|
|
280
|
+
if (diff <= 0) return "now";
|
|
281
|
+
const mins = Math.round(diff / 6e4);
|
|
282
|
+
if (mins < 60) return `${mins}m`;
|
|
283
|
+
const hrs = Math.floor(mins / 60);
|
|
284
|
+
const m = mins % 60;
|
|
285
|
+
if (hrs < 24) return `${hrs}h ${m}m`;
|
|
286
|
+
const days = Math.floor(hrs / 24);
|
|
287
|
+
const h = hrs % 24;
|
|
288
|
+
return `${days}d ${h}h`;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// src/format.ts
|
|
292
|
+
function currency(value) {
|
|
293
|
+
return `$${value.toFixed(2)}`;
|
|
294
|
+
}
|
|
295
|
+
function tokens(value) {
|
|
296
|
+
if (value >= 1e9) return `${(value / 1e9).toFixed(1)}B`;
|
|
297
|
+
if (value >= 1e6) return `${(value / 1e6).toFixed(1)}M`;
|
|
298
|
+
if (value >= 1e3) return `${(value / 1e3).toFixed(1)}K`;
|
|
299
|
+
return String(value);
|
|
300
|
+
}
|
|
301
|
+
function time(date) {
|
|
302
|
+
return date.toLocaleTimeString(void 0, {
|
|
303
|
+
hour: "2-digit",
|
|
304
|
+
minute: "2-digit",
|
|
305
|
+
second: "2-digit"
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
function shortDate(iso) {
|
|
309
|
+
const [, m, d] = iso.split("-");
|
|
310
|
+
const months = ["", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
|
|
311
|
+
return `${months[Number(m)]} ${Number(d).toString().padStart(2, " ")}`;
|
|
312
|
+
}
|
|
313
|
+
function col(s, w, align = "right") {
|
|
314
|
+
if (s.length > w) return s.slice(0, w - 1) + "~";
|
|
315
|
+
const spaces = " ".repeat(w - s.length);
|
|
316
|
+
return align === "right" ? spaces + s : s + spaces;
|
|
317
|
+
}
|
|
318
|
+
|
|
284
319
|
// src/app.tsx
|
|
285
320
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
286
321
|
var TABS = ["Dashboard", "Table"];
|
|
287
322
|
var VIEWS = ["Daily", "Weekly", "Monthly"];
|
|
288
323
|
function App({ interval: cliInterval }) {
|
|
289
324
|
const [dashboard, setDashboard] = useState(null);
|
|
325
|
+
const [billing, setBilling] = useState(null);
|
|
290
326
|
const [table, setTable] = useState(null);
|
|
291
327
|
const [tableLoading, setTableLoading] = useState(false);
|
|
292
328
|
const [error, setError] = useState(null);
|
|
@@ -299,9 +335,11 @@ function App({ interval: cliInterval }) {
|
|
|
299
335
|
const [settingsCursor, setSettingsCursor] = useState(0);
|
|
300
336
|
const tableLoadedOnce = useRef(false);
|
|
301
337
|
const { stdout } = useStdout();
|
|
338
|
+
const { exit } = useApp();
|
|
302
339
|
const rows = stdout?.rows ?? 24;
|
|
303
340
|
const cols = stdout?.columns ?? 80;
|
|
304
341
|
const interval2 = cliInterval ?? (config2?.interval ?? 2) * 1e3;
|
|
342
|
+
const cfg = config2 ?? { interval: 2, clearScreen: true };
|
|
305
343
|
useEffect(() => {
|
|
306
344
|
loadConfig().then((c) => {
|
|
307
345
|
if (cliInterval) c = { ...c, interval: cliInterval / 1e3 };
|
|
@@ -329,6 +367,19 @@ function App({ interval: cliInterval }) {
|
|
|
329
367
|
clearInterval(id);
|
|
330
368
|
};
|
|
331
369
|
}, [interval2]);
|
|
370
|
+
useEffect(() => {
|
|
371
|
+
let active = true;
|
|
372
|
+
const load = () => fetchBilling().then((b) => {
|
|
373
|
+
if (active && b) setBilling(b);
|
|
374
|
+
}).catch(() => {
|
|
375
|
+
});
|
|
376
|
+
load();
|
|
377
|
+
const id = setInterval(load, 12e4);
|
|
378
|
+
return () => {
|
|
379
|
+
active = false;
|
|
380
|
+
clearInterval(id);
|
|
381
|
+
};
|
|
382
|
+
}, []);
|
|
332
383
|
useEffect(() => {
|
|
333
384
|
if (tab !== 1) return;
|
|
334
385
|
if (tableLoadedOnce.current && table) return;
|
|
@@ -362,36 +413,29 @@ function App({ interval: cliInterval }) {
|
|
|
362
413
|
clearInterval(id);
|
|
363
414
|
};
|
|
364
415
|
}, [tab, interval2]);
|
|
365
|
-
const { exit } = useApp();
|
|
366
416
|
const isTTY = process.stdin.isTTY === true;
|
|
367
|
-
const settingsItems = 2;
|
|
368
|
-
const cfg = config2 ?? { interval: 2, clearScreen: true };
|
|
369
417
|
useInput((input, key) => {
|
|
370
418
|
if (showSettings) {
|
|
371
419
|
if (key.escape || input === "s") setShowSettings(false);
|
|
372
420
|
if (key.upArrow) setSettingsCursor((c) => Math.max(0, c - 1));
|
|
373
|
-
if (key.downArrow) setSettingsCursor((c) => Math.min(
|
|
421
|
+
if (key.downArrow) setSettingsCursor((c) => Math.min(1, c + 1));
|
|
374
422
|
if (settingsCursor === 0) {
|
|
375
|
-
if (key.leftArrow) {
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
saveConfig(next);
|
|
386
|
-
return next;
|
|
387
|
-
});
|
|
388
|
-
}
|
|
423
|
+
if (key.leftArrow) setConfig((c) => {
|
|
424
|
+
const n = { ...c, interval: Math.max(1, c.interval - 1) };
|
|
425
|
+
saveConfig(n);
|
|
426
|
+
return n;
|
|
427
|
+
});
|
|
428
|
+
if (key.rightArrow) setConfig((c) => {
|
|
429
|
+
const n = { ...c, interval: c.interval + 1 };
|
|
430
|
+
saveConfig(n);
|
|
431
|
+
return n;
|
|
432
|
+
});
|
|
389
433
|
}
|
|
390
434
|
if (settingsCursor === 1 && (key.leftArrow || key.rightArrow || key.return)) {
|
|
391
435
|
setConfig((c) => {
|
|
392
|
-
const
|
|
393
|
-
saveConfig(
|
|
394
|
-
return
|
|
436
|
+
const n = { ...c, clearScreen: !c.clearScreen };
|
|
437
|
+
saveConfig(n);
|
|
438
|
+
return n;
|
|
395
439
|
});
|
|
396
440
|
}
|
|
397
441
|
return;
|
|
@@ -481,7 +525,7 @@ function App({ interval: cliInterval }) {
|
|
|
481
525
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: " Tab/\u2190\u2192" })
|
|
482
526
|
] }),
|
|
483
527
|
/* @__PURE__ */ jsx(Box, { height: 1 }),
|
|
484
|
-
tab === 0 && /* @__PURE__ */ jsx(DashboardView, { data: dashboard }),
|
|
528
|
+
tab === 0 && /* @__PURE__ */ jsx(DashboardView, { data: dashboard, billing }),
|
|
485
529
|
tab === 1 && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
486
530
|
/* @__PURE__ */ jsx(ViewBar, { views: VIEWS, active: view }),
|
|
487
531
|
/* @__PURE__ */ jsx(Box, { height: 1 }),
|
|
@@ -493,8 +537,7 @@ function App({ interval: cliInterval }) {
|
|
|
493
537
|
/* @__PURE__ */ jsx(Text, { children: "David Ilie" }),
|
|
494
538
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: " (" }),
|
|
495
539
|
/* @__PURE__ */ jsx(Text, { color: "cyan", children: "davidilie.com" }),
|
|
496
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: ") \xB7 " })
|
|
497
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "s=settings q=quit" })
|
|
540
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: ") \xB7 s=settings q=quit" })
|
|
498
541
|
] })
|
|
499
542
|
] });
|
|
500
543
|
}
|
|
@@ -555,7 +598,7 @@ function SettingsView({ config: config2, cursor }) {
|
|
|
555
598
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2191\u2193 select \u2190\u2192 adjust s/Esc close" })
|
|
556
599
|
] });
|
|
557
600
|
}
|
|
558
|
-
function DashboardView({ data }) {
|
|
601
|
+
function DashboardView({ data, billing }) {
|
|
559
602
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
560
603
|
/* @__PURE__ */ jsxs(
|
|
561
604
|
Box,
|
|
@@ -576,9 +619,39 @@ function DashboardView({ data }) {
|
|
|
576
619
|
]
|
|
577
620
|
}
|
|
578
621
|
),
|
|
579
|
-
|
|
622
|
+
billing && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
580
623
|
/* @__PURE__ */ jsx(Box, { height: 1 }),
|
|
581
|
-
/* @__PURE__ */
|
|
624
|
+
/* @__PURE__ */ jsxs(
|
|
625
|
+
Box,
|
|
626
|
+
{
|
|
627
|
+
flexDirection: "column",
|
|
628
|
+
paddingLeft: 1,
|
|
629
|
+
borderStyle: "bold",
|
|
630
|
+
borderColor: "yellow",
|
|
631
|
+
borderRight: false,
|
|
632
|
+
borderTop: false,
|
|
633
|
+
borderBottom: false,
|
|
634
|
+
children: [
|
|
635
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: "Rate Limits" }),
|
|
636
|
+
/* @__PURE__ */ jsx(Box, { height: 1 }),
|
|
637
|
+
billing.session && /* @__PURE__ */ jsx(LimitBar, { label: "Session", pct: billing.session.utilization, resets: billing.session.resetsAt }),
|
|
638
|
+
billing.weekly && /* @__PURE__ */ jsx(LimitBar, { label: "Weekly", pct: billing.weekly.utilization, resets: billing.weekly.resetsAt }),
|
|
639
|
+
billing.sonnet && /* @__PURE__ */ jsx(LimitBar, { label: "Sonnet", pct: billing.sonnet.utilization, resets: billing.sonnet.resetsAt }),
|
|
640
|
+
billing.extraUsage && /* @__PURE__ */ jsxs(Box, { children: [
|
|
641
|
+
/* @__PURE__ */ jsx(Box, { width: 10, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Extra" }) }),
|
|
642
|
+
/* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
|
|
643
|
+
"$",
|
|
644
|
+
billing.extraUsage.used.toFixed(2)
|
|
645
|
+
] }),
|
|
646
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
647
|
+
" / $",
|
|
648
|
+
billing.extraUsage.limit.toFixed(2),
|
|
649
|
+
" limit"
|
|
650
|
+
] })
|
|
651
|
+
] })
|
|
652
|
+
]
|
|
653
|
+
}
|
|
654
|
+
)
|
|
582
655
|
] }),
|
|
583
656
|
/* @__PURE__ */ jsx(Box, { height: 1 }),
|
|
584
657
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2500".repeat(50) }),
|
|
@@ -588,46 +661,24 @@ function DashboardView({ data }) {
|
|
|
588
661
|
] })
|
|
589
662
|
] });
|
|
590
663
|
}
|
|
591
|
-
function
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
] })
|
|
610
|
-
] }),
|
|
611
|
-
/* @__PURE__ */ jsx(Box, { height: 1 }),
|
|
612
|
-
/* @__PURE__ */ jsxs(Box, { children: [
|
|
613
|
-
/* @__PURE__ */ jsx(ProgressBar, { percent: block.percent, width: 36 }),
|
|
614
|
-
/* @__PURE__ */ jsx(Text, { children: " " }),
|
|
615
|
-
/* @__PURE__ */ jsxs(Text, { bold: true, children: [
|
|
616
|
-
Math.round(block.percent),
|
|
617
|
-
"%"
|
|
618
|
-
] })
|
|
619
|
-
] }),
|
|
620
|
-
/* @__PURE__ */ jsxs(Box, { marginTop: 1, children: [
|
|
621
|
-
/* @__PURE__ */ jsx(Text, { color: "yellow", children: currency(block.spent) }),
|
|
622
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: " spent \xB7 ~" }),
|
|
623
|
-
/* @__PURE__ */ jsx(Text, { children: currency(block.projected) }),
|
|
624
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: " proj \xB7 " }),
|
|
625
|
-
/* @__PURE__ */ jsx(Text, { color: "red", children: currency(block.burnRate) }),
|
|
626
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "/hr" })
|
|
627
|
-
] })
|
|
628
|
-
]
|
|
629
|
-
}
|
|
630
|
-
);
|
|
664
|
+
function LimitBar({ label, pct, resets }) {
|
|
665
|
+
const width = 30;
|
|
666
|
+
const filled = Math.round(pct / 100 * width);
|
|
667
|
+
const color = pct >= 80 ? "red" : pct >= 50 ? "yellow" : "green";
|
|
668
|
+
return /* @__PURE__ */ jsxs(Box, { children: [
|
|
669
|
+
/* @__PURE__ */ jsx(Box, { width: 10, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: label }) }),
|
|
670
|
+
/* @__PURE__ */ jsx(Text, { color, children: "\u2501".repeat(filled) }),
|
|
671
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2500".repeat(width - filled) }),
|
|
672
|
+
/* @__PURE__ */ jsx(Text, { children: " " }),
|
|
673
|
+
/* @__PURE__ */ jsxs(Text, { bold: true, children: [
|
|
674
|
+
Math.round(pct),
|
|
675
|
+
"%"
|
|
676
|
+
] }),
|
|
677
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
678
|
+
" resets ",
|
|
679
|
+
resets
|
|
680
|
+
] })
|
|
681
|
+
] });
|
|
631
682
|
}
|
|
632
683
|
function SummaryRow({ label, summary }) {
|
|
633
684
|
return /* @__PURE__ */ jsxs(Box, { children: [
|
|
@@ -639,13 +690,6 @@ function SummaryRow({ label, summary }) {
|
|
|
639
690
|
] }) })
|
|
640
691
|
] });
|
|
641
692
|
}
|
|
642
|
-
function ProgressBar({ percent, width = 36 }) {
|
|
643
|
-
const filled = Math.round(percent / 100 * width);
|
|
644
|
-
return /* @__PURE__ */ jsxs(Text, { children: [
|
|
645
|
-
/* @__PURE__ */ jsx(Text, { color: "greenBright", children: "\u2501".repeat(filled) }),
|
|
646
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2500".repeat(width - filled) })
|
|
647
|
-
] });
|
|
648
|
-
}
|
|
649
693
|
function TableView({ rows: allRows, scroll, maxRows, wide }) {
|
|
650
694
|
const W = wide ? { label: 10, models: 18, input: 8, output: 8, cc: 8, cr: 9, total: 9, cost: 10 } : { label: 8, models: 14, input: 7, output: 7, cc: 7, cr: 8, total: 0, cost: 9 };
|
|
651
695
|
const lineW = W.label + W.models + W.input + W.output + W.cc + W.cr + W.total + W.cost;
|