codex-token-tracker 0.1.0 → 0.1.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/README.md +2 -0
- package/dist/cli.js +325 -134
- package/dist/main.js +5 -1
- package/dist/renderer/renderer.js +4 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -20,6 +20,8 @@ npm install -g codex-token-tracker
|
|
|
20
20
|
npx codex-token-tracker
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
+
> **npm 11+ / pnpm 10+ block Electron's install script by default.** That's fine: the first `codex-tracker` run downloads the Electron runtime itself (~100 MB, once). To do it during install instead: `npm install -g codex-token-tracker --allow-scripts=electron`.
|
|
24
|
+
|
|
23
25
|
Node.js 20+ is required. Electron is an *optional* dependency: if its binary cannot be downloaded (locked-down servers, WSL without a desktop), the package still installs and runs in agent mode.
|
|
24
26
|
|
|
25
27
|
## Quick start
|
package/dist/cli.js
CHANGED
|
@@ -1101,11 +1101,11 @@ var init_src = __esm({
|
|
|
1101
1101
|
|
|
1102
1102
|
// src/core/config.ts
|
|
1103
1103
|
function configDir() {
|
|
1104
|
-
return process.env.CODEX_TRACKER_HOME ||
|
|
1104
|
+
return process.env.CODEX_TRACKER_HOME || import_node_path2.default.join(import_node_os2.default.homedir(), ".codex-tracker");
|
|
1105
1105
|
}
|
|
1106
1106
|
function readJson(file, fallback) {
|
|
1107
1107
|
try {
|
|
1108
|
-
const raw =
|
|
1108
|
+
const raw = import_node_fs2.default.readFileSync(file, "utf8");
|
|
1109
1109
|
const parsed = JSON.parse(raw);
|
|
1110
1110
|
return parsed && typeof parsed === "object" ? parsed : fallback;
|
|
1111
1111
|
} catch {
|
|
@@ -1113,13 +1113,13 @@ function readJson(file, fallback) {
|
|
|
1113
1113
|
}
|
|
1114
1114
|
}
|
|
1115
1115
|
function writeJsonAtomic(file, value) {
|
|
1116
|
-
|
|
1116
|
+
import_node_fs2.default.mkdirSync(import_node_path2.default.dirname(file), { recursive: true });
|
|
1117
1117
|
const tmp = `${file}.${process.pid}.tmp`;
|
|
1118
|
-
|
|
1119
|
-
|
|
1118
|
+
import_node_fs2.default.writeFileSync(tmp, JSON.stringify(value, null, 2), { mode: 384 });
|
|
1119
|
+
import_node_fs2.default.renameSync(tmp, file);
|
|
1120
1120
|
}
|
|
1121
1121
|
function configPath() {
|
|
1122
|
-
return
|
|
1122
|
+
return import_node_path2.default.join(configDir(), "config.json");
|
|
1123
1123
|
}
|
|
1124
1124
|
function parseBool(raw) {
|
|
1125
1125
|
return ["1", "true", "yes", "on"].includes(raw.trim().toLowerCase());
|
|
@@ -1224,7 +1224,7 @@ function coerceConfigValue(key, raw) {
|
|
|
1224
1224
|
}
|
|
1225
1225
|
}
|
|
1226
1226
|
function statePath() {
|
|
1227
|
-
return
|
|
1227
|
+
return import_node_path2.default.join(configDir(), "state.json");
|
|
1228
1228
|
}
|
|
1229
1229
|
function loadState() {
|
|
1230
1230
|
const s = readJson(statePath(), {});
|
|
@@ -1241,7 +1241,7 @@ function clearState() {
|
|
|
1241
1241
|
saveState({ pushedBuckets: {}, pushedSessions: {}, lastUploadAt: null });
|
|
1242
1242
|
}
|
|
1243
1243
|
function pricingPath() {
|
|
1244
|
-
return
|
|
1244
|
+
return import_node_path2.default.join(configDir(), "pricing.json");
|
|
1245
1245
|
}
|
|
1246
1246
|
function loadPricingOverrides() {
|
|
1247
1247
|
const raw = readJson(pricingPath(), {});
|
|
@@ -1259,13 +1259,13 @@ function loadPricingOverrides() {
|
|
|
1259
1259
|
}
|
|
1260
1260
|
return Object.keys(out).length ? out : void 0;
|
|
1261
1261
|
}
|
|
1262
|
-
var
|
|
1262
|
+
var import_node_fs2, import_node_os2, import_node_path2, DEFAULT_DASHBOARD_URL, SOURCE_FORMATS, DEFAULT_SOURCES, SOURCE_IDS, DEFAULT_CONFIG, EDITABLE_KEYS, AGENT_NAME_RE;
|
|
1263
1263
|
var init_config = __esm({
|
|
1264
1264
|
"src/core/config.ts"() {
|
|
1265
1265
|
"use strict";
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1266
|
+
import_node_fs2 = __toESM(require("node:fs"));
|
|
1267
|
+
import_node_os2 = __toESM(require("node:os"));
|
|
1268
|
+
import_node_path2 = __toESM(require("node:path"));
|
|
1269
1269
|
DEFAULT_DASHBOARD_URL = "https://codex.chenli.dev";
|
|
1270
1270
|
SOURCE_FORMATS = ["codex", "pi", "generic", "opencode", "cline"];
|
|
1271
1271
|
DEFAULT_SOURCES = { codex: true, pi: true, hermes: true, opencode: true, cline: true, roo: true, kilo: true };
|
|
@@ -1404,6 +1404,8 @@ Options:
|
|
|
1404
1404
|
cliUnknownCommand: "Unknown command: {command}",
|
|
1405
1405
|
cliNoDisplay: "No display detected \u2014 starting agent mode (run `codex-tracker menubar` on a desktop).",
|
|
1406
1406
|
cliNoElectron: "Electron is not installed (optional dependency) \u2014 starting agent mode.",
|
|
1407
|
+
cliDownloadingElectron: "Electron runtime not found \u2014 downloading it now (about 100 MB, one time)\u2026",
|
|
1408
|
+
cliElectronDownloadFailed: "Electron download failed. Retry with `npm install -g codex-token-tracker --allow-scripts=electron` or `npm rebuild -g electron`; the headless `codex-tracker agent` works without it.",
|
|
1407
1409
|
cliStartingMenubar: "Starting menu bar app\u2026",
|
|
1408
1410
|
cliLoginStart: "Connecting this device to {dashboard}",
|
|
1409
1411
|
cliLoginCode: "Your code: {code}",
|
|
@@ -1538,6 +1540,8 @@ var init_zh = __esm({
|
|
|
1538
1540
|
cliUnknownCommand: "\u672A\u77E5\u547D\u4EE4\uFF1A{command}",
|
|
1539
1541
|
cliNoDisplay: "\u672A\u68C0\u6D4B\u5230\u663E\u793A\u73AF\u5883 \u2014 \u4EE5 agent \u6A21\u5F0F\u542F\u52A8\uFF08\u684C\u9762\u73AF\u5883\u8BF7\u8FD0\u884C `codex-tracker menubar`\uFF09\u3002",
|
|
1540
1542
|
cliNoElectron: "\u672A\u5B89\u88C5 Electron\uFF08\u53EF\u9009\u4F9D\u8D56\uFF09\u2014 \u4EE5 agent \u6A21\u5F0F\u542F\u52A8\u3002",
|
|
1543
|
+
cliDownloadingElectron: "\u672A\u627E\u5230 Electron \u8FD0\u884C\u65F6\uFF0C\u6B63\u5728\u4E0B\u8F7D\uFF08\u7EA6 100 MB\uFF0C\u4EC5\u9700\u4E00\u6B21\uFF09\u2026",
|
|
1544
|
+
cliElectronDownloadFailed: "Electron \u4E0B\u8F7D\u5931\u8D25\u3002\u53EF\u91CD\u8BD5 `npm install -g codex-token-tracker --allow-scripts=electron` \u6216 `npm rebuild -g electron`\uFF1B\u65E0\u754C\u9762\u7684 `codex-tracker agent` \u65E0\u9700 Electron\u3002",
|
|
1541
1545
|
cliStartingMenubar: "\u6B63\u5728\u542F\u52A8\u83DC\u5355\u680F\u5E94\u7528\u2026",
|
|
1542
1546
|
cliLoginStart: "\u6B63\u5728\u5C06\u672C\u8BBE\u5907\u8FDE\u63A5\u5230 {dashboard}",
|
|
1543
1547
|
cliLoginCode: "\u4F60\u7684\u4EE3\u7801\uFF1A{code}",
|
|
@@ -1646,7 +1650,7 @@ function isWSL() {
|
|
|
1646
1650
|
if (process.platform !== "linux") return wslCache = false;
|
|
1647
1651
|
if (process.env.WSL_DISTRO_NAME || process.env.WSL_INTEROP) return wslCache = true;
|
|
1648
1652
|
try {
|
|
1649
|
-
const v2 =
|
|
1653
|
+
const v2 = import_node_fs3.default.readFileSync("/proc/version", "utf8").toLowerCase();
|
|
1650
1654
|
return wslCache = v2.includes("microsoft") || v2.includes("wsl");
|
|
1651
1655
|
} catch {
|
|
1652
1656
|
return wslCache = false;
|
|
@@ -1662,7 +1666,7 @@ function platformLabel(kind = platformKind()) {
|
|
|
1662
1666
|
}
|
|
1663
1667
|
function hostname() {
|
|
1664
1668
|
try {
|
|
1665
|
-
return
|
|
1669
|
+
return import_node_os3.default.hostname().replace(/\.local$/, "");
|
|
1666
1670
|
} catch {
|
|
1667
1671
|
return "unknown-host";
|
|
1668
1672
|
}
|
|
@@ -1680,7 +1684,7 @@ function hasDisplay() {
|
|
|
1680
1684
|
function run(cmd, args) {
|
|
1681
1685
|
return new Promise((resolve) => {
|
|
1682
1686
|
try {
|
|
1683
|
-
const child = (0,
|
|
1687
|
+
const child = (0, import_node_child_process2.spawn)(cmd, args, { stdio: "ignore", detached: true, windowsHide: true });
|
|
1684
1688
|
child.on("error", () => resolve(false));
|
|
1685
1689
|
child.on("spawn", () => {
|
|
1686
1690
|
child.unref();
|
|
@@ -1713,13 +1717,13 @@ function systemLocale() {
|
|
|
1713
1717
|
return "en";
|
|
1714
1718
|
}
|
|
1715
1719
|
}
|
|
1716
|
-
var
|
|
1720
|
+
var import_node_fs3, import_node_os3, import_node_child_process2, wslCache;
|
|
1717
1721
|
var init_platform = __esm({
|
|
1718
1722
|
"src/core/platform.ts"() {
|
|
1719
1723
|
"use strict";
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1724
|
+
import_node_fs3 = __toESM(require("node:fs"));
|
|
1725
|
+
import_node_os3 = __toESM(require("node:os"));
|
|
1726
|
+
import_node_child_process2 = require("node:child_process");
|
|
1723
1727
|
init_i18n();
|
|
1724
1728
|
wslCache = null;
|
|
1725
1729
|
}
|
|
@@ -3190,12 +3194,12 @@ function createApi(pathParts = []) {
|
|
|
3190
3194
|
`API path is expected to be of the form \`api.moduleName.functionName\`. Found: \`${found}\``
|
|
3191
3195
|
);
|
|
3192
3196
|
}
|
|
3193
|
-
const
|
|
3197
|
+
const path12 = pathParts.slice(0, -1).join("/");
|
|
3194
3198
|
const exportName = pathParts[pathParts.length - 1];
|
|
3195
3199
|
if (exportName === "default") {
|
|
3196
|
-
return
|
|
3200
|
+
return path12;
|
|
3197
3201
|
} else {
|
|
3198
|
-
return
|
|
3202
|
+
return path12 + ":" + exportName;
|
|
3199
3203
|
}
|
|
3200
3204
|
} else if (prop === Symbol.toStringTag) {
|
|
3201
3205
|
return "FunctionReference";
|
|
@@ -3490,16 +3494,16 @@ var init_simple_client_node = __esm({
|
|
|
3490
3494
|
});
|
|
3491
3495
|
require_node_gyp_build = __commonJS({
|
|
3492
3496
|
"../node_modules/.pnpm/node-gyp-build@4.8.4/node_modules/node-gyp-build/node-gyp-build.js"(exports2, module2) {
|
|
3493
|
-
var
|
|
3494
|
-
var
|
|
3495
|
-
var
|
|
3497
|
+
var fs10 = __require("fs");
|
|
3498
|
+
var path12 = __require("path");
|
|
3499
|
+
var os8 = __require("os");
|
|
3496
3500
|
var runtimeRequire = typeof __webpack_require__ === "function" ? __non_webpack_require__ : __require;
|
|
3497
3501
|
var vars2 = process.config && process.config.variables || {};
|
|
3498
3502
|
var prebuildsOnly = !!process.env.PREBUILDS_ONLY;
|
|
3499
3503
|
var abi = process.versions.modules;
|
|
3500
3504
|
var runtime = isElectron() ? "electron" : isNwjs() ? "node-webkit" : "node";
|
|
3501
|
-
var arch = process.env.npm_config_arch ||
|
|
3502
|
-
var platform = process.env.npm_config_platform ||
|
|
3505
|
+
var arch = process.env.npm_config_arch || os8.arch();
|
|
3506
|
+
var platform = process.env.npm_config_platform || os8.platform();
|
|
3503
3507
|
var libc = process.env.LIBC || (isAlpine(platform) ? "musl" : "glibc");
|
|
3504
3508
|
var armv = process.env.ARM_VERSION || (arch === "arm64" ? "8" : vars2.arm_version) || "";
|
|
3505
3509
|
var uv = (process.versions.uv || "").split(".")[0];
|
|
@@ -3508,21 +3512,21 @@ var init_simple_client_node = __esm({
|
|
|
3508
3512
|
return runtimeRequire(load.resolve(dir));
|
|
3509
3513
|
}
|
|
3510
3514
|
load.resolve = load.path = function(dir) {
|
|
3511
|
-
dir =
|
|
3515
|
+
dir = path12.resolve(dir || ".");
|
|
3512
3516
|
try {
|
|
3513
|
-
var name = runtimeRequire(
|
|
3517
|
+
var name = runtimeRequire(path12.join(dir, "package.json")).name.toUpperCase().replace(/-/g, "_");
|
|
3514
3518
|
if (process.env[name + "_PREBUILD"]) dir = process.env[name + "_PREBUILD"];
|
|
3515
3519
|
} catch (err) {
|
|
3516
3520
|
}
|
|
3517
3521
|
if (!prebuildsOnly) {
|
|
3518
|
-
var release = getFirst(
|
|
3522
|
+
var release = getFirst(path12.join(dir, "build/Release"), matchBuild);
|
|
3519
3523
|
if (release) return release;
|
|
3520
|
-
var debug = getFirst(
|
|
3524
|
+
var debug = getFirst(path12.join(dir, "build/Debug"), matchBuild);
|
|
3521
3525
|
if (debug) return debug;
|
|
3522
3526
|
}
|
|
3523
3527
|
var prebuild = resolve(dir);
|
|
3524
3528
|
if (prebuild) return prebuild;
|
|
3525
|
-
var nearby = resolve(
|
|
3529
|
+
var nearby = resolve(path12.dirname(process.execPath));
|
|
3526
3530
|
if (nearby) return nearby;
|
|
3527
3531
|
var target = [
|
|
3528
3532
|
"platform=" + platform,
|
|
@@ -3539,26 +3543,26 @@ var init_simple_client_node = __esm({
|
|
|
3539
3543
|
].filter(Boolean).join(" ");
|
|
3540
3544
|
throw new Error("No native build was found for " + target + "\n loaded from: " + dir + "\n");
|
|
3541
3545
|
function resolve(dir2) {
|
|
3542
|
-
var tuples = readdirSync(
|
|
3546
|
+
var tuples = readdirSync(path12.join(dir2, "prebuilds")).map(parseTuple);
|
|
3543
3547
|
var tuple = tuples.filter(matchTuple(platform, arch)).sort(compareTuples)[0];
|
|
3544
3548
|
if (!tuple) return;
|
|
3545
|
-
var prebuilds =
|
|
3549
|
+
var prebuilds = path12.join(dir2, "prebuilds", tuple.name);
|
|
3546
3550
|
var parsed = readdirSync(prebuilds).map(parseTags);
|
|
3547
3551
|
var candidates = parsed.filter(matchTags(runtime, abi));
|
|
3548
3552
|
var winner = candidates.sort(compareTags(runtime))[0];
|
|
3549
|
-
if (winner) return
|
|
3553
|
+
if (winner) return path12.join(prebuilds, winner.file);
|
|
3550
3554
|
}
|
|
3551
3555
|
};
|
|
3552
3556
|
function readdirSync(dir) {
|
|
3553
3557
|
try {
|
|
3554
|
-
return
|
|
3558
|
+
return fs10.readdirSync(dir);
|
|
3555
3559
|
} catch (err) {
|
|
3556
3560
|
return [];
|
|
3557
3561
|
}
|
|
3558
3562
|
}
|
|
3559
3563
|
function getFirst(dir, filter) {
|
|
3560
3564
|
var files = readdirSync(dir).filter(filter);
|
|
3561
|
-
return files[0] &&
|
|
3565
|
+
return files[0] && path12.join(dir, files[0]);
|
|
3562
3566
|
}
|
|
3563
3567
|
function matchBuild(name) {
|
|
3564
3568
|
return /\.node$/.test(name);
|
|
@@ -3645,7 +3649,7 @@ var init_simple_client_node = __esm({
|
|
|
3645
3649
|
return typeof window !== "undefined" && window.process && window.process.type === "renderer";
|
|
3646
3650
|
}
|
|
3647
3651
|
function isAlpine(platform2) {
|
|
3648
|
-
return platform2 === "linux" &&
|
|
3652
|
+
return platform2 === "linux" && fs10.existsSync("/etc/alpine-release");
|
|
3649
3653
|
}
|
|
3650
3654
|
load.parseTags = parseTags;
|
|
3651
3655
|
load.matchTags = matchTags;
|
|
@@ -8719,8 +8723,158 @@ var init_auth = __esm({
|
|
|
8719
8723
|
});
|
|
8720
8724
|
|
|
8721
8725
|
// src/cli.ts
|
|
8722
|
-
var
|
|
8723
|
-
var
|
|
8726
|
+
var import_node_path11 = __toESM(require("node:path"));
|
|
8727
|
+
var import_node_fs9 = __toESM(require("node:fs"));
|
|
8728
|
+
var import_node_child_process4 = require("node:child_process");
|
|
8729
|
+
|
|
8730
|
+
// src/core/electron-install.ts
|
|
8731
|
+
var import_node_fs = __toESM(require("node:fs"));
|
|
8732
|
+
var import_node_os = __toESM(require("node:os"));
|
|
8733
|
+
var import_node_path = __toESM(require("node:path"));
|
|
8734
|
+
var import_node_child_process = require("node:child_process");
|
|
8735
|
+
function archName() {
|
|
8736
|
+
switch (process.arch) {
|
|
8737
|
+
case "x64":
|
|
8738
|
+
return "x64";
|
|
8739
|
+
case "arm64":
|
|
8740
|
+
return "arm64";
|
|
8741
|
+
case "ia32":
|
|
8742
|
+
return "ia32";
|
|
8743
|
+
case "arm":
|
|
8744
|
+
return "armv7l";
|
|
8745
|
+
default:
|
|
8746
|
+
return process.arch;
|
|
8747
|
+
}
|
|
8748
|
+
}
|
|
8749
|
+
function platformExecutablePath() {
|
|
8750
|
+
switch (process.platform) {
|
|
8751
|
+
case "darwin":
|
|
8752
|
+
return "Electron.app/Contents/MacOS/Electron";
|
|
8753
|
+
case "win32":
|
|
8754
|
+
return "electron.exe";
|
|
8755
|
+
default:
|
|
8756
|
+
return "electron";
|
|
8757
|
+
}
|
|
8758
|
+
}
|
|
8759
|
+
function electronCacheRoots() {
|
|
8760
|
+
const roots = [];
|
|
8761
|
+
if (process.env.electron_config_cache) roots.push(process.env.electron_config_cache);
|
|
8762
|
+
const home = import_node_os.default.homedir();
|
|
8763
|
+
if (process.platform === "darwin") roots.push(import_node_path.default.join(home, "Library", "Caches", "electron"));
|
|
8764
|
+
else if (process.platform === "win32") {
|
|
8765
|
+
if (process.env.LOCALAPPDATA) roots.push(import_node_path.default.join(process.env.LOCALAPPDATA, "electron", "Cache"));
|
|
8766
|
+
} else roots.push(import_node_path.default.join(process.env.XDG_CACHE_HOME ?? import_node_path.default.join(home, ".cache"), "electron"));
|
|
8767
|
+
return roots.filter((r) => import_node_fs.default.existsSync(r));
|
|
8768
|
+
}
|
|
8769
|
+
function findInDirs(dirs, filename, depth = 3) {
|
|
8770
|
+
for (const dir of dirs) {
|
|
8771
|
+
const found = walk(dir, filename, depth);
|
|
8772
|
+
if (found) return found;
|
|
8773
|
+
}
|
|
8774
|
+
return null;
|
|
8775
|
+
}
|
|
8776
|
+
function walk(dir, filename, depth) {
|
|
8777
|
+
let entries;
|
|
8778
|
+
try {
|
|
8779
|
+
entries = import_node_fs.default.readdirSync(dir, { withFileTypes: true });
|
|
8780
|
+
} catch {
|
|
8781
|
+
return null;
|
|
8782
|
+
}
|
|
8783
|
+
for (const e of entries) {
|
|
8784
|
+
const p = import_node_path.default.join(dir, e.name);
|
|
8785
|
+
if (e.isFile() && e.name === filename && import_node_fs.default.statSync(p).size > 1e6) return p;
|
|
8786
|
+
}
|
|
8787
|
+
if (depth <= 0) return null;
|
|
8788
|
+
for (const e of entries) {
|
|
8789
|
+
if (e.isDirectory()) {
|
|
8790
|
+
const r = walk(import_node_path.default.join(dir, e.name), filename, depth - 1);
|
|
8791
|
+
if (r) return r;
|
|
8792
|
+
}
|
|
8793
|
+
}
|
|
8794
|
+
return null;
|
|
8795
|
+
}
|
|
8796
|
+
function downloadUrl(version2, filename) {
|
|
8797
|
+
const mirror = process.env.ELECTRON_MIRROR || "https://github.com/electron/electron/releases/download/v";
|
|
8798
|
+
const dir = process.env.ELECTRON_CUSTOM_DIR ? process.env.ELECTRON_CUSTOM_DIR.replace("{{ version }}", version2) : version2;
|
|
8799
|
+
const base = mirror.endsWith("/") || mirror.endsWith("v") ? mirror : mirror + "/";
|
|
8800
|
+
return `${base}${dir}/${filename}`;
|
|
8801
|
+
}
|
|
8802
|
+
async function download(url, dest, log2) {
|
|
8803
|
+
const res = await fetch(url, { redirect: "follow" });
|
|
8804
|
+
if (!res.ok || !res.body) throw new Error(`HTTP ${res.status} for ${url}`);
|
|
8805
|
+
const total = Number(res.headers.get("content-length") || 0);
|
|
8806
|
+
import_node_fs.default.mkdirSync(import_node_path.default.dirname(dest), { recursive: true });
|
|
8807
|
+
const tmp = dest + ".part";
|
|
8808
|
+
const out = import_node_fs.default.createWriteStream(tmp);
|
|
8809
|
+
let received = 0;
|
|
8810
|
+
let lastPct = -10;
|
|
8811
|
+
const reader = res.body.getReader();
|
|
8812
|
+
try {
|
|
8813
|
+
for (; ; ) {
|
|
8814
|
+
const { done, value } = await reader.read();
|
|
8815
|
+
if (done) break;
|
|
8816
|
+
received += value.byteLength;
|
|
8817
|
+
if (!out.write(value)) await new Promise((r) => out.once("drain", () => r()));
|
|
8818
|
+
if (total) {
|
|
8819
|
+
const pct = Math.floor(received / total * 100);
|
|
8820
|
+
if (pct >= lastPct + 10) {
|
|
8821
|
+
lastPct = pct;
|
|
8822
|
+
log2.info(` ${pct}% (${(received / 1048576).toFixed(0)} / ${(total / 1048576).toFixed(0)} MB)`);
|
|
8823
|
+
}
|
|
8824
|
+
}
|
|
8825
|
+
}
|
|
8826
|
+
} finally {
|
|
8827
|
+
await new Promise((resolve) => out.end(() => resolve()));
|
|
8828
|
+
}
|
|
8829
|
+
import_node_fs.default.renameSync(tmp, dest);
|
|
8830
|
+
}
|
|
8831
|
+
function extractZip(zip, dest) {
|
|
8832
|
+
import_node_fs.default.rmSync(dest, { recursive: true, force: true });
|
|
8833
|
+
import_node_fs.default.mkdirSync(dest, { recursive: true });
|
|
8834
|
+
const attempts = process.platform === "darwin" ? [["ditto", ["-x", "-k", zip, dest]], ["unzip", ["-q", "-o", zip, "-d", dest]]] : process.platform === "win32" ? [
|
|
8835
|
+
["tar", ["-xf", zip, "-C", dest]],
|
|
8836
|
+
["powershell", ["-NoProfile", "-Command", `Expand-Archive -LiteralPath '${zip}' -DestinationPath '${dest}' -Force`]]
|
|
8837
|
+
] : [["unzip", ["-q", "-o", zip, "-d", dest]], ["bsdtar", ["-xf", zip, "-C", dest]], ["tar", ["-xf", zip, "-C", dest]]];
|
|
8838
|
+
for (const [cmd, args] of attempts) {
|
|
8839
|
+
const r = (0, import_node_child_process.spawnSync)(cmd, args, { stdio: "ignore", windowsHide: true });
|
|
8840
|
+
if (r.status === 0 && import_node_fs.default.existsSync(import_node_path.default.join(dest, platformExecutablePath()))) return true;
|
|
8841
|
+
}
|
|
8842
|
+
return false;
|
|
8843
|
+
}
|
|
8844
|
+
async function installElectronBinary(pkgDir, log2) {
|
|
8845
|
+
let version2;
|
|
8846
|
+
try {
|
|
8847
|
+
version2 = JSON.parse(import_node_fs.default.readFileSync(import_node_path.default.join(pkgDir, "package.json"), "utf8")).version;
|
|
8848
|
+
} catch {
|
|
8849
|
+
return null;
|
|
8850
|
+
}
|
|
8851
|
+
const platform = process.platform === "darwin" && process.env.npm_config_platform === "mas" ? "mas" : process.platform;
|
|
8852
|
+
const filename = `electron-v${version2}-${platform}-${archName()}.zip`;
|
|
8853
|
+
const dist = import_node_path.default.join(pkgDir, "dist");
|
|
8854
|
+
const exe = import_node_path.default.join(dist, platformExecutablePath());
|
|
8855
|
+
let zip = findInDirs(electronCacheRoots(), filename);
|
|
8856
|
+
if (zip) log2.info(` using cached ${import_node_path.default.basename(zip)}`);
|
|
8857
|
+
else {
|
|
8858
|
+
const cacheRoot = electronCacheRoots()[0] ?? import_node_path.default.join(import_node_os.default.tmpdir(), "codex-tracker-electron");
|
|
8859
|
+
zip = import_node_path.default.join(cacheRoot, "codex-token-tracker", filename);
|
|
8860
|
+
const url = downloadUrl(version2, filename);
|
|
8861
|
+
log2.info(` ${url}`);
|
|
8862
|
+
try {
|
|
8863
|
+
await download(url, zip, log2);
|
|
8864
|
+
} catch (err) {
|
|
8865
|
+
log2.error(` download failed: ${err.message}`);
|
|
8866
|
+
return null;
|
|
8867
|
+
}
|
|
8868
|
+
}
|
|
8869
|
+
if (!extractZip(zip, dist)) {
|
|
8870
|
+
log2.error(" extraction failed (no ditto/unzip/tar available?)");
|
|
8871
|
+
return null;
|
|
8872
|
+
}
|
|
8873
|
+
import_node_fs.default.writeFileSync(import_node_path.default.join(pkgDir, "path.txt"), platformExecutablePath());
|
|
8874
|
+
return import_node_fs.default.existsSync(exe) ? exe : null;
|
|
8875
|
+
}
|
|
8876
|
+
|
|
8877
|
+
// src/cli.ts
|
|
8724
8878
|
init_src();
|
|
8725
8879
|
init_config();
|
|
8726
8880
|
|
|
@@ -8730,42 +8884,42 @@ init_src();
|
|
|
8730
8884
|
init_config();
|
|
8731
8885
|
|
|
8732
8886
|
// src/core/store.ts
|
|
8733
|
-
var
|
|
8887
|
+
var import_node_fs7 = __toESM(require("node:fs"));
|
|
8734
8888
|
|
|
8735
8889
|
// src/core/sources/index.ts
|
|
8736
|
-
var
|
|
8737
|
-
var
|
|
8738
|
-
var
|
|
8739
|
-
var
|
|
8890
|
+
var import_node_fs6 = __toESM(require("node:fs"));
|
|
8891
|
+
var import_node_os7 = __toESM(require("node:os"));
|
|
8892
|
+
var import_node_path9 = __toESM(require("node:path"));
|
|
8893
|
+
var import_node_child_process3 = require("node:child_process");
|
|
8740
8894
|
init_platform();
|
|
8741
8895
|
init_config();
|
|
8742
8896
|
|
|
8743
8897
|
// src/core/sources/codex.ts
|
|
8744
|
-
var
|
|
8745
|
-
var
|
|
8898
|
+
var import_node_os4 = __toESM(require("node:os"));
|
|
8899
|
+
var import_node_path4 = __toESM(require("node:path"));
|
|
8746
8900
|
init_src();
|
|
8747
8901
|
|
|
8748
8902
|
// src/core/sources/util.ts
|
|
8749
|
-
var
|
|
8750
|
-
var
|
|
8903
|
+
var import_node_fs4 = __toESM(require("node:fs"));
|
|
8904
|
+
var import_node_path3 = __toESM(require("node:path"));
|
|
8751
8905
|
var TWO_DAYS = 2 * 864e5;
|
|
8752
8906
|
function isDir(p) {
|
|
8753
8907
|
try {
|
|
8754
|
-
return
|
|
8908
|
+
return import_node_fs4.default.statSync(p).isDirectory();
|
|
8755
8909
|
} catch {
|
|
8756
8910
|
return false;
|
|
8757
8911
|
}
|
|
8758
8912
|
}
|
|
8759
8913
|
function isFile(p) {
|
|
8760
8914
|
try {
|
|
8761
|
-
return
|
|
8915
|
+
return import_node_fs4.default.statSync(p).isFile();
|
|
8762
8916
|
} catch {
|
|
8763
8917
|
return false;
|
|
8764
8918
|
}
|
|
8765
8919
|
}
|
|
8766
8920
|
function listDirs(p) {
|
|
8767
8921
|
try {
|
|
8768
|
-
return
|
|
8922
|
+
return import_node_fs4.default.readdirSync(p, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
|
|
8769
8923
|
} catch {
|
|
8770
8924
|
return [];
|
|
8771
8925
|
}
|
|
@@ -8775,8 +8929,8 @@ function recentSubdirs(root, maxAgeMs = TWO_DAYS) {
|
|
|
8775
8929
|
const now = Date.now();
|
|
8776
8930
|
for (const name of listDirs(root)) {
|
|
8777
8931
|
try {
|
|
8778
|
-
const st =
|
|
8779
|
-
if (now - st.mtimeMs < maxAgeMs) out.push(
|
|
8932
|
+
const st = import_node_fs4.default.statSync(import_node_path3.default.join(root, name));
|
|
8933
|
+
if (now - st.mtimeMs < maxAgeMs) out.push(import_node_path3.default.join(root, name));
|
|
8780
8934
|
} catch {
|
|
8781
8935
|
}
|
|
8782
8936
|
}
|
|
@@ -8784,7 +8938,7 @@ function recentSubdirs(root, maxAgeMs = TWO_DAYS) {
|
|
|
8784
8938
|
}
|
|
8785
8939
|
function readJsonFile(p) {
|
|
8786
8940
|
try {
|
|
8787
|
-
return JSON.parse(
|
|
8941
|
+
return JSON.parse(import_node_fs4.default.readFileSync(p, "utf8"));
|
|
8788
8942
|
} catch {
|
|
8789
8943
|
return null;
|
|
8790
8944
|
}
|
|
@@ -8793,7 +8947,7 @@ function makeRoot(dir, source, agent, format, kind, origin, exts, maxDepth = 6,
|
|
|
8793
8947
|
return { dir, source, agent, format, kind, origin, exts, maxDepth, text };
|
|
8794
8948
|
}
|
|
8795
8949
|
function basenameNoExt(p) {
|
|
8796
|
-
return
|
|
8950
|
+
return import_node_path3.default.basename(p).replace(/\.[^.]+$/, "");
|
|
8797
8951
|
}
|
|
8798
8952
|
function projectNameOf(cwd) {
|
|
8799
8953
|
if (!cwd) return null;
|
|
@@ -8830,11 +8984,11 @@ function mergeSessions(parts) {
|
|
|
8830
8984
|
|
|
8831
8985
|
// src/core/sources/codex.ts
|
|
8832
8986
|
function codexHome() {
|
|
8833
|
-
return process.env.CODEX_HOME ||
|
|
8987
|
+
return process.env.CODEX_HOME || import_node_path4.default.join(import_node_os4.default.homedir(), ".codex");
|
|
8834
8988
|
}
|
|
8835
8989
|
function underHome(h, envVar, ...rel) {
|
|
8836
|
-
if (envVar && h.home ===
|
|
8837
|
-
return
|
|
8990
|
+
if (envVar && h.home === import_node_os4.default.homedir()) return envVar;
|
|
8991
|
+
return import_node_path4.default.join(h.home, ...rel);
|
|
8838
8992
|
}
|
|
8839
8993
|
function dateDirs(root) {
|
|
8840
8994
|
const dirs = [];
|
|
@@ -8842,10 +8996,10 @@ function dateDirs(root) {
|
|
|
8842
8996
|
for (const offset of [0, -1]) {
|
|
8843
8997
|
const d = /* @__PURE__ */ new Date();
|
|
8844
8998
|
d.setDate(d.getDate() + offset);
|
|
8845
|
-
dirs.push(
|
|
8999
|
+
dirs.push(import_node_path4.default.join(root, String(d.getFullYear()), pad(d.getMonth() + 1), pad(d.getDate())));
|
|
8846
9000
|
}
|
|
8847
9001
|
const u = /* @__PURE__ */ new Date();
|
|
8848
|
-
dirs.push(
|
|
9002
|
+
dirs.push(import_node_path4.default.join(root, String(u.getUTCFullYear()), pad(u.getUTCMonth() + 1), pad(u.getUTCDate())));
|
|
8849
9003
|
return [...new Set(dirs)];
|
|
8850
9004
|
}
|
|
8851
9005
|
var codexSource = {
|
|
@@ -8856,8 +9010,8 @@ var codexSource = {
|
|
|
8856
9010
|
const roots = [];
|
|
8857
9011
|
for (const h of ctx.homes) {
|
|
8858
9012
|
const home = underHome(h, process.env.CODEX_HOME, ".codex");
|
|
8859
|
-
const sessions =
|
|
8860
|
-
const archived =
|
|
9013
|
+
const sessions = import_node_path4.default.join(home, "sessions");
|
|
9014
|
+
const archived = import_node_path4.default.join(home, "archived_sessions");
|
|
8861
9015
|
if (isDir(sessions)) roots.push(makeRoot(sessions, "codex", "codex", "codex", "sessions", h.origin, [".jsonl"]));
|
|
8862
9016
|
if (isDir(archived)) roots.push(makeRoot(archived, "codex", "codex", "codex", "archived", h.origin, [".jsonl"], 1));
|
|
8863
9017
|
}
|
|
@@ -8878,12 +9032,12 @@ var codexSource = {
|
|
|
8878
9032
|
};
|
|
8879
9033
|
|
|
8880
9034
|
// src/core/sources/pi.ts
|
|
8881
|
-
var
|
|
8882
|
-
var
|
|
9035
|
+
var import_node_os5 = __toESM(require("node:os"));
|
|
9036
|
+
var import_node_path5 = __toESM(require("node:path"));
|
|
8883
9037
|
init_src();
|
|
8884
9038
|
function underHome2(h, envVar, ...rel) {
|
|
8885
|
-
if (envVar && h.home ===
|
|
8886
|
-
return
|
|
9039
|
+
if (envVar && h.home === import_node_os5.default.homedir()) return envVar;
|
|
9040
|
+
return import_node_path5.default.join(h.home, ...rel);
|
|
8887
9041
|
}
|
|
8888
9042
|
var piSource = {
|
|
8889
9043
|
id: "pi",
|
|
@@ -8892,7 +9046,7 @@ var piSource = {
|
|
|
8892
9046
|
discover(ctx) {
|
|
8893
9047
|
const roots = [];
|
|
8894
9048
|
for (const h of ctx.homes) {
|
|
8895
|
-
const dir =
|
|
9049
|
+
const dir = import_node_path5.default.join(underHome2(h, process.env.PI_CODING_AGENT_DIR, ".pi", "agent"), "sessions");
|
|
8896
9050
|
if (isDir(dir)) roots.push(makeRoot(dir, "pi", "pi", "pi", "flat", h.origin, [".jsonl"], 3));
|
|
8897
9051
|
}
|
|
8898
9052
|
return roots;
|
|
@@ -8925,12 +9079,12 @@ var genericSource = {
|
|
|
8925
9079
|
};
|
|
8926
9080
|
|
|
8927
9081
|
// src/core/sources/hermes.ts
|
|
8928
|
-
var
|
|
8929
|
-
var
|
|
9082
|
+
var import_node_os6 = __toESM(require("node:os"));
|
|
9083
|
+
var import_node_path6 = __toESM(require("node:path"));
|
|
8930
9084
|
init_src();
|
|
8931
9085
|
function underHome3(h, envVar, ...rel) {
|
|
8932
|
-
if (envVar && h.home ===
|
|
8933
|
-
return
|
|
9086
|
+
if (envVar && h.home === import_node_os6.default.homedir()) return envVar;
|
|
9087
|
+
return import_node_path6.default.join(h.home, ...rel);
|
|
8934
9088
|
}
|
|
8935
9089
|
var INPUT_COLS = ["input_tokens", "prompt_tokens", "tokens_in", "input"];
|
|
8936
9090
|
var OUTPUT_COLS = ["output_tokens", "completion_tokens", "tokens_out", "output"];
|
|
@@ -9056,9 +9210,9 @@ var hermesSource = {
|
|
|
9056
9210
|
const roots = [];
|
|
9057
9211
|
for (const h of ctx.homes) {
|
|
9058
9212
|
const home = underHome3(h, process.env.HERMES_HOME, ".hermes");
|
|
9059
|
-
const sessions =
|
|
9213
|
+
const sessions = import_node_path6.default.join(home, "sessions");
|
|
9060
9214
|
if (isDir(sessions)) roots.push(makeRoot(sessions, "hermes", "hermes", "generic", "flat", h.origin, [".jsonl", ".json"], 4));
|
|
9061
|
-
if (isFile(
|
|
9215
|
+
if (isFile(import_node_path6.default.join(home, "state.db"))) roots.push(makeRoot(home, "hermes", "hermes", "generic", "flat", h.origin, ["state.db"], 0, false));
|
|
9062
9216
|
}
|
|
9063
9217
|
return roots;
|
|
9064
9218
|
},
|
|
@@ -9086,17 +9240,17 @@ var hermesSource = {
|
|
|
9086
9240
|
};
|
|
9087
9241
|
|
|
9088
9242
|
// src/core/sources/opencode.ts
|
|
9089
|
-
var
|
|
9090
|
-
var
|
|
9243
|
+
var import_node_fs5 = __toESM(require("node:fs"));
|
|
9244
|
+
var import_node_path7 = __toESM(require("node:path"));
|
|
9091
9245
|
init_src();
|
|
9092
9246
|
function opencodeDataDirs(h, env) {
|
|
9093
9247
|
if (h.layout === "win32") {
|
|
9094
|
-
const local = h.origin === "local" && env.LOCALAPPDATA ? env.LOCALAPPDATA :
|
|
9095
|
-
const roaming = h.origin === "local" && env.APPDATA ? env.APPDATA :
|
|
9096
|
-
return [
|
|
9248
|
+
const local = h.origin === "local" && env.LOCALAPPDATA ? env.LOCALAPPDATA : import_node_path7.default.join(h.home, "AppData", "Local");
|
|
9249
|
+
const roaming = h.origin === "local" && env.APPDATA ? env.APPDATA : import_node_path7.default.join(h.home, "AppData", "Roaming");
|
|
9250
|
+
return [import_node_path7.default.join(local, "opencode"), import_node_path7.default.join(roaming, "opencode")];
|
|
9097
9251
|
}
|
|
9098
|
-
const xdg = h.origin === "local" && env.XDG_DATA_HOME ? env.XDG_DATA_HOME :
|
|
9099
|
-
return [
|
|
9252
|
+
const xdg = h.origin === "local" && env.XDG_DATA_HOME ? env.XDG_DATA_HOME : import_node_path7.default.join(h.home, ".local", "share");
|
|
9253
|
+
return [import_node_path7.default.join(xdg, "opencode")];
|
|
9100
9254
|
}
|
|
9101
9255
|
var sessionCache = /* @__PURE__ */ new Map();
|
|
9102
9256
|
var authCache = /* @__PURE__ */ new Map();
|
|
@@ -9105,13 +9259,13 @@ function findSessionInfo(storage, sessionID) {
|
|
|
9105
9259
|
const cached = sessionCache.get(key);
|
|
9106
9260
|
if (cached && (cached.info || Date.now() - cached.at < 6e4)) return cached.info;
|
|
9107
9261
|
let info = null;
|
|
9108
|
-
const sessionDir =
|
|
9109
|
-
const direct =
|
|
9110
|
-
if (
|
|
9262
|
+
const sessionDir = import_node_path7.default.join(storage, "session");
|
|
9263
|
+
const direct = import_node_path7.default.join(sessionDir, "info", `${sessionID}.json`);
|
|
9264
|
+
if (import_node_fs5.default.existsSync(direct)) info = readJsonFile(direct);
|
|
9111
9265
|
if (!info) {
|
|
9112
9266
|
for (const project of listDirs(sessionDir)) {
|
|
9113
|
-
const p =
|
|
9114
|
-
if (
|
|
9267
|
+
const p = import_node_path7.default.join(sessionDir, project, `${sessionID}.json`);
|
|
9268
|
+
if (import_node_fs5.default.existsSync(p)) {
|
|
9115
9269
|
info = readJsonFile(p);
|
|
9116
9270
|
break;
|
|
9117
9271
|
}
|
|
@@ -9121,10 +9275,10 @@ function findSessionInfo(storage, sessionID) {
|
|
|
9121
9275
|
return info;
|
|
9122
9276
|
}
|
|
9123
9277
|
function openaiIsOAuth(dataDir) {
|
|
9124
|
-
const file =
|
|
9278
|
+
const file = import_node_path7.default.join(dataDir, "auth.json");
|
|
9125
9279
|
let mtime = 0;
|
|
9126
9280
|
try {
|
|
9127
|
-
mtime =
|
|
9281
|
+
mtime = import_node_fs5.default.statSync(file).mtimeMs;
|
|
9128
9282
|
} catch {
|
|
9129
9283
|
return false;
|
|
9130
9284
|
}
|
|
@@ -9136,9 +9290,9 @@ function openaiIsOAuth(dataDir) {
|
|
|
9136
9290
|
return oauth;
|
|
9137
9291
|
}
|
|
9138
9292
|
function storageOf(file) {
|
|
9139
|
-
const parts = file.split(
|
|
9293
|
+
const parts = file.split(import_node_path7.default.sep);
|
|
9140
9294
|
const idx = parts.lastIndexOf("storage");
|
|
9141
|
-
return idx >= 0 ? parts.slice(0, idx + 1).join(
|
|
9295
|
+
return idx >= 0 ? parts.slice(0, idx + 1).join(import_node_path7.default.sep) : null;
|
|
9142
9296
|
}
|
|
9143
9297
|
var opencodeSource = {
|
|
9144
9298
|
id: "opencode",
|
|
@@ -9149,7 +9303,7 @@ var opencodeSource = {
|
|
|
9149
9303
|
const roots = [];
|
|
9150
9304
|
for (const h of ctx.homes) {
|
|
9151
9305
|
for (const data of opencodeDataDirs(h, ctx.env)) {
|
|
9152
|
-
const storage =
|
|
9306
|
+
const storage = import_node_path7.default.join(data, "storage");
|
|
9153
9307
|
if (isDir(storage)) roots.push(makeRoot(storage, "opencode", "opencode", "opencode", "flat", h.origin, [".json"], 5));
|
|
9154
9308
|
}
|
|
9155
9309
|
}
|
|
@@ -9157,7 +9311,7 @@ var opencodeSource = {
|
|
|
9157
9311
|
},
|
|
9158
9312
|
hotDirs(root) {
|
|
9159
9313
|
const out = [root.dir];
|
|
9160
|
-
for (const base of [
|
|
9314
|
+
for (const base of [import_node_path7.default.join(root.dir, "message"), import_node_path7.default.join(root.dir, "session", "message")]) out.push(...recentSubdirs(base));
|
|
9161
9315
|
return out;
|
|
9162
9316
|
},
|
|
9163
9317
|
watchRecursively: () => true,
|
|
@@ -9171,7 +9325,7 @@ var opencodeSource = {
|
|
|
9171
9325
|
if (!m || m.role !== "assistant" || !m.tokens || typeof m.sessionID !== "string") return null;
|
|
9172
9326
|
const provider = typeof m.providerID === "string" ? m.providerID : null;
|
|
9173
9327
|
const storage = storageOf(file.path);
|
|
9174
|
-
const dataDir = storage ?
|
|
9328
|
+
const dataDir = storage ? import_node_path7.default.dirname(storage) : null;
|
|
9175
9329
|
const codexAuth = isCodexAuthProvider(provider) || provider === "openai" && !!dataDir && openaiIsOAuth(dataDir);
|
|
9176
9330
|
if (!opts.includeAllProviders && !codexAuth) return null;
|
|
9177
9331
|
const t2 = m.tokens;
|
|
@@ -9214,22 +9368,22 @@ var opencodeSource = {
|
|
|
9214
9368
|
};
|
|
9215
9369
|
|
|
9216
9370
|
// src/core/sources/cline.ts
|
|
9217
|
-
var
|
|
9371
|
+
var import_node_path8 = __toESM(require("node:path"));
|
|
9218
9372
|
init_src();
|
|
9219
9373
|
var APPS = ["Code", "Code - Insiders", "Cursor", "Windsurf", "VSCodium", "Trae"];
|
|
9220
9374
|
function globalStorageDirs(h, env) {
|
|
9221
9375
|
const out = [];
|
|
9222
|
-
if (h.layout === "darwin") for (const app of APPS) out.push(
|
|
9376
|
+
if (h.layout === "darwin") for (const app of APPS) out.push(import_node_path8.default.join(h.home, "Library", "Application Support", app, "User", "globalStorage"));
|
|
9223
9377
|
else if (h.layout === "win32") {
|
|
9224
|
-
const roaming = h.origin === "local" && env.APPDATA ? env.APPDATA :
|
|
9225
|
-
for (const app of APPS) out.push(
|
|
9378
|
+
const roaming = h.origin === "local" && env.APPDATA ? env.APPDATA : import_node_path8.default.join(h.home, "AppData", "Roaming");
|
|
9379
|
+
for (const app of APPS) out.push(import_node_path8.default.join(roaming, app, "User", "globalStorage"));
|
|
9226
9380
|
} else {
|
|
9227
|
-
const cfg = h.origin === "local" && env.XDG_CONFIG_HOME ? env.XDG_CONFIG_HOME :
|
|
9228
|
-
for (const app of APPS) out.push(
|
|
9381
|
+
const cfg = h.origin === "local" && env.XDG_CONFIG_HOME ? env.XDG_CONFIG_HOME : import_node_path8.default.join(h.home, ".config");
|
|
9382
|
+
for (const app of APPS) out.push(import_node_path8.default.join(cfg, app, "User", "globalStorage"));
|
|
9229
9383
|
}
|
|
9230
9384
|
if (h.layout !== "win32") {
|
|
9231
9385
|
for (const server of [".vscode-server", ".vscode-server-insiders", ".cursor-server", ".windsurf-server"]) {
|
|
9232
|
-
out.push(
|
|
9386
|
+
out.push(import_node_path8.default.join(h.home, server, "data", "User", "globalStorage"));
|
|
9233
9387
|
}
|
|
9234
9388
|
}
|
|
9235
9389
|
return out;
|
|
@@ -9252,7 +9406,7 @@ function clineFamily(id, label, extensionId) {
|
|
|
9252
9406
|
const roots = [];
|
|
9253
9407
|
for (const h of ctx.homes) {
|
|
9254
9408
|
for (const gs of globalStorageDirs(h, ctx.env)) {
|
|
9255
|
-
const tasks =
|
|
9409
|
+
const tasks = import_node_path8.default.join(gs, extensionId, "tasks");
|
|
9256
9410
|
if (isDir(tasks)) roots.push(makeRoot(tasks, id, id, "cline", "flat", h.origin, ["ui_messages.json"], 2));
|
|
9257
9411
|
}
|
|
9258
9412
|
}
|
|
@@ -9268,8 +9422,8 @@ function clineFamily(id, label, extensionId) {
|
|
|
9268
9422
|
return null;
|
|
9269
9423
|
}
|
|
9270
9424
|
if (!Array.isArray(messages)) return null;
|
|
9271
|
-
const taskDir =
|
|
9272
|
-
const meta = readJsonFile(
|
|
9425
|
+
const taskDir = import_node_path8.default.dirname(file.path);
|
|
9426
|
+
const meta = readJsonFile(import_node_path8.default.join(taskDir, "task_metadata.json")) ?? {};
|
|
9273
9427
|
const usageList = Array.isArray(meta.model_usage) ? meta.model_usage : [];
|
|
9274
9428
|
const agent = file.root.agent;
|
|
9275
9429
|
const events = [];
|
|
@@ -9321,7 +9475,7 @@ function clineFamily(id, label, extensionId) {
|
|
|
9321
9475
|
}
|
|
9322
9476
|
const cwd = meta.cwd ?? meta.cwd_on_task_initialization ?? meta.workspace ?? null;
|
|
9323
9477
|
return {
|
|
9324
|
-
sessionId:
|
|
9478
|
+
sessionId: import_node_path8.default.basename(taskDir),
|
|
9325
9479
|
agent,
|
|
9326
9480
|
provider,
|
|
9327
9481
|
startedAt: startedAt ?? lastActivityAt,
|
|
@@ -9364,7 +9518,7 @@ function sourceFor(root) {
|
|
|
9364
9518
|
function wslDistros() {
|
|
9365
9519
|
if (process.platform !== "win32") return [];
|
|
9366
9520
|
try {
|
|
9367
|
-
const raw = (0,
|
|
9521
|
+
const raw = (0, import_node_child_process3.execFileSync)("wsl.exe", ["-l", "-q"], { timeout: 5e3, windowsHide: true });
|
|
9368
9522
|
return raw.toString("utf16le").split(String.fromCharCode(0)).join("").split(/\r?\n/).map((s) => s.trim()).filter(Boolean);
|
|
9369
9523
|
} catch {
|
|
9370
9524
|
return [];
|
|
@@ -9374,22 +9528,22 @@ var SKIP_WINDOWS_USERS = /* @__PURE__ */ new Set(["public", "default", "default
|
|
|
9374
9528
|
function userHomes() {
|
|
9375
9529
|
const kind = platformKind();
|
|
9376
9530
|
const localLayout = kind === "darwin" ? "darwin" : kind === "win32" ? "win32" : "linux";
|
|
9377
|
-
const out = [{ home:
|
|
9531
|
+
const out = [{ home: import_node_os7.default.homedir(), origin: "local", layout: localLayout }];
|
|
9378
9532
|
if (kind === "win32") {
|
|
9379
9533
|
for (const distro of wslDistros()) {
|
|
9380
9534
|
for (const prefix of [`\\\\wsl$\\${distro}`, `\\\\wsl.localhost\\${distro}`]) {
|
|
9381
|
-
const home =
|
|
9535
|
+
const home = import_node_path9.default.join(prefix, "home");
|
|
9382
9536
|
const users = listDirs(home);
|
|
9383
9537
|
if (!users.length) continue;
|
|
9384
|
-
for (const u of users) out.push({ home:
|
|
9385
|
-
out.push({ home:
|
|
9538
|
+
for (const u of users) out.push({ home: import_node_path9.default.join(home, u), origin: "wsl", layout: "linux" });
|
|
9539
|
+
out.push({ home: import_node_path9.default.join(prefix, "root"), origin: "wsl", layout: "linux" });
|
|
9386
9540
|
break;
|
|
9387
9541
|
}
|
|
9388
9542
|
}
|
|
9389
9543
|
} else if (kind === "wsl") {
|
|
9390
9544
|
for (const u of listDirs("/mnt/c/Users")) {
|
|
9391
9545
|
if (SKIP_WINDOWS_USERS.has(u.toLowerCase())) continue;
|
|
9392
|
-
out.push({ home:
|
|
9546
|
+
out.push({ home: import_node_path9.default.join("/mnt/c/Users", u), origin: "windows", layout: "win32" });
|
|
9393
9547
|
}
|
|
9394
9548
|
}
|
|
9395
9549
|
return out;
|
|
@@ -9400,7 +9554,7 @@ function discoverSessionRoots(opts = {}) {
|
|
|
9400
9554
|
const roots = [];
|
|
9401
9555
|
const seen = /* @__PURE__ */ new Set();
|
|
9402
9556
|
const add = (r) => {
|
|
9403
|
-
const key = `${
|
|
9557
|
+
const key = `${import_node_path9.default.resolve(r.dir)}|${r.exts.join(",")}`;
|
|
9404
9558
|
if (seen.has(key)) return;
|
|
9405
9559
|
seen.add(key);
|
|
9406
9560
|
roots.push(r);
|
|
@@ -9415,8 +9569,8 @@ function discoverSessionRoots(opts = {}) {
|
|
|
9415
9569
|
for (const entry of opts.extraSessionDirs ?? []) {
|
|
9416
9570
|
const e = normalizeExtraDir(entry);
|
|
9417
9571
|
if (!e) continue;
|
|
9418
|
-
const dir = e.path.replace(/^~(?=$|\/|\\)/,
|
|
9419
|
-
if (!
|
|
9572
|
+
const dir = e.path.replace(/^~(?=$|\/|\\)/, import_node_os7.default.homedir());
|
|
9573
|
+
if (!import_node_fs6.default.existsSync(dir)) continue;
|
|
9420
9574
|
const def = byFormat[e.format ?? "generic"] ?? genericSource;
|
|
9421
9575
|
add(def.extraRoot(dir, e.agent));
|
|
9422
9576
|
}
|
|
@@ -9424,28 +9578,28 @@ function discoverSessionRoots(opts = {}) {
|
|
|
9424
9578
|
}
|
|
9425
9579
|
function walkFiles(root) {
|
|
9426
9580
|
const out = [];
|
|
9427
|
-
const
|
|
9581
|
+
const walk2 = (dir, depth) => {
|
|
9428
9582
|
let entries;
|
|
9429
9583
|
try {
|
|
9430
|
-
entries =
|
|
9584
|
+
entries = import_node_fs6.default.readdirSync(dir, { withFileTypes: true });
|
|
9431
9585
|
} catch {
|
|
9432
9586
|
return;
|
|
9433
9587
|
}
|
|
9434
9588
|
for (const e of entries) {
|
|
9435
|
-
const p =
|
|
9589
|
+
const p = import_node_path9.default.join(dir, e.name);
|
|
9436
9590
|
if (e.isDirectory()) {
|
|
9437
|
-
if (depth < root.maxDepth && !e.name.startsWith("."))
|
|
9591
|
+
if (depth < root.maxDepth && !e.name.startsWith(".")) walk2(p, depth + 1);
|
|
9438
9592
|
} else if (e.isFile() && root.exts.some((x) => e.name.endsWith(x))) {
|
|
9439
9593
|
out.push(p);
|
|
9440
9594
|
}
|
|
9441
9595
|
}
|
|
9442
9596
|
};
|
|
9443
|
-
|
|
9597
|
+
walk2(root.dir, 0);
|
|
9444
9598
|
return out;
|
|
9445
9599
|
}
|
|
9446
9600
|
function listFiles(dir, exts) {
|
|
9447
9601
|
try {
|
|
9448
|
-
return
|
|
9602
|
+
return import_node_fs6.default.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isFile() && exts.some((x) => e.name.endsWith(x))).map((e) => import_node_path9.default.join(dir, e.name));
|
|
9449
9603
|
} catch {
|
|
9450
9604
|
return [];
|
|
9451
9605
|
}
|
|
@@ -9509,7 +9663,7 @@ var SessionStore = class {
|
|
|
9509
9663
|
async syncFile(p, root) {
|
|
9510
9664
|
let st;
|
|
9511
9665
|
try {
|
|
9512
|
-
st = await
|
|
9666
|
+
st = await import_node_fs7.default.promises.stat(p);
|
|
9513
9667
|
} catch {
|
|
9514
9668
|
if (this.files.delete(p)) return true;
|
|
9515
9669
|
return false;
|
|
@@ -9519,7 +9673,7 @@ var SessionStore = class {
|
|
|
9519
9673
|
let session = null;
|
|
9520
9674
|
if (st.size <= MAX_FILE_BYTES) {
|
|
9521
9675
|
try {
|
|
9522
|
-
const text = root.text ? await
|
|
9676
|
+
const text = root.text ? await import_node_fs7.default.promises.readFile(p, "utf8") : "";
|
|
9523
9677
|
session = sourceFor(root).parse({ path: p, text, root }, { includeAllProviders: this.getOptions().trackAllProviders });
|
|
9524
9678
|
} catch {
|
|
9525
9679
|
session = null;
|
|
@@ -9604,8 +9758,8 @@ var SessionStore = class {
|
|
|
9604
9758
|
for (const [dir, recursive] of wanted) {
|
|
9605
9759
|
if (this.watchers.has(dir)) continue;
|
|
9606
9760
|
try {
|
|
9607
|
-
if (!
|
|
9608
|
-
const w =
|
|
9761
|
+
if (!import_node_fs7.default.existsSync(dir)) continue;
|
|
9762
|
+
const w = import_node_fs7.default.watch(dir, { persistent: false, recursive }, () => this.scheduleChange());
|
|
9609
9763
|
w.on("error", () => {
|
|
9610
9764
|
w.close();
|
|
9611
9765
|
this.watchers.delete(dir);
|
|
@@ -9798,14 +9952,14 @@ init_auth();
|
|
|
9798
9952
|
init_platform();
|
|
9799
9953
|
|
|
9800
9954
|
// src/core/usage-api.ts
|
|
9801
|
-
var
|
|
9802
|
-
var
|
|
9955
|
+
var import_node_fs8 = __toESM(require("node:fs"));
|
|
9956
|
+
var import_node_path10 = __toESM(require("node:path"));
|
|
9803
9957
|
init_src();
|
|
9804
9958
|
function readCodexAuth() {
|
|
9805
|
-
const file =
|
|
9959
|
+
const file = import_node_path10.default.join(codexHome(), "auth.json");
|
|
9806
9960
|
let raw;
|
|
9807
9961
|
try {
|
|
9808
|
-
raw =
|
|
9962
|
+
raw = import_node_fs8.default.readFileSync(file, "utf8");
|
|
9809
9963
|
} catch {
|
|
9810
9964
|
return { error: `Codex login not found (${file})` };
|
|
9811
9965
|
}
|
|
@@ -9857,7 +10011,7 @@ async function fetchLiveRateLimits(appVersion, timeoutMs = 1e4) {
|
|
|
9857
10011
|
init_i18n();
|
|
9858
10012
|
|
|
9859
10013
|
// src/version.ts
|
|
9860
|
-
var APP_VERSION = true ? "0.1.
|
|
10014
|
+
var APP_VERSION = true ? "0.1.1" : "0.0.0-dev";
|
|
9861
10015
|
|
|
9862
10016
|
// src/core/engine.ts
|
|
9863
10017
|
var SHALLOW_MS = 3e3;
|
|
@@ -10203,23 +10357,60 @@ function applyDashboardFlag(flags) {
|
|
|
10203
10357
|
function electronBinary() {
|
|
10204
10358
|
try {
|
|
10205
10359
|
const p = require("electron");
|
|
10206
|
-
return typeof p === "string" && p ? p : null;
|
|
10360
|
+
return typeof p === "string" && p && import_node_fs9.default.existsSync(p) ? p : null;
|
|
10361
|
+
} catch {
|
|
10362
|
+
return null;
|
|
10363
|
+
}
|
|
10364
|
+
}
|
|
10365
|
+
function electronPackageDir() {
|
|
10366
|
+
try {
|
|
10367
|
+
return import_node_path11.default.dirname(require.resolve("electron/package.json"));
|
|
10207
10368
|
} catch {
|
|
10208
10369
|
return null;
|
|
10209
10370
|
}
|
|
10210
10371
|
}
|
|
10211
|
-
function
|
|
10372
|
+
async function ensureElectron() {
|
|
10373
|
+
const existing = electronBinary();
|
|
10374
|
+
if (existing) return existing;
|
|
10375
|
+
const dir = electronPackageDir();
|
|
10376
|
+
if (!dir) return null;
|
|
10377
|
+
const t2 = makeT(lang());
|
|
10378
|
+
console.log(t2("cliDownloadingElectron"));
|
|
10379
|
+
const log2 = { info: (m) => console.log(m), error: (m) => console.error(m) };
|
|
10380
|
+
let bin = null;
|
|
10381
|
+
try {
|
|
10382
|
+
bin = await installElectronBinary(dir, log2);
|
|
10383
|
+
} catch (err) {
|
|
10384
|
+
log2.error(` ${err.message}`);
|
|
10385
|
+
}
|
|
10386
|
+
if (!bin) {
|
|
10387
|
+
const installer = import_node_path11.default.join(dir, "install.js");
|
|
10388
|
+
if (import_node_fs9.default.existsSync(installer)) {
|
|
10389
|
+
const env = { ...process.env };
|
|
10390
|
+
delete env.ELECTRON_SKIP_BINARY_DOWNLOAD;
|
|
10391
|
+
(0, import_node_child_process4.spawnSync)(process.execPath, [installer], { stdio: "inherit", cwd: dir, env });
|
|
10392
|
+
}
|
|
10393
|
+
}
|
|
10394
|
+
try {
|
|
10395
|
+
delete require.cache[require.resolve("electron")];
|
|
10396
|
+
} catch {
|
|
10397
|
+
}
|
|
10398
|
+
const found = electronBinary();
|
|
10399
|
+
if (!found) console.error(t2("cliElectronDownloadFailed"));
|
|
10400
|
+
return found;
|
|
10401
|
+
}
|
|
10402
|
+
async function startMenubar(background) {
|
|
10212
10403
|
const t2 = makeT(lang());
|
|
10213
|
-
const bin =
|
|
10404
|
+
const bin = await ensureElectron();
|
|
10214
10405
|
if (!bin) {
|
|
10215
10406
|
console.error(t2("cliNoElectron"));
|
|
10216
10407
|
return 2;
|
|
10217
10408
|
}
|
|
10218
10409
|
const env = { ...process.env, CODEX_TRACKER_HOME: configDir() };
|
|
10219
10410
|
delete env.ELECTRON_RUN_AS_NODE;
|
|
10220
|
-
const mainPath =
|
|
10411
|
+
const mainPath = import_node_path11.default.join(__dirname, "main.js");
|
|
10221
10412
|
console.log(t2("cliStartingMenubar"));
|
|
10222
|
-
const child = (0,
|
|
10413
|
+
const child = (0, import_node_child_process4.spawn)(bin, [mainPath], {
|
|
10223
10414
|
stdio: background ? "ignore" : "inherit",
|
|
10224
10415
|
detached: background,
|
|
10225
10416
|
env,
|
|
@@ -10479,7 +10670,7 @@ async function main() {
|
|
|
10479
10670
|
console.log(t2("cliNoDisplay"));
|
|
10480
10671
|
return runAgent(args.flags);
|
|
10481
10672
|
}
|
|
10482
|
-
if (!
|
|
10673
|
+
if (!await ensureElectron()) {
|
|
10483
10674
|
console.log(t2("cliNoElectron"));
|
|
10484
10675
|
return runAgent(args.flags);
|
|
10485
10676
|
}
|
package/dist/main.js
CHANGED
|
@@ -1239,6 +1239,8 @@ Options:
|
|
|
1239
1239
|
cliUnknownCommand: "Unknown command: {command}",
|
|
1240
1240
|
cliNoDisplay: "No display detected \u2014 starting agent mode (run `codex-tracker menubar` on a desktop).",
|
|
1241
1241
|
cliNoElectron: "Electron is not installed (optional dependency) \u2014 starting agent mode.",
|
|
1242
|
+
cliDownloadingElectron: "Electron runtime not found \u2014 downloading it now (about 100 MB, one time)\u2026",
|
|
1243
|
+
cliElectronDownloadFailed: "Electron download failed. Retry with `npm install -g codex-token-tracker --allow-scripts=electron` or `npm rebuild -g electron`; the headless `codex-tracker agent` works without it.",
|
|
1242
1244
|
cliStartingMenubar: "Starting menu bar app\u2026",
|
|
1243
1245
|
cliLoginStart: "Connecting this device to {dashboard}",
|
|
1244
1246
|
cliLoginCode: "Your code: {code}",
|
|
@@ -1367,6 +1369,8 @@ var zh = {
|
|
|
1367
1369
|
cliUnknownCommand: "\u672A\u77E5\u547D\u4EE4\uFF1A{command}",
|
|
1368
1370
|
cliNoDisplay: "\u672A\u68C0\u6D4B\u5230\u663E\u793A\u73AF\u5883 \u2014 \u4EE5 agent \u6A21\u5F0F\u542F\u52A8\uFF08\u684C\u9762\u73AF\u5883\u8BF7\u8FD0\u884C `codex-tracker menubar`\uFF09\u3002",
|
|
1369
1371
|
cliNoElectron: "\u672A\u5B89\u88C5 Electron\uFF08\u53EF\u9009\u4F9D\u8D56\uFF09\u2014 \u4EE5 agent \u6A21\u5F0F\u542F\u52A8\u3002",
|
|
1372
|
+
cliDownloadingElectron: "\u672A\u627E\u5230 Electron \u8FD0\u884C\u65F6\uFF0C\u6B63\u5728\u4E0B\u8F7D\uFF08\u7EA6 100 MB\uFF0C\u4EC5\u9700\u4E00\u6B21\uFF09\u2026",
|
|
1373
|
+
cliElectronDownloadFailed: "Electron \u4E0B\u8F7D\u5931\u8D25\u3002\u53EF\u91CD\u8BD5 `npm install -g codex-token-tracker --allow-scripts=electron` \u6216 `npm rebuild -g electron`\uFF1B\u65E0\u754C\u9762\u7684 `codex-tracker agent` \u65E0\u9700 Electron\u3002",
|
|
1370
1374
|
cliStartingMenubar: "\u6B63\u5728\u542F\u52A8\u83DC\u5355\u680F\u5E94\u7528\u2026",
|
|
1371
1375
|
cliLoginStart: "\u6B63\u5728\u5C06\u672C\u8BBE\u5907\u8FDE\u63A5\u5230 {dashboard}",
|
|
1372
1376
|
cliLoginCode: "\u4F60\u7684\u4EE3\u7801\uFF1A{code}",
|
|
@@ -8964,7 +8968,7 @@ async function fetchLiveRateLimits(appVersion, timeoutMs = 1e4) {
|
|
|
8964
8968
|
}
|
|
8965
8969
|
|
|
8966
8970
|
// src/version.ts
|
|
8967
|
-
var APP_VERSION = true ? "0.1.
|
|
8971
|
+
var APP_VERSION = true ? "0.1.1" : "0.0.0-dev";
|
|
8968
8972
|
var APP_NAME = "Codex Tracker";
|
|
8969
8973
|
|
|
8970
8974
|
// src/core/engine.ts
|
|
@@ -12959,6 +12959,8 @@ Options:
|
|
|
12959
12959
|
cliUnknownCommand: "Unknown command: {command}",
|
|
12960
12960
|
cliNoDisplay: "No display detected \u2014 starting agent mode (run `codex-tracker menubar` on a desktop).",
|
|
12961
12961
|
cliNoElectron: "Electron is not installed (optional dependency) \u2014 starting agent mode.",
|
|
12962
|
+
cliDownloadingElectron: "Electron runtime not found \u2014 downloading it now (about 100 MB, one time)\u2026",
|
|
12963
|
+
cliElectronDownloadFailed: "Electron download failed. Retry with `npm install -g codex-token-tracker --allow-scripts=electron` or `npm rebuild -g electron`; the headless `codex-tracker agent` works without it.",
|
|
12962
12964
|
cliStartingMenubar: "Starting menu bar app\u2026",
|
|
12963
12965
|
cliLoginStart: "Connecting this device to {dashboard}",
|
|
12964
12966
|
cliLoginCode: "Your code: {code}",
|
|
@@ -13087,6 +13089,8 @@ Options:
|
|
|
13087
13089
|
cliUnknownCommand: "\u672A\u77E5\u547D\u4EE4\uFF1A{command}",
|
|
13088
13090
|
cliNoDisplay: "\u672A\u68C0\u6D4B\u5230\u663E\u793A\u73AF\u5883 \u2014 \u4EE5 agent \u6A21\u5F0F\u542F\u52A8\uFF08\u684C\u9762\u73AF\u5883\u8BF7\u8FD0\u884C `codex-tracker menubar`\uFF09\u3002",
|
|
13089
13091
|
cliNoElectron: "\u672A\u5B89\u88C5 Electron\uFF08\u53EF\u9009\u4F9D\u8D56\uFF09\u2014 \u4EE5 agent \u6A21\u5F0F\u542F\u52A8\u3002",
|
|
13092
|
+
cliDownloadingElectron: "\u672A\u627E\u5230 Electron \u8FD0\u884C\u65F6\uFF0C\u6B63\u5728\u4E0B\u8F7D\uFF08\u7EA6 100 MB\uFF0C\u4EC5\u9700\u4E00\u6B21\uFF09\u2026",
|
|
13093
|
+
cliElectronDownloadFailed: "Electron \u4E0B\u8F7D\u5931\u8D25\u3002\u53EF\u91CD\u8BD5 `npm install -g codex-token-tracker --allow-scripts=electron` \u6216 `npm rebuild -g electron`\uFF1B\u65E0\u754C\u9762\u7684 `codex-tracker agent` \u65E0\u9700 Electron\u3002",
|
|
13090
13094
|
cliStartingMenubar: "\u6B63\u5728\u542F\u52A8\u83DC\u5355\u680F\u5E94\u7528\u2026",
|
|
13091
13095
|
cliLoginStart: "\u6B63\u5728\u5C06\u672C\u8BBE\u5907\u8FDE\u63A5\u5230 {dashboard}",
|
|
13092
13096
|
cliLoginCode: "\u4F60\u7684\u4EE3\u7801\uFF1A{code}",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codex-token-tracker",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Menu bar / system tray app and headless agent that tracks OpenAI Codex token usage, cache hits, model mix and API-equivalent cost — and syncs it to your team dashboard.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Chen Li",
|