tokmon 0.21.0 → 0.22.1
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/{bootstrap-ink-QHJOOWIW.js → bootstrap-ink-CCESIGED.js} +121 -39
- package/dist/{chunk-7MFZMI5C.js → chunk-E25RUTXB.js} +12 -0
- package/dist/{chunk-YCIUMAKK.js → chunk-FLLNU6BN.js} +380 -123
- package/dist/{chunk-CPN67OK6.js → chunk-RA3SCIG6.js} +4 -52
- package/dist/cli.js +4 -4
- package/dist/{config-UPNBGIJO.js → config-F7TY5ZFA.js} +5 -1
- package/dist/{daemon-LZVP4SWF.js → daemon-A3NSDSPZ.js} +3 -3
- package/dist/server-P7T4ZMC6.js +9 -0
- package/dist/web/assets/breakdown-C3Zqnewe.js +4 -0
- package/dist/web/assets/{index-CZOCHnad.css → index-BCaPGYQA.css} +1 -1
- package/dist/web/assets/index-BkdjevbO.js +173 -0
- package/dist/web/assets/timeline-C2vHjZJ3.js +1 -0
- package/dist/web/index.html +2 -2
- package/package.json +1 -1
- package/dist/server-F7CUK4ZM.js +0 -9
- package/dist/web/assets/breakdown-ClwCJce8.js +0 -4
- package/dist/web/assets/chart-Dcuh_e3J.js +0 -69
- package/dist/web/assets/index-nAr5lqix.js +0 -105
- package/dist/web/assets/timeline-gDyrCQ0O.js +0 -2
|
@@ -13,12 +13,13 @@ import {
|
|
|
13
13
|
cursorModelSpend,
|
|
14
14
|
detectProviders,
|
|
15
15
|
fetchPeak,
|
|
16
|
+
modelColor,
|
|
16
17
|
resolveTimezone,
|
|
17
18
|
shortDate,
|
|
18
19
|
systemTimezone,
|
|
19
20
|
time,
|
|
20
21
|
tokens
|
|
21
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-FLLNU6BN.js";
|
|
22
23
|
import {
|
|
23
24
|
COLOR_PALETTE,
|
|
24
25
|
DEFAULTS,
|
|
@@ -29,10 +30,11 @@ import {
|
|
|
29
30
|
loadConfig,
|
|
30
31
|
normalizeConfig,
|
|
31
32
|
pickAccentColor,
|
|
33
|
+
redactEmail,
|
|
32
34
|
sanitizeTyped,
|
|
33
35
|
saveConfigSync,
|
|
34
36
|
snapshotCacheFile
|
|
35
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-E25RUTXB.js";
|
|
36
38
|
import {
|
|
37
39
|
glyphs
|
|
38
40
|
} from "./chunk-RF4GGQGM.js";
|
|
@@ -322,7 +324,7 @@ function computeDashLayout(groups, stats, cols, budget, focusId, layoutPref) {
|
|
|
322
324
|
}
|
|
323
325
|
return chooseLayout(content, budget, groups.length, single, cols, heights);
|
|
324
326
|
}
|
|
325
|
-
var DashboardView = memo2(function DashboardView2({ groups, stats, cols, budget, focusId, layout, page = 0 }) {
|
|
327
|
+
var DashboardView = memo2(function DashboardView2({ groups, stats, cols, budget, focusId, layout, page = 0, privacyMode: privacyMode2 = false }) {
|
|
326
328
|
if (groups.length === 0) {
|
|
327
329
|
return /* @__PURE__ */ jsxs2(Text2, { dimColor: true, children: [
|
|
328
330
|
"No providers enabled ",
|
|
@@ -337,7 +339,7 @@ var DashboardView = memo2(function DashboardView2({ groups, stats, cols, budget,
|
|
|
337
339
|
const pg = pageCount > 1 ? (page % pageCount + pageCount) % pageCount : 0;
|
|
338
340
|
const visible = pageCount > 1 ? groups.slice(pg * cardsPerPage, pg * cardsPerPage + cardsPerPage) : groups;
|
|
339
341
|
return /* @__PURE__ */ jsxs2(Box2, { height: budget, flexDirection: "column", overflow: "hidden", children: [
|
|
340
|
-
/* @__PURE__ */ jsx2(Box2, { width: content, flexWrap: "wrap", columnGap: GAP, rowGap: 1, alignItems: "flex-start", children: visible.map((g) => /* @__PURE__ */ jsx2(Box2, { flexShrink: 0, children: /* @__PURE__ */ jsx2(ProviderCard, { provider: g.provider, accounts: g.accounts, stats, width: cardW, variant }) }, g.provider)) }),
|
|
342
|
+
/* @__PURE__ */ jsx2(Box2, { width: content, flexWrap: "wrap", columnGap: GAP, rowGap: 1, alignItems: "flex-start", children: visible.map((g) => /* @__PURE__ */ jsx2(Box2, { flexShrink: 0, children: /* @__PURE__ */ jsx2(ProviderCard, { provider: g.provider, accounts: g.accounts, stats, width: cardW, variant, privacyMode: privacyMode2 }) }, g.provider)) }),
|
|
341
343
|
pageCount > 1 && /* @__PURE__ */ jsxs2(Text2, { dimColor: true, children: [
|
|
342
344
|
" ",
|
|
343
345
|
glyphs().middot,
|
|
@@ -389,9 +391,9 @@ function ProviderCard({ provider, accounts, stats, width, variant }) {
|
|
|
389
391
|
] })),
|
|
390
392
|
meta.hasBilling && showBars && /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
391
393
|
meta.hasUsage && /* @__PURE__ */ jsx2(Rule, { inner }),
|
|
392
|
-
/* @__PURE__ */ jsx2(LimitsBlock, { items, inner })
|
|
394
|
+
/* @__PURE__ */ jsx2(LimitsBlock, { items, inner, privacyMode })
|
|
393
395
|
] }),
|
|
394
|
-
meta.hasBilling && !showBars && !meta.hasUsage && /* @__PURE__ */ jsx2(CompactBilling, { items }),
|
|
396
|
+
meta.hasBilling && !showBars && !meta.hasUsage && /* @__PURE__ */ jsx2(CompactBilling, { items, privacyMode }),
|
|
395
397
|
hasSpark && showSpark && /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
396
398
|
/* @__PURE__ */ jsx2(Rule, { inner }),
|
|
397
399
|
/* @__PURE__ */ jsx2(SparkFooter, { series: agg.series, month: agg.month.cost, color: meta.color })
|
|
@@ -406,13 +408,13 @@ function ProviderCard({ provider, accounts, stats, width, variant }) {
|
|
|
406
408
|
] })
|
|
407
409
|
] });
|
|
408
410
|
}
|
|
409
|
-
function CompactBilling({ items }) {
|
|
411
|
+
function CompactBilling({ items, privacyMode: privacyMode2 }) {
|
|
410
412
|
const billing = items.map((i) => i.s?.billing).find(Boolean);
|
|
411
413
|
if (!billing) return /* @__PURE__ */ jsxs2(Text2, { dimColor: true, children: [
|
|
412
414
|
"Fetching",
|
|
413
415
|
glyphs().ellipsis
|
|
414
416
|
] });
|
|
415
|
-
if (billing.error) return /* @__PURE__ */ jsx2(Text2, { color: "red", children: billing.error });
|
|
417
|
+
if (billing.error) return /* @__PURE__ */ jsx2(Text2, { color: "red", children: privacyMode2 ? redactEmail(billing.error) : billing.error });
|
|
416
418
|
const m = billing.metrics.find((x) => x.primary) ?? billing.metrics[0];
|
|
417
419
|
if (!m) return /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "No data" });
|
|
418
420
|
return /* @__PURE__ */ jsx2(Text2, { bold: true, color: "yellow", children: metricValueText(m) });
|
|
@@ -457,11 +459,12 @@ function KpiLine({ agg }) {
|
|
|
457
459
|
] })
|
|
458
460
|
] });
|
|
459
461
|
}
|
|
460
|
-
function accountTitle(account, billing) {
|
|
462
|
+
function accountTitle(account, billing, privacyMode2 = false) {
|
|
461
463
|
const email = billing?.email;
|
|
462
|
-
|
|
464
|
+
const title = email && !account.name.includes("@") ? `${account.name} ${email}` : account.name;
|
|
465
|
+
return privacyMode2 ? redactEmail(title) : title;
|
|
463
466
|
}
|
|
464
|
-
function LimitsBlock({ items, inner }) {
|
|
467
|
+
function LimitsBlock({ items, inner, privacyMode: privacyMode2 }) {
|
|
465
468
|
const showName = items.length > 1;
|
|
466
469
|
const labels = items.flatMap((i) => i.s?.billing?.metrics ?? []).map((m) => m.label.length);
|
|
467
470
|
const labelW = Math.min(Math.max(7, ...labels) + 1, 14);
|
|
@@ -474,12 +477,12 @@ function LimitsBlock({ items, inner }) {
|
|
|
474
477
|
glyphs().dot,
|
|
475
478
|
" "
|
|
476
479
|
] }),
|
|
477
|
-
/* @__PURE__ */ jsx2(Text2, { bold: true, children: truncateName(accountTitle(account, billing), Math.max(22, inner - 2)) })
|
|
480
|
+
/* @__PURE__ */ jsx2(Text2, { bold: true, children: truncateName(accountTitle(account, billing, privacyMode2), Math.max(22, inner - 2)) })
|
|
478
481
|
] }),
|
|
479
482
|
!billing ? /* @__PURE__ */ jsxs2(Text2, { dimColor: true, children: [
|
|
480
483
|
"Fetching",
|
|
481
484
|
glyphs().ellipsis
|
|
482
|
-
] }) : billing.error ? /* @__PURE__ */ jsx2(Text2, { color: "red", wrap: "truncate-end", children: billing.error }) : billing.metrics.length === 0 ? /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "No data" }) : billing.metrics.map((m, i) => /* @__PURE__ */ jsx2(MetricRow, { m, color: account.color, barW, labelW }, `${m.label}${i}`))
|
|
485
|
+
] }) : billing.error ? /* @__PURE__ */ jsx2(Text2, { color: "red", wrap: "truncate-end", children: privacyMode2 ? redactEmail(billing.error) : billing.error }) : billing.metrics.length === 0 ? /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "No data" }) : billing.metrics.map((m, i) => /* @__PURE__ */ jsx2(MetricRow, { m, color: account.color, barW, labelW }, `${m.label}${i}`))
|
|
483
486
|
] }, account.id);
|
|
484
487
|
}) });
|
|
485
488
|
}
|
|
@@ -561,7 +564,7 @@ import { Box as Box4, Text as Text4 } from "ink";
|
|
|
561
564
|
import { memo as memo3 } from "react";
|
|
562
565
|
import { Box as Box3, Text as Text3 } from "ink";
|
|
563
566
|
import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
564
|
-
var GENERAL_ROWS =
|
|
567
|
+
var GENERAL_ROWS = 7;
|
|
565
568
|
var SETTINGS_TABS = ["general", "providers", "accounts"];
|
|
566
569
|
var SETTINGS_TAB_LABELS = {
|
|
567
570
|
general: "General",
|
|
@@ -623,16 +626,17 @@ var SettingsView = memo3(function SettingsView2({
|
|
|
623
626
|
] })
|
|
624
627
|
] }),
|
|
625
628
|
/* @__PURE__ */ jsx3(Row, { cursor, idx: 2, label: "Clear screen", children: /* @__PURE__ */ jsx3(Text3, { bold: true, color: config.clearScreen ? "green" : "red", children: config.clearScreen ? "on" : "off" }) }),
|
|
626
|
-
/* @__PURE__ */ jsx3(Row, { cursor, idx: 3, label: "
|
|
629
|
+
/* @__PURE__ */ jsx3(Row, { cursor, idx: 3, label: "Privacy mode", children: /* @__PURE__ */ jsx3(Text3, { bold: true, color: config.privacyMode ? "green" : "red", children: config.privacyMode ? "on" : "off" }) }),
|
|
630
|
+
/* @__PURE__ */ jsx3(Row, { cursor, idx: 4, label: "Timezone", children: editingTz ? /* @__PURE__ */ jsxs3(Fragment2, { children: [
|
|
627
631
|
/* @__PURE__ */ jsx3(Text3, { dimColor: true, children: "[" }),
|
|
628
632
|
/* @__PURE__ */ jsx3(CaretText, { value: tzEdit ?? "", caret: tzCaret, color: "cyan" }),
|
|
629
633
|
/* @__PURE__ */ jsx3(Text3, { dimColor: true, children: "]" })
|
|
630
634
|
] }) : /* @__PURE__ */ jsx3(Text3, { bold: true, color: "yellow", children: tzDisplay }) }),
|
|
631
|
-
cursor ===
|
|
635
|
+
cursor === 4 && tzError && /* @__PURE__ */ jsxs3(Text3, { color: "red", children: [
|
|
632
636
|
" ",
|
|
633
637
|
tzError
|
|
634
638
|
] }),
|
|
635
|
-
/* @__PURE__ */ jsxs3(Row, { cursor, idx:
|
|
639
|
+
/* @__PURE__ */ jsxs3(Row, { cursor, idx: 5, label: "Dashboard", children: [
|
|
636
640
|
/* @__PURE__ */ jsxs3(Text3, { dimColor: true, children: [
|
|
637
641
|
glyphs().caretL,
|
|
638
642
|
" "
|
|
@@ -643,7 +647,7 @@ var SettingsView = memo3(function SettingsView2({
|
|
|
643
647
|
glyphs().caretR
|
|
644
648
|
] })
|
|
645
649
|
] }),
|
|
646
|
-
/* @__PURE__ */ jsxs3(Row, { cursor, idx:
|
|
650
|
+
/* @__PURE__ */ jsxs3(Row, { cursor, idx: 6, label: "Default focus", children: [
|
|
647
651
|
/* @__PURE__ */ jsxs3(Text3, { dimColor: true, children: [
|
|
648
652
|
glyphs().caretL,
|
|
649
653
|
" "
|
|
@@ -689,7 +693,8 @@ var SettingsView = memo3(function SettingsView2({
|
|
|
689
693
|
const isActive = acc.id === activeAccountId;
|
|
690
694
|
const provider = PROVIDERS[acc.providerId];
|
|
691
695
|
const identity = accountIdentities.get(acc.id);
|
|
692
|
-
const
|
|
696
|
+
const rawIdentityLabel = identity?.email || identity?.displayName || acc.name;
|
|
697
|
+
const identityLabel = config.privacyMode ? redactEmail(rawIdentityLabel) : rawIdentityLabel;
|
|
693
698
|
const plan = identity?.plan ?? null;
|
|
694
699
|
return /* @__PURE__ */ jsxs3(Box3, { children: [
|
|
695
700
|
/* @__PURE__ */ jsxs3(Text3, { color: selected ? "green" : void 0, children: [
|
|
@@ -1086,7 +1091,7 @@ var TableProviderBar = memo4(function TableProviderBar2({ providers, active, onS
|
|
|
1086
1091
|
/* @__PURE__ */ jsx4(Text4, { dimColor: true, children: " p/P switch" })
|
|
1087
1092
|
] });
|
|
1088
1093
|
});
|
|
1089
|
-
var ControlBar = memo4(function ControlBar2({ views, period, sort, search, searchCaret, searching, showPeriod }) {
|
|
1094
|
+
var ControlBar = memo4(function ControlBar2({ views, period, sort, model, search, searchCaret, searching, showPeriod, showModel }) {
|
|
1090
1095
|
return /* @__PURE__ */ jsxs4(Box4, { children: [
|
|
1091
1096
|
showPeriod && /* @__PURE__ */ jsxs4(Fragment3, { children: [
|
|
1092
1097
|
views.map((v, i) => /* @__PURE__ */ jsx4(Box4, { marginRight: 2, children: i === period ? /* @__PURE__ */ jsxs4(Text4, { bold: true, color: "cyan", children: [
|
|
@@ -1103,6 +1108,15 @@ var ControlBar = memo4(function ControlBar2({ views, period, sort, search, searc
|
|
|
1103
1108
|
glyphs().middot,
|
|
1104
1109
|
" "
|
|
1105
1110
|
] }),
|
|
1111
|
+
showModel && /* @__PURE__ */ jsxs4(Fragment3, { children: [
|
|
1112
|
+
/* @__PURE__ */ jsx4(Text4, { dimColor: true, children: "model " }),
|
|
1113
|
+
/* @__PURE__ */ jsx4(Text4, { bold: true, color: model ? modelColor(model) : "cyan", children: model ?? "all" }),
|
|
1114
|
+
/* @__PURE__ */ jsxs4(Text4, { dimColor: true, children: [
|
|
1115
|
+
" m model ",
|
|
1116
|
+
glyphs().middot,
|
|
1117
|
+
" "
|
|
1118
|
+
] })
|
|
1119
|
+
] }),
|
|
1106
1120
|
searching ? /* @__PURE__ */ jsxs4(Fragment3, { children: [
|
|
1107
1121
|
/* @__PURE__ */ jsx4(Text4, { dimColor: true, children: "/" }),
|
|
1108
1122
|
/* @__PURE__ */ jsx4(CaretText, { value: search, caret: searchCaret, color: "cyan" })
|
|
@@ -1370,18 +1384,18 @@ function groupTodayCost(items) {
|
|
|
1370
1384
|
return sum + (d?.today.cost ?? 0);
|
|
1371
1385
|
}, 0);
|
|
1372
1386
|
}
|
|
1373
|
-
function headlineFor(group, items) {
|
|
1387
|
+
function headlineFor(group, items, privacyMode2 = false) {
|
|
1374
1388
|
const meta = PROVIDERS[group.provider];
|
|
1375
1389
|
if (meta.hasUsage) return `${currency(groupTodayCost(items))} today`;
|
|
1376
1390
|
const billing = items.map((s) => s?.billing).find(Boolean);
|
|
1377
1391
|
if (!billing) return "no data";
|
|
1378
|
-
if (billing.error) return billing.error;
|
|
1392
|
+
if (billing.error) return privacyMode2 ? redactEmail(billing.error) : billing.error;
|
|
1379
1393
|
const m = billing.metrics[0];
|
|
1380
1394
|
if (m) return metricValueText(m);
|
|
1381
1395
|
return billing.plan ?? "no data";
|
|
1382
1396
|
}
|
|
1383
1397
|
var STAGGER_FRAMES = 2;
|
|
1384
|
-
function LoadingView({ groups, stats, cols, rows, readyInput }) {
|
|
1398
|
+
function LoadingView({ groups, stats, cols, rows, readyInput, privacyMode: privacyMode2 = false }) {
|
|
1385
1399
|
const resolveReady = readyInput ?? ((id) => statsReadyInput(stats.get(id)));
|
|
1386
1400
|
const sp = glyphs().spinner;
|
|
1387
1401
|
const [frame, setFrame] = useState2(0);
|
|
@@ -1449,7 +1463,7 @@ function LoadingView({ groups, stats, cols, rows, readyInput }) {
|
|
|
1449
1463
|
sp[frame % sp.length],
|
|
1450
1464
|
" "
|
|
1451
1465
|
] }),
|
|
1452
|
-
errored ? /* @__PURE__ */ jsx6(Text6, { color: "red", children: headlineFor(g, items) }) : ready ? /* @__PURE__ */ jsx6(Text6, { children: headlineFor(g, items) }) : /* @__PURE__ */ jsxs6(Text6, { dimColor: true, children: [
|
|
1466
|
+
errored ? /* @__PURE__ */ jsx6(Text6, { color: "red", children: headlineFor(g, items, privacyMode2) }) : ready ? /* @__PURE__ */ jsx6(Text6, { children: headlineFor(g, items, privacyMode2) }) : /* @__PURE__ */ jsxs6(Text6, { dimColor: true, children: [
|
|
1453
1467
|
"loading",
|
|
1454
1468
|
glyphs().ellipsis
|
|
1455
1469
|
] })
|
|
@@ -1478,8 +1492,9 @@ function LoadingView({ groups, stats, cols, rows, readyInput }) {
|
|
|
1478
1492
|
}
|
|
1479
1493
|
|
|
1480
1494
|
// src/ui/app-layout.logic.ts
|
|
1481
|
-
function deriveSlots(accounts) {
|
|
1482
|
-
|
|
1495
|
+
function deriveSlots(accounts, privacyMode2 = false) {
|
|
1496
|
+
const label = (name) => privacyMode2 ? redactEmail(name) : name;
|
|
1497
|
+
return accounts.length > 1 ? [{ id: null, name: "All", color: "whiteBright" }, ...accounts.map((a) => ({ id: a.id, name: label(a.name), color: a.color }))] : accounts.map((a) => ({ id: a.id, name: label(a.name), color: a.color }));
|
|
1483
1498
|
}
|
|
1484
1499
|
function findActiveSlot(slots, activeAccountId) {
|
|
1485
1500
|
if (activeAccountId === null) return { activeSlotIdx: 0, focusId: slots[0]?.id ?? null };
|
|
@@ -2038,6 +2053,45 @@ function sortRows(rows, sortIdx) {
|
|
|
2038
2053
|
return sorted;
|
|
2039
2054
|
}
|
|
2040
2055
|
}
|
|
2056
|
+
function tableModelOptions(rows) {
|
|
2057
|
+
const models = /* @__PURE__ */ new Set();
|
|
2058
|
+
for (const row of rows) for (const model of row.breakdown) models.add(model.name);
|
|
2059
|
+
return [...models].sort();
|
|
2060
|
+
}
|
|
2061
|
+
function cycleTableModel(current, models, dir) {
|
|
2062
|
+
if (models.length === 0) return null;
|
|
2063
|
+
const idx = current ? models.indexOf(current) : -1;
|
|
2064
|
+
if (dir === 1) {
|
|
2065
|
+
if (idx < 0) return models[0];
|
|
2066
|
+
return idx === models.length - 1 ? null : models[idx + 1];
|
|
2067
|
+
}
|
|
2068
|
+
if (idx < 0) return models[models.length - 1];
|
|
2069
|
+
return idx === 0 ? null : models[idx - 1];
|
|
2070
|
+
}
|
|
2071
|
+
function filterRowsByModel(rows, model) {
|
|
2072
|
+
if (!model) return rows;
|
|
2073
|
+
return rows.flatMap((row) => {
|
|
2074
|
+
const detail = row.breakdown.find((m) => m.name === model);
|
|
2075
|
+
if (!detail) return [];
|
|
2076
|
+
const input = detail.input;
|
|
2077
|
+
const output = detail.output;
|
|
2078
|
+
const cacheCreate = detail.cacheCreate;
|
|
2079
|
+
const cacheRead = detail.cacheRead;
|
|
2080
|
+
return [{
|
|
2081
|
+
label: row.label,
|
|
2082
|
+
models: [model],
|
|
2083
|
+
input,
|
|
2084
|
+
output,
|
|
2085
|
+
cacheCreate,
|
|
2086
|
+
cacheRead,
|
|
2087
|
+
cacheSavings: detail.cacheSavings,
|
|
2088
|
+
total: input + output + cacheCreate + cacheRead,
|
|
2089
|
+
cost: detail.cost,
|
|
2090
|
+
count: detail.count,
|
|
2091
|
+
breakdown: [{ ...detail }]
|
|
2092
|
+
}];
|
|
2093
|
+
});
|
|
2094
|
+
}
|
|
2041
2095
|
function filterTokenRows(rows, q) {
|
|
2042
2096
|
if (!q) return rows;
|
|
2043
2097
|
const s = q.toLowerCase();
|
|
@@ -2122,6 +2176,7 @@ function handleKey(input, key, ctx) {
|
|
|
2122
2176
|
setSort,
|
|
2123
2177
|
SORTS_FOR,
|
|
2124
2178
|
tableIsCursor,
|
|
2179
|
+
cycleTableModel: cycleTableModel2,
|
|
2125
2180
|
setView,
|
|
2126
2181
|
cursor,
|
|
2127
2182
|
rowCountRef,
|
|
@@ -2420,7 +2475,11 @@ function handleKey(input, key, ctx) {
|
|
|
2420
2475
|
updateConfig((c) => ({ ...c, clearScreen: !c.clearScreen }));
|
|
2421
2476
|
return;
|
|
2422
2477
|
}
|
|
2423
|
-
if (settingsCursor === 3) {
|
|
2478
|
+
if (settingsCursor === 3 && (key.leftArrow || key.rightArrow || key.return)) {
|
|
2479
|
+
updateConfig((c) => ({ ...c, privacyMode: !c.privacyMode }));
|
|
2480
|
+
return;
|
|
2481
|
+
}
|
|
2482
|
+
if (settingsCursor === 4) {
|
|
2424
2483
|
if (key.return) {
|
|
2425
2484
|
const init = cfg.timezone ?? "";
|
|
2426
2485
|
setTzEdit(init);
|
|
@@ -2430,11 +2489,11 @@ function handleKey(input, key, ctx) {
|
|
|
2430
2489
|
if (key.leftArrow || key.rightArrow) updateConfig((c) => ({ ...c, timezone: c.timezone === null ? systemTimezone() : null }));
|
|
2431
2490
|
return;
|
|
2432
2491
|
}
|
|
2433
|
-
if (settingsCursor ===
|
|
2492
|
+
if (settingsCursor === 5 && (key.leftArrow || key.rightArrow || key.return)) {
|
|
2434
2493
|
updateConfig((c) => ({ ...c, dashboardLayout: c.dashboardLayout === "grid" ? "single" : "grid" }));
|
|
2435
2494
|
return;
|
|
2436
2495
|
}
|
|
2437
|
-
if (settingsCursor ===
|
|
2496
|
+
if (settingsCursor === 6 && (key.leftArrow || key.rightArrow || key.return)) {
|
|
2438
2497
|
updateConfig((c) => ({ ...c, defaultFocus: c.defaultFocus === "all" ? "last" : "all" }));
|
|
2439
2498
|
return;
|
|
2440
2499
|
}
|
|
@@ -2550,8 +2609,11 @@ function handleKey(input, key, ctx) {
|
|
|
2550
2609
|
return;
|
|
2551
2610
|
}
|
|
2552
2611
|
if (input === "m") {
|
|
2553
|
-
|
|
2554
|
-
|
|
2612
|
+
cycleTableModel2(1);
|
|
2613
|
+
return;
|
|
2614
|
+
}
|
|
2615
|
+
if (input === "M") {
|
|
2616
|
+
cycleTableModel2(-1);
|
|
2555
2617
|
return;
|
|
2556
2618
|
}
|
|
2557
2619
|
if (key.leftArrow) {
|
|
@@ -2977,6 +3039,7 @@ function App({ interval: cliInterval, initialConfig, baseUrl = null, wsToken = n
|
|
|
2977
3039
|
const [expanded, setExpanded] = useState8(-1);
|
|
2978
3040
|
const [sort, setSort] = useState8(1);
|
|
2979
3041
|
const [tableProvider, setTableProvider] = useState8(null);
|
|
3042
|
+
const [tableModel, setTableModel] = useState8(null);
|
|
2980
3043
|
const [search, setSearch] = useState8("");
|
|
2981
3044
|
const [searchMode, setSearchMode] = useState8(false);
|
|
2982
3045
|
const [cursorRowsLocal, setCursorRows] = useState8(null);
|
|
@@ -3063,7 +3126,7 @@ function App({ interval: cliInterval, initialConfig, baseUrl = null, wsToken = n
|
|
|
3063
3126
|
}
|
|
3064
3127
|
return statsReadyInput(statsLocal.get(id));
|
|
3065
3128
|
}, [connected, snapshot, statsLocal]);
|
|
3066
|
-
const slots = useMemo2(() => deriveSlots(accounts), [accounts]);
|
|
3129
|
+
const slots = useMemo2(() => deriveSlots(accounts, cfg.privacyMode), [accounts, cfg.privacyMode]);
|
|
3067
3130
|
const { activeSlotIdx, focusId } = useMemo2(
|
|
3068
3131
|
() => findActiveSlot(slots, cfg.activeAccountId),
|
|
3069
3132
|
[slots, cfg.activeAccountId]
|
|
@@ -3163,6 +3226,7 @@ function App({ interval: cliInterval, initialConfig, baseUrl = null, wsToken = n
|
|
|
3163
3226
|
setCursorRows(null);
|
|
3164
3227
|
setCursor(0);
|
|
3165
3228
|
setExpanded(-1);
|
|
3229
|
+
setTableModel(null);
|
|
3166
3230
|
setSort(tableIsCursor ? 0 : 1);
|
|
3167
3231
|
setTableLoading(false);
|
|
3168
3232
|
}, [tableKey]);
|
|
@@ -3202,7 +3266,7 @@ function App({ interval: cliInterval, initialConfig, baseUrl = null, wsToken = n
|
|
|
3202
3266
|
useEffect7(() => {
|
|
3203
3267
|
setCursor(0);
|
|
3204
3268
|
setExpanded(-1);
|
|
3205
|
-
}, [search]);
|
|
3269
|
+
}, [search, tableModel]);
|
|
3206
3270
|
useEffect7(() => {
|
|
3207
3271
|
setDashPage((p) => Math.min(p, dashPageCount - 1));
|
|
3208
3272
|
}, [dashPageCount]);
|
|
@@ -3319,6 +3383,7 @@ function App({ interval: cliInterval, initialConfig, baseUrl = null, wsToken = n
|
|
|
3319
3383
|
setSort(nextIsCursor ? 0 : 1);
|
|
3320
3384
|
setCursor(0);
|
|
3321
3385
|
setExpanded(-1);
|
|
3386
|
+
setTableModel(null);
|
|
3322
3387
|
setSearch("");
|
|
3323
3388
|
setSearchCaret(0);
|
|
3324
3389
|
setSearchMode(false);
|
|
@@ -3348,7 +3413,7 @@ function App({ interval: cliInterval, initialConfig, baseUrl = null, wsToken = n
|
|
|
3348
3413
|
if (webStartingRef.current) return;
|
|
3349
3414
|
webStartingRef.current = true;
|
|
3350
3415
|
try {
|
|
3351
|
-
const { startWebServer } = await import("./server-
|
|
3416
|
+
const { startWebServer } = await import("./server-P7T4ZMC6.js");
|
|
3352
3417
|
const ctrl = await startWebServer({ config: cfg, log: false });
|
|
3353
3418
|
webRef.current = ctrl;
|
|
3354
3419
|
openUrl(ctrl.url);
|
|
@@ -3369,6 +3434,7 @@ function App({ interval: cliInterval, initialConfig, baseUrl = null, wsToken = n
|
|
|
3369
3434
|
setTableProvider(p);
|
|
3370
3435
|
setCursor(0);
|
|
3371
3436
|
setExpanded(-1);
|
|
3437
|
+
setTableModel(null);
|
|
3372
3438
|
setSearch("");
|
|
3373
3439
|
setSearchCaret(0);
|
|
3374
3440
|
setSearchMode(false);
|
|
@@ -3378,9 +3444,22 @@ function App({ interval: cliInterval, initialConfig, baseUrl = null, wsToken = n
|
|
|
3378
3444
|
else setCursor(idx);
|
|
3379
3445
|
}, [cursor]);
|
|
3380
3446
|
const onRowClickCursor = useCallback4((idx) => setCursor(idx), []);
|
|
3447
|
+
const rawTokenRows = useMemo2(
|
|
3448
|
+
() => tab === 1 && !tableIsCursor ? table ? [table.daily, table.weekly, table.monthly][view] : [] : [],
|
|
3449
|
+
[tab, tableIsCursor, table, view]
|
|
3450
|
+
);
|
|
3451
|
+
const tokenModelOptions = useMemo2(() => tableModelOptions(rawTokenRows), [rawTokenRows]);
|
|
3452
|
+
useEffect7(() => {
|
|
3453
|
+
if (tableModel && !tokenModelOptions.includes(tableModel)) setTableModel(null);
|
|
3454
|
+
}, [tableModel, tokenModelOptions]);
|
|
3455
|
+
const cycleTableModelFilter = useCallback4((dir) => {
|
|
3456
|
+
setTableModel((cur) => cycleTableModel(cur, tokenModelOptions, dir));
|
|
3457
|
+
resetView();
|
|
3458
|
+
}, [tokenModelOptions, resetView]);
|
|
3459
|
+
const activeTableModel = tableModel && tokenModelOptions.includes(tableModel) ? tableModel : null;
|
|
3381
3460
|
const tokenRows = useMemo2(
|
|
3382
|
-
() => tab === 1 && !tableIsCursor ? sortRows(filterTokenRows(
|
|
3383
|
-
[tab, tableIsCursor,
|
|
3461
|
+
() => tab === 1 && !tableIsCursor ? sortRows(filterTokenRows(filterRowsByModel(rawTokenRows, activeTableModel), search), sort) : [],
|
|
3462
|
+
[tab, tableIsCursor, rawTokenRows, activeTableModel, search, sort]
|
|
3384
3463
|
);
|
|
3385
3464
|
const cursorTableRows = useMemo2(
|
|
3386
3465
|
() => tab === 1 && tableIsCursor ? sortCursorRows(filterCursorRows(cursorRows ?? [], search), sort) : [],
|
|
@@ -3446,6 +3525,7 @@ function App({ interval: cliInterval, initialConfig, baseUrl = null, wsToken = n
|
|
|
3446
3525
|
setSort,
|
|
3447
3526
|
SORTS_FOR,
|
|
3448
3527
|
tableIsCursor,
|
|
3528
|
+
cycleTableModel: cycleTableModelFilter,
|
|
3449
3529
|
setView,
|
|
3450
3530
|
cursor,
|
|
3451
3531
|
rowCountRef,
|
|
@@ -3470,7 +3550,7 @@ function App({ interval: cliInterval, initialConfig, baseUrl = null, wsToken = n
|
|
|
3470
3550
|
) });
|
|
3471
3551
|
}
|
|
3472
3552
|
if (showLoader) {
|
|
3473
|
-
return /* @__PURE__ */ jsx11(Box11, { flexDirection: "column", paddingX: 2, paddingY: 1, height: rows, overflow: "hidden", children: /* @__PURE__ */ jsx11(LoadingView, { groups: allGroups, stats, cols, rows, readyInput: readyInputFor }) });
|
|
3553
|
+
return /* @__PURE__ */ jsx11(Box11, { flexDirection: "column", paddingX: 2, paddingY: 1, height: rows, overflow: "hidden", children: /* @__PURE__ */ jsx11(LoadingView, { groups: allGroups, stats, cols, rows, readyInput: readyInputFor, privacyMode: cfg.privacyMode }) });
|
|
3474
3554
|
}
|
|
3475
3555
|
if (TOO_SMALL && !showSettings) {
|
|
3476
3556
|
return /* @__PURE__ */ jsx11(TinyFallback, { groups, stats, rows, cols });
|
|
@@ -3540,7 +3620,7 @@ function App({ interval: cliInterval, initialConfig, baseUrl = null, wsToken = n
|
|
|
3540
3620
|
] })
|
|
3541
3621
|
] }),
|
|
3542
3622
|
tab === 0 && /* @__PURE__ */ jsxs11(Fragment4, { children: [
|
|
3543
|
-
/* @__PURE__ */ jsx11(DashboardView, { groups, stats, cols, budget: gridBudget, focusId, layout: cfg.dashboardLayout, page: dashPage }),
|
|
3623
|
+
/* @__PURE__ */ jsx11(DashboardView, { groups, stats, cols, budget: gridBudget, focusId, layout: cfg.dashboardLayout, page: dashPage, privacyMode: cfg.privacyMode }),
|
|
3544
3624
|
slots.length > 1 && /* @__PURE__ */ jsxs11(Box11, { marginTop: 1, children: [
|
|
3545
3625
|
/* @__PURE__ */ jsx11(Text11, { dimColor: true, children: "focus " }),
|
|
3546
3626
|
/* @__PURE__ */ jsx11(
|
|
@@ -3563,10 +3643,12 @@ function App({ interval: cliInterval, initialConfig, baseUrl = null, wsToken = n
|
|
|
3563
3643
|
views: VIEWS,
|
|
3564
3644
|
period: view,
|
|
3565
3645
|
sort: sortLabel(SORTS_FOR[sort % SORTS_FOR.length]),
|
|
3646
|
+
model: activeTableModel,
|
|
3566
3647
|
search,
|
|
3567
3648
|
searchCaret,
|
|
3568
3649
|
searching: searchMode,
|
|
3569
|
-
showPeriod: !tableIsCursor
|
|
3650
|
+
showPeriod: !tableIsCursor,
|
|
3651
|
+
showModel: !tableIsCursor
|
|
3570
3652
|
}
|
|
3571
3653
|
),
|
|
3572
3654
|
/* @__PURE__ */ jsx11(Box11, { height: 1 }),
|
|
@@ -14,6 +14,7 @@ var DEFAULTS = {
|
|
|
14
14
|
interval: 2,
|
|
15
15
|
billingInterval: 5,
|
|
16
16
|
clearScreen: true,
|
|
17
|
+
privacyMode: true,
|
|
17
18
|
timezone: null,
|
|
18
19
|
accounts: [],
|
|
19
20
|
activeAccountId: null,
|
|
@@ -48,6 +49,14 @@ var PROVIDER_META = {
|
|
|
48
49
|
antigravity: { name: "Antigravity", color: "red" },
|
|
49
50
|
gemini: { name: "Gemini", color: "greenBright" }
|
|
50
51
|
};
|
|
52
|
+
var EMAIL_RE = /[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}/i;
|
|
53
|
+
var EMAIL_RE_GLOBAL = /[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}/gi;
|
|
54
|
+
function containsEmail(value) {
|
|
55
|
+
return typeof value === "string" && EMAIL_RE.test(value);
|
|
56
|
+
}
|
|
57
|
+
function redactEmail(value) {
|
|
58
|
+
return value.replace(EMAIL_RE_GLOBAL, "[redacted]");
|
|
59
|
+
}
|
|
51
60
|
function getTrackedAccountRows(config, trackedProviders = PROVIDER_ORDER.filter((pid) => !config.disabledProviders.includes(pid)), autoAccounts) {
|
|
52
61
|
const tracked = new Set(trackedProviders);
|
|
53
62
|
const configuredIds = /* @__PURE__ */ new Set();
|
|
@@ -128,6 +137,7 @@ function normalizeConfig(parsed) {
|
|
|
128
137
|
interval: clampNum(parsed.interval, DEFAULTS.interval, 1),
|
|
129
138
|
billingInterval: clampNum(parsed.billingInterval, DEFAULTS.billingInterval, 1),
|
|
130
139
|
clearScreen: typeof parsed.clearScreen === "boolean" ? parsed.clearScreen : DEFAULTS.clearScreen,
|
|
140
|
+
privacyMode: typeof parsed.privacyMode === "boolean" ? parsed.privacyMode : DEFAULTS.privacyMode,
|
|
131
141
|
timezone: typeof parsed.timezone === "string" && parsed.timezone.trim() && isValidTimezone(parsed.timezone.trim()) ? parsed.timezone.trim() : null,
|
|
132
142
|
accounts,
|
|
133
143
|
activeAccountId: typeof parsed.activeAccountId === "string" ? parsed.activeAccountId : null,
|
|
@@ -256,6 +266,8 @@ export {
|
|
|
256
266
|
ACCENT_COLORS,
|
|
257
267
|
COLOR_PALETTE,
|
|
258
268
|
PROVIDER_META,
|
|
269
|
+
containsEmail,
|
|
270
|
+
redactEmail,
|
|
259
271
|
getTrackedAccountRows,
|
|
260
272
|
clampNum,
|
|
261
273
|
isValidTimezone,
|