tokmon 0.11.2 → 0.12.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 +743 -127
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -8,7 +8,15 @@ import { MouseProvider } from "@zenobius/ink-mouse";
|
|
|
8
8
|
import { readFile, writeFile, mkdir } from "fs/promises";
|
|
9
9
|
import { join } from "path";
|
|
10
10
|
import { homedir } from "os";
|
|
11
|
-
var DEFAULTS = {
|
|
11
|
+
var DEFAULTS = {
|
|
12
|
+
interval: 2,
|
|
13
|
+
billingInterval: 5,
|
|
14
|
+
clearScreen: true,
|
|
15
|
+
timezone: null,
|
|
16
|
+
accounts: [],
|
|
17
|
+
activeAccountId: null
|
|
18
|
+
};
|
|
19
|
+
var ACCENT_COLORS = ["cyan", "magenta", "green", "yellow", "blue", "red"];
|
|
12
20
|
function configDir() {
|
|
13
21
|
if (process.platform === "win32") {
|
|
14
22
|
return join(process.env.APPDATA ?? join(homedir(), "AppData", "Roaming"), "tokmon");
|
|
@@ -23,7 +31,12 @@ async function loadConfig() {
|
|
|
23
31
|
try {
|
|
24
32
|
const raw = await readFile(configLocation(), "utf-8");
|
|
25
33
|
const parsed = JSON.parse(raw);
|
|
26
|
-
return {
|
|
34
|
+
return {
|
|
35
|
+
...DEFAULTS,
|
|
36
|
+
...parsed,
|
|
37
|
+
accounts: Array.isArray(parsed.accounts) ? parsed.accounts : [],
|
|
38
|
+
activeAccountId: typeof parsed.activeAccountId === "string" ? parsed.activeAccountId : null
|
|
39
|
+
};
|
|
27
40
|
} catch {
|
|
28
41
|
return { ...DEFAULTS };
|
|
29
42
|
}
|
|
@@ -33,6 +46,32 @@ async function saveConfig(config2) {
|
|
|
33
46
|
await mkdir(dir, { recursive: true });
|
|
34
47
|
await writeFile(configLocation(), JSON.stringify(config2, null, 2) + "\n");
|
|
35
48
|
}
|
|
49
|
+
function slugify(value) {
|
|
50
|
+
return value.trim().toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "").slice(0, 48);
|
|
51
|
+
}
|
|
52
|
+
function generateAccountId(name, existing) {
|
|
53
|
+
const base = slugify(name) || "account";
|
|
54
|
+
const taken = new Set(existing.map((a) => a.id));
|
|
55
|
+
if (!taken.has(base)) return base;
|
|
56
|
+
for (let i = 2; i < 1e3; i++) {
|
|
57
|
+
const candidate = `${base}_${i}`;
|
|
58
|
+
if (!taken.has(candidate)) return candidate;
|
|
59
|
+
}
|
|
60
|
+
return `${base}_${Date.now()}`;
|
|
61
|
+
}
|
|
62
|
+
function pickAccentColor(existing) {
|
|
63
|
+
const used = new Set(existing.map((a) => a.color).filter(Boolean));
|
|
64
|
+
for (const c of ACCENT_COLORS) {
|
|
65
|
+
if (!used.has(c)) return c;
|
|
66
|
+
}
|
|
67
|
+
return ACCENT_COLORS[existing.length % ACCENT_COLORS.length];
|
|
68
|
+
}
|
|
69
|
+
function expandHome(p) {
|
|
70
|
+
if (!p) return homedir();
|
|
71
|
+
if (p === "~" || p === "~/") return homedir();
|
|
72
|
+
if (p.startsWith("~/")) return join(homedir(), p.slice(2));
|
|
73
|
+
return p;
|
|
74
|
+
}
|
|
36
75
|
|
|
37
76
|
// src/app.tsx
|
|
38
77
|
import { useState, useEffect, useCallback, useRef } from "react";
|
|
@@ -163,7 +202,13 @@ var PRICING = {
|
|
|
163
202
|
};
|
|
164
203
|
var FALLBACK = PRICING["claude-opus-4"];
|
|
165
204
|
var fileCache = /* @__PURE__ */ new Map();
|
|
166
|
-
function getClaudeDirs() {
|
|
205
|
+
function getClaudeDirs(homeDir) {
|
|
206
|
+
if (homeDir) {
|
|
207
|
+
return [
|
|
208
|
+
join2(homeDir, ".claude", "projects"),
|
|
209
|
+
join2(homeDir, ".config", "claude", "projects")
|
|
210
|
+
];
|
|
211
|
+
}
|
|
167
212
|
const home = homedir2();
|
|
168
213
|
const dirs = [join2(home, ".claude", "projects")];
|
|
169
214
|
if (process.env.XDG_CONFIG_HOME) {
|
|
@@ -220,10 +265,10 @@ async function parseFile(path, since) {
|
|
|
220
265
|
}
|
|
221
266
|
return entries;
|
|
222
267
|
}
|
|
223
|
-
async function loadEntries(since) {
|
|
268
|
+
async function loadEntries(since, homeDir) {
|
|
224
269
|
const chunks = [];
|
|
225
270
|
const seen = /* @__PURE__ */ new Set();
|
|
226
|
-
for (const dir of getClaudeDirs()) {
|
|
271
|
+
for (const dir of getClaudeDirs(homeDir)) {
|
|
227
272
|
let listing;
|
|
228
273
|
try {
|
|
229
274
|
listing = await readdir(dir, { recursive: true });
|
|
@@ -318,12 +363,12 @@ function groupBy(entries, keyFn) {
|
|
|
318
363
|
}
|
|
319
364
|
return rows.sort((a, b) => a.label.localeCompare(b.label));
|
|
320
365
|
}
|
|
321
|
-
async function fetchDashboard(tz) {
|
|
366
|
+
async function fetchDashboard(tz, homeDir) {
|
|
322
367
|
const now = Date.now();
|
|
323
368
|
const monthStart = startOfMonth(now, tz);
|
|
324
369
|
const todayStart = startOfDay(now, tz);
|
|
325
370
|
const weekStart = startOfWeek(now, tz);
|
|
326
|
-
const entries = await loadEntries(monthStart);
|
|
371
|
+
const entries = await loadEntries(monthStart, homeDir);
|
|
327
372
|
const todayEntries = entries.filter((e) => e.ts >= todayStart);
|
|
328
373
|
let burnRate = 0;
|
|
329
374
|
if (todayEntries.length > 0) {
|
|
@@ -343,9 +388,9 @@ async function fetchDashboard(tz) {
|
|
|
343
388
|
burnRate
|
|
344
389
|
};
|
|
345
390
|
}
|
|
346
|
-
async function fetchTable(tz) {
|
|
391
|
+
async function fetchTable(tz, homeDir) {
|
|
347
392
|
const lookback = monthsAgoStart(Date.now(), 6, tz);
|
|
348
|
-
const entries = await loadEntries(lookback);
|
|
393
|
+
const entries = await loadEntries(lookback, homeDir);
|
|
349
394
|
return {
|
|
350
395
|
daily: groupBy(entries, (e) => dayKey(e.ts, tz)),
|
|
351
396
|
weekly: groupBy(entries, (e) => weekKey(e.ts, tz)),
|
|
@@ -360,13 +405,14 @@ import { join as join3 } from "path";
|
|
|
360
405
|
import { homedir as homedir3 } from "os";
|
|
361
406
|
import { promisify } from "util";
|
|
362
407
|
var execFile = promisify(execFileCb);
|
|
363
|
-
function credentialsFilePath() {
|
|
408
|
+
function credentialsFilePath(homeDir) {
|
|
409
|
+
if (homeDir) return join3(homeDir, ".claude", ".credentials.json");
|
|
364
410
|
const base = process.env.CLAUDE_CONFIG_DIR ?? join3(homedir3(), ".claude");
|
|
365
411
|
return join3(base, ".credentials.json");
|
|
366
412
|
}
|
|
367
|
-
async function readCredentialsFile() {
|
|
413
|
+
async function readCredentialsFile(homeDir) {
|
|
368
414
|
try {
|
|
369
|
-
const raw = await readFile2(credentialsFilePath(), "utf-8");
|
|
415
|
+
const raw = await readFile2(credentialsFilePath(homeDir), "utf-8");
|
|
370
416
|
const creds = JSON.parse(raw);
|
|
371
417
|
return creds?.claudeAiOauth?.accessToken ?? creds?.accessToken ?? null;
|
|
372
418
|
} catch {
|
|
@@ -387,7 +433,12 @@ async function readMacKeychain() {
|
|
|
387
433
|
return null;
|
|
388
434
|
}
|
|
389
435
|
}
|
|
390
|
-
async function getAccessToken() {
|
|
436
|
+
async function getAccessToken(homeDir) {
|
|
437
|
+
if (homeDir) {
|
|
438
|
+
const fromFile = await readCredentialsFile(homeDir);
|
|
439
|
+
if (fromFile) return fromFile;
|
|
440
|
+
return null;
|
|
441
|
+
}
|
|
391
442
|
if (process.platform === "darwin") {
|
|
392
443
|
const token = await readMacKeychain();
|
|
393
444
|
if (token) return token;
|
|
@@ -395,8 +446,8 @@ async function getAccessToken() {
|
|
|
395
446
|
return readCredentialsFile();
|
|
396
447
|
}
|
|
397
448
|
var EMPTY = { session: null, weekly: null, sonnet: null, extraUsage: null, peak: null, error: null };
|
|
398
|
-
async function fetchBilling() {
|
|
399
|
-
const token = await getAccessToken();
|
|
449
|
+
async function fetchBilling(homeDir) {
|
|
450
|
+
const token = await getAccessToken(homeDir);
|
|
400
451
|
if (!token) return { ...EMPTY, error: "No OAuth token \u2014 run claude and log in" };
|
|
401
452
|
const [usageRes, peak] = await Promise.all([
|
|
402
453
|
fetchUsage(token),
|
|
@@ -519,12 +570,36 @@ var VIEWS = ["Daily", "Weekly", "Monthly"];
|
|
|
519
570
|
var SORTS = ["date \u2191", "date \u2193", "cost \u2191", "cost \u2193"];
|
|
520
571
|
var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
521
572
|
var MONTHS = ["", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
|
|
522
|
-
var DEFAULT_CONFIG = {
|
|
523
|
-
|
|
573
|
+
var DEFAULT_CONFIG = {
|
|
574
|
+
interval: 2,
|
|
575
|
+
billingInterval: 5,
|
|
576
|
+
clearScreen: true,
|
|
577
|
+
timezone: null,
|
|
578
|
+
accounts: [],
|
|
579
|
+
activeAccountId: null
|
|
580
|
+
};
|
|
581
|
+
var GENERAL_ROWS = 4;
|
|
524
582
|
var IS_TTY = process.stdin.isTTY === true;
|
|
583
|
+
function buildSlots(config2) {
|
|
584
|
+
const slots = [];
|
|
585
|
+
if (config2.accounts.length === 0) {
|
|
586
|
+
slots.push({ id: null, name: "Default", homeDir: void 0, color: "green" });
|
|
587
|
+
return slots;
|
|
588
|
+
}
|
|
589
|
+
slots.push({ id: null, name: "All", homeDir: void 0, color: "whiteBright" });
|
|
590
|
+
for (const a of config2.accounts) {
|
|
591
|
+
slots.push({
|
|
592
|
+
id: a.id,
|
|
593
|
+
name: a.name,
|
|
594
|
+
homeDir: expandHome(a.homeDir),
|
|
595
|
+
color: a.color || "cyan"
|
|
596
|
+
});
|
|
597
|
+
}
|
|
598
|
+
return slots;
|
|
599
|
+
}
|
|
525
600
|
function App({ interval: cliInterval }) {
|
|
526
|
-
const [
|
|
527
|
-
const [
|
|
601
|
+
const [config2, setConfig] = useState(null);
|
|
602
|
+
const [stats, setStats] = useState(/* @__PURE__ */ new Map());
|
|
528
603
|
const [table, setTable] = useState(null);
|
|
529
604
|
const [tableLoading, setTableLoading] = useState(false);
|
|
530
605
|
const [error, setError] = useState(null);
|
|
@@ -535,18 +610,28 @@ function App({ interval: cliInterval }) {
|
|
|
535
610
|
const [expanded, setExpanded] = useState(-1);
|
|
536
611
|
const [sort, setSort] = useState(1);
|
|
537
612
|
const [showSettings, setShowSettings] = useState(false);
|
|
538
|
-
const [config2, setConfig] = useState(null);
|
|
539
613
|
const [settingsCursor, setSettingsCursor] = useState(0);
|
|
540
614
|
const [tzEdit, setTzEdit] = useState(null);
|
|
541
615
|
const [tzError, setTzError] = useState(null);
|
|
616
|
+
const [accountForm, setAccountForm] = useState(null);
|
|
542
617
|
const tableLoadedOnce = useRef(false);
|
|
543
618
|
const { stdout } = useStdout();
|
|
544
619
|
const { exit } = useApp();
|
|
545
620
|
const rows = stdout?.rows ?? 24;
|
|
546
621
|
const cols = stdout?.columns ?? 80;
|
|
547
|
-
const interval2 = cliInterval ?? (config2?.interval ?? 2) * 1e3;
|
|
548
622
|
const cfg = config2 ?? DEFAULT_CONFIG;
|
|
623
|
+
const interval2 = cliInterval ?? cfg.interval * 1e3;
|
|
549
624
|
const tz = resolveTimezone(cfg.timezone);
|
|
625
|
+
const slots = buildSlots(cfg);
|
|
626
|
+
const activeSlotIdx = (() => {
|
|
627
|
+
if (cfg.accounts.length === 0) return 0;
|
|
628
|
+
if (cfg.activeAccountId === null) return 0;
|
|
629
|
+
const i = slots.findIndex((s) => s.id === cfg.activeAccountId);
|
|
630
|
+
return i < 0 ? 0 : i;
|
|
631
|
+
})();
|
|
632
|
+
const activeSlot = slots[activeSlotIdx];
|
|
633
|
+
const slotKey = (s) => s.id ?? "__default__";
|
|
634
|
+
const visibleSlots = activeSlot.id === null && cfg.accounts.length > 0 ? slots.slice(1) : [activeSlot];
|
|
550
635
|
useEffect(() => {
|
|
551
636
|
loadConfig().then((c) => {
|
|
552
637
|
if (cliInterval) c = { ...c, interval: cliInterval / 1e3 };
|
|
@@ -554,12 +639,21 @@ function App({ interval: cliInterval }) {
|
|
|
554
639
|
});
|
|
555
640
|
}, []);
|
|
556
641
|
useEffect(() => {
|
|
642
|
+
if (!config2) return;
|
|
557
643
|
let active = true;
|
|
644
|
+
const slotsToLoad = activeSlot.id === null && cfg.accounts.length > 0 ? slots.slice(1) : [activeSlot];
|
|
558
645
|
const load = async () => {
|
|
559
646
|
try {
|
|
560
|
-
const
|
|
647
|
+
const next = /* @__PURE__ */ new Map();
|
|
648
|
+
await Promise.all(slotsToLoad.map(async (slot) => {
|
|
649
|
+
const [dashboard, billing] = await Promise.all([
|
|
650
|
+
fetchDashboard(tz, slot.homeDir),
|
|
651
|
+
fetchBilling(slot.homeDir)
|
|
652
|
+
]);
|
|
653
|
+
next.set(slotKey(slot), { slot, dashboard, billing });
|
|
654
|
+
}));
|
|
561
655
|
if (active) {
|
|
562
|
-
|
|
656
|
+
setStats(next);
|
|
563
657
|
setError(null);
|
|
564
658
|
setUpdated(/* @__PURE__ */ new Date());
|
|
565
659
|
}
|
|
@@ -573,31 +667,17 @@ function App({ interval: cliInterval }) {
|
|
|
573
667
|
active = false;
|
|
574
668
|
clearInterval(id);
|
|
575
669
|
};
|
|
576
|
-
}, [interval2, tz]);
|
|
577
|
-
const billingMs = cfg.billingInterval * 6e4;
|
|
578
|
-
useEffect(() => {
|
|
579
|
-
let active = true;
|
|
580
|
-
const load = () => fetchBilling().then((b) => {
|
|
581
|
-
if (active) setBilling(b);
|
|
582
|
-
}).catch(() => {
|
|
583
|
-
});
|
|
584
|
-
load();
|
|
585
|
-
const id = setInterval(load, billingMs);
|
|
586
|
-
return () => {
|
|
587
|
-
active = false;
|
|
588
|
-
clearInterval(id);
|
|
589
|
-
};
|
|
590
|
-
}, [billingMs]);
|
|
670
|
+
}, [interval2, tz, config2, activeSlot.id]);
|
|
591
671
|
useEffect(() => {
|
|
592
672
|
tableLoadedOnce.current = false;
|
|
593
673
|
setTable(null);
|
|
594
|
-
}, [tz]);
|
|
674
|
+
}, [tz, activeSlot.id]);
|
|
595
675
|
useEffect(() => {
|
|
596
676
|
if (tab !== 1) return;
|
|
597
677
|
if (tableLoadedOnce.current && table) return;
|
|
598
678
|
let active = true;
|
|
599
679
|
setTableLoading(true);
|
|
600
|
-
fetchTable(tz).then((result) => {
|
|
680
|
+
fetchTable(tz, activeSlot.id === null ? void 0 : activeSlot.homeDir).then((result) => {
|
|
601
681
|
if (active) {
|
|
602
682
|
setTable(result);
|
|
603
683
|
setTableLoading(false);
|
|
@@ -609,13 +689,13 @@ function App({ interval: cliInterval }) {
|
|
|
609
689
|
return () => {
|
|
610
690
|
active = false;
|
|
611
691
|
};
|
|
612
|
-
}, [tab, tz]);
|
|
692
|
+
}, [tab, tz, activeSlot.id]);
|
|
613
693
|
useEffect(() => {
|
|
614
694
|
if (tab !== 1 || !tableLoadedOnce.current) return;
|
|
615
695
|
let active = true;
|
|
616
696
|
const id = setInterval(async () => {
|
|
617
697
|
try {
|
|
618
|
-
const result = await fetchTable(tz);
|
|
698
|
+
const result = await fetchTable(tz, activeSlot.id === null ? void 0 : activeSlot.homeDir);
|
|
619
699
|
if (active) setTable(result);
|
|
620
700
|
} catch {
|
|
621
701
|
}
|
|
@@ -624,7 +704,7 @@ function App({ interval: cliInterval }) {
|
|
|
624
704
|
active = false;
|
|
625
705
|
clearInterval(id);
|
|
626
706
|
};
|
|
627
|
-
}, [tab, interval2, tz]);
|
|
707
|
+
}, [tab, interval2, tz, activeSlot.id]);
|
|
628
708
|
const resetView = useCallback(() => {
|
|
629
709
|
setCursor(0);
|
|
630
710
|
setExpanded(-1);
|
|
@@ -643,7 +723,156 @@ function App({ interval: cliInterval }) {
|
|
|
643
723
|
mouse.events.off("scroll", onScroll);
|
|
644
724
|
};
|
|
645
725
|
}, [tab]);
|
|
726
|
+
function updateConfig(fn) {
|
|
727
|
+
setConfig((prev) => {
|
|
728
|
+
const next = fn(prev ?? DEFAULT_CONFIG);
|
|
729
|
+
saveConfig(next);
|
|
730
|
+
return next;
|
|
731
|
+
});
|
|
732
|
+
}
|
|
733
|
+
function cycleAccount(dir) {
|
|
734
|
+
if (slots.length <= 1) return;
|
|
735
|
+
const next = (activeSlotIdx + dir + slots.length) % slots.length;
|
|
736
|
+
const targetId = slots[next].id;
|
|
737
|
+
updateConfig((c) => ({ ...c, activeAccountId: targetId }));
|
|
738
|
+
resetView();
|
|
739
|
+
}
|
|
740
|
+
function openAddAccount() {
|
|
741
|
+
setAccountForm({
|
|
742
|
+
mode: "add",
|
|
743
|
+
field: "name",
|
|
744
|
+
name: "",
|
|
745
|
+
homeDir: "~",
|
|
746
|
+
color: pickAccentColor(cfg.accounts),
|
|
747
|
+
editingId: null,
|
|
748
|
+
error: null
|
|
749
|
+
});
|
|
750
|
+
}
|
|
751
|
+
function openEditAccount(acc) {
|
|
752
|
+
setAccountForm({
|
|
753
|
+
mode: "edit",
|
|
754
|
+
field: "name",
|
|
755
|
+
name: acc.name,
|
|
756
|
+
homeDir: acc.homeDir,
|
|
757
|
+
color: acc.color || "cyan",
|
|
758
|
+
editingId: acc.id,
|
|
759
|
+
error: null
|
|
760
|
+
});
|
|
761
|
+
}
|
|
762
|
+
function commitAccountForm() {
|
|
763
|
+
if (!accountForm) return;
|
|
764
|
+
const name = accountForm.name.trim();
|
|
765
|
+
const homeDir = accountForm.homeDir.trim() || "~";
|
|
766
|
+
const color = accountForm.color;
|
|
767
|
+
if (!name) {
|
|
768
|
+
setAccountForm({ ...accountForm, error: "Name required", field: "name" });
|
|
769
|
+
return;
|
|
770
|
+
}
|
|
771
|
+
updateConfig((c) => {
|
|
772
|
+
if (accountForm.mode === "add") {
|
|
773
|
+
const id = generateAccountId(name, c.accounts);
|
|
774
|
+
const account = { id, name, homeDir, color };
|
|
775
|
+
return {
|
|
776
|
+
...c,
|
|
777
|
+
accounts: [...c.accounts, account],
|
|
778
|
+
activeAccountId: c.accounts.length === 0 ? id : c.activeAccountId
|
|
779
|
+
};
|
|
780
|
+
} else {
|
|
781
|
+
return {
|
|
782
|
+
...c,
|
|
783
|
+
accounts: c.accounts.map(
|
|
784
|
+
(a) => a.id === accountForm.editingId ? { ...a, name, homeDir, color } : a
|
|
785
|
+
)
|
|
786
|
+
};
|
|
787
|
+
}
|
|
788
|
+
});
|
|
789
|
+
setAccountForm(null);
|
|
790
|
+
}
|
|
791
|
+
function cycleFormField(dir) {
|
|
792
|
+
const order = ["name", "homeDir", "color"];
|
|
793
|
+
setAccountForm((f) => {
|
|
794
|
+
if (!f) return f;
|
|
795
|
+
const i = order.indexOf(f.field);
|
|
796
|
+
const next = order[(i + dir + order.length) % order.length];
|
|
797
|
+
return { ...f, field: next };
|
|
798
|
+
});
|
|
799
|
+
}
|
|
800
|
+
function cycleColor(dir) {
|
|
801
|
+
setAccountForm((f) => {
|
|
802
|
+
if (!f) return f;
|
|
803
|
+
const i = COLOR_PALETTE.indexOf(f.color);
|
|
804
|
+
const idx = i < 0 ? 0 : i;
|
|
805
|
+
const next = COLOR_PALETTE[(idx + dir + COLOR_PALETTE.length) % COLOR_PALETTE.length];
|
|
806
|
+
return { ...f, color: next };
|
|
807
|
+
});
|
|
808
|
+
}
|
|
809
|
+
function deleteAccount(id) {
|
|
810
|
+
updateConfig((c) => ({
|
|
811
|
+
...c,
|
|
812
|
+
accounts: c.accounts.filter((a) => a.id !== id),
|
|
813
|
+
activeAccountId: c.activeAccountId === id ? null : c.activeAccountId
|
|
814
|
+
}));
|
|
815
|
+
}
|
|
816
|
+
const accountRowsStart = GENERAL_ROWS;
|
|
817
|
+
const totalSettingsRows = GENERAL_ROWS + cfg.accounts.length + 1;
|
|
646
818
|
useInput((input, key) => {
|
|
819
|
+
if (showSettings && accountForm) {
|
|
820
|
+
if (key.escape) {
|
|
821
|
+
setAccountForm(null);
|
|
822
|
+
return;
|
|
823
|
+
}
|
|
824
|
+
if (key.tab) {
|
|
825
|
+
cycleFormField(key.shift ? -1 : 1);
|
|
826
|
+
return;
|
|
827
|
+
}
|
|
828
|
+
if (key.upArrow) {
|
|
829
|
+
cycleFormField(-1);
|
|
830
|
+
return;
|
|
831
|
+
}
|
|
832
|
+
if (key.downArrow) {
|
|
833
|
+
cycleFormField(1);
|
|
834
|
+
return;
|
|
835
|
+
}
|
|
836
|
+
if (accountForm.field === "color") {
|
|
837
|
+
if (key.leftArrow) {
|
|
838
|
+
cycleColor(-1);
|
|
839
|
+
return;
|
|
840
|
+
}
|
|
841
|
+
if (key.rightArrow) {
|
|
842
|
+
cycleColor(1);
|
|
843
|
+
return;
|
|
844
|
+
}
|
|
845
|
+
if (key.return) {
|
|
846
|
+
commitAccountForm();
|
|
847
|
+
return;
|
|
848
|
+
}
|
|
849
|
+
return;
|
|
850
|
+
}
|
|
851
|
+
if (key.return) {
|
|
852
|
+
if (accountForm.field === "name") {
|
|
853
|
+
setAccountForm((f) => f && { ...f, field: "homeDir" });
|
|
854
|
+
} else if (accountForm.field === "homeDir") {
|
|
855
|
+
setAccountForm((f) => f && { ...f, field: "color" });
|
|
856
|
+
}
|
|
857
|
+
return;
|
|
858
|
+
}
|
|
859
|
+
if (key.backspace || key.delete) {
|
|
860
|
+
setAccountForm((f) => {
|
|
861
|
+
if (!f || f.field === "color") return f;
|
|
862
|
+
const cur = f[f.field];
|
|
863
|
+
return { ...f, [f.field]: cur.slice(0, -1), error: null };
|
|
864
|
+
});
|
|
865
|
+
return;
|
|
866
|
+
}
|
|
867
|
+
if (input && !key.ctrl && !key.meta) {
|
|
868
|
+
setAccountForm((f) => {
|
|
869
|
+
if (!f || f.field === "color") return f;
|
|
870
|
+
return { ...f, [f.field]: f[f.field] + input, error: null };
|
|
871
|
+
});
|
|
872
|
+
return;
|
|
873
|
+
}
|
|
874
|
+
return;
|
|
875
|
+
}
|
|
647
876
|
if (showSettings && tzEdit !== null) {
|
|
648
877
|
if (key.escape) {
|
|
649
878
|
setTzEdit(null);
|
|
@@ -682,19 +911,31 @@ function App({ interval: cliInterval }) {
|
|
|
682
911
|
return;
|
|
683
912
|
}
|
|
684
913
|
if (showSettings) {
|
|
685
|
-
if (key.escape || input === "s")
|
|
686
|
-
|
|
687
|
-
|
|
914
|
+
if (key.escape || input === "s") {
|
|
915
|
+
setShowSettings(false);
|
|
916
|
+
return;
|
|
917
|
+
}
|
|
918
|
+
if (key.upArrow) {
|
|
919
|
+
setSettingsCursor((c) => Math.max(0, c - 1));
|
|
920
|
+
return;
|
|
921
|
+
}
|
|
922
|
+
if (key.downArrow) {
|
|
923
|
+
setSettingsCursor((c) => Math.min(totalSettingsRows - 1, c + 1));
|
|
924
|
+
return;
|
|
925
|
+
}
|
|
688
926
|
if (settingsCursor === 0) {
|
|
689
927
|
if (key.leftArrow) updateConfig((c) => ({ ...c, interval: Math.max(1, c.interval - 1) }));
|
|
690
928
|
if (key.rightArrow) updateConfig((c) => ({ ...c, interval: c.interval + 1 }));
|
|
929
|
+
return;
|
|
691
930
|
}
|
|
692
931
|
if (settingsCursor === 1) {
|
|
693
932
|
if (key.leftArrow) updateConfig((c) => ({ ...c, billingInterval: Math.max(1, c.billingInterval - 1) }));
|
|
694
933
|
if (key.rightArrow) updateConfig((c) => ({ ...c, billingInterval: c.billingInterval + 1 }));
|
|
934
|
+
return;
|
|
695
935
|
}
|
|
696
936
|
if (settingsCursor === 2 && (key.leftArrow || key.rightArrow || key.return)) {
|
|
697
937
|
updateConfig((c) => ({ ...c, clearScreen: !c.clearScreen }));
|
|
938
|
+
return;
|
|
698
939
|
}
|
|
699
940
|
if (settingsCursor === 3) {
|
|
700
941
|
if (key.return) {
|
|
@@ -704,11 +945,42 @@ function App({ interval: cliInterval }) {
|
|
|
704
945
|
if (key.leftArrow || key.rightArrow) {
|
|
705
946
|
updateConfig((c) => ({ ...c, timezone: c.timezone === null ? systemTimezone() : null }));
|
|
706
947
|
}
|
|
948
|
+
return;
|
|
949
|
+
}
|
|
950
|
+
const accIdx = settingsCursor - accountRowsStart;
|
|
951
|
+
if (accIdx >= 0 && accIdx < cfg.accounts.length) {
|
|
952
|
+
const acc = cfg.accounts[accIdx];
|
|
953
|
+
if (key.return) {
|
|
954
|
+
openEditAccount(acc);
|
|
955
|
+
return;
|
|
956
|
+
}
|
|
957
|
+
if (input === "d" || input === "x") {
|
|
958
|
+
deleteAccount(acc.id);
|
|
959
|
+
return;
|
|
960
|
+
}
|
|
961
|
+
if (input === " ") {
|
|
962
|
+
updateConfig((c) => ({ ...c, activeAccountId: acc.id }));
|
|
963
|
+
return;
|
|
964
|
+
}
|
|
965
|
+
return;
|
|
966
|
+
}
|
|
967
|
+
if (accIdx === cfg.accounts.length && key.return) {
|
|
968
|
+
openAddAccount();
|
|
969
|
+
return;
|
|
707
970
|
}
|
|
708
971
|
return;
|
|
709
972
|
}
|
|
710
973
|
if (input === "s") {
|
|
711
974
|
setShowSettings(true);
|
|
975
|
+
setSettingsCursor(0);
|
|
976
|
+
return;
|
|
977
|
+
}
|
|
978
|
+
if (input === "a") {
|
|
979
|
+
cycleAccount(1);
|
|
980
|
+
return;
|
|
981
|
+
}
|
|
982
|
+
if (input === "A") {
|
|
983
|
+
cycleAccount(-1);
|
|
712
984
|
return;
|
|
713
985
|
}
|
|
714
986
|
if (key.tab) {
|
|
@@ -789,15 +1061,11 @@ function App({ interval: cliInterval }) {
|
|
|
789
1061
|
return;
|
|
790
1062
|
}
|
|
791
1063
|
}, { isActive: IS_TTY });
|
|
792
|
-
function updateConfig(fn) {
|
|
793
|
-
setConfig((prev) => {
|
|
794
|
-
const next = fn(prev ?? DEFAULT_CONFIG);
|
|
795
|
-
saveConfig(next);
|
|
796
|
-
return next;
|
|
797
|
-
});
|
|
798
|
-
}
|
|
799
1064
|
if (error) return /* @__PURE__ */ jsx(Box, { padding: 1, children: /* @__PURE__ */ jsx(Text, { color: "red", children: error }) });
|
|
800
|
-
if (!
|
|
1065
|
+
if (!config2) return /* @__PURE__ */ jsx(Box, { padding: 1, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Loading..." }) });
|
|
1066
|
+
const firstStats = stats.size > 0 ? [...stats.values()][0] : null;
|
|
1067
|
+
if (!firstStats?.dashboard) return /* @__PURE__ */ jsx(Box, { padding: 1, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Loading..." }) });
|
|
1068
|
+
const peakBilling = firstStats.billing;
|
|
801
1069
|
const rawTableData = table ? [table.daily, table.weekly, table.monthly][view] : [];
|
|
802
1070
|
const tableData = sortRows(rawTableData, sort);
|
|
803
1071
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", paddingX: 2, paddingY: 1, height: rows, children: [
|
|
@@ -809,20 +1077,47 @@ function App({ interval: cliInterval }) {
|
|
|
809
1077
|
] }),
|
|
810
1078
|
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
811
1079
|
" \xB7 every ",
|
|
812
|
-
|
|
1080
|
+
cfg.interval,
|
|
813
1081
|
"s"
|
|
814
1082
|
] })
|
|
815
1083
|
] }),
|
|
816
1084
|
/* @__PURE__ */ jsxs(Box, { children: [
|
|
817
|
-
|
|
818
|
-
/* @__PURE__ */ jsx(PeakBadge, { peak:
|
|
1085
|
+
peakBilling?.peak && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1086
|
+
/* @__PURE__ */ jsx(PeakBadge, { peak: peakBilling.peak }),
|
|
819
1087
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: " \xB7 " })
|
|
820
1088
|
] }),
|
|
821
1089
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: time(updated, tz) })
|
|
822
1090
|
] })
|
|
823
1091
|
] }),
|
|
824
|
-
showSettings ? /* @__PURE__ */ jsx(
|
|
825
|
-
|
|
1092
|
+
showSettings ? /* @__PURE__ */ jsx(
|
|
1093
|
+
SettingsView,
|
|
1094
|
+
{
|
|
1095
|
+
config: cfg,
|
|
1096
|
+
cursor: settingsCursor,
|
|
1097
|
+
tzEdit,
|
|
1098
|
+
tzError,
|
|
1099
|
+
resolvedTz: tz,
|
|
1100
|
+
accountForm,
|
|
1101
|
+
onSettingsClick: (i) => setSettingsCursor(i),
|
|
1102
|
+
onAddAccount: openAddAccount,
|
|
1103
|
+
onEditAccount: openEditAccount,
|
|
1104
|
+
onActivateAccount: (id) => updateConfig((c) => ({ ...c, activeAccountId: id })),
|
|
1105
|
+
activeAccountId: cfg.activeAccountId
|
|
1106
|
+
}
|
|
1107
|
+
) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1108
|
+
slots.length > 1 && /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(
|
|
1109
|
+
AccountStrip,
|
|
1110
|
+
{
|
|
1111
|
+
slots,
|
|
1112
|
+
activeIdx: activeSlotIdx,
|
|
1113
|
+
onSelect: (i) => {
|
|
1114
|
+
const id = slots[i].id;
|
|
1115
|
+
updateConfig((c) => ({ ...c, activeAccountId: id }));
|
|
1116
|
+
resetView();
|
|
1117
|
+
}
|
|
1118
|
+
}
|
|
1119
|
+
) }),
|
|
1120
|
+
/* @__PURE__ */ jsxs(Box, { marginTop: slots.length > 1 ? 0 : 1, children: [
|
|
826
1121
|
/* @__PURE__ */ jsx(TabBar, { tabs: TABS, active: tab, onSelect: (i) => {
|
|
827
1122
|
setTab(i);
|
|
828
1123
|
resetView();
|
|
@@ -830,7 +1125,14 @@ function App({ interval: cliInterval }) {
|
|
|
830
1125
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: " Tab/\u2190\u2192" })
|
|
831
1126
|
] }),
|
|
832
1127
|
/* @__PURE__ */ jsx(Box, { height: 1 }),
|
|
833
|
-
tab === 0 && /* @__PURE__ */ jsx(
|
|
1128
|
+
tab === 0 && /* @__PURE__ */ jsx(
|
|
1129
|
+
DashboardView,
|
|
1130
|
+
{
|
|
1131
|
+
slots: visibleSlots,
|
|
1132
|
+
stats,
|
|
1133
|
+
compact: visibleSlots.length > 1
|
|
1134
|
+
}
|
|
1135
|
+
),
|
|
834
1136
|
tab === 1 && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
835
1137
|
/* @__PURE__ */ jsx(ViewBar, { views: VIEWS, active: view, sort: SORTS[sort], onSelect: (i) => {
|
|
836
1138
|
setView(i);
|
|
@@ -843,7 +1145,7 @@ function App({ interval: cliInterval }) {
|
|
|
843
1145
|
rows: tableData,
|
|
844
1146
|
cursor,
|
|
845
1147
|
expanded,
|
|
846
|
-
maxRows: rows -
|
|
1148
|
+
maxRows: rows - 14,
|
|
847
1149
|
cols,
|
|
848
1150
|
onRowClick: (idx) => {
|
|
849
1151
|
if (idx === cursor) setExpanded((e) => e === idx ? -1 : idx);
|
|
@@ -853,16 +1155,18 @@ function App({ interval: cliInterval }) {
|
|
|
853
1155
|
)
|
|
854
1156
|
] })
|
|
855
1157
|
] }),
|
|
856
|
-
(tab === 0 || showSettings) && /* @__PURE__ */ jsx(Footer, {})
|
|
1158
|
+
(tab === 0 || showSettings) && /* @__PURE__ */ jsx(Footer, { hasAccounts: slots.length > 1 })
|
|
857
1159
|
] });
|
|
858
1160
|
}
|
|
859
|
-
function Footer() {
|
|
1161
|
+
function Footer({ hasAccounts }) {
|
|
860
1162
|
return /* @__PURE__ */ jsxs(Box, { marginTop: 1, children: [
|
|
861
1163
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "by " }),
|
|
862
1164
|
/* @__PURE__ */ jsx(Text, { children: "David Ilie" }),
|
|
863
1165
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: " (" }),
|
|
864
1166
|
/* @__PURE__ */ jsx(Text, { color: "cyan", children: "davidilie.com" }),
|
|
865
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: ") \xB7 s=settings
|
|
1167
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: ") \xB7 s=settings " }),
|
|
1168
|
+
hasAccounts && /* @__PURE__ */ jsx(Text, { dimColor: true, children: "a/A=cycle account " }),
|
|
1169
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "q=quit" })
|
|
866
1170
|
] });
|
|
867
1171
|
}
|
|
868
1172
|
function TabBar({ tabs, active, onSelect }) {
|
|
@@ -876,6 +1180,30 @@ function TabBar({ tabs, active, onSelect }) {
|
|
|
876
1180
|
" "
|
|
877
1181
|
] }) }, t)) });
|
|
878
1182
|
}
|
|
1183
|
+
function AccountStrip({ slots, activeIdx, onSelect }) {
|
|
1184
|
+
return /* @__PURE__ */ jsxs(Box, { children: [
|
|
1185
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "account " }),
|
|
1186
|
+
slots.map((s, i) => {
|
|
1187
|
+
const active = i === activeIdx;
|
|
1188
|
+
const dot = s.id === null ? "\u2726" : "\u25CF";
|
|
1189
|
+
return /* @__PURE__ */ jsx(ClickableBox, { onClick: () => onSelect(i), marginRight: 2, children: active ? /* @__PURE__ */ jsxs(Text, { bold: true, color: s.color, children: [
|
|
1190
|
+
/* @__PURE__ */ jsxs(Text, { children: [
|
|
1191
|
+
dot,
|
|
1192
|
+
" "
|
|
1193
|
+
] }),
|
|
1194
|
+
/* @__PURE__ */ jsxs(Text, { inverse: true, children: [
|
|
1195
|
+
" ",
|
|
1196
|
+
s.name,
|
|
1197
|
+
" "
|
|
1198
|
+
] })
|
|
1199
|
+
] }) : /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
1200
|
+
dot,
|
|
1201
|
+
" ",
|
|
1202
|
+
s.name
|
|
1203
|
+
] }) }, s.id ?? "__all__");
|
|
1204
|
+
})
|
|
1205
|
+
] });
|
|
1206
|
+
}
|
|
879
1207
|
function ViewBar({ views, active, sort, onSelect }) {
|
|
880
1208
|
return /* @__PURE__ */ jsxs(Box, { children: [
|
|
881
1209
|
views.map((v, i) => /* @__PURE__ */ jsx(ClickableBox, { onClick: () => onSelect(i), marginRight: 2, children: i === active ? /* @__PURE__ */ jsxs(Text, { bold: true, color: "cyan", children: [
|
|
@@ -904,13 +1232,40 @@ function sortRows(rows, sortIdx) {
|
|
|
904
1232
|
return sorted;
|
|
905
1233
|
}
|
|
906
1234
|
}
|
|
907
|
-
|
|
908
|
-
|
|
1235
|
+
var COLOR_PALETTE = [
|
|
1236
|
+
"cyan",
|
|
1237
|
+
"magenta",
|
|
1238
|
+
"green",
|
|
1239
|
+
"yellow",
|
|
1240
|
+
"blue",
|
|
1241
|
+
"red",
|
|
1242
|
+
"cyanBright",
|
|
1243
|
+
"magentaBright",
|
|
1244
|
+
"greenBright"
|
|
1245
|
+
];
|
|
1246
|
+
function SettingsView({
|
|
1247
|
+
config: config2,
|
|
1248
|
+
cursor,
|
|
1249
|
+
tzEdit,
|
|
1250
|
+
tzError,
|
|
1251
|
+
resolvedTz,
|
|
1252
|
+
accountForm,
|
|
1253
|
+
onAddAccount,
|
|
1254
|
+
onEditAccount,
|
|
1255
|
+
onActivateAccount,
|
|
1256
|
+
activeAccountId
|
|
1257
|
+
}) {
|
|
1258
|
+
const editingTz = tzEdit !== null;
|
|
909
1259
|
const tzDisplay = config2.timezone === null ? `System (${resolvedTz})` : config2.timezone;
|
|
1260
|
+
const accountRowsStart = GENERAL_ROWS;
|
|
1261
|
+
if (accountForm) {
|
|
1262
|
+
return /* @__PURE__ */ jsx(AccountFormView, { form: accountForm, accounts: config2.accounts });
|
|
1263
|
+
}
|
|
910
1264
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
|
|
911
1265
|
/* @__PURE__ */ jsx(Text, { bold: true, children: "Settings" }),
|
|
912
1266
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: configLocation() }),
|
|
913
1267
|
/* @__PURE__ */ jsx(Box, { height: 1 }),
|
|
1268
|
+
/* @__PURE__ */ jsx(Text, { bold: true, dimColor: true, children: "General" }),
|
|
914
1269
|
/* @__PURE__ */ jsxs(Box, { children: [
|
|
915
1270
|
/* @__PURE__ */ jsxs(Text, { color: cursor === 0 ? "green" : void 0, children: [
|
|
916
1271
|
cursor === 0 ? "\u25B8" : " ",
|
|
@@ -963,7 +1318,7 @@ function SettingsView({ config: config2, cursor, tzEdit, tzError, resolvedTz })
|
|
|
963
1318
|
" "
|
|
964
1319
|
] }),
|
|
965
1320
|
/* @__PURE__ */ jsx(Text, { children: "Timezone " }),
|
|
966
|
-
|
|
1321
|
+
editingTz ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
967
1322
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "[" }),
|
|
968
1323
|
/* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: tzEdit }),
|
|
969
1324
|
/* @__PURE__ */ jsx(Text, { color: "cyan", children: "_" }),
|
|
@@ -975,72 +1330,323 @@ function SettingsView({ config: config2, cursor, tzEdit, tzError, resolvedTz })
|
|
|
975
1330
|
tzError
|
|
976
1331
|
] }),
|
|
977
1332
|
/* @__PURE__ */ jsx(Box, { height: 1 }),
|
|
978
|
-
|
|
1333
|
+
/* @__PURE__ */ jsx(Text, { bold: true, dimColor: true, children: "Claude accounts" }),
|
|
1334
|
+
config2.accounts.length === 0 && /* @__PURE__ */ jsx(Text, { dimColor: true, children: " none \u2014 using default Claude HOME" }),
|
|
1335
|
+
config2.accounts.map((acc, i) => {
|
|
1336
|
+
const idx = accountRowsStart + i;
|
|
1337
|
+
const selected = cursor === idx;
|
|
1338
|
+
const isActive = acc.id === activeAccountId;
|
|
1339
|
+
return /* @__PURE__ */ jsxs(Box, { children: [
|
|
1340
|
+
/* @__PURE__ */ jsxs(Text, { color: selected ? "green" : void 0, children: [
|
|
1341
|
+
selected ? "\u25B8" : " ",
|
|
1342
|
+
" "
|
|
1343
|
+
] }),
|
|
1344
|
+
/* @__PURE__ */ jsxs(Text, { color: acc.color || "cyan", children: [
|
|
1345
|
+
isActive ? "\u25CF" : "\u25CB",
|
|
1346
|
+
" "
|
|
1347
|
+
] }),
|
|
1348
|
+
/* @__PURE__ */ jsx(Box, { width: 16, children: /* @__PURE__ */ jsx(Text, { bold: true, children: acc.name }) }),
|
|
1349
|
+
/* @__PURE__ */ jsx(Box, { width: 14, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: acc.id }) }),
|
|
1350
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: acc.homeDir })
|
|
1351
|
+
] }, acc.id);
|
|
1352
|
+
}),
|
|
1353
|
+
/* @__PURE__ */ jsxs(Box, { children: [
|
|
1354
|
+
/* @__PURE__ */ jsxs(Text, { color: cursor === accountRowsStart + config2.accounts.length ? "green" : void 0, children: [
|
|
1355
|
+
cursor === accountRowsStart + config2.accounts.length ? "\u25B8" : " ",
|
|
1356
|
+
" "
|
|
1357
|
+
] }),
|
|
1358
|
+
/* @__PURE__ */ jsx(Text, { color: "greenBright", children: "+ " }),
|
|
1359
|
+
/* @__PURE__ */ jsx(Text, { children: "Add account" })
|
|
1360
|
+
] }),
|
|
1361
|
+
/* @__PURE__ */ jsx(Box, { height: 1 }),
|
|
1362
|
+
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" })
|
|
979
1363
|
] });
|
|
980
1364
|
}
|
|
981
|
-
function
|
|
982
|
-
|
|
1365
|
+
function AccountFormView({ form, accounts }) {
|
|
1366
|
+
const previewId = form.mode === "add" ? generateAccountId(form.name || "account", accounts) : form.editingId ?? "";
|
|
1367
|
+
const accent = form.color;
|
|
1368
|
+
const stepIndex = { name: 1, homeDir: 2, color: 3 };
|
|
1369
|
+
const step = stepIndex[form.field];
|
|
1370
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
|
|
1371
|
+
/* @__PURE__ */ jsxs(Box, { children: [
|
|
1372
|
+
/* @__PURE__ */ jsx(Text, { color: accent, bold: true, children: "\u258D" }),
|
|
1373
|
+
/* @__PURE__ */ jsxs(Text, { bold: true, children: [
|
|
1374
|
+
" ",
|
|
1375
|
+
form.mode === "add" ? "NEW ACCOUNT" : "EDIT ACCOUNT"
|
|
1376
|
+
] }),
|
|
1377
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
1378
|
+
" step ",
|
|
1379
|
+
step,
|
|
1380
|
+
" of 3"
|
|
1381
|
+
] })
|
|
1382
|
+
] }),
|
|
1383
|
+
/* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Stepper, { active: form.field, accent }) }),
|
|
983
1384
|
/* @__PURE__ */ jsxs(
|
|
984
1385
|
Box,
|
|
985
1386
|
{
|
|
1387
|
+
marginTop: 1,
|
|
986
1388
|
flexDirection: "column",
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
borderTop: false,
|
|
992
|
-
borderBottom: false,
|
|
1389
|
+
borderStyle: "round",
|
|
1390
|
+
borderColor: accent,
|
|
1391
|
+
paddingX: 2,
|
|
1392
|
+
paddingY: 1,
|
|
993
1393
|
children: [
|
|
994
|
-
/* @__PURE__ */ jsx(
|
|
1394
|
+
/* @__PURE__ */ jsx(
|
|
1395
|
+
FormField,
|
|
1396
|
+
{
|
|
1397
|
+
label: "Name",
|
|
1398
|
+
hint: "display name for this Claude account",
|
|
1399
|
+
value: form.name,
|
|
1400
|
+
focused: form.field === "name",
|
|
1401
|
+
accent,
|
|
1402
|
+
placeholder: "e.g. Work, Personal"
|
|
1403
|
+
}
|
|
1404
|
+
),
|
|
995
1405
|
/* @__PURE__ */ jsx(Box, { height: 1 }),
|
|
996
|
-
/* @__PURE__ */ jsx(
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1406
|
+
/* @__PURE__ */ jsx(
|
|
1407
|
+
FormField,
|
|
1408
|
+
{
|
|
1409
|
+
label: "Home directory",
|
|
1410
|
+
hint: "path containing .claude/ \xB7 ~ for default",
|
|
1411
|
+
value: form.homeDir,
|
|
1412
|
+
focused: form.field === "homeDir",
|
|
1413
|
+
accent,
|
|
1414
|
+
placeholder: "~/claude-work",
|
|
1415
|
+
mono: true
|
|
1416
|
+
}
|
|
1417
|
+
),
|
|
1418
|
+
/* @__PURE__ */ jsx(Box, { height: 1 }),
|
|
1419
|
+
/* @__PURE__ */ jsx(
|
|
1420
|
+
ColorField,
|
|
1421
|
+
{
|
|
1422
|
+
value: form.color,
|
|
1423
|
+
focused: form.field === "color"
|
|
1424
|
+
}
|
|
1425
|
+
),
|
|
1426
|
+
/* @__PURE__ */ jsx(Box, { height: 1 }),
|
|
1427
|
+
/* @__PURE__ */ jsxs(Box, { children: [
|
|
1428
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "id " }),
|
|
1429
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2524 " }),
|
|
1430
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: accent, children: previewId || "account" }),
|
|
1431
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: " \u251C" }),
|
|
1432
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: " auto-generated from name" })
|
|
1006
1433
|
] })
|
|
1007
1434
|
]
|
|
1008
1435
|
}
|
|
1009
1436
|
),
|
|
1010
|
-
/* @__PURE__ */ jsx(Box, {
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1437
|
+
form.error && /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsxs(Text, { color: "red", children: [
|
|
1438
|
+
"\u26A0 ",
|
|
1439
|
+
form.error
|
|
1440
|
+
] }) }),
|
|
1441
|
+
/* @__PURE__ */ jsxs(Box, { marginTop: 1, children: [
|
|
1442
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "tab/\u2191\u2193 " }),
|
|
1443
|
+
/* @__PURE__ */ jsx(Text, { children: "switch field" }),
|
|
1444
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: " \xB7 " }),
|
|
1445
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "enter " }),
|
|
1446
|
+
/* @__PURE__ */ jsx(Text, { children: form.field === "color" ? "save" : "next" }),
|
|
1447
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: " \xB7 " }),
|
|
1448
|
+
form.field === "color" && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1449
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2190\u2192 " }),
|
|
1450
|
+
/* @__PURE__ */ jsx(Text, { children: "pick color" }),
|
|
1451
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: " \xB7 " })
|
|
1452
|
+
] }),
|
|
1453
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "esc " }),
|
|
1454
|
+
/* @__PURE__ */ jsx(Text, { children: "cancel" })
|
|
1455
|
+
] })
|
|
1456
|
+
] });
|
|
1457
|
+
}
|
|
1458
|
+
function Stepper({ active, accent }) {
|
|
1459
|
+
const steps = [
|
|
1460
|
+
{ id: "name", label: "Name" },
|
|
1461
|
+
{ id: "homeDir", label: "Home" },
|
|
1462
|
+
{ id: "color", label: "Color" }
|
|
1463
|
+
];
|
|
1464
|
+
const order = steps.map((s) => s.id);
|
|
1465
|
+
const activeIdx = order.indexOf(active);
|
|
1466
|
+
return /* @__PURE__ */ jsx(Box, { children: steps.map((s, i) => {
|
|
1467
|
+
const done = i < activeIdx;
|
|
1468
|
+
const cur = i === activeIdx;
|
|
1469
|
+
const dot = done ? "\u25CF" : cur ? "\u25C9" : "\u25CB";
|
|
1470
|
+
return /* @__PURE__ */ jsxs(Box, { children: [
|
|
1471
|
+
/* @__PURE__ */ jsxs(Text, { color: cur ? accent : done ? accent : void 0, dimColor: !cur && !done, children: [
|
|
1472
|
+
dot,
|
|
1473
|
+
" "
|
|
1474
|
+
] }),
|
|
1475
|
+
/* @__PURE__ */ jsx(Text, { bold: cur, color: cur ? accent : void 0, dimColor: !cur, children: s.label }),
|
|
1476
|
+
i < steps.length - 1 && /* @__PURE__ */ jsx(Text, { dimColor: true, children: " \u2500 " })
|
|
1477
|
+
] }, s.id);
|
|
1478
|
+
}) });
|
|
1479
|
+
}
|
|
1480
|
+
function FormField({
|
|
1481
|
+
label,
|
|
1482
|
+
hint,
|
|
1483
|
+
value,
|
|
1484
|
+
focused,
|
|
1485
|
+
accent,
|
|
1486
|
+
placeholder,
|
|
1487
|
+
mono
|
|
1488
|
+
}) {
|
|
1489
|
+
const display = value === "" ? placeholder : value;
|
|
1490
|
+
const isPlaceholder = value === "";
|
|
1491
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
1492
|
+
/* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Text, { color: focused ? accent : void 0, bold: focused, dimColor: !focused, children: [
|
|
1493
|
+
focused ? "\u25B8" : " ",
|
|
1494
|
+
" ",
|
|
1495
|
+
label
|
|
1496
|
+
] }) }),
|
|
1497
|
+
/* @__PURE__ */ jsxs(Box, { marginTop: 0, children: [
|
|
1498
|
+
/* @__PURE__ */ jsxs(Text, { color: focused ? accent : void 0, children: [
|
|
1499
|
+
" ",
|
|
1500
|
+
focused ? "\u258C" : " ",
|
|
1501
|
+
" "
|
|
1502
|
+
] }),
|
|
1503
|
+
/* @__PURE__ */ jsx(
|
|
1504
|
+
Text,
|
|
1505
|
+
{
|
|
1506
|
+
bold: focused && !isPlaceholder,
|
|
1507
|
+
color: focused && !isPlaceholder ? accent : void 0,
|
|
1508
|
+
dimColor: isPlaceholder,
|
|
1509
|
+
italic: mono && isPlaceholder,
|
|
1510
|
+
children: display
|
|
1511
|
+
}
|
|
1512
|
+
),
|
|
1513
|
+
focused && /* @__PURE__ */ jsx(Text, { color: accent, children: "\u258F" })
|
|
1514
|
+
] }),
|
|
1515
|
+
/* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
1516
|
+
" ",
|
|
1517
|
+
hint
|
|
1518
|
+
] }) })
|
|
1519
|
+
] });
|
|
1520
|
+
}
|
|
1521
|
+
function ColorField({ value, focused }) {
|
|
1522
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
1523
|
+
/* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Text, { color: focused ? value : void 0, bold: focused, dimColor: !focused, children: [
|
|
1524
|
+
focused ? "\u25B8" : " ",
|
|
1525
|
+
" Accent color"
|
|
1526
|
+
] }) }),
|
|
1527
|
+
/* @__PURE__ */ jsxs(Box, { marginTop: 0, children: [
|
|
1528
|
+
/* @__PURE__ */ jsxs(Text, { children: [
|
|
1529
|
+
" ",
|
|
1530
|
+
focused ? "\u258C" : " ",
|
|
1531
|
+
" "
|
|
1532
|
+
] }),
|
|
1533
|
+
COLOR_PALETTE.map((c, i) => {
|
|
1534
|
+
const selected = c === value;
|
|
1535
|
+
return /* @__PURE__ */ jsx(Box, { marginRight: 1, children: selected ? /* @__PURE__ */ jsx(Text, { bold: true, color: c, children: "[\u25CF]" }) : /* @__PURE__ */ jsx(Text, { color: c, dimColor: !focused, children: i === COLOR_PALETTE.length - 1 ? " \u25CF" : " \u25CF" }) }, c);
|
|
1536
|
+
})
|
|
1537
|
+
] }),
|
|
1538
|
+
/* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: " shows on dashboard, account strip, borders" }) })
|
|
1539
|
+
] });
|
|
1540
|
+
}
|
|
1541
|
+
function DashboardView({ slots, stats, compact }) {
|
|
1542
|
+
const slotKey = (s) => s.id ?? "__default__";
|
|
1543
|
+
return /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: slots.map((slot, i) => {
|
|
1544
|
+
const s = stats.get(slotKey(slot));
|
|
1545
|
+
if (!s?.dashboard) {
|
|
1546
|
+
return /* @__PURE__ */ jsxs(Box, { children: [
|
|
1547
|
+
/* @__PURE__ */ jsxs(Text, { color: slot.color, bold: true, children: [
|
|
1548
|
+
"\u25CF ",
|
|
1549
|
+
slot.name,
|
|
1550
|
+
" "
|
|
1551
|
+
] }),
|
|
1552
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "loading..." })
|
|
1553
|
+
] }, slotKey(slot));
|
|
1554
|
+
}
|
|
1555
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
1556
|
+
/* @__PURE__ */ jsx(
|
|
1557
|
+
AccountCard,
|
|
1558
|
+
{
|
|
1559
|
+
slot,
|
|
1560
|
+
dashboard: s.dashboard,
|
|
1561
|
+
billing: s.billing,
|
|
1562
|
+
compact
|
|
1563
|
+
}
|
|
1564
|
+
),
|
|
1565
|
+
i < slots.length - 1 && /* @__PURE__ */ jsx(Box, { height: 1 })
|
|
1566
|
+
] }, slotKey(slot));
|
|
1567
|
+
}) });
|
|
1568
|
+
}
|
|
1569
|
+
function AccountCard({ slot, dashboard, billing, compact }) {
|
|
1570
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
1571
|
+
/* @__PURE__ */ jsxs(Box, { children: [
|
|
1572
|
+
/* @__PURE__ */ jsxs(Text, { color: slot.color, bold: true, children: [
|
|
1573
|
+
"\u25CF ",
|
|
1574
|
+
slot.name
|
|
1575
|
+
] }),
|
|
1576
|
+
slot.id && /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
1577
|
+
" ",
|
|
1578
|
+
slot.id
|
|
1579
|
+
] })
|
|
1580
|
+
] }),
|
|
1581
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: compact ? "row" : "column", marginTop: compact ? 0 : 0, children: [
|
|
1582
|
+
/* @__PURE__ */ jsxs(
|
|
1583
|
+
Box,
|
|
1584
|
+
{
|
|
1585
|
+
flexDirection: "column",
|
|
1586
|
+
paddingLeft: 1,
|
|
1587
|
+
marginRight: compact ? 2 : 0,
|
|
1588
|
+
borderStyle: "bold",
|
|
1589
|
+
borderColor: slot.color,
|
|
1590
|
+
borderRight: false,
|
|
1591
|
+
borderTop: false,
|
|
1592
|
+
borderBottom: false,
|
|
1593
|
+
children: [
|
|
1594
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: "Usage" }),
|
|
1595
|
+
!compact && /* @__PURE__ */ jsx(Box, { height: 1 }),
|
|
1596
|
+
/* @__PURE__ */ jsx(SummaryRow, { label: "Today", summary: dashboard.today, compact }),
|
|
1597
|
+
/* @__PURE__ */ jsx(SummaryRow, { label: compact ? "Week" : "This Week", summary: dashboard.week, compact }),
|
|
1598
|
+
/* @__PURE__ */ jsx(SummaryRow, { label: compact ? "Month" : "This Month", summary: dashboard.month, compact }),
|
|
1599
|
+
dashboard.burnRate > 0 && !compact && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1600
|
+
/* @__PURE__ */ jsx(Box, { height: 1 }),
|
|
1601
|
+
/* @__PURE__ */ jsxs(Box, { children: [
|
|
1602
|
+
/* @__PURE__ */ jsx(Box, { width: 14, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Burn rate" }) }),
|
|
1603
|
+
/* @__PURE__ */ jsx(Box, { width: 12, justifyContent: "flex-end", children: /* @__PURE__ */ jsx(Text, { color: "red", children: currency(dashboard.burnRate) }) }),
|
|
1604
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "/hr" })
|
|
1038
1605
|
] })
|
|
1606
|
+
] }),
|
|
1607
|
+
dashboard.burnRate > 0 && compact && /* @__PURE__ */ jsxs(Box, { children: [
|
|
1608
|
+
/* @__PURE__ */ jsx(Box, { width: 10, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Burn" }) }),
|
|
1609
|
+
/* @__PURE__ */ jsx(Text, { color: "red", children: currency(dashboard.burnRate) }),
|
|
1610
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "/hr" })
|
|
1039
1611
|
] })
|
|
1040
|
-
]
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1612
|
+
]
|
|
1613
|
+
}
|
|
1614
|
+
),
|
|
1615
|
+
!compact && /* @__PURE__ */ jsx(Box, { height: 1 }),
|
|
1616
|
+
/* @__PURE__ */ jsxs(
|
|
1617
|
+
Box,
|
|
1618
|
+
{
|
|
1619
|
+
flexDirection: "column",
|
|
1620
|
+
paddingLeft: 1,
|
|
1621
|
+
borderStyle: "bold",
|
|
1622
|
+
borderColor: billing?.error ? "red" : "yellow",
|
|
1623
|
+
borderRight: false,
|
|
1624
|
+
borderTop: false,
|
|
1625
|
+
borderBottom: false,
|
|
1626
|
+
children: [
|
|
1627
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: "Rate Limits" }),
|
|
1628
|
+
!compact && /* @__PURE__ */ jsx(Box, { height: 1 }),
|
|
1629
|
+
billing?.error ? /* @__PURE__ */ jsx(Text, { color: "red", children: billing.error }) : billing?.session || billing?.weekly ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1630
|
+
billing.session && /* @__PURE__ */ jsx(LimitBar, { label: "Session", pct: billing.session.utilization, resets: billing.session.resetsAt, compact }),
|
|
1631
|
+
billing.weekly && /* @__PURE__ */ jsx(LimitBar, { label: "Weekly", pct: billing.weekly.utilization, resets: billing.weekly.resetsAt, compact }),
|
|
1632
|
+
billing.sonnet && /* @__PURE__ */ jsx(LimitBar, { label: "Sonnet", pct: billing.sonnet.utilization, resets: billing.sonnet.resetsAt, compact }),
|
|
1633
|
+
billing.extraUsage && /* @__PURE__ */ jsxs(Box, { children: [
|
|
1634
|
+
/* @__PURE__ */ jsx(Box, { width: 10, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Extra" }) }),
|
|
1635
|
+
/* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
|
|
1636
|
+
"$",
|
|
1637
|
+
billing.extraUsage.used.toFixed(2)
|
|
1638
|
+
] }),
|
|
1639
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
1640
|
+
" / $",
|
|
1641
|
+
billing.extraUsage.limit.toFixed(2),
|
|
1642
|
+
" limit"
|
|
1643
|
+
] })
|
|
1644
|
+
] })
|
|
1645
|
+
] }) : /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Fetching..." })
|
|
1646
|
+
]
|
|
1647
|
+
}
|
|
1648
|
+
)
|
|
1649
|
+
] })
|
|
1044
1650
|
] });
|
|
1045
1651
|
}
|
|
1046
1652
|
function PeakBadge({ peak }) {
|
|
@@ -1061,8 +1667,8 @@ function fmtMinutes(mins) {
|
|
|
1061
1667
|
const m = mins % 60;
|
|
1062
1668
|
return m === 0 ? `${h}h` : `${h}h ${m}m`;
|
|
1063
1669
|
}
|
|
1064
|
-
function LimitBar({ label, pct, resets }) {
|
|
1065
|
-
const width = 30;
|
|
1670
|
+
function LimitBar({ label, pct, resets, compact }) {
|
|
1671
|
+
const width = compact ? 16 : 30;
|
|
1066
1672
|
const filled = Math.round(pct / 100 * width);
|
|
1067
1673
|
const color = pct >= 80 ? "red" : pct >= 50 ? "yellow" : "green";
|
|
1068
1674
|
return /* @__PURE__ */ jsxs(Box, { children: [
|
|
@@ -1074,13 +1680,23 @@ function LimitBar({ label, pct, resets }) {
|
|
|
1074
1680
|
Math.round(pct),
|
|
1075
1681
|
"%"
|
|
1076
1682
|
] }),
|
|
1077
|
-
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
1683
|
+
!compact && /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
1078
1684
|
" resets ",
|
|
1079
1685
|
resets
|
|
1080
1686
|
] })
|
|
1081
1687
|
] });
|
|
1082
1688
|
}
|
|
1083
|
-
function SummaryRow({ label, summary }) {
|
|
1689
|
+
function SummaryRow({ label, summary, compact }) {
|
|
1690
|
+
if (compact) {
|
|
1691
|
+
return /* @__PURE__ */ jsxs(Box, { children: [
|
|
1692
|
+
/* @__PURE__ */ jsx(Box, { width: 10, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: label }) }),
|
|
1693
|
+
/* @__PURE__ */ jsx(Box, { width: 10, justifyContent: "flex-end", children: /* @__PURE__ */ jsx(Text, { bold: true, color: "yellow", children: currency(summary.cost) }) }),
|
|
1694
|
+
/* @__PURE__ */ jsx(Box, { width: 14, justifyContent: "flex-end", children: /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
1695
|
+
tokens(summary.tokens),
|
|
1696
|
+
" tk"
|
|
1697
|
+
] }) })
|
|
1698
|
+
] });
|
|
1699
|
+
}
|
|
1084
1700
|
return /* @__PURE__ */ jsxs(Box, { children: [
|
|
1085
1701
|
/* @__PURE__ */ jsx(Box, { width: 14, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: label }) }),
|
|
1086
1702
|
/* @__PURE__ */ jsx(Box, { width: 12, justifyContent: "flex-end", children: /* @__PURE__ */ jsx(Text, { bold: true, color: "yellow", children: currency(summary.cost) }) }),
|
|
@@ -1092,7 +1708,7 @@ function SummaryRow({ label, summary }) {
|
|
|
1092
1708
|
}
|
|
1093
1709
|
function TableView({ rows: allRows, cursor, expanded, maxRows, cols, onRowClick }) {
|
|
1094
1710
|
const wide = cols > 90;
|
|
1095
|
-
const base = wide ? { label: 12, input: 10, output: 10, cc:
|
|
1711
|
+
const base = wide ? { label: 12, input: 10, output: 10, cc: 14, cr: 12, total: 11, cost: 13 } : { label: 8, input: 7, output: 7, cc: 7, cr: 8, total: 0, cost: 11 };
|
|
1096
1712
|
const fixed = base.label + base.input + base.output + base.cc + base.cr + base.total + base.cost;
|
|
1097
1713
|
const minModels = wide ? 22 : 14;
|
|
1098
1714
|
const available = cols - fixed - 6;
|
|
@@ -1118,8 +1734,8 @@ function TableView({ rows: allRows, cursor, expanded, maxRows, cols, onRowClick
|
|
|
1118
1734
|
/* @__PURE__ */ jsx(Text, { bold: true, children: col("Models", W.models, "left") }),
|
|
1119
1735
|
/* @__PURE__ */ jsx(Text, { bold: true, children: col("Input", W.input) }),
|
|
1120
1736
|
/* @__PURE__ */ jsx(Text, { bold: true, children: col("Output", W.output) }),
|
|
1121
|
-
/* @__PURE__ */ jsx(Text, { bold: true, children: col("CchCrt", W.cc) }),
|
|
1122
|
-
/* @__PURE__ */ jsx(Text, { bold: true, children: col("CchRd", W.cr) }),
|
|
1737
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: col(wide ? "Cache Create" : "CchCrt", W.cc) }),
|
|
1738
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: col(wide ? "Cache Read" : "CchRd", W.cr) }),
|
|
1123
1739
|
W.total > 0 && /* @__PURE__ */ jsx(Text, { bold: true, children: col("Total", W.total) }),
|
|
1124
1740
|
/* @__PURE__ */ jsx(Text, { bold: true, children: col("Cost", W.cost) })
|
|
1125
1741
|
] }),
|
|
@@ -1167,7 +1783,7 @@ function TableView({ rows: allRows, cursor, expanded, maxRows, cols, onRowClick
|
|
|
1167
1783
|
allRows.length
|
|
1168
1784
|
] }),
|
|
1169
1785
|
/* @__PURE__ */ jsx(Box, { height: 1 }),
|
|
1170
|
-
/* @__PURE__ */ jsx(Footer, {})
|
|
1786
|
+
/* @__PURE__ */ jsx(Footer, { hasAccounts: false })
|
|
1171
1787
|
] });
|
|
1172
1788
|
}
|
|
1173
1789
|
function RowDetail({ row, indent }) {
|