tokmon 0.20.5 → 0.21.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/{bootstrap-ink-MVH5QEVR.js → bootstrap-ink-QHJOOWIW.js} +552 -439
- package/dist/{chunk-XQEJ4WQ5.js → chunk-7MFZMI5C.js} +2 -2
- package/dist/{chunk-YYATNY5E.js → chunk-CPN67OK6.js} +70 -111
- package/dist/{chunk-EHIQHGJL.js → chunk-YCIUMAKK.js} +832 -425
- package/dist/cli.js +4 -4
- package/dist/{config-C6Z65JUP.js → config-UPNBGIJO.js} +1 -1
- package/dist/{daemon-HEBPH6PG.js → daemon-LZVP4SWF.js} +3 -3
- package/dist/server-F7CUK4ZM.js +9 -0
- package/dist/web/assets/{breakdown-DFnPYZtA.js → breakdown-ClwCJce8.js} +1 -1
- package/dist/web/assets/{chart-C8J22kR3.js → chart-Dcuh_e3J.js} +1 -1
- package/dist/web/assets/index-nAr5lqix.js +105 -0
- package/dist/web/assets/{timeline-BjoaOdbh.js → timeline-gDyrCQ0O.js} +1 -1
- package/dist/web/index.html +1 -1
- package/package.json +1 -1
- package/dist/server-RM4ZXN6C.js +0 -9
- package/dist/web/assets/index-B9eW55YB.js +0 -105
|
@@ -122,13 +122,13 @@ function isValidTimezone(tz) {
|
|
|
122
122
|
}
|
|
123
123
|
function normalizeConfig(parsed) {
|
|
124
124
|
try {
|
|
125
|
-
const accounts = (Array.isArray(parsed.accounts) ? parsed.accounts : []).map((a) => ({ ...a, providerId: a.providerId ?? "claude" })).filter((a) => typeof a?.id === "string" && typeof a?.name === "string" && PROVIDER_IDS.includes(a.providerId));
|
|
125
|
+
const accounts = (Array.isArray(parsed.accounts) ? parsed.accounts : []).map((a) => ({ ...a, providerId: a.providerId ?? "claude" })).filter((a) => typeof a?.id === "string" && typeof a?.name === "string" && PROVIDER_IDS.includes(a.providerId)).map((a) => ({ ...a, homeDir: typeof a.homeDir === "string" && a.homeDir.trim() ? a.homeDir : "~" }));
|
|
126
126
|
return {
|
|
127
127
|
...DEFAULTS,
|
|
128
128
|
interval: clampNum(parsed.interval, DEFAULTS.interval, 1),
|
|
129
129
|
billingInterval: clampNum(parsed.billingInterval, DEFAULTS.billingInterval, 1),
|
|
130
130
|
clearScreen: typeof parsed.clearScreen === "boolean" ? parsed.clearScreen : DEFAULTS.clearScreen,
|
|
131
|
-
timezone: typeof parsed.timezone === "string" && parsed.timezone.trim() && isValidTimezone(parsed.timezone.trim()) ? parsed.timezone : null,
|
|
131
|
+
timezone: typeof parsed.timezone === "string" && parsed.timezone.trim() && isValidTimezone(parsed.timezone.trim()) ? parsed.timezone.trim() : null,
|
|
132
132
|
accounts,
|
|
133
133
|
activeAccountId: typeof parsed.activeAccountId === "string" ? parsed.activeAccountId : null,
|
|
134
134
|
disabledProviders: (Array.isArray(parsed.disabledProviders) ? parsed.disabledProviders : []).filter((p) => PROVIDER_IDS.includes(p)),
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
detectProviders,
|
|
9
9
|
fetchPeak,
|
|
10
10
|
resolveTimezone
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-YCIUMAKK.js";
|
|
12
12
|
import {
|
|
13
13
|
cacheDir,
|
|
14
14
|
expandHome,
|
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
normalizeConfig,
|
|
17
17
|
saveConfig,
|
|
18
18
|
snapshotCacheFile
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-7MFZMI5C.js";
|
|
20
20
|
|
|
21
21
|
// src/web/server.ts
|
|
22
22
|
import { createServer } from "http";
|
|
@@ -96,10 +96,10 @@ async function fetchAccountTable(account, tz) {
|
|
|
96
96
|
if (!p.fetchTable) return null;
|
|
97
97
|
return p.fetchTable(account, tz);
|
|
98
98
|
}
|
|
99
|
-
async function fetchAccountBilling(account) {
|
|
99
|
+
async function fetchAccountBilling(account, tz) {
|
|
100
100
|
const p = PROVIDERS[account.providerId];
|
|
101
101
|
if (!p.fetchBilling) return null;
|
|
102
|
-
return p.fetchBilling(account);
|
|
102
|
+
return p.fetchBilling(account, tz);
|
|
103
103
|
}
|
|
104
104
|
function assembleSnapshot(opts) {
|
|
105
105
|
const accounts = opts.resolved.map((r) => {
|
|
@@ -429,123 +429,78 @@ function createDataEngine(opts) {
|
|
|
429
429
|
};
|
|
430
430
|
let usageAccounts = resolved.filter((r) => r.hasUsage);
|
|
431
431
|
let billingAccounts = resolved.filter((r) => r.hasBilling);
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
if (
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
if (!force && idle()) return;
|
|
441
|
-
const epoch = configEpoch;
|
|
442
|
-
summaryBusy = true;
|
|
443
|
-
try {
|
|
444
|
-
for (const r of usageAccounts) {
|
|
445
|
-
if (stopped) return;
|
|
446
|
-
let dashboard = null;
|
|
447
|
-
let ok = true;
|
|
448
|
-
try {
|
|
449
|
-
dashboard = await withTimeout(fetchAccountSummary(r.account, tz), FETCH_TIMEOUT_MS);
|
|
450
|
-
} catch {
|
|
451
|
-
ok = false;
|
|
452
|
-
}
|
|
453
|
-
if (stopped || epoch !== configEpoch) return;
|
|
454
|
-
if (ok) {
|
|
455
|
-
usageEntry(r.account.id).dashboard = dashboard;
|
|
456
|
-
summaryState.set(r.account.id, "ready");
|
|
457
|
-
} else summaryState.set(r.account.id, "error");
|
|
458
|
-
reveal();
|
|
459
|
-
}
|
|
460
|
-
rebuild();
|
|
461
|
-
} finally {
|
|
462
|
-
summaryBusy = false;
|
|
463
|
-
if (summaryForcePending && !stopped) {
|
|
464
|
-
summaryForcePending = false;
|
|
465
|
-
void refreshSummary(true);
|
|
432
|
+
const makeRefreshLoop = (opts2) => {
|
|
433
|
+
let busy = false;
|
|
434
|
+
let forcePending = false;
|
|
435
|
+
const run = async (force = false) => {
|
|
436
|
+
if (stopped) return;
|
|
437
|
+
if (busy) {
|
|
438
|
+
if (force) forcePending = true;
|
|
439
|
+
return;
|
|
466
440
|
}
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
table = await withTimeout(fetchAccountTable(r.account, tz), FETCH_TIMEOUT_MS);
|
|
487
|
-
} catch {
|
|
488
|
-
ok = false;
|
|
441
|
+
if (!force && idle()) return;
|
|
442
|
+
const epoch = configEpoch;
|
|
443
|
+
busy = true;
|
|
444
|
+
try {
|
|
445
|
+
for (const r of opts2.accounts()) {
|
|
446
|
+
if (stopped) return;
|
|
447
|
+
let value = null;
|
|
448
|
+
let ok = true;
|
|
449
|
+
try {
|
|
450
|
+
value = await withTimeout(opts2.fetch(r), FETCH_TIMEOUT_MS);
|
|
451
|
+
} catch {
|
|
452
|
+
ok = false;
|
|
453
|
+
}
|
|
454
|
+
if (stopped || epoch !== configEpoch) return;
|
|
455
|
+
if (ok) {
|
|
456
|
+
opts2.apply(r.account.id, value);
|
|
457
|
+
opts2.state.set(r.account.id, "ready");
|
|
458
|
+
} else opts2.state.set(r.account.id, "error");
|
|
459
|
+
reveal();
|
|
489
460
|
}
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
}
|
|
497
|
-
rebuild();
|
|
498
|
-
} finally {
|
|
499
|
-
tableBusy = false;
|
|
500
|
-
if (tableForcePending && !stopped) {
|
|
501
|
-
tableForcePending = false;
|
|
502
|
-
void refreshTable(true);
|
|
503
|
-
}
|
|
504
|
-
}
|
|
505
|
-
};
|
|
506
|
-
let billingBusy = false;
|
|
507
|
-
let billingForcePending = false;
|
|
508
|
-
const refreshBilling = async (force = false) => {
|
|
509
|
-
if (stopped) return;
|
|
510
|
-
if (billingBusy) {
|
|
511
|
-
if (force) billingForcePending = true;
|
|
512
|
-
return;
|
|
513
|
-
}
|
|
514
|
-
if (!force && idle()) return;
|
|
515
|
-
const epoch = configEpoch;
|
|
516
|
-
billingBusy = true;
|
|
517
|
-
try {
|
|
518
|
-
for (const r of billingAccounts) {
|
|
519
|
-
if (stopped) return;
|
|
520
|
-
let result = null;
|
|
521
|
-
let ok = true;
|
|
522
|
-
try {
|
|
523
|
-
result = await withTimeout(fetchAccountBilling(r.account), FETCH_TIMEOUT_MS);
|
|
524
|
-
} catch {
|
|
525
|
-
ok = false;
|
|
461
|
+
rebuild();
|
|
462
|
+
} finally {
|
|
463
|
+
busy = false;
|
|
464
|
+
if (forcePending && !stopped) {
|
|
465
|
+
forcePending = false;
|
|
466
|
+
void run(true);
|
|
526
467
|
}
|
|
527
|
-
if (stopped || epoch !== configEpoch) return;
|
|
528
|
-
if (ok) {
|
|
529
|
-
billing.set(r.account.id, result);
|
|
530
|
-
billingState.set(r.account.id, "ready");
|
|
531
|
-
} else billingState.set(r.account.id, "error");
|
|
532
|
-
reveal();
|
|
533
468
|
}
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
billingBusy = false;
|
|
537
|
-
if (billingForcePending && !stopped) {
|
|
538
|
-
billingForcePending = false;
|
|
539
|
-
void refreshBilling(true);
|
|
540
|
-
}
|
|
541
|
-
}
|
|
469
|
+
};
|
|
470
|
+
return run;
|
|
542
471
|
};
|
|
472
|
+
const refreshSummary = makeRefreshLoop({
|
|
473
|
+
accounts: () => usageAccounts,
|
|
474
|
+
fetch: (r) => fetchAccountSummary(r.account, tz),
|
|
475
|
+
apply: (id, dashboard) => {
|
|
476
|
+
usageEntry(id).dashboard = dashboard;
|
|
477
|
+
},
|
|
478
|
+
state: summaryState
|
|
479
|
+
});
|
|
480
|
+
const refreshTable = makeRefreshLoop({
|
|
481
|
+
accounts: () => usageAccounts,
|
|
482
|
+
fetch: (r) => fetchAccountTable(r.account, tz),
|
|
483
|
+
apply: (id, table) => {
|
|
484
|
+
usageEntry(id).table = table;
|
|
485
|
+
},
|
|
486
|
+
state: tableState
|
|
487
|
+
});
|
|
488
|
+
const refreshBilling = makeRefreshLoop({
|
|
489
|
+
accounts: () => billingAccounts,
|
|
490
|
+
fetch: (r) => fetchAccountBilling(r.account, tz),
|
|
491
|
+
apply: (id, result) => {
|
|
492
|
+
billing.set(id, result);
|
|
493
|
+
},
|
|
494
|
+
state: billingState
|
|
495
|
+
});
|
|
543
496
|
let peakBusy = false;
|
|
544
497
|
const refreshPeak = async (force = false) => {
|
|
545
498
|
if (stopped || peakBusy || !hasClaude || !force && idle()) return;
|
|
499
|
+
const epoch = configEpoch;
|
|
546
500
|
peakBusy = true;
|
|
547
501
|
try {
|
|
548
502
|
const next = await fetchPeak();
|
|
503
|
+
if (stopped || epoch !== configEpoch || !hasClaude) return;
|
|
549
504
|
if (next) {
|
|
550
505
|
peak = next;
|
|
551
506
|
rebuild();
|
|
@@ -611,12 +566,16 @@ function createDataEngine(opts) {
|
|
|
611
566
|
tz = next.tz;
|
|
612
567
|
summaryIntervalMs = next.summaryIntervalMs;
|
|
613
568
|
billingIntervalMs = next.billingIntervalMs;
|
|
569
|
+
const sourceKey = (r) => `${r.account.providerId}:${r.account.homeDir ?? ""}`;
|
|
570
|
+
const prevSources = new Map(resolved.map((r) => [r.account.id, sourceKey(r)]));
|
|
614
571
|
resolved = next.resolved;
|
|
615
572
|
hasClaude = resolved.some((r) => r.account.providerId === "claude");
|
|
616
573
|
if (!hasClaude) peak = null;
|
|
617
574
|
usageAccounts = resolved.filter((r) => r.hasUsage);
|
|
618
575
|
billingAccounts = resolved.filter((r) => r.hasBilling);
|
|
619
|
-
const survivors = new Set(
|
|
576
|
+
const survivors = new Set(
|
|
577
|
+
resolved.filter((r) => !prevSources.has(r.account.id) || prevSources.get(r.account.id) === sourceKey(r)).map((r) => r.account.id)
|
|
578
|
+
);
|
|
620
579
|
for (const id of [...usage.keys()]) if (!survivors.has(id)) usage.delete(id);
|
|
621
580
|
for (const id of [...billing.keys()]) if (!survivors.has(id)) billing.delete(id);
|
|
622
581
|
for (const map of [summaryState, billingState, tableState]) {
|