codex-token-tracker 0.2.1 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,30 @@
2
2
 
3
3
  All notable changes to `codex-token-tracker`. This project follows [Semantic Versioning](https://semver.org/).
4
4
 
5
+ ## 0.2.2 — 2026-09-02
6
+
7
+ Installs on machines that cannot download Electron.
8
+
9
+ ### Fixed
10
+
11
+ - **`npm install -g` no longer runs Electron's install script.** `electron` was an optional dependency, and
12
+ `menubar` declared it as a hard peer dependency, so every install ran Electron's `install.js` — a ~100 MB
13
+ download from GitHub. When that download failed (firewalled build servers, no proxy) npm aborted the
14
+ **entire** install instead of skipping the optional package — Node 16's npm 8 does so outright, npm 11 does
15
+ the same once the script runs — and the retry died with
16
+ `Cannot find module …/node_modules/electron/install.js`, leaving the machine unable to install the tracker
17
+ even for headless use. Neither package is a dependency any more: `menubar` is bundled into `dist/main.js`,
18
+ and the CLI downloads the Electron runtime itself on first GUI launch into
19
+ `~/.codex-tracker/electron/<version>/` — the same downloader 0.1.1 added for package managers that skip
20
+ install scripts — honouring `ELECTRON_MIRROR` and `HTTPS_PROXY`. A globally installed `electron` is still
21
+ preferred when present. Headless machines never download Electron at all, and a plain install is ~40
22
+ packages instead of ~75.
23
+
24
+ ### Changed
25
+
26
+ - The *Electron download failed* message now points at `ELECTRON_MIRROR` / `HTTPS_PROXY` and
27
+ `codex-tracker menubar` rather than `npm rebuild electron`.
28
+
5
29
  ## 0.2.1 — 2026-09-01
6
30
 
7
31
  A manual **Sync** button that recalibrates this device's numbers on the dashboard.
package/README.md CHANGED
@@ -27,9 +27,11 @@ This installs two equivalent commands on your PATH: **`codex-token-tracker`** an
27
27
  Already installed? `codex-token-tracker update` fetches the newest published version and installs it
28
28
  with whichever package manager you used (npm / pnpm / yarn / bun).
29
29
 
30
- > **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`.
30
+ > **Electron is downloaded on first launch, not during install.** `npm install -g` never runs Electron's install script, so the install succeeds on locked-down servers and headless machines download nothing. The first `codex-tracker` run on a desktop fetches the runtime (~100 MB, once) into `~/.codex-tracker/electron/<version>/`, honouring `ELECTRON_MIRROR` (e.g. `https://npmmirror.com/mirrors/electron/`) and `HTTPS_PROXY`. A globally installed `electron` (`npm i -g electron`) is used instead when present.
31
31
 
32
- 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.
32
+ Node.js 20+ is required. Electron is not an npm dependency: if the runtime cannot be downloaded (locked-down servers, WSL without a desktop), the package still installs and runs in agent mode.
33
+
34
+ > **Stuck on Node 16?** Install [`codex-token-tracker-nodejs16`](https://www.npmjs.com/package/codex-token-tracker-nodejs16) instead — the same app, same features, same version number, built from these same sources for Node 16.8+. Use one or the other on a machine, not both, since they install the same commands.
33
35
 
34
36
  ## Quick start
35
37
 
@@ -268,6 +270,6 @@ MIT
268
270
 
269
271
  ## Troubleshooting
270
272
 
271
- - **"Electron is not installed" / tray app does not start** – the Electron binary is downloaded by an install script. If your package manager skipped or cached it incompletely, run `npm rebuild electron` (or `node "$(npm root -g)/codex-token-tracker/node_modules/electron/install.js"`). With pnpm, allow the build script (`pnpm approve-builds`). The headless `codex-tracker agent` and `codex-tracker status` work without Electron.
273
+ - **"Electron download failed" / tray app does not start** – the CLI downloads the Electron runtime on first launch from GitHub releases into `~/.codex-tracker/electron/<version>/`. Behind a firewall set `ELECTRON_MIRROR=https://npmmirror.com/mirrors/electron/` (or `HTTPS_PROXY`) and run `codex-tracker menubar` again; a half-finished download can be cleared by deleting that directory. A manually installed `npm i -g electron` is also picked up. The headless `codex-tracker agent` and `codex-tracker status` work without Electron.
272
274
  - **Nothing is tracked** – run `codex-tracker paths`; Codex must have written rollouts under `~/.codex/sessions` (or set `CODEX_HOME`). Add other locations with `codex-tracker config set extraSessionDirs '["/path/to/sessions"]'`.
273
275
  - **Uploads fail with BAD_TOKEN** – the device was revoked in the dashboard; run `codex-tracker login` again.
package/dist/cli.js CHANGED
@@ -1143,7 +1143,7 @@ var APP_VERSION, APP_CHANNEL, IS_DEV_BUILD;
1143
1143
  var init_version = __esm({
1144
1144
  "src/version.ts"() {
1145
1145
  "use strict";
1146
- APP_VERSION = true ? "0.2.1" : "0.0.0-dev";
1146
+ APP_VERSION = true ? "0.2.2" : "0.0.0-dev";
1147
1147
  APP_CHANNEL = true ? "prod" : "dev";
1148
1148
  IS_DEV_BUILD = APP_CHANNEL === "dev";
1149
1149
  }
@@ -1493,9 +1493,9 @@ Options:
1493
1493
  cliVersion: "codex-token-tracker {version}",
1494
1494
  cliUnknownCommand: "Unknown command: {command}",
1495
1495
  cliNoDisplay: "No display detected \u2014 starting agent mode (run `codex-tracker menubar` on a desktop).",
1496
- cliNoElectron: "Electron is not installed (optional dependency) \u2014 starting agent mode.",
1496
+ cliNoElectron: "No Electron runtime available \u2014 starting agent mode.",
1497
1497
  cliDownloadingElectron: "Electron runtime not found \u2014 downloading it now (about 100 MB, one time)\u2026",
1498
- 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.",
1498
+ cliElectronDownloadFailed: "Electron download failed. Check the network (set ELECTRON_MIRROR, e.g. https://npmmirror.com/mirrors/electron/, or HTTPS_PROXY) and run `codex-tracker menubar` again; the headless `codex-tracker agent` works without Electron.",
1499
1499
  cliStartingMenubar: "Starting menu bar app\u2026",
1500
1500
  cliLoginStart: "Connecting this device to {dashboard}",
1501
1501
  cliLoginCode: "Your code: {code}",
@@ -1674,9 +1674,9 @@ var init_zh = __esm({
1674
1674
  cliVersion: "codex-token-tracker {version}",
1675
1675
  cliUnknownCommand: "\u672A\u77E5\u547D\u4EE4\uFF1A{command}",
1676
1676
  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",
1677
- cliNoElectron: "\u672A\u5B89\u88C5 Electron\uFF08\u53EF\u9009\u4F9D\u8D56\uFF09\u2014 \u4EE5 agent \u6A21\u5F0F\u542F\u52A8\u3002",
1677
+ cliNoElectron: "\u6CA1\u6709\u53EF\u7528\u7684 Electron \u8FD0\u884C\u65F6 \u2014 \u4EE5 agent \u6A21\u5F0F\u542F\u52A8\u3002",
1678
1678
  cliDownloadingElectron: "\u672A\u627E\u5230 Electron \u8FD0\u884C\u65F6\uFF0C\u6B63\u5728\u4E0B\u8F7D\uFF08\u7EA6 100 MB\uFF0C\u4EC5\u9700\u4E00\u6B21\uFF09\u2026",
1679
- 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",
1679
+ cliElectronDownloadFailed: "Electron \u4E0B\u8F7D\u5931\u8D25\u3002\u8BF7\u68C0\u67E5\u7F51\u7EDC\uFF08\u53EF\u8BBE\u7F6E ELECTRON_MIRROR\uFF0C\u4F8B\u5982 https://npmmirror.com/mirrors/electron/\uFF0C\u6216 HTTPS_PROXY\uFF09\u540E\u518D\u6B21\u8FD0\u884C `codex-tracker menubar`\uFF1B\u65E0\u754C\u9762\u7684 `codex-tracker agent` \u65E0\u9700 Electron\u3002",
1680
1680
  cliStartingMenubar: "\u6B63\u5728\u542F\u52A8\u83DC\u5355\u680F\u5E94\u7528\u2026",
1681
1681
  cliLoginStart: "\u6B63\u5728\u5C06\u672C\u8BBE\u5907\u8FDE\u63A5\u5230 {dashboard}",
1682
1682
  cliLoginCode: "\u4F60\u7684\u4EE3\u7801\uFF1A{code}",
@@ -8895,6 +8895,7 @@ var import_node_fs = __toESM(require("node:fs"));
8895
8895
  var import_node_os = __toESM(require("node:os"));
8896
8896
  var import_node_path = __toESM(require("node:path"));
8897
8897
  var import_node_child_process = require("node:child_process");
8898
+ var DEFAULT_ELECTRON_VERSION = true ? "38.8.6" : "38.8.6";
8898
8899
  function archName() {
8899
8900
  switch (process.arch) {
8900
8901
  case "x64":
@@ -9036,6 +9037,33 @@ async function installElectronBinary(pkgDir, log2) {
9036
9037
  import_node_fs.default.writeFileSync(import_node_path.default.join(pkgDir, "path.txt"), platformExecutablePath());
9037
9038
  return import_node_fs.default.existsSync(exe) ? exe : null;
9038
9039
  }
9040
+ function managedElectronDir(configHome, version2 = DEFAULT_ELECTRON_VERSION) {
9041
+ return import_node_path.default.join(configHome, "electron", version2);
9042
+ }
9043
+ function ensureManagedElectronDir(configHome, version2 = DEFAULT_ELECTRON_VERSION) {
9044
+ const dir = managedElectronDir(configHome, version2);
9045
+ const manifest = import_node_path.default.join(dir, "package.json");
9046
+ let current = null;
9047
+ try {
9048
+ current = JSON.parse(import_node_fs.default.readFileSync(manifest, "utf8")).version ?? null;
9049
+ } catch {
9050
+ }
9051
+ if (current !== version2) {
9052
+ import_node_fs.default.mkdirSync(dir, { recursive: true });
9053
+ import_node_fs.default.writeFileSync(manifest, JSON.stringify({ name: "electron", version: version2, private: true }, null, 2) + "\n");
9054
+ }
9055
+ return dir;
9056
+ }
9057
+ function binaryFromPackageDir(pkgDir) {
9058
+ try {
9059
+ const rel = import_node_fs.default.readFileSync(import_node_path.default.join(pkgDir, "path.txt"), "utf8").trim();
9060
+ if (!rel) return null;
9061
+ const exe = import_node_path.default.join(pkgDir, "dist", rel);
9062
+ return import_node_fs.default.existsSync(exe) ? exe : null;
9063
+ } catch {
9064
+ return null;
9065
+ }
9066
+ }
9039
9067
 
9040
9068
  // src/cli.ts
9041
9069
  init_src();
@@ -10198,7 +10226,7 @@ var import_node_path11 = __toESM(require("node:path"));
10198
10226
  var import_node_child_process4 = require("node:child_process");
10199
10227
  init_config();
10200
10228
  init_version();
10201
- var NPM_PACKAGE = "codex-token-tracker";
10229
+ var NPM_PACKAGE = true ? "codex-token-tracker" : "codex-token-tracker";
10202
10230
  var CHECK_TTL_MS = 6 * 60 * 60 * 1e3;
10203
10231
  var REQUEST_TIMEOUT_MS = 8e3;
10204
10232
  var INSTALL_TIMEOUT_MS = 10 * 60 * 1e3;
@@ -10272,7 +10300,8 @@ function updateCommand(pm, spec) {
10272
10300
  return `${pm} ${updateArgs(pm, spec).join(" ")}`;
10273
10301
  }
10274
10302
  function cachePath() {
10275
- return import_node_path11.default.join(configDir(), "update.json");
10303
+ const suffix = NPM_PACKAGE === "codex-token-tracker" ? "" : `-${NPM_PACKAGE}`;
10304
+ return import_node_path11.default.join(configDir(), `update${suffix}.json`);
10276
10305
  }
10277
10306
  function readCache() {
10278
10307
  try {
@@ -10870,10 +10899,10 @@ function applyDashboardFlag(flags) {
10870
10899
  function electronBinary() {
10871
10900
  try {
10872
10901
  const p = require("electron");
10873
- return typeof p === "string" && p && import_node_fs10.default.existsSync(p) ? p : null;
10902
+ if (typeof p === "string" && p && import_node_fs10.default.existsSync(p)) return p;
10874
10903
  } catch {
10875
- return null;
10876
10904
  }
10905
+ return binaryFromPackageDir(managedElectronDir(configDir()));
10877
10906
  }
10878
10907
  function electronPackageDir() {
10879
10908
  try {
@@ -10885,8 +10914,7 @@ function electronPackageDir() {
10885
10914
  async function ensureElectron() {
10886
10915
  const existing = electronBinary();
10887
10916
  if (existing) return existing;
10888
- const dir = electronPackageDir();
10889
- if (!dir) return null;
10917
+ const dir = electronPackageDir() ?? ensureManagedElectronDir(configDir());
10890
10918
  const t2 = makeT(lang());
10891
10919
  console.log(t2("cliDownloadingElectron"));
10892
10920
  const log2 = { info: (m) => console.log(m), error: (m) => console.error(m) };
package/dist/main.js CHANGED
@@ -5,6 +5,13 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
6
  var __getProtoOf = Object.getPrototypeOf;
7
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __commonJS = (cb, mod) => function __require2() {
9
+ try {
10
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
11
+ } catch (e) {
12
+ throw mod = 0, e;
13
+ }
14
+ };
8
15
  var __copyProps = (to, from, except, desc) => {
9
16
  if (from && typeof from === "object" || typeof from === "function") {
10
17
  for (let key of __getOwnPropNames(from))
@@ -22,13 +29,691 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
22
29
  mod
23
30
  ));
24
31
 
32
+ // ../../node_modules/.pnpm/electron-positioner@4.1.0/node_modules/electron-positioner/index.js
33
+ var require_electron_positioner = __commonJS({
34
+ "../../node_modules/.pnpm/electron-positioner@4.1.0/node_modules/electron-positioner/index.js"(exports2, module2) {
35
+ "use strict";
36
+ module2.exports = class Positioner {
37
+ constructor(browserWindow) {
38
+ this.browserWindow = browserWindow;
39
+ this.electronScreen = require("electron").screen;
40
+ }
41
+ _getCoords(position, trayPosition) {
42
+ let screenSize = this._getScreenSize(trayPosition);
43
+ let windowSize = this._getWindowSize();
44
+ if (trayPosition === void 0) trayPosition = {};
45
+ let positions = {
46
+ trayLeft: {
47
+ x: Math.floor(trayPosition.x),
48
+ y: screenSize.y
49
+ },
50
+ trayBottomLeft: {
51
+ x: Math.floor(trayPosition.x),
52
+ y: Math.floor(screenSize.height - (windowSize[1] - screenSize.y))
53
+ },
54
+ trayRight: {
55
+ x: Math.floor(trayPosition.x - windowSize[0] + trayPosition.width),
56
+ y: screenSize.y
57
+ },
58
+ trayBottomRight: {
59
+ x: Math.floor(trayPosition.x - windowSize[0] + trayPosition.width),
60
+ y: Math.floor(screenSize.height - (windowSize[1] - screenSize.y))
61
+ },
62
+ trayCenter: {
63
+ x: Math.floor(trayPosition.x - windowSize[0] / 2 + trayPosition.width / 2),
64
+ y: screenSize.y
65
+ },
66
+ trayBottomCenter: {
67
+ x: Math.floor(trayPosition.x - windowSize[0] / 2 + trayPosition.width / 2),
68
+ y: Math.floor(screenSize.height - (windowSize[1] - screenSize.y))
69
+ },
70
+ topLeft: {
71
+ x: screenSize.x,
72
+ y: screenSize.y
73
+ },
74
+ topRight: {
75
+ x: Math.floor(screenSize.x + (screenSize.width - windowSize[0])),
76
+ y: screenSize.y
77
+ },
78
+ bottomLeft: {
79
+ x: screenSize.x,
80
+ y: Math.floor(screenSize.height - (windowSize[1] - screenSize.y))
81
+ },
82
+ bottomRight: {
83
+ x: Math.floor(screenSize.x + (screenSize.width - windowSize[0])),
84
+ y: Math.floor(screenSize.height - (windowSize[1] - screenSize.y))
85
+ },
86
+ topCenter: {
87
+ x: Math.floor(screenSize.x + (screenSize.width / 2 - windowSize[0] / 2)),
88
+ y: screenSize.y
89
+ },
90
+ bottomCenter: {
91
+ x: Math.floor(screenSize.x + (screenSize.width / 2 - windowSize[0] / 2)),
92
+ y: Math.floor(screenSize.height - (windowSize[1] - screenSize.y))
93
+ },
94
+ leftCenter: {
95
+ x: screenSize.x,
96
+ y: screenSize.y + Math.floor(screenSize.height / 2) - Math.floor(windowSize[1] / 2)
97
+ },
98
+ rightCenter: {
99
+ x: Math.floor(screenSize.x + (screenSize.width - windowSize[0])),
100
+ y: screenSize.y + Math.floor(screenSize.height / 2) - Math.floor(windowSize[1] / 2)
101
+ },
102
+ center: {
103
+ x: Math.floor(screenSize.x + (screenSize.width / 2 - windowSize[0] / 2)),
104
+ y: Math.floor((screenSize.height + screenSize.y) / 2 - windowSize[1] / 2)
105
+ }
106
+ };
107
+ if (position.substr(0, 4) === "tray") {
108
+ if (positions[position].x + windowSize[0] > screenSize.width + screenSize.x) {
109
+ return {
110
+ x: positions["topRight"].x,
111
+ y: positions[position].y
112
+ };
113
+ }
114
+ }
115
+ return positions[position];
116
+ }
117
+ _getWindowSize() {
118
+ return this.browserWindow.getSize();
119
+ }
120
+ _getScreenSize(trayPosition) {
121
+ if (trayPosition) {
122
+ return this.electronScreen.getDisplayMatching(trayPosition).workArea;
123
+ } else {
124
+ return this.electronScreen.getDisplayNearestPoint(this.electronScreen.getCursorScreenPoint()).workArea;
125
+ }
126
+ }
127
+ move(position, trayPos) {
128
+ var coords = this._getCoords(position, trayPos);
129
+ this.browserWindow.setPosition(coords.x, coords.y);
130
+ }
131
+ calculate(position, trayPos) {
132
+ var coords = this._getCoords(position, trayPos);
133
+ return {
134
+ x: coords.x,
135
+ y: coords.y
136
+ };
137
+ }
138
+ };
139
+ }
140
+ });
141
+
142
+ // ../../node_modules/.pnpm/menubar@9.5.3_electron@38.8.6/node_modules/menubar/lib/util/cleanOptions.js
143
+ var require_cleanOptions = __commonJS({
144
+ "../../node_modules/.pnpm/menubar@9.5.3_electron@38.8.6/node_modules/menubar/lib/util/cleanOptions.js"(exports2) {
145
+ "use strict";
146
+ var __assign = exports2 && exports2.__assign || function() {
147
+ __assign = Object.assign || function(t2) {
148
+ for (var s, i2 = 1, n = arguments.length; i2 < n; i2++) {
149
+ s = arguments[i2];
150
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
151
+ t2[p] = s[p];
152
+ }
153
+ return t2;
154
+ };
155
+ return __assign.apply(this, arguments);
156
+ };
157
+ var __importDefault = exports2 && exports2.__importDefault || function(mod) {
158
+ return mod && mod.__esModule ? mod : { "default": mod };
159
+ };
160
+ Object.defineProperty(exports2, "__esModule", { value: true });
161
+ exports2.cleanOptions = void 0;
162
+ var path_1 = __importDefault(require("path"));
163
+ var url_1 = __importDefault(require("url"));
164
+ var electron_1 = require("electron");
165
+ var DEFAULT_WINDOW_HEIGHT = 400;
166
+ var DEFAULT_WINDOW_WIDTH = 400;
167
+ function cleanOptions(opts) {
168
+ var options = __assign({}, opts);
169
+ if (options.activateWithApp === void 0) {
170
+ options.activateWithApp = true;
171
+ }
172
+ if (!options.dir) {
173
+ options.dir = electron_1.app.getAppPath();
174
+ }
175
+ if (!path_1.default.isAbsolute(options.dir)) {
176
+ options.dir = path_1.default.resolve(options.dir);
177
+ }
178
+ if (options.index === void 0) {
179
+ options.index = url_1.default.format({
180
+ pathname: path_1.default.join(options.dir, "index.html"),
181
+ protocol: "file:",
182
+ slashes: true
183
+ });
184
+ }
185
+ options.loadUrlOptions = options.loadUrlOptions || {};
186
+ options.tooltip = options.tooltip || "";
187
+ if (!options.browserWindow) {
188
+ options.browserWindow = {};
189
+ }
190
+ options.browserWindow.width = // Note: not using `options.browserWindow.width || DEFAULT_WINDOW_WIDTH` so
191
+ // that users can put a 0 width
192
+ options.browserWindow.width !== void 0 ? options.browserWindow.width : DEFAULT_WINDOW_WIDTH;
193
+ options.browserWindow.height = options.browserWindow.height !== void 0 ? options.browserWindow.height : DEFAULT_WINDOW_HEIGHT;
194
+ return options;
195
+ }
196
+ exports2.cleanOptions = cleanOptions;
197
+ }
198
+ });
199
+
200
+ // ../../node_modules/.pnpm/menubar@9.5.3_electron@38.8.6/node_modules/menubar/lib/util/getWindowPosition.js
201
+ var require_getWindowPosition = __commonJS({
202
+ "../../node_modules/.pnpm/menubar@9.5.3_electron@38.8.6/node_modules/menubar/lib/util/getWindowPosition.js"(exports2) {
203
+ "use strict";
204
+ Object.defineProperty(exports2, "__esModule", { value: true });
205
+ exports2.getWindowPosition = exports2.taskbarLocation = void 0;
206
+ var electron_1 = require("electron");
207
+ var isLinux = process.platform === "linux";
208
+ var trayToScreenRects = function(tray) {
209
+ var _a2 = electron_1.screen.getDisplayMatching(tray.getBounds()), workArea = _a2.workArea, screenBounds = _a2.bounds;
210
+ workArea.x -= screenBounds.x;
211
+ workArea.y -= screenBounds.y;
212
+ return [screenBounds, workArea];
213
+ };
214
+ function taskbarLocation(tray) {
215
+ var _a2 = trayToScreenRects(tray), screenBounds = _a2[0], workArea = _a2[1];
216
+ if (workArea.x > 0) {
217
+ if (isLinux && workArea.y > 0)
218
+ return "top";
219
+ return "left";
220
+ }
221
+ if (workArea.y > 0) {
222
+ return "top";
223
+ }
224
+ if (workArea.width < screenBounds.width) {
225
+ return "right";
226
+ }
227
+ return "bottom";
228
+ }
229
+ exports2.taskbarLocation = taskbarLocation;
230
+ function getWindowPosition(tray) {
231
+ switch (process.platform) {
232
+ // macOS
233
+ // Supports top taskbars
234
+ case "darwin":
235
+ return "trayCenter";
236
+ // Linux
237
+ // Windows
238
+ // Supports top/bottom/left/right taskbar
239
+ case "linux":
240
+ case "win32": {
241
+ var traySide = taskbarLocation(tray);
242
+ if (traySide === "top") {
243
+ return isLinux ? "topRight" : "trayCenter";
244
+ }
245
+ if (traySide === "bottom") {
246
+ return "bottomRight";
247
+ }
248
+ if (traySide === "left") {
249
+ return "bottomLeft";
250
+ }
251
+ if (traySide === "right") {
252
+ return "bottomRight";
253
+ }
254
+ }
255
+ }
256
+ return "topRight";
257
+ }
258
+ exports2.getWindowPosition = getWindowPosition;
259
+ }
260
+ });
261
+
262
+ // ../../node_modules/.pnpm/menubar@9.5.3_electron@38.8.6/node_modules/menubar/lib/Menubar.js
263
+ var require_Menubar = __commonJS({
264
+ "../../node_modules/.pnpm/menubar@9.5.3_electron@38.8.6/node_modules/menubar/lib/Menubar.js"(exports2) {
265
+ "use strict";
266
+ var __extends = exports2 && exports2.__extends || /* @__PURE__ */ (function() {
267
+ var extendStatics = function(d, b) {
268
+ extendStatics = Object.setPrototypeOf || { __proto__: [] } instanceof Array && function(d2, b2) {
269
+ d2.__proto__ = b2;
270
+ } || function(d2, b2) {
271
+ for (var p in b2) if (Object.prototype.hasOwnProperty.call(b2, p)) d2[p] = b2[p];
272
+ };
273
+ return extendStatics(d, b);
274
+ };
275
+ return function(d, b) {
276
+ if (typeof b !== "function" && b !== null)
277
+ throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
278
+ extendStatics(d, b);
279
+ function __() {
280
+ this.constructor = d;
281
+ }
282
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
283
+ };
284
+ })();
285
+ var __assign = exports2 && exports2.__assign || function() {
286
+ __assign = Object.assign || function(t2) {
287
+ for (var s, i2 = 1, n = arguments.length; i2 < n; i2++) {
288
+ s = arguments[i2];
289
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
290
+ t2[p] = s[p];
291
+ }
292
+ return t2;
293
+ };
294
+ return __assign.apply(this, arguments);
295
+ };
296
+ var __awaiter = exports2 && exports2.__awaiter || function(thisArg, _arguments, P, generator) {
297
+ function adopt(value) {
298
+ return value instanceof P ? value : new P(function(resolve) {
299
+ resolve(value);
300
+ });
301
+ }
302
+ return new (P || (P = Promise))(function(resolve, reject) {
303
+ function fulfilled(value) {
304
+ try {
305
+ step(generator.next(value));
306
+ } catch (e) {
307
+ reject(e);
308
+ }
309
+ }
310
+ function rejected(value) {
311
+ try {
312
+ step(generator["throw"](value));
313
+ } catch (e) {
314
+ reject(e);
315
+ }
316
+ }
317
+ function step(result) {
318
+ result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected);
319
+ }
320
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
321
+ });
322
+ };
323
+ var __generator = exports2 && exports2.__generator || function(thisArg, body) {
324
+ var _ = { label: 0, sent: function() {
325
+ if (t2[0] & 1) throw t2[1];
326
+ return t2[1];
327
+ }, trys: [], ops: [] }, f, y, t2, g;
328
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() {
329
+ return this;
330
+ }), g;
331
+ function verb(n) {
332
+ return function(v2) {
333
+ return step([n, v2]);
334
+ };
335
+ }
336
+ function step(op) {
337
+ if (f) throw new TypeError("Generator is already executing.");
338
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
339
+ if (f = 1, y && (t2 = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t2 = y["return"]) && t2.call(y), 0) : y.next) && !(t2 = t2.call(y, op[1])).done) return t2;
340
+ if (y = 0, t2) op = [op[0] & 2, t2.value];
341
+ switch (op[0]) {
342
+ case 0:
343
+ case 1:
344
+ t2 = op;
345
+ break;
346
+ case 4:
347
+ _.label++;
348
+ return { value: op[1], done: false };
349
+ case 5:
350
+ _.label++;
351
+ y = op[1];
352
+ op = [0];
353
+ continue;
354
+ case 7:
355
+ op = _.ops.pop();
356
+ _.trys.pop();
357
+ continue;
358
+ default:
359
+ if (!(t2 = _.trys, t2 = t2.length > 0 && t2[t2.length - 1]) && (op[0] === 6 || op[0] === 2)) {
360
+ _ = 0;
361
+ continue;
362
+ }
363
+ if (op[0] === 3 && (!t2 || op[1] > t2[0] && op[1] < t2[3])) {
364
+ _.label = op[1];
365
+ break;
366
+ }
367
+ if (op[0] === 6 && _.label < t2[1]) {
368
+ _.label = t2[1];
369
+ t2 = op;
370
+ break;
371
+ }
372
+ if (t2 && _.label < t2[2]) {
373
+ _.label = t2[2];
374
+ _.ops.push(op);
375
+ break;
376
+ }
377
+ if (t2[2]) _.ops.pop();
378
+ _.trys.pop();
379
+ continue;
380
+ }
381
+ op = body.call(thisArg, _);
382
+ } catch (e) {
383
+ op = [6, e];
384
+ y = 0;
385
+ } finally {
386
+ f = t2 = 0;
387
+ }
388
+ if (op[0] & 5) throw op[1];
389
+ return { value: op[0] ? op[1] : void 0, done: true };
390
+ }
391
+ };
392
+ var __importDefault = exports2 && exports2.__importDefault || function(mod) {
393
+ return mod && mod.__esModule ? mod : { "default": mod };
394
+ };
395
+ Object.defineProperty(exports2, "__esModule", { value: true });
396
+ exports2.Menubar = void 0;
397
+ var events_1 = require("events");
398
+ var fs_1 = __importDefault(require("fs"));
399
+ var path_1 = __importDefault(require("path"));
400
+ var electron_1 = require("electron");
401
+ var electron_positioner_1 = __importDefault(require_electron_positioner());
402
+ var cleanOptions_1 = require_cleanOptions();
403
+ var getWindowPosition_1 = require_getWindowPosition();
404
+ var Menubar = (
405
+ /** @class */
406
+ (function(_super) {
407
+ __extends(Menubar2, _super);
408
+ function Menubar2(app2, options) {
409
+ var _this = _super.call(this) || this;
410
+ _this._blurTimeout = null;
411
+ _this._app = app2;
412
+ _this._options = (0, cleanOptions_1.cleanOptions)(options);
413
+ _this._isVisible = false;
414
+ if (app2.isReady()) {
415
+ process.nextTick(function() {
416
+ return _this.appReady().catch(function(err) {
417
+ return console.error("menubar: ", err);
418
+ });
419
+ });
420
+ } else {
421
+ app2.on("ready", function() {
422
+ _this.appReady().catch(function(err) {
423
+ return console.error("menubar: ", err);
424
+ });
425
+ });
426
+ }
427
+ return _this;
428
+ }
429
+ Object.defineProperty(Menubar2.prototype, "app", {
430
+ /**
431
+ * The Electron [App](https://electronjs.org/docs/api/app)
432
+ * instance.
433
+ */
434
+ get: function() {
435
+ return this._app;
436
+ },
437
+ enumerable: false,
438
+ configurable: true
439
+ });
440
+ Object.defineProperty(Menubar2.prototype, "positioner", {
441
+ /**
442
+ * The [electron-positioner](https://github.com/jenslind/electron-positioner)
443
+ * instance.
444
+ */
445
+ get: function() {
446
+ if (!this._positioner) {
447
+ throw new Error("Please access `this.positioner` after the `after-create-window` event has fired.");
448
+ }
449
+ return this._positioner;
450
+ },
451
+ enumerable: false,
452
+ configurable: true
453
+ });
454
+ Object.defineProperty(Menubar2.prototype, "tray", {
455
+ /**
456
+ * The Electron [Tray](https://electronjs.org/docs/api/tray) instance.
457
+ */
458
+ get: function() {
459
+ if (!this._tray) {
460
+ throw new Error("Please access `this.tray` after the `ready` event has fired.");
461
+ }
462
+ return this._tray;
463
+ },
464
+ enumerable: false,
465
+ configurable: true
466
+ });
467
+ Object.defineProperty(Menubar2.prototype, "window", {
468
+ /**
469
+ * The Electron [BrowserWindow](https://electronjs.org/docs/api/browser-window)
470
+ * instance, if it's present.
471
+ */
472
+ get: function() {
473
+ return this._browserWindow;
474
+ },
475
+ enumerable: false,
476
+ configurable: true
477
+ });
478
+ Menubar2.prototype.getOption = function(key) {
479
+ return this._options[key];
480
+ };
481
+ Menubar2.prototype.hideWindow = function() {
482
+ if (!this._browserWindow || !this._isVisible) {
483
+ return;
484
+ }
485
+ this.emit("hide");
486
+ this._browserWindow.hide();
487
+ this.emit("after-hide");
488
+ this._isVisible = false;
489
+ if (this._blurTimeout) {
490
+ clearTimeout(this._blurTimeout);
491
+ this._blurTimeout = null;
492
+ }
493
+ };
494
+ Menubar2.prototype.setOption = function(key, value) {
495
+ this._options[key] = value;
496
+ };
497
+ Menubar2.prototype.showWindow = function(trayPos) {
498
+ return __awaiter(this, void 0, void 0, function() {
499
+ var noBoundsPosition, position, x, y;
500
+ return __generator(this, function(_a2) {
501
+ switch (_a2.label) {
502
+ case 0:
503
+ if (!this.tray) {
504
+ throw new Error("Tray should have been instantiated by now");
505
+ }
506
+ if (!!this._browserWindow) return [3, 2];
507
+ return [4, this.createWindow()];
508
+ case 1:
509
+ _a2.sent();
510
+ _a2.label = 2;
511
+ case 2:
512
+ if (!this._browserWindow) {
513
+ throw new Error("Window has been initialized just above. qed.");
514
+ }
515
+ if (["win32", "linux"].includes(process.platform)) {
516
+ this._options.windowPosition = (0, getWindowPosition_1.getWindowPosition)(this.tray);
517
+ }
518
+ this.emit("show");
519
+ if (trayPos && trayPos.x !== 0) {
520
+ this._cachedBounds = trayPos;
521
+ } else if (this._cachedBounds) {
522
+ trayPos = this._cachedBounds;
523
+ } else if (this.tray.getBounds) {
524
+ trayPos = this.tray.getBounds();
525
+ }
526
+ noBoundsPosition = void 0;
527
+ if ((trayPos === void 0 || trayPos.x === 0) && this._options.windowPosition && this._options.windowPosition.startsWith("tray")) {
528
+ noBoundsPosition = process.platform === "win32" ? "bottomRight" : "topRight";
529
+ }
530
+ position = this.positioner.calculate(this._options.windowPosition || noBoundsPosition, trayPos);
531
+ x = this._options.browserWindow.x !== void 0 ? this._options.browserWindow.x : position.x;
532
+ y = this._options.browserWindow.y !== void 0 ? this._options.browserWindow.y : position.y;
533
+ this._browserWindow.setPosition(Math.round(x), Math.round(y));
534
+ this._browserWindow.show();
535
+ this._isVisible = true;
536
+ this.emit("after-show");
537
+ return [
538
+ 2
539
+ /*return*/
540
+ ];
541
+ }
542
+ });
543
+ });
544
+ };
545
+ Menubar2.prototype.appReady = function() {
546
+ return __awaiter(this, void 0, void 0, function() {
547
+ var trayImage, defaultClickEvent;
548
+ var _this = this;
549
+ return __generator(this, function(_a2) {
550
+ switch (_a2.label) {
551
+ case 0:
552
+ if (this.app.dock && !this._options.showDockIcon) {
553
+ this.app.dock.hide();
554
+ }
555
+ if (this._options.activateWithApp) {
556
+ this.app.on("activate", function(_event, hasVisibleWindows) {
557
+ if (!hasVisibleWindows) {
558
+ _this.showWindow().catch(console.error);
559
+ }
560
+ });
561
+ }
562
+ trayImage = this._options.icon || path_1.default.join(this._options.dir, "IconTemplate.png");
563
+ if (typeof trayImage === "string" && !fs_1.default.existsSync(trayImage)) {
564
+ trayImage = path_1.default.join(__dirname, "..", "assets", "IconTemplate.png");
565
+ }
566
+ defaultClickEvent = this._options.showOnRightClick ? "right-click" : "click";
567
+ this._tray = this._options.tray || new electron_1.Tray(trayImage);
568
+ if (!this.tray) {
569
+ throw new Error("Tray has been initialized above");
570
+ }
571
+ this.tray.on(defaultClickEvent, this.clicked.bind(this));
572
+ this.tray.on("double-click", this.clicked.bind(this));
573
+ this.tray.setToolTip(this._options.tooltip);
574
+ if (!this._options.windowPosition) {
575
+ this._options.windowPosition = (0, getWindowPosition_1.getWindowPosition)(this.tray);
576
+ }
577
+ if (!this._options.preloadWindow) return [3, 2];
578
+ return [4, this.createWindow()];
579
+ case 1:
580
+ _a2.sent();
581
+ _a2.label = 2;
582
+ case 2:
583
+ this.emit("ready");
584
+ return [
585
+ 2
586
+ /*return*/
587
+ ];
588
+ }
589
+ });
590
+ });
591
+ };
592
+ Menubar2.prototype.clicked = function(event, bounds) {
593
+ return __awaiter(this, void 0, void 0, function() {
594
+ return __generator(this, function(_a2) {
595
+ switch (_a2.label) {
596
+ case 0:
597
+ if (event && (event.shiftKey || event.ctrlKey || event.metaKey)) {
598
+ return [2, this.hideWindow()];
599
+ }
600
+ if (this._blurTimeout) {
601
+ clearInterval(this._blurTimeout);
602
+ }
603
+ if (this._browserWindow && this._isVisible) {
604
+ return [2, this.hideWindow()];
605
+ }
606
+ this._cachedBounds = bounds || this._cachedBounds;
607
+ return [4, this.showWindow(this._cachedBounds)];
608
+ case 1:
609
+ _a2.sent();
610
+ return [
611
+ 2
612
+ /*return*/
613
+ ];
614
+ }
615
+ });
616
+ });
617
+ };
618
+ Menubar2.prototype.createWindow = function() {
619
+ return __awaiter(this, void 0, void 0, function() {
620
+ var defaults;
621
+ var _this = this;
622
+ return __generator(this, function(_a2) {
623
+ switch (_a2.label) {
624
+ case 0:
625
+ this.emit("create-window");
626
+ defaults = {
627
+ show: false,
628
+ frame: false
629
+ // Remove window frame
630
+ };
631
+ this._browserWindow = new electron_1.BrowserWindow(__assign(__assign({}, defaults), this._options.browserWindow));
632
+ this._positioner = new electron_positioner_1.default(this._browserWindow);
633
+ this._browserWindow.on("blur", function() {
634
+ if (!_this._browserWindow) {
635
+ return;
636
+ }
637
+ _this._browserWindow.isAlwaysOnTop() ? _this.emit("focus-lost") : _this._blurTimeout = setTimeout(function() {
638
+ _this.hideWindow();
639
+ }, 100);
640
+ });
641
+ if (this._options.showOnAllWorkspaces !== false) {
642
+ this._browserWindow.setVisibleOnAllWorkspaces(true, {
643
+ skipTransformProcessType: true
644
+ // Avoid damaging the original visible state of app.dock
645
+ });
646
+ }
647
+ this._browserWindow.on("close", this.windowClear.bind(this));
648
+ this.emit("before-load");
649
+ if (!(this._options.index !== false)) return [3, 2];
650
+ return [4, this._browserWindow.loadURL(this._options.index, this._options.loadUrlOptions)];
651
+ case 1:
652
+ _a2.sent();
653
+ _a2.label = 2;
654
+ case 2:
655
+ this.emit("after-create-window");
656
+ return [
657
+ 2
658
+ /*return*/
659
+ ];
660
+ }
661
+ });
662
+ });
663
+ };
664
+ Menubar2.prototype.windowClear = function() {
665
+ this._browserWindow = void 0;
666
+ this.emit("after-close");
667
+ };
668
+ return Menubar2;
669
+ })(events_1.EventEmitter)
670
+ );
671
+ exports2.Menubar = Menubar;
672
+ }
673
+ });
674
+
675
+ // ../../node_modules/.pnpm/menubar@9.5.3_electron@38.8.6/node_modules/menubar/lib/index.js
676
+ var require_lib = __commonJS({
677
+ "../../node_modules/.pnpm/menubar@9.5.3_electron@38.8.6/node_modules/menubar/lib/index.js"(exports2) {
678
+ "use strict";
679
+ var __createBinding = exports2 && exports2.__createBinding || (Object.create ? (function(o, m, k, k2) {
680
+ if (k2 === void 0) k2 = k;
681
+ var desc = Object.getOwnPropertyDescriptor(m, k);
682
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
683
+ desc = { enumerable: true, get: function() {
684
+ return m[k];
685
+ } };
686
+ }
687
+ Object.defineProperty(o, k2, desc);
688
+ }) : (function(o, m, k, k2) {
689
+ if (k2 === void 0) k2 = k;
690
+ o[k2] = m[k];
691
+ }));
692
+ var __exportStar = exports2 && exports2.__exportStar || function(m, exports3) {
693
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p)) __createBinding(exports3, m, p);
694
+ };
695
+ Object.defineProperty(exports2, "__esModule", { value: true });
696
+ exports2.menubar = exports2.Menubar = void 0;
697
+ var electron_1 = require("electron");
698
+ var Menubar_1 = require_Menubar();
699
+ Object.defineProperty(exports2, "Menubar", { enumerable: true, get: function() {
700
+ return Menubar_1.Menubar;
701
+ } });
702
+ __exportStar(require_getWindowPosition(), exports2);
703
+ function menubar2(options) {
704
+ return new Menubar_1.Menubar(electron_1.app, options);
705
+ }
706
+ exports2.menubar = menubar2;
707
+ }
708
+ });
709
+
25
710
  // src/main.ts
26
711
  var import_electron = require("electron");
27
712
  var import_node_fs9 = __toESM(require("node:fs"));
28
713
  var import_node_os7 = __toESM(require("node:os"));
29
714
  var import_node_path11 = __toESM(require("node:path"));
30
715
  var import_node_child_process4 = require("node:child_process");
31
- var import_menubar = require("menubar");
716
+ var import_menubar = __toESM(require_lib());
32
717
 
33
718
  // ../shared/src/usage.ts
34
719
  function emptyUsage() {
@@ -1044,7 +1729,7 @@ var import_node_os = __toESM(require("node:os"));
1044
1729
  var import_node_path = __toESM(require("node:path"));
1045
1730
 
1046
1731
  // src/version.ts
1047
- var APP_VERSION = true ? "0.2.1" : "0.0.0-dev";
1732
+ var APP_VERSION = true ? "0.2.2" : "0.0.0-dev";
1048
1733
  var APP_CHANNEL = true ? "prod" : "dev";
1049
1734
  var IS_DEV_BUILD = APP_CHANNEL === "dev";
1050
1735
  var APP_NAME = IS_DEV_BUILD ? "Codex Tracker (dev)" : "Codex Tracker";
@@ -1322,9 +2007,9 @@ Options:
1322
2007
  cliVersion: "codex-token-tracker {version}",
1323
2008
  cliUnknownCommand: "Unknown command: {command}",
1324
2009
  cliNoDisplay: "No display detected \u2014 starting agent mode (run `codex-tracker menubar` on a desktop).",
1325
- cliNoElectron: "Electron is not installed (optional dependency) \u2014 starting agent mode.",
2010
+ cliNoElectron: "No Electron runtime available \u2014 starting agent mode.",
1326
2011
  cliDownloadingElectron: "Electron runtime not found \u2014 downloading it now (about 100 MB, one time)\u2026",
1327
- 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.",
2012
+ cliElectronDownloadFailed: "Electron download failed. Check the network (set ELECTRON_MIRROR, e.g. https://npmmirror.com/mirrors/electron/, or HTTPS_PROXY) and run `codex-tracker menubar` again; the headless `codex-tracker agent` works without Electron.",
1328
2013
  cliStartingMenubar: "Starting menu bar app\u2026",
1329
2014
  cliLoginStart: "Connecting this device to {dashboard}",
1330
2015
  cliLoginCode: "Your code: {code}",
@@ -1497,9 +2182,9 @@ var zh = {
1497
2182
  cliVersion: "codex-token-tracker {version}",
1498
2183
  cliUnknownCommand: "\u672A\u77E5\u547D\u4EE4\uFF1A{command}",
1499
2184
  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",
1500
- cliNoElectron: "\u672A\u5B89\u88C5 Electron\uFF08\u53EF\u9009\u4F9D\u8D56\uFF09\u2014 \u4EE5 agent \u6A21\u5F0F\u542F\u52A8\u3002",
2185
+ cliNoElectron: "\u6CA1\u6709\u53EF\u7528\u7684 Electron \u8FD0\u884C\u65F6 \u2014 \u4EE5 agent \u6A21\u5F0F\u542F\u52A8\u3002",
1501
2186
  cliDownloadingElectron: "\u672A\u627E\u5230 Electron \u8FD0\u884C\u65F6\uFF0C\u6B63\u5728\u4E0B\u8F7D\uFF08\u7EA6 100 MB\uFF0C\u4EC5\u9700\u4E00\u6B21\uFF09\u2026",
1502
- 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",
2187
+ cliElectronDownloadFailed: "Electron \u4E0B\u8F7D\u5931\u8D25\u3002\u8BF7\u68C0\u67E5\u7F51\u7EDC\uFF08\u53EF\u8BBE\u7F6E ELECTRON_MIRROR\uFF0C\u4F8B\u5982 https://npmmirror.com/mirrors/electron/\uFF0C\u6216 HTTPS_PROXY\uFF09\u540E\u518D\u6B21\u8FD0\u884C `codex-tracker menubar`\uFF1B\u65E0\u754C\u9762\u7684 `codex-tracker agent` \u65E0\u9700 Electron\u3002",
1503
2188
  cliStartingMenubar: "\u6B63\u5728\u542F\u52A8\u83DC\u5355\u680F\u5E94\u7528\u2026",
1504
2189
  cliLoginStart: "\u6B63\u5728\u5C06\u672C\u8BBE\u5907\u8FDE\u63A5\u5230 {dashboard}",
1505
2190
  cliLoginCode: "\u4F60\u7684\u4EE3\u7801\uFF1A{code}",
@@ -4158,7 +4843,7 @@ var __require = /* @__PURE__ */ ((x) => typeof require2 !== "undefined" ? requir
4158
4843
  if (typeof require2 !== "undefined") return require2.apply(this, arguments);
4159
4844
  throw Error('Dynamic require of "' + x + '" is not supported');
4160
4845
  });
4161
- var __commonJS = (cb, mod) => function __require2() {
4846
+ var __commonJS2 = (cb, mod) => function __require2() {
4162
4847
  return mod || (0, cb[__getOwnPropNames2(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
4163
4848
  };
4164
4849
  var __copyProps2 = (to, from, except, desc) => {
@@ -4177,7 +4862,7 @@ var __toESM2 = (mod, isNodeMode, target) => (target = mod != null ? __create2(__
4177
4862
  isNodeMode || !mod || !mod.__esModule ? __defProp6(target, "default", { value: mod, enumerable: true }) : target,
4178
4863
  mod
4179
4864
  ));
4180
- var require_constants = __commonJS({
4865
+ var require_constants = __commonJS2({
4181
4866
  "../node_modules/.pnpm/ws@8.21.0_bufferutil@4.0.9/node_modules/ws/lib/constants.js"(exports2, module2) {
4182
4867
  "use strict";
4183
4868
  var BINARY_TYPES = ["nodebuffer", "arraybuffer", "fragments"];
@@ -4198,7 +4883,7 @@ var require_constants = __commonJS({
4198
4883
  };
4199
4884
  }
4200
4885
  });
4201
- var require_node_gyp_build = __commonJS({
4886
+ var require_node_gyp_build = __commonJS2({
4202
4887
  "../node_modules/.pnpm/node-gyp-build@4.8.4/node_modules/node-gyp-build/node-gyp-build.js"(exports2, module2) {
4203
4888
  var fs10 = __require("fs");
4204
4889
  var path12 = __require("path");
@@ -4365,7 +5050,7 @@ var require_node_gyp_build = __commonJS({
4365
5050
  load.compareTuples = compareTuples;
4366
5051
  }
4367
5052
  });
4368
- var require_node_gyp_build2 = __commonJS({
5053
+ var require_node_gyp_build2 = __commonJS2({
4369
5054
  "../node_modules/.pnpm/node-gyp-build@4.8.4/node_modules/node-gyp-build/index.js"(exports2, module2) {
4370
5055
  var runtimeRequire = typeof __webpack_require__ === "function" ? __non_webpack_require__ : __require;
4371
5056
  if (typeof runtimeRequire.addon === "function") {
@@ -4375,7 +5060,7 @@ var require_node_gyp_build2 = __commonJS({
4375
5060
  }
4376
5061
  }
4377
5062
  });
4378
- var require_fallback = __commonJS({
5063
+ var require_fallback = __commonJS2({
4379
5064
  "../node_modules/.pnpm/bufferutil@4.0.9/node_modules/bufferutil/fallback.js"(exports2, module2) {
4380
5065
  "use strict";
4381
5066
  var mask = (source, mask2, output, offset, length) => {
@@ -4392,7 +5077,7 @@ var require_fallback = __commonJS({
4392
5077
  module2.exports = { mask, unmask };
4393
5078
  }
4394
5079
  });
4395
- var require_bufferutil = __commonJS({
5080
+ var require_bufferutil = __commonJS2({
4396
5081
  "../node_modules/.pnpm/bufferutil@4.0.9/node_modules/bufferutil/index.js"(exports2, module2) {
4397
5082
  "use strict";
4398
5083
  try {
@@ -4402,7 +5087,7 @@ var require_bufferutil = __commonJS({
4402
5087
  }
4403
5088
  }
4404
5089
  });
4405
- var require_buffer_util = __commonJS({
5090
+ var require_buffer_util = __commonJS2({
4406
5091
  "../node_modules/.pnpm/ws@8.21.0_bufferutil@4.0.9/node_modules/ws/lib/buffer-util.js"(exports2, module2) {
4407
5092
  "use strict";
4408
5093
  var { EMPTY_BUFFER } = require_constants();
@@ -4475,7 +5160,7 @@ var require_buffer_util = __commonJS({
4475
5160
  }
4476
5161
  }
4477
5162
  });
4478
- var require_limiter = __commonJS({
5163
+ var require_limiter = __commonJS2({
4479
5164
  "../node_modules/.pnpm/ws@8.21.0_bufferutil@4.0.9/node_modules/ws/lib/limiter.js"(exports2, module2) {
4480
5165
  "use strict";
4481
5166
  var kDone = /* @__PURE__ */ Symbol("kDone");
@@ -4523,7 +5208,7 @@ var require_limiter = __commonJS({
4523
5208
  module2.exports = Limiter;
4524
5209
  }
4525
5210
  });
4526
- var require_permessage_deflate = __commonJS({
5211
+ var require_permessage_deflate = __commonJS2({
4527
5212
  "../node_modules/.pnpm/ws@8.21.0_bufferutil@4.0.9/node_modules/ws/lib/permessage-deflate.js"(exports2, module2) {
4528
5213
  "use strict";
4529
5214
  var zlib = __require("zlib");
@@ -4904,7 +5589,7 @@ var require_permessage_deflate = __commonJS({
4904
5589
  }
4905
5590
  }
4906
5591
  });
4907
- var require_validation = __commonJS({
5592
+ var require_validation = __commonJS2({
4908
5593
  "../node_modules/.pnpm/ws@8.21.0_bufferutil@4.0.9/node_modules/ws/lib/validation.js"(exports2, module2) {
4909
5594
  "use strict";
4910
5595
  var { isUtf8 } = __require("buffer");
@@ -5103,7 +5788,7 @@ var require_validation = __commonJS({
5103
5788
  }
5104
5789
  }
5105
5790
  });
5106
- var require_receiver = __commonJS({
5791
+ var require_receiver = __commonJS2({
5107
5792
  "../node_modules/.pnpm/ws@8.21.0_bufferutil@4.0.9/node_modules/ws/lib/receiver.js"(exports2, module2) {
5108
5793
  "use strict";
5109
5794
  var { Writable } = __require("stream");
@@ -5733,7 +6418,7 @@ var require_receiver = __commonJS({
5733
6418
  module2.exports = Receiver2;
5734
6419
  }
5735
6420
  });
5736
- var require_sender = __commonJS({
6421
+ var require_sender = __commonJS2({
5737
6422
  "../node_modules/.pnpm/ws@8.21.0_bufferutil@4.0.9/node_modules/ws/lib/sender.js"(exports2, module2) {
5738
6423
  "use strict";
5739
6424
  var { Duplex } = __require("stream");
@@ -6224,7 +6909,7 @@ var require_sender = __commonJS({
6224
6909
  }
6225
6910
  }
6226
6911
  });
6227
- var require_event_target = __commonJS({
6912
+ var require_event_target = __commonJS2({
6228
6913
  "../node_modules/.pnpm/ws@8.21.0_bufferutil@4.0.9/node_modules/ws/lib/event-target.js"(exports2, module2) {
6229
6914
  "use strict";
6230
6915
  var { kForOnEventAttribute, kListener } = require_constants();
@@ -6451,7 +7136,7 @@ var require_event_target = __commonJS({
6451
7136
  }
6452
7137
  }
6453
7138
  });
6454
- var require_extension = __commonJS({
7139
+ var require_extension = __commonJS2({
6455
7140
  "../node_modules/.pnpm/ws@8.21.0_bufferutil@4.0.9/node_modules/ws/lib/extension.js"(exports2, module2) {
6456
7141
  "use strict";
6457
7142
  var { tokenChars } = require_validation();
@@ -6602,7 +7287,7 @@ var require_extension = __commonJS({
6602
7287
  module2.exports = { format, parse };
6603
7288
  }
6604
7289
  });
6605
- var require_websocket = __commonJS({
7290
+ var require_websocket = __commonJS2({
6606
7291
  "../node_modules/.pnpm/ws@8.21.0_bufferutil@4.0.9/node_modules/ws/lib/websocket.js"(exports2, module2) {
6607
7292
  "use strict";
6608
7293
  var EventEmitter2 = __require("events");
@@ -7496,7 +8181,7 @@ var require_websocket = __commonJS({
7496
8181
  }
7497
8182
  }
7498
8183
  });
7499
- var require_stream = __commonJS({
8184
+ var require_stream = __commonJS2({
7500
8185
  "../node_modules/.pnpm/ws@8.21.0_bufferutil@4.0.9/node_modules/ws/lib/stream.js"(exports2, module2) {
7501
8186
  "use strict";
7502
8187
  var WebSocket2 = require_websocket();
@@ -7592,7 +8277,7 @@ var require_stream = __commonJS({
7592
8277
  module2.exports = createWebSocketStream2;
7593
8278
  }
7594
8279
  });
7595
- var require_subprotocol = __commonJS({
8280
+ var require_subprotocol = __commonJS2({
7596
8281
  "../node_modules/.pnpm/ws@8.21.0_bufferutil@4.0.9/node_modules/ws/lib/subprotocol.js"(exports2, module2) {
7597
8282
  "use strict";
7598
8283
  var { tokenChars } = require_validation();
@@ -7635,7 +8320,7 @@ var require_subprotocol = __commonJS({
7635
8320
  module2.exports = { parse };
7636
8321
  }
7637
8322
  });
7638
- var require_websocket_server = __commonJS({
8323
+ var require_websocket_server = __commonJS2({
7639
8324
  "../node_modules/.pnpm/ws@8.21.0_bufferutil@4.0.9/node_modules/ws/lib/websocket-server.js"(exports2, module2) {
7640
8325
  "use strict";
7641
8326
  var EventEmitter2 = __require("events");
@@ -9147,7 +9832,7 @@ async function fetchLiveRateLimits(appVersion, timeoutMs = 1e4) {
9147
9832
  var import_node_fs8 = __toESM(require("node:fs"));
9148
9833
  var import_node_path10 = __toESM(require("node:path"));
9149
9834
  var import_node_child_process3 = require("node:child_process");
9150
- var NPM_PACKAGE = "codex-token-tracker";
9835
+ var NPM_PACKAGE = true ? "codex-token-tracker" : "codex-token-tracker";
9151
9836
  var CHECK_TTL_MS = 6 * 60 * 60 * 1e3;
9152
9837
  var REQUEST_TIMEOUT_MS = 8e3;
9153
9838
  var INSTALL_TIMEOUT_MS = 10 * 60 * 1e3;
@@ -9221,7 +9906,8 @@ function updateCommand(pm, spec) {
9221
9906
  return `${pm} ${updateArgs(pm, spec).join(" ")}`;
9222
9907
  }
9223
9908
  function cachePath() {
9224
- return import_node_path10.default.join(configDir(), "update.json");
9909
+ const suffix = NPM_PACKAGE === "codex-token-tracker" ? "" : `-${NPM_PACKAGE}`;
9910
+ return import_node_path10.default.join(configDir(), `update${suffix}.json`);
9225
9911
  }
9226
9912
  function readCache() {
9227
9913
  try {
@@ -13054,9 +13054,9 @@ Options:
13054
13054
  cliVersion: "codex-token-tracker {version}",
13055
13055
  cliUnknownCommand: "Unknown command: {command}",
13056
13056
  cliNoDisplay: "No display detected \u2014 starting agent mode (run `codex-tracker menubar` on a desktop).",
13057
- cliNoElectron: "Electron is not installed (optional dependency) \u2014 starting agent mode.",
13057
+ cliNoElectron: "No Electron runtime available \u2014 starting agent mode.",
13058
13058
  cliDownloadingElectron: "Electron runtime not found \u2014 downloading it now (about 100 MB, one time)\u2026",
13059
- 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.",
13059
+ cliElectronDownloadFailed: "Electron download failed. Check the network (set ELECTRON_MIRROR, e.g. https://npmmirror.com/mirrors/electron/, or HTTPS_PROXY) and run `codex-tracker menubar` again; the headless `codex-tracker agent` works without Electron.",
13060
13060
  cliStartingMenubar: "Starting menu bar app\u2026",
13061
13061
  cliLoginStart: "Connecting this device to {dashboard}",
13062
13062
  cliLoginCode: "Your code: {code}",
@@ -13229,9 +13229,9 @@ Options:
13229
13229
  cliVersion: "codex-token-tracker {version}",
13230
13230
  cliUnknownCommand: "\u672A\u77E5\u547D\u4EE4\uFF1A{command}",
13231
13231
  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",
13232
- cliNoElectron: "\u672A\u5B89\u88C5 Electron\uFF08\u53EF\u9009\u4F9D\u8D56\uFF09\u2014 \u4EE5 agent \u6A21\u5F0F\u542F\u52A8\u3002",
13232
+ cliNoElectron: "\u6CA1\u6709\u53EF\u7528\u7684 Electron \u8FD0\u884C\u65F6 \u2014 \u4EE5 agent \u6A21\u5F0F\u542F\u52A8\u3002",
13233
13233
  cliDownloadingElectron: "\u672A\u627E\u5230 Electron \u8FD0\u884C\u65F6\uFF0C\u6B63\u5728\u4E0B\u8F7D\uFF08\u7EA6 100 MB\uFF0C\u4EC5\u9700\u4E00\u6B21\uFF09\u2026",
13234
- 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",
13234
+ cliElectronDownloadFailed: "Electron \u4E0B\u8F7D\u5931\u8D25\u3002\u8BF7\u68C0\u67E5\u7F51\u7EDC\uFF08\u53EF\u8BBE\u7F6E ELECTRON_MIRROR\uFF0C\u4F8B\u5982 https://npmmirror.com/mirrors/electron/\uFF0C\u6216 HTTPS_PROXY\uFF09\u540E\u518D\u6B21\u8FD0\u884C `codex-tracker menubar`\uFF1B\u65E0\u754C\u9762\u7684 `codex-tracker agent` \u65E0\u9700 Electron\u3002",
13235
13235
  cliStartingMenubar: "\u6B63\u5728\u542F\u52A8\u83DC\u5355\u680F\u5E94\u7528\u2026",
13236
13236
  cliLoginStart: "\u6B63\u5728\u5C06\u672C\u8BBE\u5907\u8FDE\u63A5\u5230 {dashboard}",
13237
13237
  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.2.1",
3
+ "version": "0.2.2",
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",
@@ -47,18 +47,14 @@
47
47
  "publishConfig": {
48
48
  "access": "public"
49
49
  },
50
- "dependencies": {
51
- "menubar": "^9.5.3"
52
- },
53
- "optionalDependencies": {
54
- "electron": "^38.8.6"
55
- },
56
50
  "devDependencies": {
57
51
  "@types/node": "^22.15.0",
58
52
  "@types/react": "^19.2.0",
59
53
  "@types/react-dom": "^19.2.0",
60
54
  "convex": "^1.45.0",
55
+ "electron": "^38.8.6",
61
56
  "esbuild": "^0.28.2",
57
+ "menubar": "^9.5.3",
62
58
  "react": "19.2.8",
63
59
  "react-dom": "19.2.8",
64
60
  "typescript": "~5.9.3",