tokmon 0.27.0 → 0.28.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/dist/{bootstrap-ink-3YNJFKCW.js → bootstrap-ink-5LQMSU4B.js} +27 -7
- package/dist/{chunk-RTGMDE7U.js → chunk-IWKSA64G.js} +139 -78
- package/dist/{chunk-OWPJUG4C.js → chunk-JK3U54G7.js} +2 -2
- package/dist/{chunk-VGYBQH5I.js → chunk-KCY53RUE.js} +1 -1
- package/dist/{chunk-4CY725NY.js → chunk-QOA6KOJQ.js} +1 -1
- package/dist/{cli-command-U7RZ2GTD.js → cli-command-HXKWB6IP.js} +2 -2
- package/dist/cli.js +4 -4
- package/dist/{daemon-PQWKWRC6.js → daemon-JCQF645I.js} +3 -3
- package/dist/{server-5WIWS27N.js → server-BJOXAGRI.js} +3 -3
- package/dist/web/assets/{Area-Tx1mUuqM.js → Area-DgGVYaNT.js} +1 -1
- package/dist/web/assets/{analytics-CAzklhXc.js → analytics-D5EvgF4d.js} +2 -2
- package/dist/web/assets/{breakdown-BoPnOv7Y.js → breakdown-CGdJkAHx.js} +1 -1
- package/dist/web/assets/{chart-jK7A9m7R.js → chart-D4KHj2-J.js} +1 -1
- package/dist/web/assets/{explore-e8wtwk7s.js → explore-B2QnGzfO.js} +1 -1
- package/dist/web/assets/{index-C8oe6EfM.js → index-C0txIEHK.js} +6 -6
- package/dist/web/assets/{models-_4IZNDxW.js → models-D7w7JJCX.js} +2 -2
- package/dist/web/assets/{overview-BBOfd_Fd.js → overview-BPz0j397.js} +2 -2
- package/dist/web/assets/{panel-CstB4hPm.js → panel-Da3rkvLu.js} +1 -1
- package/dist/web/assets/{primitives-G9ALG7ih.js → primitives-B8eGD8S_.js} +1 -1
- package/dist/web/assets/{settings-sheet-rq6vbYXM.js → settings-sheet-D6tnWqmt.js} +1 -1
- package/dist/web/assets/{share-sheet-BwmnebRB.js → share-sheet-BXrrMoLk.js} +1 -1
- package/dist/web/assets/{timeline-DkYWH6XW.js → timeline-CiGI4EmA.js} +1 -1
- package/dist/web/assets/{use-dialog-trap-Jci2xaMX.js → use-dialog-trap-Dhs8W7s1.js} +1 -1
- package/dist/web/index.html +1 -1
- package/package.json +1 -1
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
createDaemonRpcClient
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-QOA6KOJQ.js";
|
|
5
5
|
import {
|
|
6
6
|
accountsByProvider,
|
|
7
7
|
buildAccounts,
|
|
8
8
|
fetchPeak,
|
|
9
9
|
modelColor
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-KCY53RUE.js";
|
|
11
11
|
import {
|
|
12
12
|
PROVIDERS,
|
|
13
13
|
PROVIDER_ORDER,
|
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
col,
|
|
16
16
|
currency,
|
|
17
17
|
detectProviders,
|
|
18
|
+
formatAgo,
|
|
18
19
|
formatResetAt,
|
|
19
20
|
resetAt,
|
|
20
21
|
resolveTimezone,
|
|
@@ -23,7 +24,7 @@ import {
|
|
|
23
24
|
time,
|
|
24
25
|
tokens,
|
|
25
26
|
withTimeout
|
|
26
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-IWKSA64G.js";
|
|
27
28
|
import {
|
|
28
29
|
COLOR_PALETTE,
|
|
29
30
|
DEFAULTS,
|
|
@@ -219,6 +220,12 @@ import { memo as memo2 } from "react";
|
|
|
219
220
|
import { Box as Box2, Text as Text2 } from "ink";
|
|
220
221
|
|
|
221
222
|
// src/ui/provider-card.logic.ts
|
|
223
|
+
var BILLING_STALE_AFTER_MS = 30 * 6e4;
|
|
224
|
+
function billingStaleLabel(billingUpdatedAt, now) {
|
|
225
|
+
if (billingUpdatedAt == null || billingUpdatedAt <= 0) return null;
|
|
226
|
+
if (now - billingUpdatedAt < BILLING_STALE_AFTER_MS) return null;
|
|
227
|
+
return `as of ${formatAgo(billingUpdatedAt, now)}`;
|
|
228
|
+
}
|
|
222
229
|
function normalizePlan(plan) {
|
|
223
230
|
if (plan == null) return null;
|
|
224
231
|
const t = plan.trim();
|
|
@@ -253,7 +260,9 @@ function estimateCardHeights(groups, stats) {
|
|
|
253
260
|
if (meta.hasUsage) h += 1;
|
|
254
261
|
const multi = g.accounts.length > 1;
|
|
255
262
|
g.accounts.forEach((a, i) => {
|
|
256
|
-
const
|
|
263
|
+
const s = stats.get(a.id);
|
|
264
|
+
const staleRow = s?.billing && !s.billing.error && s.billing.metrics.length > 0 && billingStaleLabel(s.billing.asOfMs ?? s.billingUpdatedAt, Date.now()) ? 1 : 0;
|
|
265
|
+
const metricRows = (s?.billing?.metrics.length || 1) + staleRow;
|
|
257
266
|
h += metricRows + (multi ? 1 : 0) + (multi && i > 0 ? 1 : 0);
|
|
258
267
|
});
|
|
259
268
|
}
|
|
@@ -460,6 +469,7 @@ function LimitsBlock({ items, inner, showRowPlans, privacyMode, resetDisplay, tz
|
|
|
460
469
|
const barW = Math.max(10, Math.min(46, inner - labelW - resetW - 5));
|
|
461
470
|
return /* @__PURE__ */ jsx2(Box2, { flexDirection: "column", children: items.map(({ account, s }, idx) => {
|
|
462
471
|
const billing = s?.billing;
|
|
472
|
+
const staleLabel = billing && !billing.error && billing.metrics.length > 0 ? billingStaleLabel(billing.asOfMs ?? s?.billingUpdatedAt, Date.now()) : null;
|
|
463
473
|
return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", marginTop: showName && idx > 0 ? 1 : 0, children: [
|
|
464
474
|
showName && (() => {
|
|
465
475
|
const rowPlan = showRowPlans ? normalizePlan(billing?.plan) : null;
|
|
@@ -482,7 +492,16 @@ function LimitsBlock({ items, inner, showRowPlans, privacyMode, resetDisplay, tz
|
|
|
482
492
|
!billing ? /* @__PURE__ */ jsxs2(Text2, { dimColor: true, children: [
|
|
483
493
|
"Fetching",
|
|
484
494
|
glyphs().ellipsis
|
|
485
|
-
] }) : billing.error ? /* @__PURE__ */ jsx2(Text2, { color: "red", wrap: "truncate-end", children: privacyMode ? redactEmail(billing.error) : billing.error }) : billing.metrics.length === 0 ? /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "No data" }) : billing.metrics.map((m, i) => /* @__PURE__ */ jsx2(MetricRow, { m, color: account.color, barW, labelW, resetW, resetDisplay, tz }, `${m.label}${i}`))
|
|
495
|
+
] }) : billing.error ? /* @__PURE__ */ jsx2(Text2, { color: "red", wrap: "truncate-end", children: privacyMode ? redactEmail(billing.error) : billing.error }) : billing.metrics.length === 0 ? /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "No data" }) : billing.metrics.map((m, i) => /* @__PURE__ */ jsx2(MetricRow, { m, color: account.color, barW, labelW, resetW, resetDisplay, tz }, `${m.label}${i}`)),
|
|
496
|
+
staleLabel && /* @__PURE__ */ jsxs2(Text2, { color: "yellow", dimColor: true, children: [
|
|
497
|
+
glyphs().warn,
|
|
498
|
+
" ",
|
|
499
|
+
staleLabel,
|
|
500
|
+
" ",
|
|
501
|
+
glyphs().middot,
|
|
502
|
+
" refreshing",
|
|
503
|
+
glyphs().ellipsis
|
|
504
|
+
] })
|
|
486
505
|
] }, account.id);
|
|
487
506
|
}) });
|
|
488
507
|
}
|
|
@@ -1711,7 +1730,8 @@ function toStatsMap(snapshot, accounts) {
|
|
|
1711
1730
|
out.set(account.id, {
|
|
1712
1731
|
account,
|
|
1713
1732
|
dashboard: wa?.dashboard ?? null,
|
|
1714
|
-
billing: wa?.billing ?? null
|
|
1733
|
+
billing: wa?.billing ?? null,
|
|
1734
|
+
billingUpdatedAt: wa?.billingUpdatedAt ?? null
|
|
1715
1735
|
});
|
|
1716
1736
|
}
|
|
1717
1737
|
return out;
|
|
@@ -3441,7 +3461,7 @@ function App({ interval: cliInterval, initialConfig, baseUrl = null, mode = "deg
|
|
|
3441
3461
|
if (webStartingRef.current) return;
|
|
3442
3462
|
webStartingRef.current = true;
|
|
3443
3463
|
try {
|
|
3444
|
-
const { startWebServer } = await import("./server-
|
|
3464
|
+
const { startWebServer } = await import("./server-BJOXAGRI.js");
|
|
3445
3465
|
const ctrl = await startWebServer({ config: cfg, log: false });
|
|
3446
3466
|
webRef.current = ctrl;
|
|
3447
3467
|
openUrl(ctrl.url);
|
|
@@ -892,7 +892,8 @@ var BillingResultSchema = Schema.Struct({
|
|
|
892
892
|
name: Schema.String,
|
|
893
893
|
usd: Schema.Finite,
|
|
894
894
|
requests: Schema.Finite
|
|
895
|
-
}))))
|
|
895
|
+
})))),
|
|
896
|
+
asOfMs: Schema.optionalKey(Schema.Finite)
|
|
896
897
|
});
|
|
897
898
|
var WebAccountSchema = Schema.Struct({
|
|
898
899
|
id: Schema.String,
|
|
@@ -1003,6 +1004,16 @@ function formatTime(date, tz) {
|
|
|
1003
1004
|
timeZone: tz
|
|
1004
1005
|
});
|
|
1005
1006
|
}
|
|
1007
|
+
function formatAgo(ms, now) {
|
|
1008
|
+
const seconds = Math.max(0, Math.round((now - ms) / 1e3));
|
|
1009
|
+
if (seconds < 2) return "just now";
|
|
1010
|
+
if (seconds < 60) return `${seconds}s ago`;
|
|
1011
|
+
const minutes = Math.round(seconds / 60);
|
|
1012
|
+
if (minutes < 60) return `${minutes}m ago`;
|
|
1013
|
+
const hours = Math.round(minutes / 60);
|
|
1014
|
+
if (hours < 24) return `${hours}h ago`;
|
|
1015
|
+
return `${Math.round(hours / 24)}d ago`;
|
|
1016
|
+
}
|
|
1006
1017
|
function formatShortDate(label, opts = {}) {
|
|
1007
1018
|
const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(label);
|
|
1008
1019
|
if (!match) return label;
|
|
@@ -1128,7 +1139,7 @@ async function detectClaude(homeDir) {
|
|
|
1128
1139
|
return false;
|
|
1129
1140
|
}
|
|
1130
1141
|
function claudePriceFor(model, timestamp = Date.now()) {
|
|
1131
|
-
const m = model.toLowerCase().trim();
|
|
1142
|
+
const m = model.toLowerCase().trim().replace(/\[[^\]]*\]$/, "");
|
|
1132
1143
|
for (const key of PRICE_KEYS) {
|
|
1133
1144
|
if (!m.startsWith(key)) continue;
|
|
1134
1145
|
const rest = m.slice(key.length);
|
|
@@ -2076,7 +2087,7 @@ async function fetchResetCredits(headers) {
|
|
|
2076
2087
|
return void 0;
|
|
2077
2088
|
}
|
|
2078
2089
|
}
|
|
2079
|
-
async function liveBilling(auth) {
|
|
2090
|
+
async function liveBilling(auth, failure) {
|
|
2080
2091
|
try {
|
|
2081
2092
|
const headers = {
|
|
2082
2093
|
"Authorization": `Bearer ${auth.accessToken}`,
|
|
@@ -2085,7 +2096,10 @@ async function liveBilling(auth) {
|
|
|
2085
2096
|
};
|
|
2086
2097
|
if (auth.accountId) headers["ChatGPT-Account-Id"] = auth.accountId;
|
|
2087
2098
|
const res = await fetch(USAGE_URL, { headers, signal: AbortSignal.timeout(1e4) });
|
|
2088
|
-
if (!res.ok)
|
|
2099
|
+
if (!res.ok) {
|
|
2100
|
+
if (failure) failure.status = res.status;
|
|
2101
|
+
return null;
|
|
2102
|
+
}
|
|
2089
2103
|
const data = await readJson(res);
|
|
2090
2104
|
if (!data) return null;
|
|
2091
2105
|
const headerPct = (name) => {
|
|
@@ -2186,19 +2200,19 @@ async function snapshotBilling(homeDir, auth = null) {
|
|
|
2186
2200
|
}
|
|
2187
2201
|
async function codexBilling(account) {
|
|
2188
2202
|
const auth = await getAuth2(account.homeDir);
|
|
2203
|
+
const failure = {};
|
|
2189
2204
|
if (auth) {
|
|
2190
|
-
const live = await liveBilling(auth);
|
|
2205
|
+
const live = await liveBilling(auth, failure);
|
|
2191
2206
|
if (live) return live;
|
|
2192
2207
|
}
|
|
2193
2208
|
const snap = await snapshotBilling(account.homeDir, auth);
|
|
2194
2209
|
if (snap && Date.now() - snap.asOfMs < SNAPSHOT_STALE_MS) {
|
|
2195
|
-
|
|
2196
|
-
return result;
|
|
2210
|
+
return snap;
|
|
2197
2211
|
}
|
|
2198
2212
|
return {
|
|
2199
2213
|
plan: auth?.plan ?? snap?.plan ?? null,
|
|
2200
2214
|
metrics: [],
|
|
2201
|
-
error: auth ?
|
|
2215
|
+
error: auth ? `Usage API failed${failure.status ? ` (HTTP ${failure.status})` : ""} \u2014 run codex to refresh` : "Not logged in \u2014 run codex",
|
|
2202
2216
|
...identityFields(auth)
|
|
2203
2217
|
};
|
|
2204
2218
|
}
|
|
@@ -2789,8 +2803,15 @@ async function fetchLocalEntries(tz, homeDir) {
|
|
|
2789
2803
|
function overlayEntries(api, local, tz) {
|
|
2790
2804
|
if (api.length === 0) return local.map((l) => l.entry);
|
|
2791
2805
|
if (local.length === 0) return api;
|
|
2792
|
-
|
|
2793
|
-
|
|
2806
|
+
let apiMin = Infinity;
|
|
2807
|
+
let apiMax = -Infinity;
|
|
2808
|
+
for (const e of api) {
|
|
2809
|
+
if (e.ts < apiMin) apiMin = e.ts;
|
|
2810
|
+
if (e.ts > apiMax) apiMax = e.ts;
|
|
2811
|
+
}
|
|
2812
|
+
const minDay = dayKey(apiMin, tz);
|
|
2813
|
+
const maxDay = dayKey(apiMax, tz);
|
|
2814
|
+
return [...api, ...local.filter((l) => l.day < minDay || l.day > maxDay).map((l) => l.entry)];
|
|
2794
2815
|
}
|
|
2795
2816
|
async function cursorEntries(since, tz, homeDir) {
|
|
2796
2817
|
const [apiResult, local] = await Promise.all([fetchApiEntries(homeDir), fetchLocalEntries(tz, homeDir)]);
|
|
@@ -2833,6 +2854,33 @@ async function detectPi(homeDir) {
|
|
|
2833
2854
|
return false;
|
|
2834
2855
|
}
|
|
2835
2856
|
}
|
|
2857
|
+
function recordToEntry(obj) {
|
|
2858
|
+
if (obj?.type !== "message") return null;
|
|
2859
|
+
const msg = obj.message;
|
|
2860
|
+
if (msg?.role !== "assistant" || !msg?.usage) return null;
|
|
2861
|
+
const u = msg.usage;
|
|
2862
|
+
const ts = timestampMs(obj.timestamp ?? msg.timestamp);
|
|
2863
|
+
if (ts === null) return null;
|
|
2864
|
+
const input = safeNum(u.input);
|
|
2865
|
+
const output = safeNum(u.output);
|
|
2866
|
+
const cacheRead = safeNum(u.cacheRead);
|
|
2867
|
+
const cacheCreate = safeNum(u.cacheWrite);
|
|
2868
|
+
if (input + output + cacheRead + cacheCreate === 0) return null;
|
|
2869
|
+
const c = u.cost ?? {};
|
|
2870
|
+
const costInput = finitePositive(c.input);
|
|
2871
|
+
const cacheSavings = input > 0 && cacheRead > 0 ? Math.max(0, cacheRead * (costInput / input) - finitePositive(c.cacheRead)) : 0;
|
|
2872
|
+
const model = typeof msg.responseModel === "string" && msg.responseModel || typeof msg.model === "string" && msg.model || "unknown";
|
|
2873
|
+
return {
|
|
2874
|
+
ts,
|
|
2875
|
+
model,
|
|
2876
|
+
cost: finitePositive(c.total),
|
|
2877
|
+
input,
|
|
2878
|
+
output,
|
|
2879
|
+
cacheCreate,
|
|
2880
|
+
cacheRead,
|
|
2881
|
+
cacheSavings
|
|
2882
|
+
};
|
|
2883
|
+
}
|
|
2836
2884
|
async function parseFile3(path) {
|
|
2837
2885
|
const entries = [];
|
|
2838
2886
|
const stream = createReadStream4(path);
|
|
@@ -2844,32 +2892,8 @@ async function parseFile3(path) {
|
|
|
2844
2892
|
if (!rawLine.includes('"usage"')) continue;
|
|
2845
2893
|
try {
|
|
2846
2894
|
const line = rawLine.charCodeAt(0) === 65279 ? rawLine.slice(1) : rawLine;
|
|
2847
|
-
const
|
|
2848
|
-
if (
|
|
2849
|
-
const msg = obj.message;
|
|
2850
|
-
if (msg?.role !== "assistant" || !msg?.usage) continue;
|
|
2851
|
-
const u = msg.usage;
|
|
2852
|
-
const ts = timestampMs(obj.timestamp ?? msg.timestamp);
|
|
2853
|
-
if (ts === null) continue;
|
|
2854
|
-
const input = safeNum(u.input);
|
|
2855
|
-
const output = safeNum(u.output);
|
|
2856
|
-
const cacheRead = safeNum(u.cacheRead);
|
|
2857
|
-
const cacheCreate = safeNum(u.cacheWrite);
|
|
2858
|
-
if (input + output + cacheRead + cacheCreate === 0) continue;
|
|
2859
|
-
const c = u.cost ?? {};
|
|
2860
|
-
const costInput = finitePositive(c.input);
|
|
2861
|
-
const cacheSavings = input > 0 && cacheRead > 0 ? Math.max(0, cacheRead * (costInput / input) - finitePositive(c.cacheRead)) : 0;
|
|
2862
|
-
const model = typeof msg.responseModel === "string" && msg.responseModel || typeof msg.model === "string" && msg.model || "unknown";
|
|
2863
|
-
entries.push({
|
|
2864
|
-
ts,
|
|
2865
|
-
model,
|
|
2866
|
-
cost: finitePositive(c.total),
|
|
2867
|
-
input,
|
|
2868
|
-
output,
|
|
2869
|
-
cacheCreate,
|
|
2870
|
-
cacheRead,
|
|
2871
|
-
cacheSavings
|
|
2872
|
-
});
|
|
2895
|
+
const entry = recordToEntry(JSON.parse(line));
|
|
2896
|
+
if (entry) entries.push(entry);
|
|
2873
2897
|
} catch {
|
|
2874
2898
|
}
|
|
2875
2899
|
}
|
|
@@ -2951,31 +2975,35 @@ async function findDb(homeDir) {
|
|
|
2951
2975
|
async function detectOpencode(homeDir) {
|
|
2952
2976
|
return await findDb(homeDir) !== null;
|
|
2953
2977
|
}
|
|
2978
|
+
function rowToEntry(row) {
|
|
2979
|
+
const ts = finitePositive(row.ts);
|
|
2980
|
+
if (!ts) return null;
|
|
2981
|
+
const input = finitePositive(row.input);
|
|
2982
|
+
const output = finitePositive(row.output);
|
|
2983
|
+
const cacheRead = finitePositive(row.cacheRead);
|
|
2984
|
+
const cacheCreate = finitePositive(row.cacheWrite);
|
|
2985
|
+
if (input + output + cacheRead + cacheCreate === 0) return null;
|
|
2986
|
+
return {
|
|
2987
|
+
ts,
|
|
2988
|
+
model: typeof row.model === "string" && row.model ? row.model : "unknown",
|
|
2989
|
+
cost: finitePositive(row.cost),
|
|
2990
|
+
input,
|
|
2991
|
+
output,
|
|
2992
|
+
cacheCreate,
|
|
2993
|
+
cacheRead,
|
|
2994
|
+
cacheSavings: 0
|
|
2995
|
+
};
|
|
2996
|
+
}
|
|
2954
2997
|
async function loadEntries4(since, homeDir) {
|
|
2955
2998
|
const db = await findDb(homeDir);
|
|
2956
2999
|
if (!db) return [];
|
|
2957
|
-
const sql = "SELECT CASE WHEN time_created < 10000000000 THEN time_created * 1000 ELSE time_created END AS ts, json_extract(data,'$.modelID') AS model, json_extract(data,'$.cost') AS cost, json_extract(data,'$.tokens.input') AS input, json_extract(data,'$.tokens.output') AS output, json_extract(data,'$.tokens.
|
|
3000
|
+
const sql = "SELECT CASE WHEN time_created < 10000000000 THEN time_created * 1000 ELSE time_created END AS ts, json_extract(data,'$.modelID') AS model, json_extract(data,'$.cost') AS cost, json_extract(data,'$.tokens.input') AS input, json_extract(data,'$.tokens.output') AS output, json_extract(data,'$.tokens.cache.read') AS cacheRead, json_extract(data,'$.tokens.cache.write') AS cacheWrite FROM message WHERE json_valid(data) AND json_extract(data,'$.role')='assistant' AND json_type(data,'$.tokens')='object' AND (CASE WHEN time_created < 10000000000 THEN time_created * 1000 ELSE time_created END) >= ?;";
|
|
2958
3001
|
const res = await runSqlite(db, sql, [Math.floor(since)]);
|
|
2959
3002
|
if (res.status !== "ok") return [];
|
|
2960
3003
|
const entries = [];
|
|
2961
3004
|
for (const row of res.rows) {
|
|
2962
|
-
const
|
|
2963
|
-
if (
|
|
2964
|
-
const input = finitePositive(row.input);
|
|
2965
|
-
const output = finitePositive(row.output) + finitePositive(row.reasoning);
|
|
2966
|
-
const cacheRead = finitePositive(row.cacheRead);
|
|
2967
|
-
const cacheCreate = finitePositive(row.cacheWrite);
|
|
2968
|
-
if (input + output + cacheRead + cacheCreate === 0) continue;
|
|
2969
|
-
entries.push({
|
|
2970
|
-
ts,
|
|
2971
|
-
model: typeof row.model === "string" && row.model ? row.model : "unknown",
|
|
2972
|
-
cost: finitePositive(row.cost),
|
|
2973
|
-
input,
|
|
2974
|
-
output,
|
|
2975
|
-
cacheCreate,
|
|
2976
|
-
cacheRead,
|
|
2977
|
-
cacheSavings: 0
|
|
2978
|
-
});
|
|
3005
|
+
const entry = rowToEntry(row);
|
|
3006
|
+
if (entry) entries.push(entry);
|
|
2979
3007
|
}
|
|
2980
3008
|
return entries;
|
|
2981
3009
|
}
|
|
@@ -3442,11 +3470,16 @@ async function discoverGoogleOAuthClient() {
|
|
|
3442
3470
|
}
|
|
3443
3471
|
return null;
|
|
3444
3472
|
}
|
|
3473
|
+
var discoverClient = discoverGoogleOAuthClient;
|
|
3445
3474
|
async function resolveGoogleClient() {
|
|
3446
3475
|
const envId = process.env.TOKMON_GOOGLE_CLIENT_ID?.trim();
|
|
3447
3476
|
const envSecret = process.env.TOKMON_GOOGLE_CLIENT_SECRET?.trim();
|
|
3448
3477
|
if (envId && envSecret) return { clientId: envId, clientSecret: envSecret };
|
|
3449
|
-
if (cachedClient
|
|
3478
|
+
if (cachedClient == null) {
|
|
3479
|
+
const client = await discoverClient();
|
|
3480
|
+
if (client) cachedClient = client;
|
|
3481
|
+
return client;
|
|
3482
|
+
}
|
|
3450
3483
|
return cachedClient;
|
|
3451
3484
|
}
|
|
3452
3485
|
async function refreshAccessToken(refreshToken) {
|
|
@@ -3737,38 +3770,38 @@ import { createInterface as createInterface5 } from "readline";
|
|
|
3737
3770
|
import { join as join16 } from "path";
|
|
3738
3771
|
import { homedir as homedir12 } from "os";
|
|
3739
3772
|
var PRICING3 = {
|
|
3740
|
-
"gemini-3.1-pro-preview": { in: 2e-6, out: 12e-6, cr: 2e-7 },
|
|
3741
|
-
"gemini-3.1-pro": { in: 2e-6, out: 12e-6, cr: 2e-7 },
|
|
3742
|
-
"gemini-3-pro-preview": { in: 2e-6, out: 12e-6, cr: 2e-7 },
|
|
3743
|
-
"gemini-3-pro": { in: 2e-6, out: 12e-6, cr: 2e-7 },
|
|
3773
|
+
"gemini-3.1-pro-preview": { in: 2e-6, out: 12e-6, cr: 2e-7, long: { in: 4e-6, out: 18e-6, cr: 4e-7 } },
|
|
3774
|
+
"gemini-3.1-pro": { in: 2e-6, out: 12e-6, cr: 2e-7, long: { in: 4e-6, out: 18e-6, cr: 4e-7 } },
|
|
3775
|
+
"gemini-3-pro-preview": { in: 2e-6, out: 12e-6, cr: 2e-7, long: { in: 4e-6, out: 18e-6, cr: 4e-7 } },
|
|
3776
|
+
"gemini-3-pro": { in: 2e-6, out: 12e-6, cr: 2e-7, long: { in: 4e-6, out: 18e-6, cr: 4e-7 } },
|
|
3744
3777
|
"gemini-3.5-flash": { in: 75e-8, out: 45e-7, cr: 75e-9 },
|
|
3745
3778
|
"gemini-3-flash-preview": { in: 5e-7, out: 3e-6, cr: 5e-8 },
|
|
3746
3779
|
"gemini-3-flash": { in: 5e-7, out: 3e-6, cr: 5e-8 },
|
|
3747
3780
|
"gemini-2.5-flash-lite": { in: 1e-7, out: 4e-7, cr: 1e-8 },
|
|
3748
3781
|
"gemini-3.1-flash-lite": { in: 25e-8, out: 15e-7, cr: 25e-9 },
|
|
3749
3782
|
"gemini-2.5-flash": { in: 3e-7, out: 25e-7, cr: 3e-8 },
|
|
3750
|
-
"gemini-2.5-pro": { in: 125e-8, out: 1e-5, cr: 125e-9 },
|
|
3783
|
+
"gemini-2.5-pro": { in: 125e-8, out: 1e-5, cr: 125e-9, long: { in: 25e-7, out: 15e-6, cr: 25e-8 } },
|
|
3751
3784
|
"gemini-2.0-flash": { in: 1e-7, out: 4e-7, cr: 25e-9 }
|
|
3752
3785
|
};
|
|
3753
3786
|
var PRICE_KEYS3 = Object.keys(PRICING3).sort((a, b) => b.length - a.length);
|
|
3754
|
-
var
|
|
3755
|
-
var GEMINI_31_PRO_LONG_PRICE = { in: 4e-6, out: 18e-6, cr: 4e-7 };
|
|
3787
|
+
var FALLBACK_PRICE2 = PRICING3["gemini-3.1-pro"];
|
|
3756
3788
|
var MAX_SESSION_FILE_BYTES = 16 * 1024 * 1024;
|
|
3757
3789
|
var MAX_JSON_ENTRIES = 1e5;
|
|
3758
3790
|
function geminiTmpDir(homeDir) {
|
|
3759
3791
|
return join16(homeDir ?? homedir12(), ".gemini", "tmp");
|
|
3760
3792
|
}
|
|
3761
|
-
function
|
|
3762
|
-
const m = model.toLowerCase().trim();
|
|
3793
|
+
function resolvePricing(m) {
|
|
3763
3794
|
for (const key of PRICE_KEYS3) {
|
|
3764
3795
|
if (!m.startsWith(key)) continue;
|
|
3765
3796
|
const rest = m.slice(key.length);
|
|
3766
|
-
if (rest === "" || rest[0] === "-")
|
|
3767
|
-
if (key.startsWith("gemini-3.1-pro") && promptTokens > 2e5) return GEMINI_31_PRO_LONG_PRICE;
|
|
3768
|
-
return PRICING3[key];
|
|
3769
|
-
}
|
|
3797
|
+
if (rest === "" || rest[0] === "-") return PRICING3[key];
|
|
3770
3798
|
}
|
|
3771
|
-
return
|
|
3799
|
+
return FALLBACK_PRICE2;
|
|
3800
|
+
}
|
|
3801
|
+
function geminiPriceFor(model, promptTokens = 0) {
|
|
3802
|
+
const p = resolvePricing(model.toLowerCase().trim());
|
|
3803
|
+
if (promptTokens > 2e5 && p.long) return p.long;
|
|
3804
|
+
return { in: p.in, out: p.out, cr: p.cr };
|
|
3772
3805
|
}
|
|
3773
3806
|
function shortModel2(model) {
|
|
3774
3807
|
return model.replace(/(-preview|-customtools)+$/, "");
|
|
@@ -4242,7 +4275,7 @@ var PRICING4 = {
|
|
|
4242
4275
|
"grok-code-fast": { in: 1e-6, cr: 2e-7, out: 2e-6 },
|
|
4243
4276
|
"grok-build": { in: 1e-6, cr: 2e-7, out: 2e-6 }
|
|
4244
4277
|
};
|
|
4245
|
-
var
|
|
4278
|
+
var FALLBACK_PRICE3 = PRICING4["grok-4.5"];
|
|
4246
4279
|
var PRICE_KEYS4 = Object.keys(PRICING4).sort((a, b) => b.length - a.length);
|
|
4247
4280
|
var MAX_SESSION_GROUPS = 128;
|
|
4248
4281
|
var MAX_SESSIONS_PER_GROUP = 512;
|
|
@@ -4265,7 +4298,7 @@ function priceFor(model) {
|
|
|
4265
4298
|
for (const key of PRICE_KEYS4) {
|
|
4266
4299
|
if (modelKeyMatches2(m, key)) return PRICING4[key];
|
|
4267
4300
|
}
|
|
4268
|
-
return
|
|
4301
|
+
return FALLBACK_PRICE3;
|
|
4269
4302
|
}
|
|
4270
4303
|
async function detectGrok(homeDir) {
|
|
4271
4304
|
for (const home of grokHomes(homeDir)) {
|
|
@@ -4279,6 +4312,14 @@ async function detectGrok(homeDir) {
|
|
|
4279
4312
|
}
|
|
4280
4313
|
return false;
|
|
4281
4314
|
}
|
|
4315
|
+
async function byMtimeDesc(dir, names) {
|
|
4316
|
+
const stated = await Promise.all(names.map(async (name) => {
|
|
4317
|
+
const st = await fsStat6(join19(dir, name)).catch(() => null);
|
|
4318
|
+
return { name, mtimeMs: st ? st.mtimeMs : -Infinity };
|
|
4319
|
+
}));
|
|
4320
|
+
stated.sort((a, b) => b.mtimeMs - a.mtimeMs || a.name.localeCompare(b.name));
|
|
4321
|
+
return stated.map((s) => s.name);
|
|
4322
|
+
}
|
|
4282
4323
|
async function loadSessionModels(home) {
|
|
4283
4324
|
const out = /* @__PURE__ */ new Map();
|
|
4284
4325
|
const sessionsRoot = join19(home, "sessions");
|
|
@@ -4288,8 +4329,9 @@ async function loadSessionModels(home) {
|
|
|
4288
4329
|
} catch {
|
|
4289
4330
|
return out;
|
|
4290
4331
|
}
|
|
4291
|
-
|
|
4292
|
-
|
|
4332
|
+
const groupNames = groups.filter((g) => g !== "session_search.sqlite" && !g.startsWith("."));
|
|
4333
|
+
const orderedGroups = (await byMtimeDesc(sessionsRoot, groupNames)).slice(0, MAX_SESSION_GROUPS);
|
|
4334
|
+
for (const group of orderedGroups) {
|
|
4293
4335
|
const groupDir = join19(sessionsRoot, group);
|
|
4294
4336
|
let sessions;
|
|
4295
4337
|
try {
|
|
@@ -4297,7 +4339,9 @@ async function loadSessionModels(home) {
|
|
|
4297
4339
|
} catch {
|
|
4298
4340
|
continue;
|
|
4299
4341
|
}
|
|
4300
|
-
|
|
4342
|
+
const sessionNames = sessions.filter((s) => !s.startsWith("."));
|
|
4343
|
+
const orderedSessions = (await byMtimeDesc(groupDir, sessionNames)).slice(0, MAX_SESSIONS_PER_GROUP);
|
|
4344
|
+
for (const sid of orderedSessions) {
|
|
4301
4345
|
try {
|
|
4302
4346
|
const raw = JSON.parse(await readFile8(join19(groupDir, sid, "summary.json"), "utf-8"));
|
|
4303
4347
|
const model = typeof raw?.current_model_id === "string" && raw.current_model_id ? raw.current_model_id : null;
|
|
@@ -4332,21 +4376,37 @@ function costOf2(model, input, cacheRead, output) {
|
|
|
4332
4376
|
const cacheSavings = cacheRead * Math.max(0, p.in - p.cr);
|
|
4333
4377
|
return { cost, cacheSavings };
|
|
4334
4378
|
}
|
|
4379
|
+
var DEFAULT_MODEL = "grok-4.5";
|
|
4380
|
+
function modelChangeFrom(obj) {
|
|
4381
|
+
if (obj?.msg !== "model changed" && obj?.msg !== "backend_search: model switch") return null;
|
|
4382
|
+
const ctx = obj.ctx;
|
|
4383
|
+
if (!ctx || typeof ctx !== "object") return null;
|
|
4384
|
+
const c = ctx;
|
|
4385
|
+
const model = typeof c.model === "string" ? c.model : typeof c.new_model === "string" ? c.new_model : null;
|
|
4386
|
+
return model && model.trim() ? model : null;
|
|
4387
|
+
}
|
|
4335
4388
|
async function parseUnifiedLog(path, models) {
|
|
4336
4389
|
const entries = [];
|
|
4390
|
+
const activeModel = /* @__PURE__ */ new Map();
|
|
4337
4391
|
const input = createReadStream6(path);
|
|
4338
4392
|
input.on("error", () => {
|
|
4339
4393
|
});
|
|
4340
4394
|
const rl = createInterface6({ input, crlfDelay: Infinity });
|
|
4341
4395
|
try {
|
|
4342
4396
|
for await (const line of rl) {
|
|
4343
|
-
|
|
4397
|
+
const isTurn = line.includes("shell.turn.inference_done");
|
|
4398
|
+
if (!isTurn && !line.includes("model changed") && !line.includes("model switch")) continue;
|
|
4344
4399
|
try {
|
|
4345
4400
|
const obj = JSON.parse(line.charCodeAt(0) === 65279 ? line.slice(1) : line);
|
|
4401
|
+
const sid = typeof obj.sid === "string" ? obj.sid : "unknown";
|
|
4402
|
+
const switched = modelChangeFrom(obj);
|
|
4403
|
+
if (switched) {
|
|
4404
|
+
activeModel.set(sid, switched);
|
|
4405
|
+
continue;
|
|
4406
|
+
}
|
|
4346
4407
|
if (obj?.msg !== "shell.turn.inference_done" || !obj.ctx) continue;
|
|
4347
4408
|
const ts = Date.parse(String(obj.ts ?? ""));
|
|
4348
4409
|
if (!Number.isFinite(ts)) continue;
|
|
4349
|
-
const sid = typeof obj.sid === "string" ? obj.sid : "unknown";
|
|
4350
4410
|
const ctx = obj.ctx;
|
|
4351
4411
|
const prompt = safeNum(ctx.prompt_tokens);
|
|
4352
4412
|
const cached = safeNum(ctx.cached_prompt_tokens);
|
|
@@ -4355,7 +4415,7 @@ async function parseUnifiedLog(path, models) {
|
|
|
4355
4415
|
const cacheRead = cached;
|
|
4356
4416
|
const output = completion;
|
|
4357
4417
|
if (inputTokens + cacheRead + output <= 0) continue;
|
|
4358
|
-
const model = models.get(sid) ??
|
|
4418
|
+
const model = activeModel.get(sid) ?? models.get(sid) ?? DEFAULT_MODEL;
|
|
4359
4419
|
const { cost, cacheSavings } = costOf2(model, inputTokens, cacheRead, output);
|
|
4360
4420
|
const loop = safeNum(ctx.loop_index);
|
|
4361
4421
|
entries.push({
|
|
@@ -4398,7 +4458,7 @@ async function loadEntries6(since, homeDir) {
|
|
|
4398
4458
|
files,
|
|
4399
4459
|
async (path) => parseUnifiedLog(path, modelByHome.get(path) ?? /* @__PURE__ */ new Map()),
|
|
4400
4460
|
since,
|
|
4401
|
-
{ fingerprint: { parser: `grok-unified-
|
|
4461
|
+
{ fingerprint: { parser: `grok-unified-v3.${grokModelMapFingerprint(modelByHome)}` } }
|
|
4402
4462
|
);
|
|
4403
4463
|
}
|
|
4404
4464
|
async function grokDashboard(tz, homeDir) {
|
|
@@ -4579,6 +4639,7 @@ export {
|
|
|
4579
4639
|
readClaudeIdentity,
|
|
4580
4640
|
codexHomes,
|
|
4581
4641
|
identityFromIdToken,
|
|
4642
|
+
formatAgo,
|
|
4582
4643
|
formatResetAt,
|
|
4583
4644
|
currency,
|
|
4584
4645
|
tokens,
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
colorHex,
|
|
12
12
|
fetchPeak,
|
|
13
13
|
namedHex
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-KCY53RUE.js";
|
|
15
15
|
import {
|
|
16
16
|
PROVIDERS,
|
|
17
17
|
TOKMON_CAPABILITIES,
|
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
detectProviders,
|
|
23
23
|
resolveTimezone,
|
|
24
24
|
withTimeout
|
|
25
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-IWKSA64G.js";
|
|
26
26
|
import {
|
|
27
27
|
cacheDir,
|
|
28
28
|
expandHome,
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
TOKMON_WS_METHODS,
|
|
4
4
|
TOKMON_WS_PATH,
|
|
5
5
|
TokmonRpcGroup
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-IWKSA64G.js";
|
|
7
7
|
|
|
8
8
|
// src/client/daemon-rpc-client.ts
|
|
9
9
|
import { Cause, Context, Duration, Effect, Exit, Fiber, Layer, ManagedRuntime, Schedule, Stream } from "effect";
|
|
@@ -6,7 +6,7 @@ import "./chunk-QM5E5RJZ.js";
|
|
|
6
6
|
import "./chunk-SMPY52EV.js";
|
|
7
7
|
import {
|
|
8
8
|
createDaemonRpcClient
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-QOA6KOJQ.js";
|
|
10
10
|
import {
|
|
11
11
|
PROVIDERS,
|
|
12
12
|
antigravityStateDb,
|
|
@@ -26,7 +26,7 @@ import {
|
|
|
26
26
|
startOfMonth,
|
|
27
27
|
startOfWeek,
|
|
28
28
|
withTimeout
|
|
29
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-IWKSA64G.js";
|
|
30
30
|
import {
|
|
31
31
|
PROVIDER_IDS,
|
|
32
32
|
configLocation
|
package/dist/cli.js
CHANGED
|
@@ -41,7 +41,7 @@ function validateServeArgs(serveArgs) {
|
|
|
41
41
|
}
|
|
42
42
|
async function main() {
|
|
43
43
|
if (subcommand && ["usage", "models", "query", "providers", "snapshot", "config"].includes(subcommand)) {
|
|
44
|
-
const { runQueryCommand } = await import("./cli-command-
|
|
44
|
+
const { runQueryCommand } = await import("./cli-command-HXKWB6IP.js");
|
|
45
45
|
try {
|
|
46
46
|
const output = await runQueryCommand(
|
|
47
47
|
subcommand,
|
|
@@ -60,14 +60,14 @@ Run tokmon ${subcommand} --help for usage.
|
|
|
60
60
|
return;
|
|
61
61
|
}
|
|
62
62
|
if (subcommand === "__daemon") {
|
|
63
|
-
const { runDaemon } = await import("./daemon-
|
|
63
|
+
const { runDaemon } = await import("./daemon-JCQF645I.js");
|
|
64
64
|
await runDaemon(args.slice(1), { foreground: false });
|
|
65
65
|
process.exitCode ??= 0;
|
|
66
66
|
return;
|
|
67
67
|
}
|
|
68
68
|
if (subcommand === "serve" || subcommand === "web") {
|
|
69
69
|
validateServeArgs(args.slice(1));
|
|
70
|
-
const { runDaemon } = await import("./daemon-
|
|
70
|
+
const { runDaemon } = await import("./daemon-JCQF645I.js");
|
|
71
71
|
await runDaemon(args.slice(1), { foreground: true });
|
|
72
72
|
process.exitCode ??= 0;
|
|
73
73
|
return;
|
|
@@ -128,7 +128,7 @@ Run tokmon ${subcommand} --help for usage.
|
|
|
128
128
|
}));
|
|
129
129
|
const daemon = await attachOrSpawn();
|
|
130
130
|
const mode = daemon.kind === "spawned" ? "connected" : "degraded";
|
|
131
|
-
const { bootstrapInk } = await import("./bootstrap-ink-
|
|
131
|
+
const { bootstrapInk } = await import("./bootstrap-ink-5LQMSU4B.js");
|
|
132
132
|
await bootstrapInk({ interval, config, daemon, mode });
|
|
133
133
|
}
|
|
134
134
|
void main().catch((error) => {
|
|
@@ -11,14 +11,14 @@ import {
|
|
|
11
11
|
} from "./chunk-QM5E5RJZ.js";
|
|
12
12
|
import {
|
|
13
13
|
startWebServer
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-JK3U54G7.js";
|
|
15
15
|
import {
|
|
16
16
|
appVersion
|
|
17
17
|
} from "./chunk-SMPY52EV.js";
|
|
18
|
-
import "./chunk-
|
|
18
|
+
import "./chunk-KCY53RUE.js";
|
|
19
19
|
import {
|
|
20
20
|
flushDisk
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-IWKSA64G.js";
|
|
22
22
|
import {
|
|
23
23
|
loadConfig
|
|
24
24
|
} from "./chunk-E2YXYU73.js";
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
startWebServer
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-JK3U54G7.js";
|
|
5
5
|
import "./chunk-SMPY52EV.js";
|
|
6
|
-
import "./chunk-
|
|
7
|
-
import "./chunk-
|
|
6
|
+
import "./chunk-KCY53RUE.js";
|
|
7
|
+
import "./chunk-IWKSA64G.js";
|
|
8
8
|
import "./chunk-E2YXYU73.js";
|
|
9
9
|
export {
|
|
10
10
|
startWebServer
|