tokmon 0.20.2 → 0.20.4
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-KWHXVQYS.js → bootstrap-ink-3VQODLRG.js} +82 -41
- package/dist/{chunk-5IHAR2RZ.js → chunk-F7RJIR3Z.js} +33 -13
- package/dist/{chunk-7HJIP4U6.js → chunk-HSUYWU4V.js} +460 -279
- package/dist/cli.js +4 -4
- package/dist/{daemon-NVWX3RRK.js → daemon-O3R6R2R6.js} +2 -2
- package/dist/{daemon-handle-ZHECQZ6Q.js → daemon-handle-HLSKLMWU.js} +1 -1
- package/dist/{server-BXMRN774.js → server-6DGQI25X.js} +2 -2
- package/dist/web/assets/{breakdown-Dhq6Rqnu.js → breakdown-DFnPYZtA.js} +1 -1
- package/dist/web/assets/{chart-CDwPcOeB.js → chart-C8J22kR3.js} +1 -1
- package/dist/web/assets/index-B9eW55YB.js +105 -0
- package/dist/web/assets/{timeline-D0GFoRzM.js → timeline-BjoaOdbh.js} +1 -1
- package/dist/web/index.html +1 -1
- package/package.json +1 -1
- package/dist/web/assets/index-Bqe9b8BZ.js +0 -105
|
@@ -501,7 +501,7 @@ var resetIn = formatResetIn;
|
|
|
501
501
|
|
|
502
502
|
// src/providers/cursor/billing.ts
|
|
503
503
|
import { access } from "fs/promises";
|
|
504
|
-
import { join as
|
|
504
|
+
import { join as join4 } from "path";
|
|
505
505
|
import { homedir as homedir2 } from "os";
|
|
506
506
|
|
|
507
507
|
// src/http.ts
|
|
@@ -521,11 +521,13 @@ function msToIso(ms) {
|
|
|
521
521
|
}
|
|
522
522
|
|
|
523
523
|
// src/providers/cursor/activity.ts
|
|
524
|
-
import { join as
|
|
524
|
+
import { join as join3 } from "path";
|
|
525
525
|
import { homedir } from "os";
|
|
526
526
|
|
|
527
527
|
// src/providers/cursor/sqlite.ts
|
|
528
528
|
import { execFile as execFileCb } from "child_process";
|
|
529
|
+
import { accessSync, constants } from "fs";
|
|
530
|
+
import { delimiter, join as join2 } from "path";
|
|
529
531
|
import { promisify } from "util";
|
|
530
532
|
var execFile = promisify(execFileCb);
|
|
531
533
|
var nativeDb;
|
|
@@ -539,8 +541,8 @@ async function getNativeDb() {
|
|
|
539
541
|
return nativeDb;
|
|
540
542
|
}
|
|
541
543
|
function classify(msg) {
|
|
544
|
+
if (/database is (locked|busy)|SQLITE_(BUSY|LOCKED)|EBUSY|sharing violation|resource busy|readonly/i.test(msg)) return "locked";
|
|
542
545
|
if (/unable to open|no such file|cannot open|ENOENT/i.test(msg)) return "missing";
|
|
543
|
-
if (/database is (locked|busy)|readonly/i.test(msg)) return "locked";
|
|
544
546
|
if (/no such (function|table|column)|unknown option/i.test(msg)) return "old";
|
|
545
547
|
return "error";
|
|
546
548
|
}
|
|
@@ -548,20 +550,48 @@ async function runSqlite(db, sql, params = []) {
|
|
|
548
550
|
const DB = await getNativeDb();
|
|
549
551
|
if (DB) {
|
|
550
552
|
let handle;
|
|
553
|
+
let nativeErr;
|
|
551
554
|
try {
|
|
552
|
-
|
|
555
|
+
try {
|
|
556
|
+
handle = new DB(db, { readOnly: true, timeout: 1500 });
|
|
557
|
+
} catch (e) {
|
|
558
|
+
if (!(e instanceof TypeError)) throw e;
|
|
559
|
+
handle = new DB(db, { readOnly: true });
|
|
560
|
+
}
|
|
553
561
|
const rows = handle.prepare(sql).all(...params);
|
|
554
562
|
return { status: "ok", rows };
|
|
555
|
-
} catch {
|
|
563
|
+
} catch (e) {
|
|
564
|
+
nativeErr = e;
|
|
556
565
|
} finally {
|
|
557
566
|
try {
|
|
558
567
|
handle?.close();
|
|
559
568
|
} catch {
|
|
560
569
|
}
|
|
561
570
|
}
|
|
571
|
+
if (nativeErr) {
|
|
572
|
+
return { status: classify(String(nativeErr?.message ?? nativeErr)), rows: [] };
|
|
573
|
+
}
|
|
562
574
|
}
|
|
563
575
|
return runSqliteCli(db, sql, params);
|
|
564
576
|
}
|
|
577
|
+
function isExec(p) {
|
|
578
|
+
try {
|
|
579
|
+
accessSync(p, process.platform === "win32" ? constants.F_OK : constants.X_OK);
|
|
580
|
+
return true;
|
|
581
|
+
} catch {
|
|
582
|
+
return false;
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
function resolveSqliteCli() {
|
|
586
|
+
const names = process.platform === "win32" ? ["sqlite3.exe", "sqlite3.cmd", "sqlite3.bat"] : ["sqlite3"];
|
|
587
|
+
for (const dir of (process.env.PATH ?? "").split(delimiter).filter(Boolean)) {
|
|
588
|
+
for (const name of names) {
|
|
589
|
+
const path = join2(dir, name);
|
|
590
|
+
if (isExec(path)) return path;
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
return null;
|
|
594
|
+
}
|
|
565
595
|
function inlineParams(sql, params) {
|
|
566
596
|
let i = 0;
|
|
567
597
|
return sql.replace(/\?/g, () => {
|
|
@@ -570,9 +600,11 @@ function inlineParams(sql, params) {
|
|
|
570
600
|
});
|
|
571
601
|
}
|
|
572
602
|
async function runSqliteCli(db, sql, params) {
|
|
603
|
+
const sqlite = resolveSqliteCli();
|
|
604
|
+
if (!sqlite) return { status: "missing", rows: [] };
|
|
573
605
|
try {
|
|
574
606
|
const { stdout } = await execFile(
|
|
575
|
-
|
|
607
|
+
sqlite,
|
|
576
608
|
["-readonly", "-json", "-cmd", ".timeout 1500", db, inlineParams(sql, params)],
|
|
577
609
|
{ timeout: 1e4, maxBuffer: 8 << 20 }
|
|
578
610
|
);
|
|
@@ -605,7 +637,7 @@ function sqliteStatusMessage(status) {
|
|
|
605
637
|
// src/providers/cursor/activity.ts
|
|
606
638
|
var DAY_MS2 = 864e5;
|
|
607
639
|
function trackingDb(homeDir) {
|
|
608
|
-
return
|
|
640
|
+
return join3(homeDir ?? homedir(), ".cursor", "ai-tracking", "ai-code-tracking.db");
|
|
609
641
|
}
|
|
610
642
|
function localDayKey(ms) {
|
|
611
643
|
const d = new Date(ms);
|
|
@@ -645,14 +677,14 @@ function cursorStateDb(homeDir) {
|
|
|
645
677
|
const base = homeDir ?? homedir2();
|
|
646
678
|
const tail = ["Cursor", "User", "globalStorage", "state.vscdb"];
|
|
647
679
|
if (process.platform === "darwin") {
|
|
648
|
-
return
|
|
680
|
+
return join4(base, "Library", "Application Support", ...tail);
|
|
649
681
|
}
|
|
650
682
|
if (process.platform === "win32") {
|
|
651
|
-
const roaming = homeDir ?
|
|
652
|
-
return
|
|
683
|
+
const roaming = homeDir ? join4(homeDir, "AppData", "Roaming") : envDir("APPDATA") ?? join4(base, "AppData", "Roaming");
|
|
684
|
+
return join4(roaming, ...tail);
|
|
653
685
|
}
|
|
654
|
-
const cfg = homeDir ?
|
|
655
|
-
return
|
|
686
|
+
const cfg = homeDir ? join4(homeDir, ".config") : envDir("XDG_CONFIG_HOME") ?? join4(base, ".config");
|
|
687
|
+
return join4(cfg, ...tail);
|
|
656
688
|
}
|
|
657
689
|
async function detectCursor(homeDir) {
|
|
658
690
|
try {
|
|
@@ -852,7 +884,7 @@ async function cursorUsageTable(tz, homeDir) {
|
|
|
852
884
|
import { readdir, stat as fsStat, access as access2 } from "fs/promises";
|
|
853
885
|
import { createReadStream } from "fs";
|
|
854
886
|
import { createInterface } from "readline";
|
|
855
|
-
import { join as
|
|
887
|
+
import { join as join5, isAbsolute } from "path";
|
|
856
888
|
import { homedir as homedir3 } from "os";
|
|
857
889
|
var PRICING = {
|
|
858
890
|
"claude-opus-4-1": { i: 15e-6, o: 75e-6, cc: 1875e-8, cr: 15e-7 },
|
|
@@ -868,18 +900,18 @@ var PRICE_KEYS = Object.keys(PRICING).sort((a, b) => b.length - a.length);
|
|
|
868
900
|
var ZERO_PRICE = { i: 0, o: 0, cc: 0, cr: 0 };
|
|
869
901
|
function claudeConfigDirs(homeDir) {
|
|
870
902
|
if (homeDir) {
|
|
871
|
-
return [
|
|
903
|
+
return [join5(homeDir, ".claude"), join5(homeDir, ".config", "claude")];
|
|
872
904
|
}
|
|
873
905
|
const home = homedir3();
|
|
874
|
-
const dirs = [
|
|
906
|
+
const dirs = [join5(home, ".claude")];
|
|
875
907
|
const xdg = envDir("XDG_CONFIG_HOME");
|
|
876
908
|
if (xdg) {
|
|
877
|
-
dirs.push(
|
|
909
|
+
dirs.push(join5(xdg, "claude"));
|
|
878
910
|
} else if (process.platform !== "win32") {
|
|
879
|
-
dirs.push(
|
|
911
|
+
dirs.push(join5(home, ".config", "claude"));
|
|
880
912
|
}
|
|
881
913
|
const appData = envDir("APPDATA");
|
|
882
|
-
if (appData) dirs.push(
|
|
914
|
+
if (appData) dirs.push(join5(appData, "claude"));
|
|
883
915
|
if (process.env.CLAUDE_CONFIG_DIR) {
|
|
884
916
|
for (const p of process.env.CLAUDE_CONFIG_DIR.split(process.platform === "win32" ? ";" : ",")) {
|
|
885
917
|
const t = p.trim();
|
|
@@ -889,7 +921,7 @@ function claudeConfigDirs(homeDir) {
|
|
|
889
921
|
return [...new Set(dirs)];
|
|
890
922
|
}
|
|
891
923
|
function getClaudeDirs(homeDir) {
|
|
892
|
-
return claudeConfigDirs(homeDir).map((d) =>
|
|
924
|
+
return claudeConfigDirs(homeDir).map((d) => join5(d, "projects"));
|
|
893
925
|
}
|
|
894
926
|
async function detectClaude(homeDir) {
|
|
895
927
|
for (const dir of getClaudeDirs(homeDir)) {
|
|
@@ -919,36 +951,42 @@ function shortModel(model) {
|
|
|
919
951
|
}
|
|
920
952
|
async function parseFile(path) {
|
|
921
953
|
const entries = [];
|
|
922
|
-
const
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
954
|
+
const input = createReadStream(path);
|
|
955
|
+
input.on("error", () => {
|
|
956
|
+
});
|
|
957
|
+
const rl = createInterface({ input, crlfDelay: Infinity });
|
|
958
|
+
try {
|
|
959
|
+
for await (const line of rl) {
|
|
960
|
+
if (!line.includes('"usage"')) continue;
|
|
961
|
+
try {
|
|
962
|
+
const obj = JSON.parse(line.charCodeAt(0) === 65279 ? line.slice(1) : line);
|
|
963
|
+
if (obj.type !== "assistant" || !obj.message?.usage) continue;
|
|
964
|
+
const ts = new Date(obj.timestamp ?? 0).getTime();
|
|
965
|
+
if (!Number.isFinite(ts)) continue;
|
|
966
|
+
const u = obj.message.usage;
|
|
967
|
+
const model = typeof obj.message.model === "string" && obj.message.model ? obj.message.model : "unknown";
|
|
968
|
+
const inputTokens = safeNum(u.input_tokens);
|
|
969
|
+
const output = safeNum(u.output_tokens);
|
|
970
|
+
const cacheCreate = safeNum(u.cache_creation_input_tokens);
|
|
971
|
+
const cacheRead = safeNum(u.cache_read_input_tokens);
|
|
972
|
+
if (inputTokens + output + cacheCreate + cacheRead === 0) continue;
|
|
973
|
+
const p = priceFor(model);
|
|
974
|
+
const msgId = obj.message?.id;
|
|
975
|
+
entries.push({
|
|
976
|
+
id: msgId ? msgId + (obj.requestId ? ":" + obj.requestId : "") : void 0,
|
|
977
|
+
ts,
|
|
978
|
+
model: shortModel(model),
|
|
979
|
+
cost: costOf(model, u),
|
|
980
|
+
input: inputTokens,
|
|
981
|
+
output,
|
|
982
|
+
cacheCreate,
|
|
983
|
+
cacheRead,
|
|
984
|
+
cacheSavings: cacheRead * (p.i - p.cr)
|
|
985
|
+
});
|
|
986
|
+
} catch {
|
|
987
|
+
}
|
|
951
988
|
}
|
|
989
|
+
} catch {
|
|
952
990
|
}
|
|
953
991
|
return entries;
|
|
954
992
|
}
|
|
@@ -965,7 +1003,7 @@ async function loadEntries(since, homeDir) {
|
|
|
965
1003
|
}
|
|
966
1004
|
for (const f of listing) {
|
|
967
1005
|
if (!f.endsWith(".jsonl")) continue;
|
|
968
|
-
const path =
|
|
1006
|
+
const path = join5(dir, f);
|
|
969
1007
|
if (seen.has(path)) continue;
|
|
970
1008
|
seen.add(path);
|
|
971
1009
|
try {
|
|
@@ -994,7 +1032,7 @@ async function claudeTable(tz, homeDir) {
|
|
|
994
1032
|
|
|
995
1033
|
// src/providers/claude/billing.ts
|
|
996
1034
|
import { readFile as readFile2 } from "fs/promises";
|
|
997
|
-
import { join as
|
|
1035
|
+
import { join as join6 } from "path";
|
|
998
1036
|
import { homedir as homedir4 } from "os";
|
|
999
1037
|
|
|
1000
1038
|
// src/providers/_shared/keychain.ts
|
|
@@ -1036,7 +1074,7 @@ function claudeOrgPlanLabel(orgType) {
|
|
|
1036
1074
|
async function readClaudeIdentity(homeDir) {
|
|
1037
1075
|
const base = homeDir ? expandHome(homeDir) : homedir4();
|
|
1038
1076
|
try {
|
|
1039
|
-
const parsed = JSON.parse(await readFile2(
|
|
1077
|
+
const parsed = JSON.parse(await readFile2(join6(base, ".claude.json"), "utf-8"));
|
|
1040
1078
|
const oauth = parsed?.oauthAccount;
|
|
1041
1079
|
const email = typeof oauth?.emailAddress === "string" && oauth.emailAddress.trim() ? oauth.emailAddress.trim() : void 0;
|
|
1042
1080
|
const displayName = typeof oauth?.displayName === "string" && oauth.displayName.trim() ? oauth.displayName.trim() : void 0;
|
|
@@ -1070,7 +1108,7 @@ function parseAuth(raw) {
|
|
|
1070
1108
|
async function readCredentialsFile(homeDir) {
|
|
1071
1109
|
for (const dir of claudeConfigDirs(homeDir)) {
|
|
1072
1110
|
try {
|
|
1073
|
-
const auth = parseAuth(await readFile2(
|
|
1111
|
+
const auth = parseAuth(await readFile2(join6(dir, ".credentials.json"), "utf-8"));
|
|
1074
1112
|
if (auth) return auth;
|
|
1075
1113
|
} catch {
|
|
1076
1114
|
}
|
|
@@ -1169,7 +1207,7 @@ var claudeProvider = {
|
|
|
1169
1207
|
import { readdir as readdir2, stat as fsStat2, access as access3 } from "fs/promises";
|
|
1170
1208
|
import { createReadStream as createReadStream2 } from "fs";
|
|
1171
1209
|
import { createInterface as createInterface2 } from "readline";
|
|
1172
|
-
import { join as
|
|
1210
|
+
import { join as join7 } from "path";
|
|
1173
1211
|
import { homedir as homedir5 } from "os";
|
|
1174
1212
|
var PRICING2 = {
|
|
1175
1213
|
"gpt-5-codex": { in: 125e-8, cr: 125e-9, out: 1e-5 },
|
|
@@ -1181,18 +1219,18 @@ var PRICING2 = {
|
|
|
1181
1219
|
var ZERO_PRICE2 = { in: 0, cr: 0, out: 0 };
|
|
1182
1220
|
var PRICE_KEYS2 = Object.keys(PRICING2).sort((a, b) => b.length - a.length);
|
|
1183
1221
|
function codexHomes(homeDir) {
|
|
1184
|
-
if (homeDir) return [.../* @__PURE__ */ new Set([
|
|
1222
|
+
if (homeDir) return [.../* @__PURE__ */ new Set([join7(homeDir, ".codex"), homeDir])];
|
|
1185
1223
|
const homes = [];
|
|
1186
1224
|
const codexHome = envDir("CODEX_HOME");
|
|
1187
1225
|
if (codexHome) homes.push(codexHome);
|
|
1188
|
-
homes.push(
|
|
1189
|
-
homes.push(
|
|
1226
|
+
homes.push(join7(homedir5(), ".codex"));
|
|
1227
|
+
homes.push(join7(homedir5(), ".config", "codex"));
|
|
1190
1228
|
return [...new Set(homes)];
|
|
1191
1229
|
}
|
|
1192
1230
|
async function detectCodex(homeDir) {
|
|
1193
1231
|
for (const home of codexHomes(homeDir)) {
|
|
1194
1232
|
try {
|
|
1195
|
-
await access3(
|
|
1233
|
+
await access3(join7(home, "sessions"));
|
|
1196
1234
|
return true;
|
|
1197
1235
|
} catch {
|
|
1198
1236
|
}
|
|
@@ -1240,52 +1278,58 @@ async function parseFile2(path) {
|
|
|
1240
1278
|
let model = "unknown";
|
|
1241
1279
|
let prevTotal = null;
|
|
1242
1280
|
let prevSig = null;
|
|
1243
|
-
const
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
const
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1281
|
+
const input = createReadStream2(path);
|
|
1282
|
+
input.on("error", () => {
|
|
1283
|
+
});
|
|
1284
|
+
const rl = createInterface2({ input, crlfDelay: Infinity });
|
|
1285
|
+
try {
|
|
1286
|
+
for await (const rawLine of rl) {
|
|
1287
|
+
if (!rawLine.includes("token_count") && !rawLine.includes("turn_context")) continue;
|
|
1288
|
+
try {
|
|
1289
|
+
const line = rawLine.charCodeAt(0) === 65279 ? rawLine.slice(1) : rawLine;
|
|
1290
|
+
const obj = JSON.parse(line);
|
|
1291
|
+
const payloadType = obj?.payload?.type ?? obj?.type;
|
|
1292
|
+
if (payloadType === "turn_context") {
|
|
1293
|
+
const m = extractModel(obj);
|
|
1294
|
+
if (typeof m === "string" && m.trim()) model = m;
|
|
1295
|
+
continue;
|
|
1296
|
+
}
|
|
1297
|
+
if (payloadType !== "token_count") continue;
|
|
1298
|
+
const info = obj?.payload?.info;
|
|
1299
|
+
const total = info?.total_token_usage;
|
|
1300
|
+
const last = info?.last_token_usage;
|
|
1301
|
+
const sig = eventSig(last, total);
|
|
1302
|
+
if (sig === prevSig) continue;
|
|
1303
|
+
prevSig = sig;
|
|
1304
|
+
let d = last;
|
|
1305
|
+
if (!d && total) {
|
|
1306
|
+
const reset = !!prevTotal && (total.input_tokens ?? 0) < (prevTotal.input_tokens ?? 0);
|
|
1307
|
+
d = reset ? total : subtractClamped(total, prevTotal);
|
|
1308
|
+
}
|
|
1309
|
+
if (total) prevTotal = total;
|
|
1310
|
+
if (!d) continue;
|
|
1311
|
+
const ts = new Date(obj.timestamp ?? obj?.payload?.timestamp ?? 0).getTime();
|
|
1312
|
+
if (!Number.isFinite(ts)) continue;
|
|
1313
|
+
const inputTotal = safeNum(d.input_tokens);
|
|
1314
|
+
const cached = Math.min(safeNum(d.cached_input_tokens), inputTotal);
|
|
1315
|
+
const inputTokens = inputTotal - cached;
|
|
1316
|
+
const output = safeNum(d.output_tokens);
|
|
1317
|
+
if (inputTokens + output + cached === 0) continue;
|
|
1318
|
+
const p = priceFor2(model);
|
|
1319
|
+
entries.push({
|
|
1320
|
+
ts,
|
|
1321
|
+
model,
|
|
1322
|
+
cost: inputTokens * p.in + cached * p.cr + output * p.out,
|
|
1323
|
+
input: inputTokens,
|
|
1324
|
+
output,
|
|
1325
|
+
cacheCreate: 0,
|
|
1326
|
+
cacheRead: cached,
|
|
1327
|
+
cacheSavings: cached * (p.in - p.cr)
|
|
1328
|
+
});
|
|
1329
|
+
} catch {
|
|
1266
1330
|
}
|
|
1267
|
-
if (total) prevTotal = total;
|
|
1268
|
-
if (!d) continue;
|
|
1269
|
-
const ts = new Date(obj.timestamp ?? obj?.payload?.timestamp ?? 0).getTime();
|
|
1270
|
-
if (!Number.isFinite(ts)) continue;
|
|
1271
|
-
const inputTotal = safeNum(d.input_tokens);
|
|
1272
|
-
const cached = Math.min(safeNum(d.cached_input_tokens), inputTotal);
|
|
1273
|
-
const input = inputTotal - cached;
|
|
1274
|
-
const output = safeNum(d.output_tokens);
|
|
1275
|
-
if (input + output + cached === 0) continue;
|
|
1276
|
-
const p = priceFor2(model);
|
|
1277
|
-
entries.push({
|
|
1278
|
-
ts,
|
|
1279
|
-
model,
|
|
1280
|
-
cost: input * p.in + cached * p.cr + output * p.out,
|
|
1281
|
-
input,
|
|
1282
|
-
output,
|
|
1283
|
-
cacheCreate: 0,
|
|
1284
|
-
cacheRead: cached,
|
|
1285
|
-
cacheSavings: cached * (p.in - p.cr)
|
|
1286
|
-
});
|
|
1287
|
-
} catch {
|
|
1288
1331
|
}
|
|
1332
|
+
} catch {
|
|
1289
1333
|
}
|
|
1290
1334
|
return entries;
|
|
1291
1335
|
}
|
|
@@ -1294,7 +1338,7 @@ async function loadEntries2(since, homeDir) {
|
|
|
1294
1338
|
const seen = /* @__PURE__ */ new Set();
|
|
1295
1339
|
const seenIno = /* @__PURE__ */ new Set();
|
|
1296
1340
|
for (const home of codexHomes(homeDir)) {
|
|
1297
|
-
const dir =
|
|
1341
|
+
const dir = join7(home, "sessions");
|
|
1298
1342
|
let listing;
|
|
1299
1343
|
try {
|
|
1300
1344
|
listing = await readdir2(dir, { recursive: true });
|
|
@@ -1303,7 +1347,7 @@ async function loadEntries2(since, homeDir) {
|
|
|
1303
1347
|
}
|
|
1304
1348
|
for (const f of listing) {
|
|
1305
1349
|
if (!f.endsWith(".jsonl") || !f.includes("rollout-")) continue;
|
|
1306
|
-
const path =
|
|
1350
|
+
const path = join7(dir, f);
|
|
1307
1351
|
if (seen.has(path)) continue;
|
|
1308
1352
|
seen.add(path);
|
|
1309
1353
|
try {
|
|
@@ -1334,7 +1378,7 @@ async function codexTable(tz, homeDir) {
|
|
|
1334
1378
|
import { readFile as readFile3, readdir as readdir3, stat as fsStat3 } from "fs/promises";
|
|
1335
1379
|
import { createReadStream as createReadStream3 } from "fs";
|
|
1336
1380
|
import { createInterface as createInterface3 } from "readline";
|
|
1337
|
-
import { join as
|
|
1381
|
+
import { join as join8 } from "path";
|
|
1338
1382
|
var USAGE_URL2 = "https://chatgpt.com/backend-api/wham/usage";
|
|
1339
1383
|
var CREDIT_USD_RATE = 0.04;
|
|
1340
1384
|
function decodeBase64UrlJson(segment) {
|
|
@@ -1377,7 +1421,7 @@ function identityFields3(auth) {
|
|
|
1377
1421
|
}
|
|
1378
1422
|
async function readAuthFile(home) {
|
|
1379
1423
|
try {
|
|
1380
|
-
const raw = await readFile3(
|
|
1424
|
+
const raw = await readFile3(join8(home, "auth.json"), "utf-8");
|
|
1381
1425
|
const auth = JSON.parse(raw);
|
|
1382
1426
|
const accessToken = auth?.tokens?.access_token;
|
|
1383
1427
|
if (!accessToken) return null;
|
|
@@ -1460,7 +1504,7 @@ async function liveBilling(auth) {
|
|
|
1460
1504
|
async function newestRolloutFile(homeDir) {
|
|
1461
1505
|
let best = null;
|
|
1462
1506
|
for (const home of codexHomes(homeDir)) {
|
|
1463
|
-
const dir =
|
|
1507
|
+
const dir = join8(home, "sessions");
|
|
1464
1508
|
let listing;
|
|
1465
1509
|
try {
|
|
1466
1510
|
listing = await readdir3(dir, { recursive: true });
|
|
@@ -1469,7 +1513,7 @@ async function newestRolloutFile(homeDir) {
|
|
|
1469
1513
|
}
|
|
1470
1514
|
for (const f of listing) {
|
|
1471
1515
|
if (!f.endsWith(".jsonl") || !f.includes("rollout-")) continue;
|
|
1472
|
-
const path =
|
|
1516
|
+
const path = join8(dir, f);
|
|
1473
1517
|
try {
|
|
1474
1518
|
const s = await fsStat3(path);
|
|
1475
1519
|
if (!best || s.mtimeMs > best.mtime) best = { path, mtime: s.mtimeMs };
|
|
@@ -1484,7 +1528,10 @@ async function snapshotBilling(homeDir, auth = null) {
|
|
|
1484
1528
|
if (!path) return null;
|
|
1485
1529
|
let last = null;
|
|
1486
1530
|
try {
|
|
1487
|
-
const
|
|
1531
|
+
const input = createReadStream3(path);
|
|
1532
|
+
input.on("error", () => {
|
|
1533
|
+
});
|
|
1534
|
+
const rl = createInterface3({ input, crlfDelay: Infinity });
|
|
1488
1535
|
for await (const line of rl) {
|
|
1489
1536
|
if (!line.includes("rate_limits")) continue;
|
|
1490
1537
|
try {
|
|
@@ -1707,10 +1754,10 @@ var cursorProvider = {
|
|
|
1707
1754
|
import { readdir as readdir4, stat as fsStat4, access as access4 } from "fs/promises";
|
|
1708
1755
|
import { createReadStream as createReadStream4 } from "fs";
|
|
1709
1756
|
import { createInterface as createInterface4 } from "readline";
|
|
1710
|
-
import { join as
|
|
1757
|
+
import { join as join9 } from "path";
|
|
1711
1758
|
import { homedir as homedir6 } from "os";
|
|
1712
1759
|
function piSessionsDir(homeDir) {
|
|
1713
|
-
return
|
|
1760
|
+
return join9(homeDir ?? homedir6(), ".pi", "agent", "sessions");
|
|
1714
1761
|
}
|
|
1715
1762
|
async function detectPi(homeDir) {
|
|
1716
1763
|
try {
|
|
@@ -1770,7 +1817,7 @@ async function loadEntries3(since, homeDir) {
|
|
|
1770
1817
|
}
|
|
1771
1818
|
for (const f of listing) {
|
|
1772
1819
|
if (!f.endsWith(".jsonl")) continue;
|
|
1773
|
-
const path =
|
|
1820
|
+
const path = join9(dir, f);
|
|
1774
1821
|
try {
|
|
1775
1822
|
const s = await fsStat4(path);
|
|
1776
1823
|
if (s.mtimeMs < since) continue;
|
|
@@ -1806,17 +1853,17 @@ var piProvider = {
|
|
|
1806
1853
|
|
|
1807
1854
|
// src/providers/opencode/usage.ts
|
|
1808
1855
|
import { access as access5 } from "fs/promises";
|
|
1809
|
-
import { join as
|
|
1856
|
+
import { join as join10 } from "path";
|
|
1810
1857
|
import { homedir as homedir7 } from "os";
|
|
1811
1858
|
function opencodeDbPaths(homeDir) {
|
|
1812
1859
|
const base = homeDir ?? homedir7();
|
|
1813
1860
|
const paths = [];
|
|
1814
|
-
if (!homeDir && process.env.XDG_DATA_HOME) paths.push(
|
|
1815
|
-
paths.push(
|
|
1816
|
-
if (process.platform === "darwin") paths.push(
|
|
1861
|
+
if (!homeDir && process.env.XDG_DATA_HOME) paths.push(join10(process.env.XDG_DATA_HOME, "opencode", "opencode.db"));
|
|
1862
|
+
paths.push(join10(base, ".local", "share", "opencode", "opencode.db"));
|
|
1863
|
+
if (process.platform === "darwin") paths.push(join10(base, "Library", "Application Support", "opencode", "opencode.db"));
|
|
1817
1864
|
if (process.platform === "win32") {
|
|
1818
|
-
const lad = homeDir ?
|
|
1819
|
-
if (lad) paths.push(
|
|
1865
|
+
const lad = homeDir ? join10(homeDir, "AppData", "Local") : process.env.LOCALAPPDATA;
|
|
1866
|
+
if (lad) paths.push(join10(lad, "opencode", "opencode.db"));
|
|
1820
1867
|
}
|
|
1821
1868
|
return [...new Set(paths)];
|
|
1822
1869
|
}
|
|
@@ -1881,12 +1928,110 @@ var opencodeProvider = {
|
|
|
1881
1928
|
};
|
|
1882
1929
|
|
|
1883
1930
|
// src/providers/copilot/billing.ts
|
|
1884
|
-
import { execFile as execFileCb3 } from "child_process";
|
|
1885
1931
|
import { access as access6, readFile as readFile4, readdir as readdir5 } from "fs/promises";
|
|
1886
|
-
import { join as
|
|
1932
|
+
import { join as join12 } from "path";
|
|
1933
|
+
import { homedir as homedir9 } from "os";
|
|
1934
|
+
|
|
1935
|
+
// src/providers/detect.ts
|
|
1936
|
+
import { accessSync as accessSync2, constants as constants2, existsSync } from "fs";
|
|
1937
|
+
import { join as join11, delimiter as delimiter2, isAbsolute as isAbsolute2 } from "path";
|
|
1887
1938
|
import { homedir as homedir8 } from "os";
|
|
1888
|
-
|
|
1889
|
-
|
|
1939
|
+
function searchDirs() {
|
|
1940
|
+
const home = homedir8();
|
|
1941
|
+
const fromEnv = (process.env.PATH ?? "").split(delimiter2).filter(Boolean);
|
|
1942
|
+
const extra = process.platform === "win32" ? [
|
|
1943
|
+
process.env.APPDATA && join11(process.env.APPDATA, "npm"),
|
|
1944
|
+
process.env.LOCALAPPDATA && join11(process.env.LOCALAPPDATA, "pnpm"),
|
|
1945
|
+
join11(home, "scoop", "shims")
|
|
1946
|
+
] : [
|
|
1947
|
+
"/opt/homebrew/bin",
|
|
1948
|
+
"/usr/local/bin",
|
|
1949
|
+
"/usr/bin",
|
|
1950
|
+
"/bin",
|
|
1951
|
+
"/opt/local/bin",
|
|
1952
|
+
join11(home, ".local", "bin"),
|
|
1953
|
+
join11(home, "bin"),
|
|
1954
|
+
join11(home, ".npm-global", "bin"),
|
|
1955
|
+
join11(home, ".bun", "bin"),
|
|
1956
|
+
join11(home, ".local", "share", "pnpm")
|
|
1957
|
+
];
|
|
1958
|
+
return [.../* @__PURE__ */ new Set([...fromEnv, ...extra.filter((d) => !!d)])];
|
|
1959
|
+
}
|
|
1960
|
+
function isExec2(p) {
|
|
1961
|
+
try {
|
|
1962
|
+
accessSync2(p, process.platform === "win32" ? constants2.F_OK : constants2.X_OK);
|
|
1963
|
+
return true;
|
|
1964
|
+
} catch {
|
|
1965
|
+
return false;
|
|
1966
|
+
}
|
|
1967
|
+
}
|
|
1968
|
+
function onPath(names) {
|
|
1969
|
+
const exts = process.platform === "win32" ? (process.env.PATHEXT ?? ".EXE;.CMD;.BAT;.COM").split(";").map((e) => e.toLowerCase()).concat("") : [""];
|
|
1970
|
+
for (const dir of searchDirs()) {
|
|
1971
|
+
for (const n of names) {
|
|
1972
|
+
for (const e of exts) {
|
|
1973
|
+
if (isExec2(join11(dir, n + e))) return true;
|
|
1974
|
+
}
|
|
1975
|
+
}
|
|
1976
|
+
}
|
|
1977
|
+
return false;
|
|
1978
|
+
}
|
|
1979
|
+
function anyExists(paths) {
|
|
1980
|
+
return paths.some((p) => !!p && isExec2(p));
|
|
1981
|
+
}
|
|
1982
|
+
function installSignals(id) {
|
|
1983
|
+
const home = homedir8();
|
|
1984
|
+
const pf = process.env.ProgramFiles;
|
|
1985
|
+
const pf86 = process.env["ProgramFiles(x86)"];
|
|
1986
|
+
const lad = process.env.LOCALAPPDATA;
|
|
1987
|
+
switch (id) {
|
|
1988
|
+
case "claude":
|
|
1989
|
+
return onPath(["claude"]) || anyExists([
|
|
1990
|
+
"/Applications/Claude.app",
|
|
1991
|
+
join11(home, "Applications", "Claude.app"),
|
|
1992
|
+
lad && join11(lad, "Programs", "claude", "Claude.exe")
|
|
1993
|
+
]);
|
|
1994
|
+
case "codex": {
|
|
1995
|
+
const bin = process.env.CODEX_BIN;
|
|
1996
|
+
if (bin && isAbsolute2(bin) && isExec2(bin)) return true;
|
|
1997
|
+
return onPath(["codex"]) || anyExists([
|
|
1998
|
+
lad && join11(lad, "Programs", "OpenAI", "Codex", "bin", "codex.exe"),
|
|
1999
|
+
lad && join11(lad, "Programs", "OpenAI", "Codex", "codex.exe"),
|
|
2000
|
+
lad && join11(lad, "Programs", "codex", "codex.exe"),
|
|
2001
|
+
pf && join11(pf, "OpenAI", "Codex", "bin", "codex.exe")
|
|
2002
|
+
]) || existsSync(join11(home, ".codex", "sessions")) || existsSync(join11(home, ".codex", "auth.json"));
|
|
2003
|
+
}
|
|
2004
|
+
case "cursor":
|
|
2005
|
+
return onPath(["cursor", "cursor-agent"]) || anyExists([
|
|
2006
|
+
"/Applications/Cursor.app",
|
|
2007
|
+
join11(home, "Applications", "Cursor.app"),
|
|
2008
|
+
lad && join11(lad, "Programs", "cursor", "Cursor.exe"),
|
|
2009
|
+
pf && join11(pf, "Cursor", "Cursor.exe"),
|
|
2010
|
+
pf86 && join11(pf86, "Cursor", "Cursor.exe"),
|
|
2011
|
+
"/opt/Cursor/cursor",
|
|
2012
|
+
"/usr/share/cursor/cursor",
|
|
2013
|
+
"/usr/bin/cursor"
|
|
2014
|
+
]);
|
|
2015
|
+
case "pi":
|
|
2016
|
+
return onPath(["pi"]);
|
|
2017
|
+
case "opencode":
|
|
2018
|
+
return onPath(["opencode"]);
|
|
2019
|
+
case "copilot":
|
|
2020
|
+
return onPath(["gh"]);
|
|
2021
|
+
case "antigravity":
|
|
2022
|
+
return onPath(["antigravity"]) || anyExists([
|
|
2023
|
+
"/Applications/Antigravity.app",
|
|
2024
|
+
join11(home, "Applications", "Antigravity.app"),
|
|
2025
|
+
lad && join11(lad, "Programs", "Antigravity", "Antigravity.exe")
|
|
2026
|
+
]);
|
|
2027
|
+
case "gemini":
|
|
2028
|
+
return onPath(["gemini"]);
|
|
2029
|
+
default:
|
|
2030
|
+
return false;
|
|
2031
|
+
}
|
|
2032
|
+
}
|
|
2033
|
+
|
|
2034
|
+
// src/providers/copilot/billing.ts
|
|
1890
2035
|
var USAGE_URL3 = "https://api.github.com/copilot_internal/user";
|
|
1891
2036
|
var GH_KEYCHAIN_SERVICE = "gh:github.com";
|
|
1892
2037
|
function ghConfigDir(homeDir) {
|
|
@@ -1894,15 +2039,15 @@ function ghConfigDir(homeDir) {
|
|
|
1894
2039
|
const explicit = process.env.GH_CONFIG_DIR;
|
|
1895
2040
|
if (explicit && explicit.trim()) return explicit.trim();
|
|
1896
2041
|
if (process.platform === "win32") {
|
|
1897
|
-
return
|
|
2042
|
+
return join12(envDir("APPDATA") ?? join12(homedir9(), "AppData", "Roaming"), "GitHub CLI");
|
|
1898
2043
|
}
|
|
1899
2044
|
const xdg = envDir("XDG_CONFIG_HOME");
|
|
1900
|
-
return xdg ?
|
|
2045
|
+
return xdg ? join12(xdg, "gh") : join12(homedir9(), ".config", "gh");
|
|
1901
2046
|
}
|
|
1902
|
-
return process.platform === "win32" ?
|
|
2047
|
+
return process.platform === "win32" ? join12(homeDir, "AppData", "Roaming", "GitHub CLI") : join12(homeDir, ".config", "gh");
|
|
1903
2048
|
}
|
|
1904
2049
|
function ghHostsPath(homeDir) {
|
|
1905
|
-
return
|
|
2050
|
+
return join12(ghConfigDir(homeDir), "hosts.yml");
|
|
1906
2051
|
}
|
|
1907
2052
|
async function detectCopilot(homeDir) {
|
|
1908
2053
|
try {
|
|
@@ -1910,12 +2055,7 @@ async function detectCopilot(homeDir) {
|
|
|
1910
2055
|
return true;
|
|
1911
2056
|
} catch {
|
|
1912
2057
|
}
|
|
1913
|
-
|
|
1914
|
-
await execFile3("gh", ["--version"], { timeout: 3e3 });
|
|
1915
|
-
return true;
|
|
1916
|
-
} catch {
|
|
1917
|
-
return false;
|
|
1918
|
-
}
|
|
2058
|
+
return onPath(["gh"]);
|
|
1919
2059
|
}
|
|
1920
2060
|
function unquoteYamlValue(value) {
|
|
1921
2061
|
const trimmed = value.trim();
|
|
@@ -1962,10 +2102,10 @@ async function loadTokenFromGhKeychain() {
|
|
|
1962
2102
|
return token ? { token, source: "gh-keychain" } : null;
|
|
1963
2103
|
}
|
|
1964
2104
|
function vscodeUserDir(homeDir) {
|
|
1965
|
-
const home = homeDir ??
|
|
1966
|
-
if (process.platform === "darwin") return
|
|
1967
|
-
if (process.platform === "win32") return
|
|
1968
|
-
return
|
|
2105
|
+
const home = homeDir ?? homedir9();
|
|
2106
|
+
if (process.platform === "darwin") return join12(home, "Library", "Application Support", "Code", "User");
|
|
2107
|
+
if (process.platform === "win32") return join12(home, "AppData", "Roaming", "Code", "User");
|
|
2108
|
+
return join12(home, ".config", "Code", "User");
|
|
1969
2109
|
}
|
|
1970
2110
|
function tokenFromText(raw) {
|
|
1971
2111
|
const patterns = [
|
|
@@ -1982,14 +2122,14 @@ function tokenFromText(raw) {
|
|
|
1982
2122
|
async function loadTokenFromVsCode(homeDir) {
|
|
1983
2123
|
const userDir = vscodeUserDir(homeDir);
|
|
1984
2124
|
const candidates = [
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
2125
|
+
join12(userDir, "globalStorage", "github.copilot-chat", "auth.json"),
|
|
2126
|
+
join12(userDir, "globalStorage", "github.copilot", "auth.json"),
|
|
2127
|
+
join12(userDir, "globalStorage", "state.vscdb")
|
|
1988
2128
|
];
|
|
1989
2129
|
try {
|
|
1990
|
-
for (const dirent of await readdir5(
|
|
2130
|
+
for (const dirent of await readdir5(join12(userDir, "globalStorage"), { withFileTypes: true })) {
|
|
1991
2131
|
if (dirent.isDirectory() && dirent.name.toLowerCase().includes("github")) {
|
|
1992
|
-
candidates.push(
|
|
2132
|
+
candidates.push(join12(userDir, "globalStorage", dirent.name, "auth.json"));
|
|
1993
2133
|
}
|
|
1994
2134
|
}
|
|
1995
2135
|
} catch {
|
|
@@ -2097,14 +2237,14 @@ var copilotProvider = {
|
|
|
2097
2237
|
|
|
2098
2238
|
// src/providers/antigravity/billing.ts
|
|
2099
2239
|
import { access as access7, readdir as readdir7 } from "fs/promises";
|
|
2100
|
-
import { join as
|
|
2101
|
-
import { homedir as
|
|
2240
|
+
import { join as join14 } from "path";
|
|
2241
|
+
import { homedir as homedir11 } from "os";
|
|
2102
2242
|
|
|
2103
2243
|
// src/providers/cloud-code.ts
|
|
2104
2244
|
import { readFile as readFile5, readdir as readdir6, realpath, stat } from "fs/promises";
|
|
2105
2245
|
import { spawnSync } from "child_process";
|
|
2106
|
-
import { homedir as
|
|
2107
|
-
import { dirname, join as
|
|
2246
|
+
import { homedir as homedir10 } from "os";
|
|
2247
|
+
import { dirname, join as join13 } from "path";
|
|
2108
2248
|
var CLOUD_CODE_URLS = [
|
|
2109
2249
|
"https://daily-cloudcode-pa.googleapis.com",
|
|
2110
2250
|
"https://cloudcode-pa.googleapis.com"
|
|
@@ -2230,30 +2370,40 @@ function geminiBundleCandidates() {
|
|
|
2230
2370
|
const candidates = [];
|
|
2231
2371
|
const addBundle = (nodeModulesRoot) => {
|
|
2232
2372
|
if (!nodeModulesRoot) return;
|
|
2233
|
-
candidates.push(
|
|
2373
|
+
candidates.push(join13(nodeModulesRoot, "@google", "gemini-cli", "bundle"));
|
|
2234
2374
|
};
|
|
2235
2375
|
try {
|
|
2236
|
-
const which = spawnSync("
|
|
2376
|
+
const which = process.platform === "win32" ? spawnSync("where", ["gemini"], { encoding: "utf8", timeout: 5e3 }) : spawnSync("sh", ["-lc", "command -v gemini"], { encoding: "utf8", timeout: 5e3 });
|
|
2237
2377
|
const resolved = typeof which.stdout === "string" ? which.stdout.trim().split("\n")[0]?.trim() : "";
|
|
2238
2378
|
if (resolved) candidates.push(resolved);
|
|
2239
2379
|
} catch {
|
|
2240
2380
|
}
|
|
2241
|
-
const home =
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2381
|
+
const home = homedir10();
|
|
2382
|
+
if (process.platform === "win32") {
|
|
2383
|
+
addBundle(join13(process.env.APPDATA ?? join13(home, "AppData", "Roaming"), "npm", "node_modules"));
|
|
2384
|
+
} else {
|
|
2385
|
+
addBundle("/opt/homebrew/lib/node_modules");
|
|
2386
|
+
addBundle("/usr/local/lib/node_modules");
|
|
2387
|
+
addBundle(join13(home, ".local", "share", "node_modules"));
|
|
2388
|
+
addBundle(join13(home, ".bun", "install", "global", "node_modules"));
|
|
2389
|
+
}
|
|
2246
2390
|
try {
|
|
2247
|
-
const prefix = spawnSync("npm", ["config", "get", "prefix"], {
|
|
2391
|
+
const prefix = spawnSync(process.platform === "win32" ? "npm.cmd" : "npm", ["config", "get", "prefix"], {
|
|
2392
|
+
encoding: "utf8",
|
|
2393
|
+
timeout: 5e3,
|
|
2394
|
+
shell: process.platform === "win32"
|
|
2395
|
+
});
|
|
2248
2396
|
const root = typeof prefix.stdout === "string" ? prefix.stdout.trim() : "";
|
|
2249
|
-
if (root && root !== "undefined")
|
|
2397
|
+
if (root && root !== "undefined") {
|
|
2398
|
+
addBundle(process.platform === "win32" ? join13(root, "node_modules") : join13(root, "lib", "node_modules"));
|
|
2399
|
+
}
|
|
2250
2400
|
} catch {
|
|
2251
2401
|
}
|
|
2252
2402
|
return [...new Set(candidates.filter(Boolean))];
|
|
2253
2403
|
}
|
|
2254
2404
|
async function resolveBundleDir(candidate) {
|
|
2255
2405
|
try {
|
|
2256
|
-
if (candidate.endsWith(`${
|
|
2406
|
+
if (candidate.endsWith(`${join13("@google", "gemini-cli", "bundle")}`)) {
|
|
2257
2407
|
return candidate;
|
|
2258
2408
|
}
|
|
2259
2409
|
const real = await realpath(candidate);
|
|
@@ -2271,7 +2421,7 @@ async function scanBundleDir(dir) {
|
|
|
2271
2421
|
}
|
|
2272
2422
|
const targets = entries.filter((name) => name === "gemini.js" || name.startsWith("chunk-") && name.endsWith(".js"));
|
|
2273
2423
|
for (const name of targets) {
|
|
2274
|
-
const filePath =
|
|
2424
|
+
const filePath = join13(dir, name);
|
|
2275
2425
|
try {
|
|
2276
2426
|
const info = await stat(filePath);
|
|
2277
2427
|
if (!info.isFile() || info.size > MAX_BUNDLE_READ) continue;
|
|
@@ -2497,33 +2647,33 @@ async function firstExisting(paths) {
|
|
|
2497
2647
|
return paths[0];
|
|
2498
2648
|
}
|
|
2499
2649
|
async function antigravityStateDb(homeDir) {
|
|
2500
|
-
const base = homeDir ??
|
|
2650
|
+
const base = homeDir ?? homedir11();
|
|
2501
2651
|
const tail = ["User", "globalStorage", "state.vscdb"];
|
|
2502
2652
|
if (process.platform === "darwin") {
|
|
2503
|
-
const support =
|
|
2653
|
+
const support = join14(base, "Library", "Application Support");
|
|
2504
2654
|
const exact = [
|
|
2505
|
-
|
|
2506
|
-
|
|
2655
|
+
join14(support, "Antigravity IDE", ...tail),
|
|
2656
|
+
join14(support, "Antigravity", ...tail)
|
|
2507
2657
|
];
|
|
2508
2658
|
try {
|
|
2509
2659
|
const entries = await readdir7(support, { withFileTypes: true });
|
|
2510
|
-
const matches = entries.filter((e) => e.isDirectory() && e.name.includes("Antigravity")).map((e) =>
|
|
2660
|
+
const matches = entries.filter((e) => e.isDirectory() && e.name.includes("Antigravity")).map((e) => join14(support, e.name, ...tail));
|
|
2511
2661
|
return firstExisting([...exact, ...matches]);
|
|
2512
2662
|
} catch {
|
|
2513
2663
|
return firstExisting(exact);
|
|
2514
2664
|
}
|
|
2515
2665
|
}
|
|
2516
2666
|
if (process.platform === "win32") {
|
|
2517
|
-
const roaming = homeDir ?
|
|
2667
|
+
const roaming = homeDir ? join14(homeDir, "AppData", "Roaming") : envDir("APPDATA") ?? join14(base, "AppData", "Roaming");
|
|
2518
2668
|
return firstExisting([
|
|
2519
|
-
|
|
2520
|
-
|
|
2669
|
+
join14(roaming, "Antigravity IDE", ...tail),
|
|
2670
|
+
join14(roaming, "Antigravity", ...tail)
|
|
2521
2671
|
]);
|
|
2522
2672
|
}
|
|
2523
|
-
const cfg = homeDir ?
|
|
2673
|
+
const cfg = homeDir ? join14(homeDir, ".config") : envDir("XDG_CONFIG_HOME") ?? join14(base, ".config");
|
|
2524
2674
|
return firstExisting([
|
|
2525
|
-
|
|
2526
|
-
|
|
2675
|
+
join14(cfg, "Antigravity IDE", ...tail),
|
|
2676
|
+
join14(cfg, "Antigravity", ...tail)
|
|
2527
2677
|
]);
|
|
2528
2678
|
}
|
|
2529
2679
|
async function detectAntigravity(homeDir) {
|
|
@@ -2554,14 +2704,127 @@ var antigravityProvider = {
|
|
|
2554
2704
|
};
|
|
2555
2705
|
|
|
2556
2706
|
// src/providers/gemini/billing.ts
|
|
2557
|
-
import { access as access8, readFile as readFile6 } from "fs/promises";
|
|
2558
|
-
import { join as
|
|
2559
|
-
import { homedir as
|
|
2707
|
+
import { access as access8, readFile as readFile6, readdir as readdir9 } from "fs/promises";
|
|
2708
|
+
import { join as join16 } from "path";
|
|
2709
|
+
import { homedir as homedir13 } from "os";
|
|
2710
|
+
|
|
2711
|
+
// src/providers/gemini/usage.ts
|
|
2712
|
+
import { readdir as readdir8, stat as fsStat5 } from "fs/promises";
|
|
2713
|
+
import { createReadStream as createReadStream5 } from "fs";
|
|
2714
|
+
import { createInterface as createInterface5 } from "readline";
|
|
2715
|
+
import { join as join15 } from "path";
|
|
2716
|
+
import { homedir as homedir12 } from "os";
|
|
2717
|
+
var PRICING3 = {
|
|
2718
|
+
"gemini-3.1-pro-preview": { in: 2e-6, out: 12e-6, cr: 2e-7 },
|
|
2719
|
+
"gemini-3.1-pro": { in: 2e-6, out: 12e-6, cr: 2e-7 },
|
|
2720
|
+
"gemini-3-pro-preview": { in: 2e-6, out: 12e-6, cr: 2e-7 },
|
|
2721
|
+
"gemini-3-pro": { in: 2e-6, out: 12e-6, cr: 2e-7 },
|
|
2722
|
+
"gemini-3.5-flash": { in: 15e-7, out: 9e-6, cr: 15e-8 },
|
|
2723
|
+
"gemini-3-flash-preview": { in: 15e-7, out: 9e-6, cr: 15e-8 },
|
|
2724
|
+
"gemini-3-flash": { in: 15e-7, out: 9e-6, cr: 15e-8 },
|
|
2725
|
+
"gemini-2.5-flash-lite": { in: 1e-7, out: 4e-7, cr: 1e-8 },
|
|
2726
|
+
"gemini-3.1-flash-lite": { in: 1e-7, out: 4e-7, cr: 1e-8 },
|
|
2727
|
+
"gemini-2.5-flash": { in: 3e-7, out: 25e-7, cr: 3e-8 },
|
|
2728
|
+
"gemini-2.5-pro": { in: 125e-8, out: 1e-5, cr: 125e-9 },
|
|
2729
|
+
"gemini-2.0-flash": { in: 1e-7, out: 4e-7, cr: 25e-9 }
|
|
2730
|
+
};
|
|
2731
|
+
var PRICE_KEYS3 = Object.keys(PRICING3).sort((a, b) => b.length - a.length);
|
|
2732
|
+
var ZERO_PRICE3 = { in: 0, out: 0, cr: 0 };
|
|
2733
|
+
function geminiTmpDir(homeDir) {
|
|
2734
|
+
return join15(homeDir ?? homedir12(), ".gemini", "tmp");
|
|
2735
|
+
}
|
|
2736
|
+
function priceFor3(model) {
|
|
2737
|
+
const m = model.toLowerCase().trim();
|
|
2738
|
+
for (const key of PRICE_KEYS3) {
|
|
2739
|
+
if (!m.startsWith(key)) continue;
|
|
2740
|
+
const rest = m.slice(key.length);
|
|
2741
|
+
if (rest === "" || rest[0] === "-") return PRICING3[key];
|
|
2742
|
+
}
|
|
2743
|
+
return ZERO_PRICE3;
|
|
2744
|
+
}
|
|
2745
|
+
function shortModel2(model) {
|
|
2746
|
+
return model.replace(/(-preview|-customtools)+$/, "");
|
|
2747
|
+
}
|
|
2748
|
+
function isGeminiSessionFile(path) {
|
|
2749
|
+
return /(^|[\\/])chats[\\/]session-.*\.jsonl$/.test(path) || /(^|[\\/])chats[\\/]session-.*\.json$/.test(path);
|
|
2750
|
+
}
|
|
2751
|
+
async function parseFile4(path) {
|
|
2752
|
+
const entries = [];
|
|
2753
|
+
const rl = createInterface5({ input: createReadStream5(path), crlfDelay: Infinity });
|
|
2754
|
+
for await (const line of rl) {
|
|
2755
|
+
try {
|
|
2756
|
+
const obj = JSON.parse(line.charCodeAt(0) === 65279 ? line.slice(1) : line);
|
|
2757
|
+
if (obj.sessionId && obj.kind || obj.$set || obj.$rewindTo) continue;
|
|
2758
|
+
if (obj.type !== "gemini" || !obj.tokens) continue;
|
|
2759
|
+
const ts = Date.parse(obj.timestamp ?? "");
|
|
2760
|
+
if (!Number.isFinite(ts)) continue;
|
|
2761
|
+
const t = obj.tokens;
|
|
2762
|
+
const input = Math.max(0, safeNum(t.input) + safeNum(t.tool) - safeNum(t.cached));
|
|
2763
|
+
const output = safeNum(t.output) + safeNum(t.thoughts);
|
|
2764
|
+
const cacheRead = safeNum(t.cached);
|
|
2765
|
+
if (input + output + cacheRead === 0) continue;
|
|
2766
|
+
const model = typeof obj.model === "string" && obj.model ? obj.model : "unknown";
|
|
2767
|
+
const p = priceFor3(model);
|
|
2768
|
+
entries.push({
|
|
2769
|
+
id: typeof obj.id === "string" ? obj.id : void 0,
|
|
2770
|
+
ts,
|
|
2771
|
+
model: shortModel2(model),
|
|
2772
|
+
cost: input * p.in + cacheRead * p.cr + output * p.out,
|
|
2773
|
+
input,
|
|
2774
|
+
output,
|
|
2775
|
+
cacheCreate: 0,
|
|
2776
|
+
cacheRead,
|
|
2777
|
+
cacheSavings: cacheRead * (p.in - p.cr)
|
|
2778
|
+
});
|
|
2779
|
+
} catch {
|
|
2780
|
+
}
|
|
2781
|
+
}
|
|
2782
|
+
return entries;
|
|
2783
|
+
}
|
|
2784
|
+
async function loadEntries5(since, homeDir) {
|
|
2785
|
+
const files = [];
|
|
2786
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2787
|
+
const seenIno = /* @__PURE__ */ new Set();
|
|
2788
|
+
let listing;
|
|
2789
|
+
try {
|
|
2790
|
+
listing = await readdir8(geminiTmpDir(homeDir), { recursive: true });
|
|
2791
|
+
} catch {
|
|
2792
|
+
return [];
|
|
2793
|
+
}
|
|
2794
|
+
for (const f of listing) {
|
|
2795
|
+
if (!isGeminiSessionFile(f)) continue;
|
|
2796
|
+
const path = join15(geminiTmpDir(homeDir), f);
|
|
2797
|
+
if (seen.has(path)) continue;
|
|
2798
|
+
seen.add(path);
|
|
2799
|
+
try {
|
|
2800
|
+
const s = await fsStat5(path);
|
|
2801
|
+
if (s.mtimeMs < since) continue;
|
|
2802
|
+
if (s.ino && process.platform !== "win32") {
|
|
2803
|
+
const idn = `${s.dev}:${s.ino}`;
|
|
2804
|
+
if (seenIno.has(idn)) continue;
|
|
2805
|
+
seenIno.add(idn);
|
|
2806
|
+
}
|
|
2807
|
+
files.push({ path, mtimeMs: s.mtimeMs, size: s.size });
|
|
2808
|
+
} catch {
|
|
2809
|
+
}
|
|
2810
|
+
}
|
|
2811
|
+
return loadCachedEntries(files, parseFile4, since);
|
|
2812
|
+
}
|
|
2813
|
+
async function geminiDashboard(tz, homeDir) {
|
|
2814
|
+
const entries = await loadEntries5(dashboardSince(tz), homeDir);
|
|
2815
|
+
return summarize(entries, tz);
|
|
2816
|
+
}
|
|
2817
|
+
async function geminiTable(tz, homeDir) {
|
|
2818
|
+
const entries = await loadEntries5(tableSince(tz), homeDir);
|
|
2819
|
+
return tabulate(entries, tz);
|
|
2820
|
+
}
|
|
2821
|
+
|
|
2822
|
+
// src/providers/gemini/billing.ts
|
|
2560
2823
|
function geminiCredsPath(homeDir) {
|
|
2561
|
-
return
|
|
2824
|
+
return join16(homeDir ?? homedir13(), ".gemini", "oauth_creds.json");
|
|
2562
2825
|
}
|
|
2563
2826
|
function geminiDir(homeDir) {
|
|
2564
|
-
return
|
|
2827
|
+
return join16(homeDir ?? homedir13(), ".gemini");
|
|
2565
2828
|
}
|
|
2566
2829
|
function authTypeFromSettings(settings) {
|
|
2567
2830
|
const raw = settings?.security?.auth?.selectedType ?? settings?.selectedAuthType;
|
|
@@ -2574,7 +2837,7 @@ function authTypeFromSettings(settings) {
|
|
|
2574
2837
|
}
|
|
2575
2838
|
async function authMethodFromSettings(homeDir) {
|
|
2576
2839
|
try {
|
|
2577
|
-
const raw = await readFile6(
|
|
2840
|
+
const raw = await readFile6(join16(geminiDir(homeDir), "settings.json"), "utf8");
|
|
2578
2841
|
return authTypeFromSettings(JSON.parse(raw));
|
|
2579
2842
|
} catch {
|
|
2580
2843
|
return "none";
|
|
@@ -2582,12 +2845,12 @@ async function authMethodFromSettings(homeDir) {
|
|
|
2582
2845
|
}
|
|
2583
2846
|
async function hasGeminiApiKeyFile(homeDir) {
|
|
2584
2847
|
try {
|
|
2585
|
-
await access8(
|
|
2848
|
+
await access8(join16(geminiDir(homeDir), "api_key"));
|
|
2586
2849
|
return true;
|
|
2587
2850
|
} catch {
|
|
2588
2851
|
}
|
|
2589
2852
|
try {
|
|
2590
|
-
const env = await readFile6(
|
|
2853
|
+
const env = await readFile6(join16(geminiDir(homeDir), ".env"), "utf8");
|
|
2591
2854
|
return /^\s*GEMINI_API_KEY\s*=/m.test(env);
|
|
2592
2855
|
} catch {
|
|
2593
2856
|
return false;
|
|
@@ -2606,12 +2869,22 @@ async function noOAuthAuthMessage(homeDir) {
|
|
|
2606
2869
|
return "Not signed in \u2014 run gemini and log in with Google";
|
|
2607
2870
|
}
|
|
2608
2871
|
async function detectGemini(homeDir) {
|
|
2872
|
+
let oauthOk = false;
|
|
2609
2873
|
try {
|
|
2610
2874
|
await access8(geminiCredsPath(homeDir));
|
|
2611
|
-
|
|
2875
|
+
oauthOk = true;
|
|
2876
|
+
} catch {
|
|
2877
|
+
}
|
|
2878
|
+
return oauthOk || await hasGeminiChatSessions(homeDir);
|
|
2879
|
+
}
|
|
2880
|
+
async function hasGeminiChatSessions(homeDir) {
|
|
2881
|
+
let listing;
|
|
2882
|
+
try {
|
|
2883
|
+
listing = await readdir9(geminiTmpDir(homeDir), { recursive: true });
|
|
2612
2884
|
} catch {
|
|
2613
2885
|
return false;
|
|
2614
2886
|
}
|
|
2887
|
+
return listing.some((path) => /(^|[\\/])chats[\\/]session-.*\.jsonl$/.test(path));
|
|
2615
2888
|
}
|
|
2616
2889
|
function decodeBase64UrlJson2(segment) {
|
|
2617
2890
|
try {
|
|
@@ -2666,106 +2939,14 @@ var geminiProvider = {
|
|
|
2666
2939
|
id: "gemini",
|
|
2667
2940
|
name: "Gemini",
|
|
2668
2941
|
color: "greenBright",
|
|
2669
|
-
hasUsage:
|
|
2942
|
+
hasUsage: true,
|
|
2670
2943
|
hasBilling: true,
|
|
2671
2944
|
detect: (homeDir) => detectGemini(homeDir),
|
|
2945
|
+
fetchSummary: (account, tz) => geminiDashboard(tz, account.homeDir),
|
|
2946
|
+
fetchTable: (account, tz) => geminiTable(tz, account.homeDir),
|
|
2672
2947
|
fetchBilling: (account) => geminiBilling(account)
|
|
2673
2948
|
};
|
|
2674
2949
|
|
|
2675
|
-
// src/providers/detect.ts
|
|
2676
|
-
import { accessSync, constants } from "fs";
|
|
2677
|
-
import { join as join14, delimiter, isAbsolute as isAbsolute2 } from "path";
|
|
2678
|
-
import { homedir as homedir12 } from "os";
|
|
2679
|
-
function searchDirs() {
|
|
2680
|
-
const home = homedir12();
|
|
2681
|
-
const fromEnv = (process.env.PATH ?? "").split(delimiter).filter(Boolean);
|
|
2682
|
-
const extra = process.platform === "win32" ? [
|
|
2683
|
-
process.env.APPDATA && join14(process.env.APPDATA, "npm"),
|
|
2684
|
-
process.env.LOCALAPPDATA && join14(process.env.LOCALAPPDATA, "pnpm"),
|
|
2685
|
-
join14(home, "scoop", "shims")
|
|
2686
|
-
] : [
|
|
2687
|
-
"/opt/homebrew/bin",
|
|
2688
|
-
"/usr/local/bin",
|
|
2689
|
-
"/usr/bin",
|
|
2690
|
-
"/bin",
|
|
2691
|
-
"/opt/local/bin",
|
|
2692
|
-
join14(home, ".local", "bin"),
|
|
2693
|
-
join14(home, "bin"),
|
|
2694
|
-
join14(home, ".npm-global", "bin"),
|
|
2695
|
-
join14(home, ".bun", "bin"),
|
|
2696
|
-
join14(home, ".local", "share", "pnpm")
|
|
2697
|
-
];
|
|
2698
|
-
return [.../* @__PURE__ */ new Set([...fromEnv, ...extra.filter((d) => !!d)])];
|
|
2699
|
-
}
|
|
2700
|
-
function isExec(p) {
|
|
2701
|
-
try {
|
|
2702
|
-
accessSync(p, process.platform === "win32" ? constants.F_OK : constants.X_OK);
|
|
2703
|
-
return true;
|
|
2704
|
-
} catch {
|
|
2705
|
-
return false;
|
|
2706
|
-
}
|
|
2707
|
-
}
|
|
2708
|
-
function onPath(names) {
|
|
2709
|
-
const exts = process.platform === "win32" ? (process.env.PATHEXT ?? ".EXE;.CMD;.BAT;.COM").split(";").map((e) => e.toLowerCase()).concat("") : [""];
|
|
2710
|
-
for (const dir of searchDirs()) {
|
|
2711
|
-
for (const n of names) {
|
|
2712
|
-
for (const e of exts) {
|
|
2713
|
-
if (isExec(join14(dir, n + e))) return true;
|
|
2714
|
-
}
|
|
2715
|
-
}
|
|
2716
|
-
}
|
|
2717
|
-
return false;
|
|
2718
|
-
}
|
|
2719
|
-
function anyExists(paths) {
|
|
2720
|
-
return paths.some((p) => !!p && isExec(p));
|
|
2721
|
-
}
|
|
2722
|
-
function installSignals(id) {
|
|
2723
|
-
const home = homedir12();
|
|
2724
|
-
const pf = process.env.ProgramFiles;
|
|
2725
|
-
const pf86 = process.env["ProgramFiles(x86)"];
|
|
2726
|
-
const lad = process.env.LOCALAPPDATA;
|
|
2727
|
-
switch (id) {
|
|
2728
|
-
case "claude":
|
|
2729
|
-
return onPath(["claude"]) || anyExists([
|
|
2730
|
-
"/Applications/Claude.app",
|
|
2731
|
-
join14(home, "Applications", "Claude.app"),
|
|
2732
|
-
lad && join14(lad, "Programs", "claude", "Claude.exe")
|
|
2733
|
-
]);
|
|
2734
|
-
case "codex": {
|
|
2735
|
-
const bin = process.env.CODEX_BIN;
|
|
2736
|
-
if (bin && isAbsolute2(bin) && isExec(bin)) return true;
|
|
2737
|
-
return onPath(["codex"]);
|
|
2738
|
-
}
|
|
2739
|
-
case "cursor":
|
|
2740
|
-
return onPath(["cursor", "cursor-agent"]) || anyExists([
|
|
2741
|
-
"/Applications/Cursor.app",
|
|
2742
|
-
join14(home, "Applications", "Cursor.app"),
|
|
2743
|
-
lad && join14(lad, "Programs", "cursor", "Cursor.exe"),
|
|
2744
|
-
pf && join14(pf, "Cursor", "Cursor.exe"),
|
|
2745
|
-
pf86 && join14(pf86, "Cursor", "Cursor.exe"),
|
|
2746
|
-
"/opt/Cursor/cursor",
|
|
2747
|
-
"/usr/share/cursor/cursor",
|
|
2748
|
-
"/usr/bin/cursor"
|
|
2749
|
-
]);
|
|
2750
|
-
case "pi":
|
|
2751
|
-
return onPath(["pi"]);
|
|
2752
|
-
case "opencode":
|
|
2753
|
-
return onPath(["opencode"]);
|
|
2754
|
-
case "copilot":
|
|
2755
|
-
return onPath(["gh"]);
|
|
2756
|
-
case "antigravity":
|
|
2757
|
-
return onPath(["antigravity"]) || anyExists([
|
|
2758
|
-
"/Applications/Antigravity.app",
|
|
2759
|
-
join14(home, "Applications", "Antigravity.app"),
|
|
2760
|
-
lad && join14(lad, "Programs", "Antigravity", "Antigravity.exe")
|
|
2761
|
-
]);
|
|
2762
|
-
case "gemini":
|
|
2763
|
-
return onPath(["gemini"]);
|
|
2764
|
-
default:
|
|
2765
|
-
return false;
|
|
2766
|
-
}
|
|
2767
|
-
}
|
|
2768
|
-
|
|
2769
2950
|
// src/providers/index.ts
|
|
2770
2951
|
var PROVIDER_ORDER = [...PROVIDER_IDS];
|
|
2771
2952
|
var PROVIDERS = {
|
|
@@ -2793,11 +2974,11 @@ async function detectProviders() {
|
|
|
2793
2974
|
}
|
|
2794
2975
|
|
|
2795
2976
|
// src/accounts.ts
|
|
2796
|
-
import { existsSync, readdirSync, readFileSync, statSync } from "fs";
|
|
2797
|
-
import { homedir as
|
|
2798
|
-
import { basename, join as
|
|
2977
|
+
import { existsSync as existsSync2, readdirSync, readFileSync, statSync } from "fs";
|
|
2978
|
+
import { homedir as homedir14 } from "os";
|
|
2979
|
+
import { basename, join as join17, resolve } from "path";
|
|
2799
2980
|
function accountKey(providerId, homeDir) {
|
|
2800
|
-
return `${providerId}:${homeDir ? resolve(expandHome(homeDir)) :
|
|
2981
|
+
return `${providerId}:${homeDir ? resolve(expandHome(homeDir)) : homedir14()}`;
|
|
2801
2982
|
}
|
|
2802
2983
|
function uniqueId(base, used) {
|
|
2803
2984
|
let id = slugify(base) || "account";
|
|
@@ -2818,7 +2999,7 @@ function uniqueId(base, used) {
|
|
|
2818
2999
|
}
|
|
2819
3000
|
function readClaudeIdentity2(homeDir) {
|
|
2820
3001
|
try {
|
|
2821
|
-
const parsed = JSON.parse(readFileSync(
|
|
3002
|
+
const parsed = JSON.parse(readFileSync(join17(homeDir, ".claude.json"), "utf-8"));
|
|
2822
3003
|
const oauth = parsed?.oauthAccount;
|
|
2823
3004
|
return {
|
|
2824
3005
|
email: typeof oauth?.emailAddress === "string" && oauth.emailAddress.trim() ? oauth.emailAddress.trim() : void 0,
|
|
@@ -2829,10 +3010,10 @@ function readClaudeIdentity2(homeDir) {
|
|
|
2829
3010
|
}
|
|
2830
3011
|
}
|
|
2831
3012
|
function hasClaudeState(homeDir) {
|
|
2832
|
-
return
|
|
3013
|
+
return existsSync2(join17(homeDir, ".claude.json")) || existsSync2(join17(homeDir, ".claude", ".credentials.json")) || existsSync2(join17(homeDir, ".claude", "projects")) || existsSync2(join17(homeDir, ".config", "claude", ".credentials.json")) || existsSync2(join17(homeDir, ".config", "claude", "projects"));
|
|
2833
3014
|
}
|
|
2834
3015
|
function candidateAlternateHomes(prefix) {
|
|
2835
|
-
const home =
|
|
3016
|
+
const home = homedir14();
|
|
2836
3017
|
let entries;
|
|
2837
3018
|
try {
|
|
2838
3019
|
entries = readdirSync(home);
|
|
@@ -2843,7 +3024,7 @@ function candidateAlternateHomes(prefix) {
|
|
|
2843
3024
|
const pattern = new RegExp(`^\\.${prefix}[_-]`);
|
|
2844
3025
|
for (const name of entries) {
|
|
2845
3026
|
if (!pattern.test(name)) continue;
|
|
2846
|
-
const path =
|
|
3027
|
+
const path = join17(home, name);
|
|
2847
3028
|
try {
|
|
2848
3029
|
if (!statSync(path).isDirectory()) continue;
|
|
2849
3030
|
out.push(path);
|
|
@@ -2869,7 +3050,7 @@ function decodeBase64UrlJson3(segment) {
|
|
|
2869
3050
|
}
|
|
2870
3051
|
}
|
|
2871
3052
|
function codexAuthPaths(homeDir) {
|
|
2872
|
-
return [
|
|
3053
|
+
return [join17(homeDir, ".codex", "auth.json"), join17(homeDir, "auth.json")];
|
|
2873
3054
|
}
|
|
2874
3055
|
function readCodexIdentity(homeDir) {
|
|
2875
3056
|
for (const path of codexAuthPaths(homeDir)) {
|