tokmon 0.14.0 → 0.14.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/cli.js +199 -70
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1987,11 +1987,15 @@ var copilotProvider = {
|
|
|
1987
1987
|
};
|
|
1988
1988
|
|
|
1989
1989
|
// src/providers/antigravity/billing.ts
|
|
1990
|
-
import { access as access7, readdir as
|
|
1991
|
-
import { join as
|
|
1992
|
-
import { homedir as
|
|
1990
|
+
import { access as access7, readdir as readdir7 } from "fs/promises";
|
|
1991
|
+
import { join as join13 } from "path";
|
|
1992
|
+
import { homedir as homedir11 } from "os";
|
|
1993
1993
|
|
|
1994
1994
|
// src/providers/cloud-code.ts
|
|
1995
|
+
import { readFile as readFile6, readdir as readdir6, realpath, stat } from "fs/promises";
|
|
1996
|
+
import { spawnSync } from "child_process";
|
|
1997
|
+
import { homedir as homedir10 } from "os";
|
|
1998
|
+
import { dirname, join as join12 } from "path";
|
|
1995
1999
|
var CLOUD_CODE_URLS = [
|
|
1996
2000
|
"https://daily-cloudcode-pa.googleapis.com",
|
|
1997
2001
|
"https://cloudcode-pa.googleapis.com"
|
|
@@ -2000,8 +2004,9 @@ var LOAD_CODE_ASSIST_PATH = "/v1internal:loadCodeAssist";
|
|
|
2000
2004
|
var FETCH_MODELS_PATH = "/v1internal:fetchAvailableModels";
|
|
2001
2005
|
var RETRIEVE_QUOTA_PATH = "/v1internal:retrieveUserQuota";
|
|
2002
2006
|
var GOOGLE_OAUTH_URL = "https://oauth2.googleapis.com/token";
|
|
2003
|
-
var
|
|
2004
|
-
var
|
|
2007
|
+
var GOOGLE_OAUTH_CLIENT_REGEX = /OAUTH_CLIENT_ID\s*=\s*["']([0-9]{6,}-[a-z0-9]+\.apps\.googleusercontent\.com)["']\s*;?\s*(?:var|const|let)?\s*OAUTH_CLIENT_SECRET\s*=\s*["'](GOCSPX-[A-Za-z0-9_-]+)["']/s;
|
|
2008
|
+
var MAX_BUNDLE_READ = 32 * 1024 * 1024;
|
|
2009
|
+
var cachedClient;
|
|
2005
2010
|
var OAUTH_TOKEN_KEY = "antigravityUnifiedStateSync.oauthToken";
|
|
2006
2011
|
var OAUTH_TOKEN_SENTINEL = "oauthTokenInfoSentinelKey";
|
|
2007
2012
|
var CC_MODEL_BLACKLIST = {
|
|
@@ -2112,11 +2117,90 @@ function redact(token) {
|
|
|
2112
2117
|
if (!token) return "none";
|
|
2113
2118
|
return `...${token.slice(-4)}`;
|
|
2114
2119
|
}
|
|
2120
|
+
function geminiBundleCandidates() {
|
|
2121
|
+
const candidates = [];
|
|
2122
|
+
const addBundle = (nodeModulesRoot) => {
|
|
2123
|
+
if (!nodeModulesRoot) return;
|
|
2124
|
+
candidates.push(join12(nodeModulesRoot, "@google", "gemini-cli", "bundle"));
|
|
2125
|
+
};
|
|
2126
|
+
try {
|
|
2127
|
+
const which = spawnSync("command", ["-v", "gemini"], { encoding: "utf8", timeout: 5e3 });
|
|
2128
|
+
const resolved = typeof which.stdout === "string" ? which.stdout.trim().split("\n")[0]?.trim() : "";
|
|
2129
|
+
if (resolved) candidates.push(resolved);
|
|
2130
|
+
} catch {
|
|
2131
|
+
}
|
|
2132
|
+
const home = homedir10();
|
|
2133
|
+
addBundle("/opt/homebrew/lib/node_modules");
|
|
2134
|
+
addBundle("/usr/local/lib/node_modules");
|
|
2135
|
+
addBundle(join12(home, ".local", "share", "node_modules"));
|
|
2136
|
+
addBundle(join12(home, ".bun", "install", "global", "node_modules"));
|
|
2137
|
+
try {
|
|
2138
|
+
const prefix = spawnSync("npm", ["config", "get", "prefix"], { encoding: "utf8", timeout: 5e3 });
|
|
2139
|
+
const root = typeof prefix.stdout === "string" ? prefix.stdout.trim() : "";
|
|
2140
|
+
if (root && root !== "undefined") addBundle(join12(root, "lib", "node_modules"));
|
|
2141
|
+
} catch {
|
|
2142
|
+
}
|
|
2143
|
+
return [...new Set(candidates.filter(Boolean))];
|
|
2144
|
+
}
|
|
2145
|
+
async function resolveBundleDir(candidate) {
|
|
2146
|
+
try {
|
|
2147
|
+
if (candidate.endsWith(`${join12("@google", "gemini-cli", "bundle")}`)) {
|
|
2148
|
+
return candidate;
|
|
2149
|
+
}
|
|
2150
|
+
const real = await realpath(candidate);
|
|
2151
|
+
return dirname(real);
|
|
2152
|
+
} catch {
|
|
2153
|
+
return null;
|
|
2154
|
+
}
|
|
2155
|
+
}
|
|
2156
|
+
async function scanBundleDir(dir) {
|
|
2157
|
+
let entries;
|
|
2158
|
+
try {
|
|
2159
|
+
entries = await readdir6(dir);
|
|
2160
|
+
} catch {
|
|
2161
|
+
return null;
|
|
2162
|
+
}
|
|
2163
|
+
const targets = entries.filter((name) => name === "gemini.js" || name.startsWith("chunk-") && name.endsWith(".js"));
|
|
2164
|
+
for (const name of targets) {
|
|
2165
|
+
const filePath = join12(dir, name);
|
|
2166
|
+
try {
|
|
2167
|
+
const info = await stat(filePath);
|
|
2168
|
+
if (!info.isFile() || info.size > MAX_BUNDLE_READ) continue;
|
|
2169
|
+
const contents = await readFile6(filePath, "utf8");
|
|
2170
|
+
if (!contents.includes("OAUTH_CLIENT_SECRET")) continue;
|
|
2171
|
+
const match = GOOGLE_OAUTH_CLIENT_REGEX.exec(contents);
|
|
2172
|
+
if (match) return { clientId: match[1], clientSecret: match[2] };
|
|
2173
|
+
} catch {
|
|
2174
|
+
}
|
|
2175
|
+
}
|
|
2176
|
+
return null;
|
|
2177
|
+
}
|
|
2178
|
+
async function discoverGoogleOAuthClient() {
|
|
2179
|
+
try {
|
|
2180
|
+
for (const candidate of geminiBundleCandidates()) {
|
|
2181
|
+
const dir = await resolveBundleDir(candidate);
|
|
2182
|
+
if (!dir) continue;
|
|
2183
|
+
const found = await scanBundleDir(dir);
|
|
2184
|
+
if (found) return found;
|
|
2185
|
+
}
|
|
2186
|
+
} catch {
|
|
2187
|
+
}
|
|
2188
|
+
return null;
|
|
2189
|
+
}
|
|
2190
|
+
async function resolveGoogleClient() {
|
|
2191
|
+
const envId = process.env.TOKMON_GOOGLE_CLIENT_ID?.trim();
|
|
2192
|
+
const envSecret = process.env.TOKMON_GOOGLE_CLIENT_SECRET?.trim();
|
|
2193
|
+
if (envId && envSecret) return { clientId: envId, clientSecret: envSecret };
|
|
2194
|
+
if (cachedClient === void 0) cachedClient = await discoverGoogleOAuthClient();
|
|
2195
|
+
return cachedClient;
|
|
2196
|
+
}
|
|
2115
2197
|
async function refreshAccessToken(refreshToken) {
|
|
2116
|
-
if (!refreshToken
|
|
2198
|
+
if (!refreshToken) return null;
|
|
2199
|
+
const client = await resolveGoogleClient();
|
|
2200
|
+
if (!client) return null;
|
|
2117
2201
|
const body = new URLSearchParams({
|
|
2118
|
-
client_id:
|
|
2119
|
-
client_secret:
|
|
2202
|
+
client_id: client.clientId,
|
|
2203
|
+
client_secret: client.clientSecret,
|
|
2120
2204
|
refresh_token: refreshToken,
|
|
2121
2205
|
grant_type: "refresh_token"
|
|
2122
2206
|
});
|
|
@@ -2289,33 +2373,33 @@ async function firstExisting(paths) {
|
|
|
2289
2373
|
return paths[0];
|
|
2290
2374
|
}
|
|
2291
2375
|
async function antigravityStateDb(homeDir) {
|
|
2292
|
-
const base = homeDir ??
|
|
2376
|
+
const base = homeDir ?? homedir11();
|
|
2293
2377
|
const tail = ["User", "globalStorage", "state.vscdb"];
|
|
2294
2378
|
if (process.platform === "darwin") {
|
|
2295
|
-
const support =
|
|
2379
|
+
const support = join13(base, "Library", "Application Support");
|
|
2296
2380
|
const exact = [
|
|
2297
|
-
|
|
2298
|
-
|
|
2381
|
+
join13(support, "Antigravity IDE", ...tail),
|
|
2382
|
+
join13(support, "Antigravity", ...tail)
|
|
2299
2383
|
];
|
|
2300
2384
|
try {
|
|
2301
|
-
const entries = await
|
|
2302
|
-
const matches = entries.filter((e) => e.isDirectory() && e.name.includes("Antigravity")).map((e) =>
|
|
2385
|
+
const entries = await readdir7(support, { withFileTypes: true });
|
|
2386
|
+
const matches = entries.filter((e) => e.isDirectory() && e.name.includes("Antigravity")).map((e) => join13(support, e.name, ...tail));
|
|
2303
2387
|
return firstExisting([...exact, ...matches]);
|
|
2304
2388
|
} catch {
|
|
2305
2389
|
return firstExisting(exact);
|
|
2306
2390
|
}
|
|
2307
2391
|
}
|
|
2308
2392
|
if (process.platform === "win32") {
|
|
2309
|
-
const roaming = homeDir ?
|
|
2393
|
+
const roaming = homeDir ? join13(homeDir, "AppData", "Roaming") : envDir("APPDATA") ?? join13(base, "AppData", "Roaming");
|
|
2310
2394
|
return firstExisting([
|
|
2311
|
-
|
|
2312
|
-
|
|
2395
|
+
join13(roaming, "Antigravity IDE", ...tail),
|
|
2396
|
+
join13(roaming, "Antigravity", ...tail)
|
|
2313
2397
|
]);
|
|
2314
2398
|
}
|
|
2315
|
-
const cfg = homeDir ?
|
|
2399
|
+
const cfg = homeDir ? join13(homeDir, ".config") : envDir("XDG_CONFIG_HOME") ?? join13(base, ".config");
|
|
2316
2400
|
return firstExisting([
|
|
2317
|
-
|
|
2318
|
-
|
|
2401
|
+
join13(cfg, "Antigravity IDE", ...tail),
|
|
2402
|
+
join13(cfg, "Antigravity", ...tail)
|
|
2319
2403
|
]);
|
|
2320
2404
|
}
|
|
2321
2405
|
async function detectAntigravity(homeDir) {
|
|
@@ -2346,11 +2430,11 @@ var antigravityProvider = {
|
|
|
2346
2430
|
};
|
|
2347
2431
|
|
|
2348
2432
|
// src/providers/gemini/billing.ts
|
|
2349
|
-
import { access as access8, readFile as
|
|
2350
|
-
import { join as
|
|
2351
|
-
import { homedir as
|
|
2433
|
+
import { access as access8, readFile as readFile7 } from "fs/promises";
|
|
2434
|
+
import { join as join14 } from "path";
|
|
2435
|
+
import { homedir as homedir12 } from "os";
|
|
2352
2436
|
function geminiCredsPath(homeDir) {
|
|
2353
|
-
return
|
|
2437
|
+
return join14(homeDir ?? homedir12(), ".gemini", "oauth_creds.json");
|
|
2354
2438
|
}
|
|
2355
2439
|
async function detectGemini(homeDir) {
|
|
2356
2440
|
try {
|
|
@@ -2362,7 +2446,7 @@ async function detectGemini(homeDir) {
|
|
|
2362
2446
|
}
|
|
2363
2447
|
async function readGeminiCreds(path) {
|
|
2364
2448
|
try {
|
|
2365
|
-
return JSON.parse(await
|
|
2449
|
+
return JSON.parse(await readFile7(path, "utf8"));
|
|
2366
2450
|
} catch {
|
|
2367
2451
|
return null;
|
|
2368
2452
|
}
|
|
@@ -2398,26 +2482,26 @@ var geminiProvider = {
|
|
|
2398
2482
|
|
|
2399
2483
|
// src/providers/detect.ts
|
|
2400
2484
|
import { accessSync, constants } from "fs";
|
|
2401
|
-
import { join as
|
|
2402
|
-
import { homedir as
|
|
2485
|
+
import { join as join15, delimiter, isAbsolute as isAbsolute3 } from "path";
|
|
2486
|
+
import { homedir as homedir13 } from "os";
|
|
2403
2487
|
function searchDirs() {
|
|
2404
|
-
const home =
|
|
2488
|
+
const home = homedir13();
|
|
2405
2489
|
const fromEnv = (process.env.PATH ?? "").split(delimiter).filter(Boolean);
|
|
2406
2490
|
const extra = process.platform === "win32" ? [
|
|
2407
|
-
process.env.APPDATA &&
|
|
2408
|
-
process.env.LOCALAPPDATA &&
|
|
2409
|
-
|
|
2491
|
+
process.env.APPDATA && join15(process.env.APPDATA, "npm"),
|
|
2492
|
+
process.env.LOCALAPPDATA && join15(process.env.LOCALAPPDATA, "pnpm"),
|
|
2493
|
+
join15(home, "scoop", "shims")
|
|
2410
2494
|
] : [
|
|
2411
2495
|
"/opt/homebrew/bin",
|
|
2412
2496
|
"/usr/local/bin",
|
|
2413
2497
|
"/usr/bin",
|
|
2414
2498
|
"/bin",
|
|
2415
2499
|
"/opt/local/bin",
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
2500
|
+
join15(home, ".local", "bin"),
|
|
2501
|
+
join15(home, "bin"),
|
|
2502
|
+
join15(home, ".npm-global", "bin"),
|
|
2503
|
+
join15(home, ".bun", "bin"),
|
|
2504
|
+
join15(home, ".local", "share", "pnpm")
|
|
2421
2505
|
];
|
|
2422
2506
|
return [.../* @__PURE__ */ new Set([...fromEnv, ...extra.filter((d) => !!d)])];
|
|
2423
2507
|
}
|
|
@@ -2434,7 +2518,7 @@ function onPath(names) {
|
|
|
2434
2518
|
for (const dir of searchDirs()) {
|
|
2435
2519
|
for (const n of names) {
|
|
2436
2520
|
for (const e of exts) {
|
|
2437
|
-
if (isExec(
|
|
2521
|
+
if (isExec(join15(dir, n + e))) return true;
|
|
2438
2522
|
}
|
|
2439
2523
|
}
|
|
2440
2524
|
}
|
|
@@ -2444,7 +2528,7 @@ function anyExists(paths) {
|
|
|
2444
2528
|
return paths.some((p) => !!p && isExec(p));
|
|
2445
2529
|
}
|
|
2446
2530
|
function installSignals(id) {
|
|
2447
|
-
const home =
|
|
2531
|
+
const home = homedir13();
|
|
2448
2532
|
const pf = process.env.ProgramFiles;
|
|
2449
2533
|
const pf86 = process.env["ProgramFiles(x86)"];
|
|
2450
2534
|
const lad = process.env.LOCALAPPDATA;
|
|
@@ -2452,8 +2536,8 @@ function installSignals(id) {
|
|
|
2452
2536
|
case "claude":
|
|
2453
2537
|
return onPath(["claude"]) || anyExists([
|
|
2454
2538
|
"/Applications/Claude.app",
|
|
2455
|
-
|
|
2456
|
-
lad &&
|
|
2539
|
+
join15(home, "Applications", "Claude.app"),
|
|
2540
|
+
lad && join15(lad, "Programs", "claude", "Claude.exe")
|
|
2457
2541
|
]);
|
|
2458
2542
|
case "codex": {
|
|
2459
2543
|
const bin = process.env.CODEX_BIN;
|
|
@@ -2463,10 +2547,10 @@ function installSignals(id) {
|
|
|
2463
2547
|
case "cursor":
|
|
2464
2548
|
return onPath(["cursor", "cursor-agent"]) || anyExists([
|
|
2465
2549
|
"/Applications/Cursor.app",
|
|
2466
|
-
|
|
2467
|
-
lad &&
|
|
2468
|
-
pf &&
|
|
2469
|
-
pf86 &&
|
|
2550
|
+
join15(home, "Applications", "Cursor.app"),
|
|
2551
|
+
lad && join15(lad, "Programs", "cursor", "Cursor.exe"),
|
|
2552
|
+
pf && join15(pf, "Cursor", "Cursor.exe"),
|
|
2553
|
+
pf86 && join15(pf86, "Cursor", "Cursor.exe"),
|
|
2470
2554
|
"/opt/Cursor/cursor",
|
|
2471
2555
|
"/usr/share/cursor/cursor",
|
|
2472
2556
|
"/usr/bin/cursor"
|
|
@@ -2480,8 +2564,8 @@ function installSignals(id) {
|
|
|
2480
2564
|
case "antigravity":
|
|
2481
2565
|
return onPath(["antigravity"]) || anyExists([
|
|
2482
2566
|
"/Applications/Antigravity.app",
|
|
2483
|
-
|
|
2484
|
-
lad &&
|
|
2567
|
+
join15(home, "Applications", "Antigravity.app"),
|
|
2568
|
+
lad && join15(lad, "Programs", "Antigravity", "Antigravity.exe")
|
|
2485
2569
|
]);
|
|
2486
2570
|
case "gemini":
|
|
2487
2571
|
return onPath(["gemini"]);
|
|
@@ -2550,14 +2634,14 @@ function accountsByProvider(accounts) {
|
|
|
2550
2634
|
}
|
|
2551
2635
|
|
|
2552
2636
|
// src/snapshot.ts
|
|
2553
|
-
import { readFile as
|
|
2554
|
-
import { join as
|
|
2637
|
+
import { readFile as readFile8, writeFile as writeFile3, mkdir as mkdir3, rename as rename3 } from "fs/promises";
|
|
2638
|
+
import { join as join16 } from "path";
|
|
2555
2639
|
function snapshotFile() {
|
|
2556
|
-
return
|
|
2640
|
+
return join16(cacheDir(), "dashboard-snapshot.json");
|
|
2557
2641
|
}
|
|
2558
2642
|
async function loadSnapshot() {
|
|
2559
2643
|
try {
|
|
2560
|
-
const obj = JSON.parse(await
|
|
2644
|
+
const obj = JSON.parse(await readFile8(snapshotFile(), "utf-8"));
|
|
2561
2645
|
return obj && typeof obj === "object" ? obj : {};
|
|
2562
2646
|
} catch {
|
|
2563
2647
|
return {};
|
|
@@ -2573,7 +2657,7 @@ function saveSnapshot(stats) {
|
|
|
2573
2657
|
try {
|
|
2574
2658
|
const dir = cacheDir();
|
|
2575
2659
|
await mkdir3(dir, { recursive: true });
|
|
2576
|
-
const tmp =
|
|
2660
|
+
const tmp = join16(dir, `dashboard-snapshot.json.${process.pid}.tmp`);
|
|
2577
2661
|
await writeFile3(tmp, JSON.stringify(obj));
|
|
2578
2662
|
await rename3(tmp, snapshotFile());
|
|
2579
2663
|
} catch {
|
|
@@ -2930,6 +3014,30 @@ function aggregate(list) {
|
|
|
2930
3014
|
}
|
|
2931
3015
|
return z;
|
|
2932
3016
|
}
|
|
3017
|
+
function TotalsRow({ groups, stats, cols }) {
|
|
3018
|
+
const zero = () => ({ cost: 0, tokens: 0, cacheRead: 0, cacheSavings: 0 });
|
|
3019
|
+
const t = zero(), w = zero(), m = zero();
|
|
3020
|
+
for (const g of groups) {
|
|
3021
|
+
if (!PROVIDERS[g.provider].hasUsage) continue;
|
|
3022
|
+
for (const a of g.accounts) {
|
|
3023
|
+
const d = stats.get(a.id)?.dashboard;
|
|
3024
|
+
if (!d) continue;
|
|
3025
|
+
t.cost += d.today.cost;
|
|
3026
|
+
t.tokens += d.today.tokens;
|
|
3027
|
+
w.cost += d.week.cost;
|
|
3028
|
+
w.tokens += d.week.tokens;
|
|
3029
|
+
m.cost += d.month.cost;
|
|
3030
|
+
m.tokens += d.month.tokens;
|
|
3031
|
+
}
|
|
3032
|
+
}
|
|
3033
|
+
const inner = cols - 4;
|
|
3034
|
+
const dot = glyphs().middot;
|
|
3035
|
+
const full = `${glyphs().dotAll} Today ${currency(t.cost)} (${tokens(t.tokens)} tok) ${dot} Week ${currency(w.cost)} (${tokens(w.tokens)} tok) ${dot} Month ${currency(m.cost)} (${tokens(m.tokens)} tok)`;
|
|
3036
|
+
const noTok = `${glyphs().dotAll} Today ${currency(t.cost)} ${dot} Week ${currency(w.cost)} ${dot} Month ${currency(m.cost)}`;
|
|
3037
|
+
const tight = `${glyphs().dotAll} ${currency(t.cost)} ${dot} ${currency(w.cost)} ${dot} ${currency(m.cost)}`;
|
|
3038
|
+
const text = full.length <= inner ? full : noTok.length <= inner ? noTok : tight;
|
|
3039
|
+
return /* @__PURE__ */ jsx2(Box2, { marginTop: 1, children: /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: text }) });
|
|
3040
|
+
}
|
|
2933
3041
|
|
|
2934
3042
|
// src/ui/table.tsx
|
|
2935
3043
|
import { Box as Box3, Text as Text3 } from "ink";
|
|
@@ -3778,6 +3886,7 @@ var IS_TTY = process.stdin.isTTY === true;
|
|
|
3778
3886
|
var DEBOUNCE_MS = 300;
|
|
3779
3887
|
var LOADER_GRACE_MS = 600;
|
|
3780
3888
|
var LOADER_MAX_MS = 8e3;
|
|
3889
|
+
var LOADER_MIN_VISIBLE_MS = 700;
|
|
3781
3890
|
var DEFAULT_CONFIG = {
|
|
3782
3891
|
interval: 2,
|
|
3783
3892
|
billingInterval: 5,
|
|
@@ -3792,8 +3901,13 @@ var DEFAULT_CONFIG = {
|
|
|
3792
3901
|
ascii: "auto",
|
|
3793
3902
|
knownProviders: []
|
|
3794
3903
|
};
|
|
3795
|
-
function
|
|
3796
|
-
|
|
3904
|
+
function applyStartup(c, cliInterval) {
|
|
3905
|
+
if (cliInterval) c = { ...c, interval: cliInterval / 1e3 };
|
|
3906
|
+
if (c.defaultFocus === "all") c = { ...c, activeAccountId: null };
|
|
3907
|
+
return c;
|
|
3908
|
+
}
|
|
3909
|
+
function App({ interval: cliInterval, initialConfig }) {
|
|
3910
|
+
const [config2, setConfig] = useState3(() => initialConfig ? applyStartup(initialConfig, cliInterval) : null);
|
|
3797
3911
|
const [detected, setDetected] = useState3([]);
|
|
3798
3912
|
const [stats, setStats] = useState3(/* @__PURE__ */ new Map());
|
|
3799
3913
|
const [peak, setPeak] = useState3(null);
|
|
@@ -3820,7 +3934,9 @@ function App({ interval: cliInterval }) {
|
|
|
3820
3934
|
const [dashPage, setDashPage] = useState3(0);
|
|
3821
3935
|
const [debouncePassed, setDebouncePassed] = useState3(false);
|
|
3822
3936
|
const [graceHold, setGraceHold] = useState3(false);
|
|
3937
|
+
const [loaderShownAt, setLoaderShownAt] = useState3(null);
|
|
3823
3938
|
const loaderDone = useRef2(false);
|
|
3939
|
+
const prevShowPicker = useRef2(false);
|
|
3824
3940
|
const { stdout } = useStdout();
|
|
3825
3941
|
const { exit } = useApp();
|
|
3826
3942
|
const rows = stdout?.rows ?? 24;
|
|
@@ -3858,7 +3974,7 @@ function App({ interval: cliInterval }) {
|
|
|
3858
3974
|
/*"focus "*/
|
|
3859
3975
|
))) : 0;
|
|
3860
3976
|
const headerRows = cols < 70 ? 2 : 1;
|
|
3861
|
-
const CHROME = 2 + headerRows + 3 + (hasStrip ? 1 + stripLines : 0) + 2;
|
|
3977
|
+
const CHROME = 2 + headerRows + 3 + (hasStrip ? 1 + stripLines : 0) + 2 + 2;
|
|
3862
3978
|
const gridBudget = Math.max(1, rows - CHROME);
|
|
3863
3979
|
const dashLayout = chooseLayout(
|
|
3864
3980
|
Math.max(56, cols - 4),
|
|
@@ -3878,7 +3994,8 @@ function App({ interval: cliInterval }) {
|
|
|
3878
3994
|
const needsOnboarding = configReady && !cfg.onboarded;
|
|
3879
3995
|
const newProviders = configReady && cfg.onboarded ? PROVIDER_ORDER.filter((p) => !cfg.knownProviders.includes(p) && detected.includes(p)) : [];
|
|
3880
3996
|
const showPicker = needsOnboarding || newProviders.length > 0;
|
|
3881
|
-
const
|
|
3997
|
+
const minVisibleHold = loaderShownAt !== null && Date.now() - loaderShownAt < LOADER_MIN_VISIBLE_MS;
|
|
3998
|
+
const showLoader = configReady && !showPicker && !showSettings && !TOO_SMALL && accounts.length > 0 && (!allReady || graceHold || minVisibleHold) && (debouncePassed || loaderShownAt !== null) && !loaderDone.current;
|
|
3882
3999
|
const pickerProviders = needsOnboarding ? PROVIDER_ORDER : newProviders;
|
|
3883
4000
|
const onboardEnabled = onboardSel ?? detected;
|
|
3884
4001
|
const onboardItems = pickerProviders.map((pid) => ({
|
|
@@ -3889,15 +4006,24 @@ function App({ interval: cliInterval }) {
|
|
|
3889
4006
|
enabled: onboardEnabled.includes(pid)
|
|
3890
4007
|
}));
|
|
3891
4008
|
useEffect3(() => {
|
|
3892
|
-
|
|
3893
|
-
|
|
3894
|
-
|
|
3895
|
-
|
|
3896
|
-
|
|
4009
|
+
const wasPicker = prevShowPicker.current;
|
|
4010
|
+
prevShowPicker.current = showPicker;
|
|
4011
|
+
if (wasPicker && !showPicker) {
|
|
4012
|
+
loaderDone.current = false;
|
|
4013
|
+
setDebouncePassed(false);
|
|
4014
|
+
setGraceHold(false);
|
|
4015
|
+
setLoaderShownAt(null);
|
|
4016
|
+
}
|
|
4017
|
+
}, [showPicker]);
|
|
4018
|
+
useEffect3(() => {
|
|
4019
|
+
if (showLoader && loaderShownAt === null) setLoaderShownAt(Date.now());
|
|
4020
|
+
}, [showLoader, loaderShownAt]);
|
|
4021
|
+
useEffect3(() => {
|
|
4022
|
+
if (!initialConfig) loadConfig().then((c) => setConfig(applyStartup(c, cliInterval)));
|
|
3897
4023
|
detectProviders().then(setDetected);
|
|
3898
4024
|
}, []);
|
|
3899
4025
|
useEffect3(() => {
|
|
3900
|
-
if (seededRef.current || !configReady || accounts.length === 0) return;
|
|
4026
|
+
if (seededRef.current || !configReady || showPicker || accounts.length === 0) return;
|
|
3901
4027
|
seededRef.current = true;
|
|
3902
4028
|
loadSnapshot().then((snap) => {
|
|
3903
4029
|
setStats((prev) => {
|
|
@@ -3910,7 +4036,7 @@ function App({ interval: cliInterval }) {
|
|
|
3910
4036
|
return next;
|
|
3911
4037
|
});
|
|
3912
4038
|
});
|
|
3913
|
-
}, [configReady, accountsKey]);
|
|
4039
|
+
}, [configReady, showPicker, accountsKey]);
|
|
3914
4040
|
useEffect3(() => {
|
|
3915
4041
|
if (stats.size === 0) return;
|
|
3916
4042
|
const t = setTimeout(() => saveSnapshot(stats), 500);
|
|
@@ -3931,19 +4057,21 @@ function App({ interval: cliInterval }) {
|
|
|
3931
4057
|
}, [configReady, showPicker, accountsKey]);
|
|
3932
4058
|
useEffect3(() => {
|
|
3933
4059
|
if (!allReady || loaderDone.current) return;
|
|
3934
|
-
if (
|
|
4060
|
+
if (loaderShownAt === null) {
|
|
3935
4061
|
loaderDone.current = true;
|
|
3936
4062
|
return;
|
|
3937
4063
|
}
|
|
3938
4064
|
setGraceHold(true);
|
|
4065
|
+
const minRemaining = Math.max(0, LOADER_MIN_VISIBLE_MS - (Date.now() - loaderShownAt));
|
|
4066
|
+
const hold = Math.max(LOADER_GRACE_MS, minRemaining);
|
|
3939
4067
|
const t = setTimeout(() => {
|
|
3940
4068
|
loaderDone.current = true;
|
|
3941
4069
|
setGraceHold(false);
|
|
3942
|
-
},
|
|
4070
|
+
}, hold);
|
|
3943
4071
|
return () => clearTimeout(t);
|
|
3944
4072
|
}, [allReady]);
|
|
3945
4073
|
useEffect3(() => {
|
|
3946
|
-
if (!configReady) return;
|
|
4074
|
+
if (!configReady || showPicker) return;
|
|
3947
4075
|
let active2 = true;
|
|
3948
4076
|
let timer;
|
|
3949
4077
|
const load = async () => {
|
|
@@ -3970,9 +4098,9 @@ function App({ interval: cliInterval }) {
|
|
|
3970
4098
|
active2 = false;
|
|
3971
4099
|
clearTimeout(timer);
|
|
3972
4100
|
};
|
|
3973
|
-
}, [interval2, tz, configReady, accountsKey]);
|
|
4101
|
+
}, [interval2, tz, configReady, showPicker, accountsKey]);
|
|
3974
4102
|
useEffect3(() => {
|
|
3975
|
-
if (!configReady) return;
|
|
4103
|
+
if (!configReady || showPicker) return;
|
|
3976
4104
|
let active2 = true;
|
|
3977
4105
|
let timer;
|
|
3978
4106
|
const load = async () => {
|
|
@@ -3998,7 +4126,7 @@ function App({ interval: cliInterval }) {
|
|
|
3998
4126
|
active2 = false;
|
|
3999
4127
|
clearTimeout(timer);
|
|
4000
4128
|
};
|
|
4001
|
-
}, [billingMs, configReady, accountsKey]);
|
|
4129
|
+
}, [billingMs, configReady, showPicker, accountsKey]);
|
|
4002
4130
|
const tableKey = `${effTableProvider}|${tableAccounts.map((a) => `${a.id}:${a.homeDir ?? ""}`).join(",")}|${tz}`;
|
|
4003
4131
|
useEffect3(() => {
|
|
4004
4132
|
setTable(null);
|
|
@@ -4636,7 +4764,8 @@ function App({ interval: cliInterval }) {
|
|
|
4636
4764
|
}
|
|
4637
4765
|
}
|
|
4638
4766
|
)
|
|
4639
|
-
] })
|
|
4767
|
+
] }),
|
|
4768
|
+
/* @__PURE__ */ jsx7(TotalsRow, { groups, stats, cols })
|
|
4640
4769
|
] }),
|
|
4641
4770
|
tab === 1 && /* @__PURE__ */ jsxs7(Fragment4, { children: [
|
|
4642
4771
|
tableProvs.length > 0 && /* @__PURE__ */ jsx7(TableProviderBar, { providers: tableProvs, active: effTableProvider, onSelect: (p) => {
|
|
@@ -4883,6 +5012,6 @@ setGlyphs(resolveGlyphs({
|
|
|
4883
5012
|
isTTY: !!process.stdout.isTTY,
|
|
4884
5013
|
platform: process.platform
|
|
4885
5014
|
}));
|
|
4886
|
-
var { waitUntilExit } = render(/* @__PURE__ */ jsx8(MouseProvider, { children: /* @__PURE__ */ jsx8(App, { interval }) }));
|
|
5015
|
+
var { waitUntilExit } = render(/* @__PURE__ */ jsx8(MouseProvider, { children: /* @__PURE__ */ jsx8(App, { interval, initialConfig: config }) }));
|
|
4887
5016
|
await waitUntilExit();
|
|
4888
5017
|
await flushDisk();
|