tokmon 0.14.0 → 0.14.2
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 +234 -75
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -609,7 +609,7 @@ function glyphs() {
|
|
|
609
609
|
|
|
610
610
|
// src/app.tsx
|
|
611
611
|
import { useState as useState3, useEffect as useEffect3, useCallback, useRef as useRef2, useMemo } from "react";
|
|
612
|
-
import { Box as Box7, Text as Text7, useInput, useStdout, useApp } from "ink";
|
|
612
|
+
import { Box as Box7, Text as Text7, Transform, useInput, useStdout, useApp } from "ink";
|
|
613
613
|
import { useMouse } from "@zenobius/ink-mouse";
|
|
614
614
|
|
|
615
615
|
// src/http.ts
|
|
@@ -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";
|
|
@@ -3775,9 +3883,31 @@ var CURSOR_SORTS = [
|
|
|
3775
3883
|
{ label: "model", dir: null }
|
|
3776
3884
|
];
|
|
3777
3885
|
var IS_TTY = process.stdin.isTTY === true;
|
|
3886
|
+
var REPO_URL = "https://github.com/DavidIlie/tokmon";
|
|
3887
|
+
function detectHyperlinks(env, isTTY) {
|
|
3888
|
+
const force = env.FORCE_HYPERLINK;
|
|
3889
|
+
if (force != null && force !== "") return force !== "0" && force.toLowerCase() !== "false";
|
|
3890
|
+
if (!isTTY || env.TERM === "dumb" || env.NO_HYPERLINK) return false;
|
|
3891
|
+
if (env.WT_SESSION || env.ConEmuANSI === "ON" || env.KITTY_WINDOW_ID || env.TERM === "xterm-kitty") return true;
|
|
3892
|
+
if (env.KONSOLE_VERSION || env.TERMINAL_EMULATOR === "JetBrains-JediTerm") return true;
|
|
3893
|
+
if (env.VTE_VERSION && Number(env.VTE_VERSION) >= 5e3) return true;
|
|
3894
|
+
const tp = env.TERM_PROGRAM;
|
|
3895
|
+
if (tp) {
|
|
3896
|
+
const [maj, min] = (env.TERM_PROGRAM_VERSION ?? "").split(".").map((n) => Number(n) || 0);
|
|
3897
|
+
if (tp === "iTerm.app") return maj > 3 || maj === 3 && min >= 1;
|
|
3898
|
+
if (tp === "vscode" || tp === "WezTerm" || tp === "ghostty" || tp === "Hyper" || tp === "Tabby" || tp === "rio") return true;
|
|
3899
|
+
}
|
|
3900
|
+
return false;
|
|
3901
|
+
}
|
|
3902
|
+
var HYPERLINKS = detectHyperlinks(process.env, process.stdout.isTTY === true);
|
|
3903
|
+
function osc8(text, url) {
|
|
3904
|
+
if (!HYPERLINKS) return text;
|
|
3905
|
+
return `\x1B]8;;${url}\x07${text}\x1B]8;;\x07`;
|
|
3906
|
+
}
|
|
3778
3907
|
var DEBOUNCE_MS = 300;
|
|
3779
3908
|
var LOADER_GRACE_MS = 600;
|
|
3780
3909
|
var LOADER_MAX_MS = 8e3;
|
|
3910
|
+
var LOADER_MIN_VISIBLE_MS = 700;
|
|
3781
3911
|
var DEFAULT_CONFIG = {
|
|
3782
3912
|
interval: 2,
|
|
3783
3913
|
billingInterval: 5,
|
|
@@ -3792,8 +3922,13 @@ var DEFAULT_CONFIG = {
|
|
|
3792
3922
|
ascii: "auto",
|
|
3793
3923
|
knownProviders: []
|
|
3794
3924
|
};
|
|
3795
|
-
function
|
|
3796
|
-
|
|
3925
|
+
function applyStartup(c, cliInterval) {
|
|
3926
|
+
if (cliInterval) c = { ...c, interval: cliInterval / 1e3 };
|
|
3927
|
+
if (c.defaultFocus === "all") c = { ...c, activeAccountId: null };
|
|
3928
|
+
return c;
|
|
3929
|
+
}
|
|
3930
|
+
function App({ interval: cliInterval, initialConfig }) {
|
|
3931
|
+
const [config2, setConfig] = useState3(() => initialConfig ? applyStartup(initialConfig, cliInterval) : null);
|
|
3797
3932
|
const [detected, setDetected] = useState3([]);
|
|
3798
3933
|
const [stats, setStats] = useState3(/* @__PURE__ */ new Map());
|
|
3799
3934
|
const [peak, setPeak] = useState3(null);
|
|
@@ -3820,7 +3955,9 @@ function App({ interval: cliInterval }) {
|
|
|
3820
3955
|
const [dashPage, setDashPage] = useState3(0);
|
|
3821
3956
|
const [debouncePassed, setDebouncePassed] = useState3(false);
|
|
3822
3957
|
const [graceHold, setGraceHold] = useState3(false);
|
|
3958
|
+
const [loaderShownAt, setLoaderShownAt] = useState3(null);
|
|
3823
3959
|
const loaderDone = useRef2(false);
|
|
3960
|
+
const prevShowPicker = useRef2(false);
|
|
3824
3961
|
const { stdout } = useStdout();
|
|
3825
3962
|
const { exit } = useApp();
|
|
3826
3963
|
const rows = stdout?.rows ?? 24;
|
|
@@ -3858,7 +3995,7 @@ function App({ interval: cliInterval }) {
|
|
|
3858
3995
|
/*"focus "*/
|
|
3859
3996
|
))) : 0;
|
|
3860
3997
|
const headerRows = cols < 70 ? 2 : 1;
|
|
3861
|
-
const CHROME = 2 + headerRows + 3 + (hasStrip ? 1 + stripLines : 0) + 2;
|
|
3998
|
+
const CHROME = 2 + headerRows + 3 + (hasStrip ? 1 + stripLines : 0) + 2 + 2;
|
|
3862
3999
|
const gridBudget = Math.max(1, rows - CHROME);
|
|
3863
4000
|
const dashLayout = chooseLayout(
|
|
3864
4001
|
Math.max(56, cols - 4),
|
|
@@ -3878,7 +4015,8 @@ function App({ interval: cliInterval }) {
|
|
|
3878
4015
|
const needsOnboarding = configReady && !cfg.onboarded;
|
|
3879
4016
|
const newProviders = configReady && cfg.onboarded ? PROVIDER_ORDER.filter((p) => !cfg.knownProviders.includes(p) && detected.includes(p)) : [];
|
|
3880
4017
|
const showPicker = needsOnboarding || newProviders.length > 0;
|
|
3881
|
-
const
|
|
4018
|
+
const minVisibleHold = loaderShownAt !== null && Date.now() - loaderShownAt < LOADER_MIN_VISIBLE_MS;
|
|
4019
|
+
const showLoader = configReady && !showPicker && !showSettings && !TOO_SMALL && accounts.length > 0 && (!allReady || graceHold || minVisibleHold) && (debouncePassed || loaderShownAt !== null) && !loaderDone.current;
|
|
3882
4020
|
const pickerProviders = needsOnboarding ? PROVIDER_ORDER : newProviders;
|
|
3883
4021
|
const onboardEnabled = onboardSel ?? detected;
|
|
3884
4022
|
const onboardItems = pickerProviders.map((pid) => ({
|
|
@@ -3889,15 +4027,24 @@ function App({ interval: cliInterval }) {
|
|
|
3889
4027
|
enabled: onboardEnabled.includes(pid)
|
|
3890
4028
|
}));
|
|
3891
4029
|
useEffect3(() => {
|
|
3892
|
-
|
|
3893
|
-
|
|
3894
|
-
|
|
3895
|
-
|
|
3896
|
-
|
|
4030
|
+
const wasPicker = prevShowPicker.current;
|
|
4031
|
+
prevShowPicker.current = showPicker;
|
|
4032
|
+
if (wasPicker && !showPicker) {
|
|
4033
|
+
loaderDone.current = false;
|
|
4034
|
+
setDebouncePassed(false);
|
|
4035
|
+
setGraceHold(false);
|
|
4036
|
+
setLoaderShownAt(null);
|
|
4037
|
+
}
|
|
4038
|
+
}, [showPicker]);
|
|
4039
|
+
useEffect3(() => {
|
|
4040
|
+
if (showLoader && loaderShownAt === null) setLoaderShownAt(Date.now());
|
|
4041
|
+
}, [showLoader, loaderShownAt]);
|
|
4042
|
+
useEffect3(() => {
|
|
4043
|
+
if (!initialConfig) loadConfig().then((c) => setConfig(applyStartup(c, cliInterval)));
|
|
3897
4044
|
detectProviders().then(setDetected);
|
|
3898
4045
|
}, []);
|
|
3899
4046
|
useEffect3(() => {
|
|
3900
|
-
if (seededRef.current || !configReady || accounts.length === 0) return;
|
|
4047
|
+
if (seededRef.current || !configReady || showPicker || accounts.length === 0) return;
|
|
3901
4048
|
seededRef.current = true;
|
|
3902
4049
|
loadSnapshot().then((snap) => {
|
|
3903
4050
|
setStats((prev) => {
|
|
@@ -3910,7 +4057,7 @@ function App({ interval: cliInterval }) {
|
|
|
3910
4057
|
return next;
|
|
3911
4058
|
});
|
|
3912
4059
|
});
|
|
3913
|
-
}, [configReady, accountsKey]);
|
|
4060
|
+
}, [configReady, showPicker, accountsKey]);
|
|
3914
4061
|
useEffect3(() => {
|
|
3915
4062
|
if (stats.size === 0) return;
|
|
3916
4063
|
const t = setTimeout(() => saveSnapshot(stats), 500);
|
|
@@ -3931,19 +4078,21 @@ function App({ interval: cliInterval }) {
|
|
|
3931
4078
|
}, [configReady, showPicker, accountsKey]);
|
|
3932
4079
|
useEffect3(() => {
|
|
3933
4080
|
if (!allReady || loaderDone.current) return;
|
|
3934
|
-
if (
|
|
4081
|
+
if (loaderShownAt === null) {
|
|
3935
4082
|
loaderDone.current = true;
|
|
3936
4083
|
return;
|
|
3937
4084
|
}
|
|
3938
4085
|
setGraceHold(true);
|
|
4086
|
+
const minRemaining = Math.max(0, LOADER_MIN_VISIBLE_MS - (Date.now() - loaderShownAt));
|
|
4087
|
+
const hold = Math.max(LOADER_GRACE_MS, minRemaining);
|
|
3939
4088
|
const t = setTimeout(() => {
|
|
3940
4089
|
loaderDone.current = true;
|
|
3941
4090
|
setGraceHold(false);
|
|
3942
|
-
},
|
|
4091
|
+
}, hold);
|
|
3943
4092
|
return () => clearTimeout(t);
|
|
3944
4093
|
}, [allReady]);
|
|
3945
4094
|
useEffect3(() => {
|
|
3946
|
-
if (!configReady) return;
|
|
4095
|
+
if (!configReady || showPicker) return;
|
|
3947
4096
|
let active2 = true;
|
|
3948
4097
|
let timer;
|
|
3949
4098
|
const load = async () => {
|
|
@@ -3970,9 +4119,9 @@ function App({ interval: cliInterval }) {
|
|
|
3970
4119
|
active2 = false;
|
|
3971
4120
|
clearTimeout(timer);
|
|
3972
4121
|
};
|
|
3973
|
-
}, [interval2, tz, configReady, accountsKey]);
|
|
4122
|
+
}, [interval2, tz, configReady, showPicker, accountsKey]);
|
|
3974
4123
|
useEffect3(() => {
|
|
3975
|
-
if (!configReady) return;
|
|
4124
|
+
if (!configReady || showPicker) return;
|
|
3976
4125
|
let active2 = true;
|
|
3977
4126
|
let timer;
|
|
3978
4127
|
const load = async () => {
|
|
@@ -3998,7 +4147,7 @@ function App({ interval: cliInterval }) {
|
|
|
3998
4147
|
active2 = false;
|
|
3999
4148
|
clearTimeout(timer);
|
|
4000
4149
|
};
|
|
4001
|
-
}, [billingMs, configReady, accountsKey]);
|
|
4150
|
+
}, [billingMs, configReady, showPicker, accountsKey]);
|
|
4002
4151
|
const tableKey = `${effTableProvider}|${tableAccounts.map((a) => `${a.id}:${a.homeDir ?? ""}`).join(",")}|${tz}`;
|
|
4003
4152
|
useEffect3(() => {
|
|
4004
4153
|
setTable(null);
|
|
@@ -4636,7 +4785,8 @@ function App({ interval: cliInterval }) {
|
|
|
4636
4785
|
}
|
|
4637
4786
|
}
|
|
4638
4787
|
)
|
|
4639
|
-
] })
|
|
4788
|
+
] }),
|
|
4789
|
+
/* @__PURE__ */ jsx7(TotalsRow, { groups, stats, cols })
|
|
4640
4790
|
] }),
|
|
4641
4791
|
tab === 1 && /* @__PURE__ */ jsxs7(Fragment4, { children: [
|
|
4642
4792
|
tableProvs.length > 0 && /* @__PURE__ */ jsx7(TableProviderBar, { providers: tableProvs, active: effTableProvider, onSelect: (p) => {
|
|
@@ -4775,9 +4925,9 @@ function Footer({ hasAccounts, paginated, cols }) {
|
|
|
4775
4925
|
const showPage = paginated && inner >= BASE2 + (showJump ? JUMP : 0) + PAGE;
|
|
4776
4926
|
return /* @__PURE__ */ jsxs7(Box7, { marginTop: 1, flexWrap: "nowrap", children: [
|
|
4777
4927
|
/* @__PURE__ */ jsx7(Text7, { dimColor: true, children: "by " }),
|
|
4778
|
-
/* @__PURE__ */ jsx7(Text7, { children: "David Ilie" }),
|
|
4928
|
+
/* @__PURE__ */ jsx7(Transform, { transform: (s) => osc8(s, REPO_URL), children: /* @__PURE__ */ jsx7(Text7, { children: "David Ilie" }) }),
|
|
4779
4929
|
/* @__PURE__ */ jsx7(Text7, { dimColor: true, children: " (" }),
|
|
4780
|
-
/* @__PURE__ */ jsx7(Text7, { color: "cyan", children: "davidilie.com" }),
|
|
4930
|
+
/* @__PURE__ */ jsx7(Transform, { transform: (s) => osc8(s, "https://davidilie.com"), children: /* @__PURE__ */ jsx7(Text7, { color: "cyan", children: "davidilie.com" }) }),
|
|
4781
4931
|
/* @__PURE__ */ jsxs7(Text7, { dimColor: true, children: [
|
|
4782
4932
|
") ",
|
|
4783
4933
|
glyphs().middot,
|
|
@@ -4873,8 +5023,16 @@ for (let i = 0; i < args.length; i++) {
|
|
|
4873
5023
|
}
|
|
4874
5024
|
}
|
|
4875
5025
|
var config = await loadConfig();
|
|
4876
|
-
|
|
4877
|
-
|
|
5026
|
+
var altScreen = config.clearScreen && process.stdout.isTTY === true;
|
|
5027
|
+
var leaveAltScreen = () => {
|
|
5028
|
+
try {
|
|
5029
|
+
process.stdout.write("\x1B[?1049l");
|
|
5030
|
+
} catch {
|
|
5031
|
+
}
|
|
5032
|
+
};
|
|
5033
|
+
if (altScreen) {
|
|
5034
|
+
process.stdout.write("\x1B[?1049h\x1B[H");
|
|
5035
|
+
process.once("exit", leaveAltScreen);
|
|
4878
5036
|
}
|
|
4879
5037
|
setGlyphs(resolveGlyphs({
|
|
4880
5038
|
flag: asciiFlag,
|
|
@@ -4883,6 +5041,7 @@ setGlyphs(resolveGlyphs({
|
|
|
4883
5041
|
isTTY: !!process.stdout.isTTY,
|
|
4884
5042
|
platform: process.platform
|
|
4885
5043
|
}));
|
|
4886
|
-
var { waitUntilExit } = render(/* @__PURE__ */ jsx8(MouseProvider, { children: /* @__PURE__ */ jsx8(App, { interval }) }));
|
|
5044
|
+
var { waitUntilExit } = render(/* @__PURE__ */ jsx8(MouseProvider, { children: /* @__PURE__ */ jsx8(App, { interval, initialConfig: config }) }));
|
|
4887
5045
|
await waitUntilExit();
|
|
4888
5046
|
await flushDisk();
|
|
5047
|
+
if (altScreen) leaveAltScreen();
|