tokmon 0.23.5 → 0.25.0
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 +25 -3
- package/dist/{bootstrap-ink-WA3ENW2M.js → bootstrap-ink-O55MPGXJ.js} +52 -314
- package/dist/chunk-45YYP2FJ.js +299 -0
- package/dist/{daemon-handle-Y2N2NA6D.js → chunk-AMD4PXDG.js} +2 -2
- package/dist/{chunk-5CWOJMAH.js → chunk-E2YXYU73.js} +2 -0
- package/dist/{chunk-IELQ5EY3.js → chunk-INBZLHJQ.js} +306 -549
- package/dist/{chunk-MJWFCDBB.js → chunk-IOIAXKW2.js} +38 -16
- package/dist/{chunk-3TJVFKXV.js → chunk-QM5E5RJZ.js} +1 -1
- package/dist/chunk-QUGH2XA6.js +275 -0
- package/dist/cli-command-YQ5T4R73.js +526 -0
- package/dist/cli.js +30 -5
- package/dist/{config-QC5QSP3G.js → config-2PXUENQL.js} +1 -1
- package/dist/{daemon-PVYTXJMS.js → daemon-QBOXJFRA.js} +7 -6
- package/dist/daemon-handle-2GVZT55B.js +10 -0
- package/dist/server-23ERUOJ7.js +11 -0
- package/dist/web/assets/{Area-DCES17aZ.js → Area-DbVPPS7M.js} +1 -1
- package/dist/web/assets/{analytics-DDW6zcnj.js → analytics-DS5p9Duq.js} +2 -2
- package/dist/web/assets/{breakdown-D5LPPtqh.js → breakdown-zYF0TXN5.js} +1 -1
- package/dist/web/assets/{chart-bHY7MQV0.js → chart-BZHliIXk.js} +1 -1
- package/dist/web/assets/{explore-DdWB-Pu7.js → explore-DYv8bb2r.js} +1 -1
- package/dist/web/assets/{index-C9jxb2o3.js → index-BO8m4dq1.js} +24 -24
- package/dist/web/assets/index-NnKaHxPO.css +1 -0
- package/dist/web/assets/{models-o1wJnG6w.js → models-P3OwakgO.js} +2 -2
- package/dist/web/assets/overview-5WswYjWK.js +2 -0
- package/dist/web/assets/{panel-DBnK1oy0.js → panel-CpwRWsNg.js} +1 -1
- package/dist/web/assets/{primitives-CBmteetD.js → primitives-Do0zWLZ4.js} +1 -1
- package/dist/web/assets/settings-sheet-uD6-A3tV.js +1 -0
- package/dist/web/assets/{share-sheet-DUee3FlK.js → share-sheet-CimegH2K.js} +2 -2
- package/dist/web/assets/{timeline-BxHwOJA_.js → timeline-Ch94Yv4z.js} +1 -1
- package/dist/web/assets/{use-dialog-trap-30EqxYF-.js → use-dialog-trap-LxEFLutK.js} +1 -1
- package/dist/web/index.html +2 -2
- package/package.json +1 -1
- package/dist/server-XUCQWX6N.js +0 -10
- package/dist/web/assets/index-m0KfWnN2.css +0 -1
- package/dist/web/assets/overview-wq2uAEk4.js +0 -2
- package/dist/web/assets/settings-sheet-CZ6GEPl3.js +0 -1
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
PROVIDERS,
|
|
4
|
+
PROVIDER_ORDER,
|
|
5
|
+
identityFromIdToken,
|
|
6
|
+
readClaudeIdentity,
|
|
7
|
+
readJson
|
|
8
|
+
} from "./chunk-INBZLHJQ.js";
|
|
9
|
+
import {
|
|
10
|
+
expandHome,
|
|
11
|
+
slugify
|
|
12
|
+
} from "./chunk-E2YXYU73.js";
|
|
13
|
+
|
|
14
|
+
// src/accounts.ts
|
|
15
|
+
import { existsSync, readdirSync, readFileSync as readFileSync2, statSync } from "fs";
|
|
16
|
+
import { homedir } from "os";
|
|
17
|
+
import { basename, join as join2, resolve } from "path";
|
|
18
|
+
|
|
19
|
+
// src/providers/codex/identity.ts
|
|
20
|
+
import { readFileSync } from "fs";
|
|
21
|
+
import { join } from "path";
|
|
22
|
+
function codexAuthPaths(homeDir) {
|
|
23
|
+
return [join(homeDir, ".codex", "auth.json"), join(homeDir, "auth.json")];
|
|
24
|
+
}
|
|
25
|
+
function readCodexIdentity(homeDir) {
|
|
26
|
+
for (const path of codexAuthPaths(homeDir)) {
|
|
27
|
+
try {
|
|
28
|
+
const parsed = JSON.parse(readFileSync(path, "utf-8"));
|
|
29
|
+
const { email, displayName, payload } = identityFromIdToken(parsed?.tokens?.id_token);
|
|
30
|
+
if (!payload) continue;
|
|
31
|
+
return { email, displayName };
|
|
32
|
+
} catch {
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return {};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// src/accounts.ts
|
|
39
|
+
function accountKey(providerId, homeDir) {
|
|
40
|
+
return `${providerId}:${homeDir ? resolve(expandHome(homeDir)) : homedir()}`;
|
|
41
|
+
}
|
|
42
|
+
function uniqueId(base, used) {
|
|
43
|
+
let id = slugify(base) || "account";
|
|
44
|
+
if (!used.has(id)) {
|
|
45
|
+
used.add(id);
|
|
46
|
+
return id;
|
|
47
|
+
}
|
|
48
|
+
for (let i = 2; i < 1e3; i++) {
|
|
49
|
+
const next = `${id}_${i}`;
|
|
50
|
+
if (!used.has(next)) {
|
|
51
|
+
used.add(next);
|
|
52
|
+
return next;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
id = `${id}_${Date.now()}`;
|
|
56
|
+
used.add(id);
|
|
57
|
+
return id;
|
|
58
|
+
}
|
|
59
|
+
function hasClaudeState(homeDir) {
|
|
60
|
+
return existsSync(join2(homeDir, ".claude.json")) || existsSync(join2(homeDir, ".claude", ".credentials.json")) || existsSync(join2(homeDir, ".claude", "projects")) || existsSync(join2(homeDir, ".config", "claude", ".credentials.json")) || existsSync(join2(homeDir, ".config", "claude", "projects"));
|
|
61
|
+
}
|
|
62
|
+
function candidateAlternateHomes(prefix) {
|
|
63
|
+
const home = homedir();
|
|
64
|
+
let entries;
|
|
65
|
+
try {
|
|
66
|
+
entries = readdirSync(home);
|
|
67
|
+
} catch {
|
|
68
|
+
return [];
|
|
69
|
+
}
|
|
70
|
+
const out = [];
|
|
71
|
+
const pattern = new RegExp(`^\\.${prefix}[_-]`);
|
|
72
|
+
for (const name of entries) {
|
|
73
|
+
if (!pattern.test(name)) continue;
|
|
74
|
+
const path = join2(home, name);
|
|
75
|
+
try {
|
|
76
|
+
if (!statSync(path).isDirectory()) continue;
|
|
77
|
+
out.push(path);
|
|
78
|
+
} catch {
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return out.sort();
|
|
82
|
+
}
|
|
83
|
+
function labelForClaudeHome(homeDir) {
|
|
84
|
+
const identity = readClaudeIdentity(homeDir);
|
|
85
|
+
if (identity.email) return `Claude ${identity.email}`;
|
|
86
|
+
if (identity.displayName) return `Claude ${identity.displayName}`;
|
|
87
|
+
const raw = basename(homeDir).replace(/^\.claude[_-]?/, "").replace(/[_-]+/g, " ").trim();
|
|
88
|
+
return raw ? `Claude ${raw}` : "Claude";
|
|
89
|
+
}
|
|
90
|
+
function hasCodexAuth(homeDir) {
|
|
91
|
+
for (const path of codexAuthPaths(homeDir)) {
|
|
92
|
+
try {
|
|
93
|
+
const parsed = JSON.parse(readFileSync2(path, "utf-8"));
|
|
94
|
+
const accessToken = parsed?.tokens?.access_token;
|
|
95
|
+
if (typeof accessToken === "string" && accessToken.trim()) return true;
|
|
96
|
+
} catch {
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
function labelForCodexHome(homeDir) {
|
|
102
|
+
const identity = readCodexIdentity(homeDir);
|
|
103
|
+
if (identity.email) return `Codex ${identity.email}`;
|
|
104
|
+
if (identity.displayName) return `Codex ${identity.displayName}`;
|
|
105
|
+
const raw = basename(homeDir).replace(/^\.codex[_-]?/, "").replace(/[_-]+/g, " ").trim();
|
|
106
|
+
return raw ? `Codex ${raw}` : "Codex";
|
|
107
|
+
}
|
|
108
|
+
function discoverClaudeAccounts(usedIds) {
|
|
109
|
+
const provider = PROVIDERS.claude;
|
|
110
|
+
const out = [];
|
|
111
|
+
for (const homeDir of candidateAlternateHomes("claude")) {
|
|
112
|
+
if (!hasClaudeState(homeDir)) continue;
|
|
113
|
+
const suffix = basename(homeDir).replace(/^\.claude[_-]?/, "") || basename(homeDir);
|
|
114
|
+
out.push({
|
|
115
|
+
id: uniqueId(`claude_${suffix}`, usedIds),
|
|
116
|
+
providerId: "claude",
|
|
117
|
+
name: labelForClaudeHome(homeDir),
|
|
118
|
+
color: provider.color,
|
|
119
|
+
homeDir
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
return out;
|
|
123
|
+
}
|
|
124
|
+
function discoverCodexAccounts(usedIds) {
|
|
125
|
+
const provider = PROVIDERS.codex;
|
|
126
|
+
const out = [];
|
|
127
|
+
for (const homeDir of candidateAlternateHomes("codex")) {
|
|
128
|
+
if (!hasCodexAuth(homeDir)) continue;
|
|
129
|
+
const suffix = basename(homeDir).replace(/^\.codex[_-]?/, "") || basename(homeDir);
|
|
130
|
+
out.push({
|
|
131
|
+
id: uniqueId(`codex_${suffix}`, usedIds),
|
|
132
|
+
providerId: "codex",
|
|
133
|
+
name: labelForCodexHome(homeDir),
|
|
134
|
+
color: provider.color,
|
|
135
|
+
homeDir
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
return out;
|
|
139
|
+
}
|
|
140
|
+
function discoverProviderAccounts(providerId, usedIds) {
|
|
141
|
+
if (providerId === "claude") return discoverClaudeAccounts(usedIds);
|
|
142
|
+
if (providerId === "codex") return discoverCodexAccounts(usedIds);
|
|
143
|
+
return [];
|
|
144
|
+
}
|
|
145
|
+
function buildAccounts(config, detected) {
|
|
146
|
+
const out = [];
|
|
147
|
+
const usedIds = new Set(config.accounts.map((a) => a.id));
|
|
148
|
+
const seenKeys = /* @__PURE__ */ new Set();
|
|
149
|
+
const add = (account) => {
|
|
150
|
+
const key = accountKey(account.providerId, account.homeDir);
|
|
151
|
+
if (seenKeys.has(key)) return;
|
|
152
|
+
seenKeys.add(key);
|
|
153
|
+
out.push(account);
|
|
154
|
+
};
|
|
155
|
+
for (const pid of PROVIDER_ORDER) {
|
|
156
|
+
if (config.disabledProviders.includes(pid)) continue;
|
|
157
|
+
const provider = PROVIDERS[pid];
|
|
158
|
+
const configured = config.accounts.filter((a) => a.providerId === pid);
|
|
159
|
+
for (const a of configured) {
|
|
160
|
+
add({
|
|
161
|
+
id: a.id,
|
|
162
|
+
providerId: pid,
|
|
163
|
+
name: a.name,
|
|
164
|
+
color: a.color || provider.color,
|
|
165
|
+
homeDir: a.homeDir && a.homeDir !== "~" ? expandHome(a.homeDir) : void 0
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
const discovered = discoverProviderAccounts(pid, usedIds);
|
|
169
|
+
if (detected.includes(pid)) {
|
|
170
|
+
add({ id: pid, providerId: pid, name: provider.name, color: provider.color, homeDir: void 0 });
|
|
171
|
+
}
|
|
172
|
+
for (const account of discovered) {
|
|
173
|
+
add(account);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
return out;
|
|
177
|
+
}
|
|
178
|
+
function accountsByProvider(accounts) {
|
|
179
|
+
const groups = [];
|
|
180
|
+
for (const pid of PROVIDER_ORDER) {
|
|
181
|
+
const list = accounts.filter((a) => a.providerId === pid);
|
|
182
|
+
if (list.length > 0) groups.push({ provider: pid, accounts: list });
|
|
183
|
+
}
|
|
184
|
+
return groups;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// src/shared/colors.ts
|
|
188
|
+
var FALLBACK_HEX = "#8d9090";
|
|
189
|
+
var NAMED_HEX = {
|
|
190
|
+
green: "#6caa71",
|
|
191
|
+
greenBright: "#79be7e",
|
|
192
|
+
cyan: "#7ccbcd",
|
|
193
|
+
cyanBright: "#84dde0",
|
|
194
|
+
blue: "#6d96b4",
|
|
195
|
+
blueBright: "#67b5ed",
|
|
196
|
+
magenta: "#bd7bcd",
|
|
197
|
+
magentaBright: "#d389e5",
|
|
198
|
+
yellow: "#c4ac62",
|
|
199
|
+
yellowBright: "#d9c074",
|
|
200
|
+
red: "#b45648",
|
|
201
|
+
redBright: "#cf6a5a",
|
|
202
|
+
white: "#dee5eb",
|
|
203
|
+
whiteBright: "#f3f5f5",
|
|
204
|
+
gray: FALLBACK_HEX,
|
|
205
|
+
grey: FALLBACK_HEX
|
|
206
|
+
};
|
|
207
|
+
var PROVIDER_HEX = {
|
|
208
|
+
claude: NAMED_HEX.green,
|
|
209
|
+
codex: NAMED_HEX.cyan,
|
|
210
|
+
cursor: NAMED_HEX.magenta,
|
|
211
|
+
copilot: NAMED_HEX.white,
|
|
212
|
+
pi: NAMED_HEX.blue,
|
|
213
|
+
opencode: NAMED_HEX.yellow,
|
|
214
|
+
antigravity: NAMED_HEX.red,
|
|
215
|
+
gemini: NAMED_HEX.greenBright,
|
|
216
|
+
grok: NAMED_HEX.yellowBright
|
|
217
|
+
};
|
|
218
|
+
function namedHex(name) {
|
|
219
|
+
if (!name) return FALLBACK_HEX;
|
|
220
|
+
if (name.startsWith("#")) return name;
|
|
221
|
+
return NAMED_HEX[name] ?? FALLBACK_HEX;
|
|
222
|
+
}
|
|
223
|
+
function colorHex(accountColor, providerColorName) {
|
|
224
|
+
if (accountColor) {
|
|
225
|
+
if (accountColor.startsWith("#")) return accountColor;
|
|
226
|
+
const named = NAMED_HEX[accountColor];
|
|
227
|
+
if (named) return named;
|
|
228
|
+
}
|
|
229
|
+
return namedHex(providerColorName);
|
|
230
|
+
}
|
|
231
|
+
var MODEL_PALETTE = [
|
|
232
|
+
"#00d7ff",
|
|
233
|
+
"#00d787",
|
|
234
|
+
"#e6b450",
|
|
235
|
+
"#d75f87",
|
|
236
|
+
"#5f87ff",
|
|
237
|
+
"#af87ff",
|
|
238
|
+
"#5fd7a7",
|
|
239
|
+
"#ff8787",
|
|
240
|
+
"#d7af5f",
|
|
241
|
+
"#87d7ff",
|
|
242
|
+
"#d787d7",
|
|
243
|
+
"#9ee493",
|
|
244
|
+
"#ffb454",
|
|
245
|
+
"#7aa2f7",
|
|
246
|
+
"#bb9af7"
|
|
247
|
+
];
|
|
248
|
+
var modelColorCache = /* @__PURE__ */ new Map();
|
|
249
|
+
function modelColor(name) {
|
|
250
|
+
const cached = modelColorCache.get(name);
|
|
251
|
+
if (cached) return cached;
|
|
252
|
+
let hash = 0;
|
|
253
|
+
for (let i = 0; i < name.length; i++) hash = hash * 31 + name.charCodeAt(i) >>> 0;
|
|
254
|
+
const color = MODEL_PALETTE[hash % MODEL_PALETTE.length];
|
|
255
|
+
modelColorCache.set(name, color);
|
|
256
|
+
return color;
|
|
257
|
+
}
|
|
258
|
+
var TOKEN_BUCKET = {
|
|
259
|
+
input: NAMED_HEX.blue,
|
|
260
|
+
output: NAMED_HEX.green,
|
|
261
|
+
cacheCreate: NAMED_HEX.yellow,
|
|
262
|
+
cacheRead: NAMED_HEX.cyan
|
|
263
|
+
};
|
|
264
|
+
|
|
265
|
+
// src/peak.ts
|
|
266
|
+
async function fetchPeak() {
|
|
267
|
+
try {
|
|
268
|
+
const res = await fetch("https://promoclock.co/api/status", {
|
|
269
|
+
headers: { "Accept": "application/json", "User-Agent": "tokmon" },
|
|
270
|
+
signal: AbortSignal.timeout(3e3)
|
|
271
|
+
});
|
|
272
|
+
if (!res.ok) return null;
|
|
273
|
+
const data = await readJson(res);
|
|
274
|
+
if (!data) return null;
|
|
275
|
+
let state;
|
|
276
|
+
if (data.isPeak === true || data.status === "peak") state = "peak";
|
|
277
|
+
else if (data.isWeekend === true || data.status === "weekend") state = "weekend";
|
|
278
|
+
else if (data.isOffPeak === true || data.status === "off_peak" || data.status === "off-peak") state = "off-peak";
|
|
279
|
+
else return null;
|
|
280
|
+
const minutesUntilChange = typeof data.minutesUntilChange === "number" && Number.isFinite(data.minutesUntilChange) ? data.minutesUntilChange : null;
|
|
281
|
+
return {
|
|
282
|
+
state,
|
|
283
|
+
label: state === "peak" ? "Peak" : state === "weekend" ? "Weekend" : "Off-Peak",
|
|
284
|
+
minutesUntilChange,
|
|
285
|
+
changesAt: minutesUntilChange !== null ? new Date(Date.now() + minutesUntilChange * 6e4).toISOString() : null
|
|
286
|
+
};
|
|
287
|
+
} catch {
|
|
288
|
+
return null;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
export {
|
|
293
|
+
buildAccounts,
|
|
294
|
+
accountsByProvider,
|
|
295
|
+
namedHex,
|
|
296
|
+
colorHex,
|
|
297
|
+
modelColor,
|
|
298
|
+
fetchPeak
|
|
299
|
+
};
|
|
@@ -5,11 +5,10 @@ import {
|
|
|
5
5
|
readLock,
|
|
6
6
|
reclaimDeadLock,
|
|
7
7
|
verifyLock
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-QM5E5RJZ.js";
|
|
9
9
|
import {
|
|
10
10
|
appVersion
|
|
11
11
|
} from "./chunk-SMPY52EV.js";
|
|
12
|
-
import "./chunk-5CWOJMAH.js";
|
|
13
12
|
|
|
14
13
|
// src/client/daemon-handle.ts
|
|
15
14
|
import { spawn } from "child_process";
|
|
@@ -157,6 +156,7 @@ function degraded() {
|
|
|
157
156
|
return { kind: "degraded", baseUrl: null, stop: () => {
|
|
158
157
|
} };
|
|
159
158
|
}
|
|
159
|
+
|
|
160
160
|
export {
|
|
161
161
|
attachOrSpawn
|
|
162
162
|
};
|
|
@@ -26,6 +26,7 @@ var DEFAULTS = {
|
|
|
26
26
|
defaultFocus: "all",
|
|
27
27
|
ascii: "auto",
|
|
28
28
|
allowNetworkAccess: false,
|
|
29
|
+
resetDisplay: "relative",
|
|
29
30
|
knownProviders: []
|
|
30
31
|
};
|
|
31
32
|
var LEGACY_KNOWN = ["claude", "codex", "cursor"];
|
|
@@ -216,6 +217,7 @@ function repairConfig(input) {
|
|
|
216
217
|
defaultFocus: parsed.defaultFocus === "last" ? "last" : "all",
|
|
217
218
|
ascii: parsed.ascii === "on" ? "on" : parsed.ascii === "off" ? "off" : "auto",
|
|
218
219
|
allowNetworkAccess: parsed.allowNetworkAccess === true,
|
|
220
|
+
resetDisplay: parsed.resetDisplay === "absolute" ? "absolute" : "relative",
|
|
219
221
|
knownProviders
|
|
220
222
|
};
|
|
221
223
|
for (const key of Object.keys(DEFAULTS)) {
|