tokentracker-cli 0.5.70 → 0.5.72
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 +3 -2
- package/dashboard/dist/assets/{Card-Bmd_CiIj.js → Card-D_q1XGfK.js} +1 -1
- package/dashboard/dist/assets/{DashboardPage-o3xjHuSr.js → DashboardPage-CuBSoNgI.js} +2 -2
- package/dashboard/dist/assets/{FadeIn-Dqezp4M6.js → FadeIn-ClpHby-T.js} +1 -1
- package/dashboard/dist/assets/{IpCheckPage-Dvo1fWrV.js → IpCheckPage-B5TpHE6G.js} +1 -1
- package/dashboard/dist/assets/{LeaderboardPage-sarzdedp.js → LeaderboardPage-BOrtGeIf.js} +2 -2
- package/dashboard/dist/assets/LeaderboardProfilePage-C8xexZ08.js +1 -0
- package/dashboard/dist/assets/{LimitsPage-BYVQqh0y.js → LimitsPage-CERWQyIU.js} +1 -1
- package/dashboard/dist/assets/{SettingsPage-C0bLU9fQ.js → SettingsPage-DUwt4x-H.js} +1 -1
- package/dashboard/dist/assets/{WidgetsPage-DH1pg04g.js → WidgetsPage-Cmr2tbD7.js} +1 -1
- package/dashboard/dist/assets/{download-Dqdzgt-u.js → download-M8e1PJC-.js} +1 -1
- package/dashboard/dist/assets/leaderboard-columns-Dcg9r7R2.js +1 -0
- package/dashboard/dist/assets/{main-Vhl9rhYB.js → main-D1VdJk4V.js} +16 -15
- package/dashboard/dist/assets/{use-limits-display-prefs-CJuYd6SN.js → use-limits-display-prefs-CSj55sfK.js} +1 -1
- package/dashboard/dist/assets/{use-usage-limits-BEbR2ySJ.js → use-usage-limits-BuWINUAm.js} +1 -1
- package/dashboard/dist/brand-logos/kimi.svg +1 -0
- package/dashboard/dist/index.html +1 -1
- package/dashboard/dist/share.html +1 -1
- package/package.json +1 -1
- package/src/commands/init.js +11 -0
- package/src/commands/status.js +9 -0
- package/src/commands/sync.js +52 -1
- package/src/lib/local-api.js +159 -56
- package/src/lib/rollout.js +217 -4
- package/dashboard/dist/assets/LeaderboardProfilePage-DsoEom4U.js +0 -1
- package/dashboard/dist/assets/leaderboard-columns-eDzDr_Xs.js +0 -1
package/src/lib/rollout.js
CHANGED
|
@@ -676,12 +676,21 @@ async function parseOpenclawSessionFile({
|
|
|
676
676
|
|
|
677
677
|
const model = normalizeModelInput(msg.model) || DEFAULT_MODEL;
|
|
678
678
|
|
|
679
|
+
// Per CLAUDE.md: cached_input_tokens = cache reads,
|
|
680
|
+
// cache_creation_input_tokens = cache writes. Also re-derive total_tokens
|
|
681
|
+
// as input + output + cache_creation + cache_read so cost math works
|
|
682
|
+
// even when the source's own totalTokens is stale or rounded.
|
|
683
|
+
const inputTok = Number(usage.input || 0);
|
|
684
|
+
const cacheReadTok = Number(usage.cacheRead || 0);
|
|
685
|
+
const cacheWriteTok = Number(usage.cacheWrite || 0);
|
|
686
|
+
const outputTok = Number(usage.output || 0);
|
|
679
687
|
const delta = {
|
|
680
|
-
input_tokens:
|
|
681
|
-
cached_input_tokens:
|
|
682
|
-
|
|
688
|
+
input_tokens: inputTok,
|
|
689
|
+
cached_input_tokens: cacheReadTok,
|
|
690
|
+
cache_creation_input_tokens: cacheWriteTok,
|
|
691
|
+
output_tokens: outputTok,
|
|
683
692
|
reasoning_output_tokens: 0,
|
|
684
|
-
total_tokens:
|
|
693
|
+
total_tokens: inputTok + outputTok + cacheReadTok + cacheWriteTok,
|
|
685
694
|
conversation_count: 1,
|
|
686
695
|
};
|
|
687
696
|
|
|
@@ -2083,6 +2092,7 @@ function sameGeminiTotals(a, b) {
|
|
|
2083
2092
|
return (
|
|
2084
2093
|
a.input_tokens === b.input_tokens &&
|
|
2085
2094
|
a.cached_input_tokens === b.cached_input_tokens &&
|
|
2095
|
+
a.cache_creation_input_tokens === b.cache_creation_input_tokens &&
|
|
2086
2096
|
a.output_tokens === b.output_tokens &&
|
|
2087
2097
|
a.reasoning_output_tokens === b.reasoning_output_tokens &&
|
|
2088
2098
|
a.total_tokens === b.total_tokens
|
|
@@ -2097,12 +2107,20 @@ function diffGeminiTotals(current, previous) {
|
|
|
2097
2107
|
const totalReset = (current.total_tokens || 0) < (previous.total_tokens || 0);
|
|
2098
2108
|
if (totalReset) return current;
|
|
2099
2109
|
|
|
2110
|
+
// Must include cache_creation_input_tokens in both the equality check and
|
|
2111
|
+
// the delta — OpenCode routes through this diff and its cache.write number
|
|
2112
|
+
// would otherwise be permanently reported as zero. Gemini itself always
|
|
2113
|
+
// emits cache_creation=0 so the extra field is a no-op for Gemini.
|
|
2100
2114
|
const delta = {
|
|
2101
2115
|
input_tokens: Math.max(0, (current.input_tokens || 0) - (previous.input_tokens || 0)),
|
|
2102
2116
|
cached_input_tokens: Math.max(
|
|
2103
2117
|
0,
|
|
2104
2118
|
(current.cached_input_tokens || 0) - (previous.cached_input_tokens || 0),
|
|
2105
2119
|
),
|
|
2120
|
+
cache_creation_input_tokens: Math.max(
|
|
2121
|
+
0,
|
|
2122
|
+
(current.cache_creation_input_tokens || 0) - (previous.cache_creation_input_tokens || 0),
|
|
2123
|
+
),
|
|
2106
2124
|
output_tokens: Math.max(0, (current.output_tokens || 0) - (previous.output_tokens || 0)),
|
|
2107
2125
|
reasoning_output_tokens: Math.max(
|
|
2108
2126
|
0,
|
|
@@ -2651,6 +2669,16 @@ function readKiroDbTokens(dbPath, sinceId) {
|
|
|
2651
2669
|
// The fallback file does not include per-row timestamps, so newly appended rows are
|
|
2652
2670
|
// bucketed using the file mtime observed during this sync. We track a separate JSONL
|
|
2653
2671
|
// cursor so it never shares state with the SQLite path.
|
|
2672
|
+
function countKiroJsonlLines(jsonlPath) {
|
|
2673
|
+
if (!jsonlPath || !fssync.existsSync(jsonlPath)) return 0;
|
|
2674
|
+
try {
|
|
2675
|
+
const raw = fssync.readFileSync(jsonlPath, "utf8");
|
|
2676
|
+
return raw.split("\n").filter((l) => l.trim()).length;
|
|
2677
|
+
} catch (_e) {
|
|
2678
|
+
return 0;
|
|
2679
|
+
}
|
|
2680
|
+
}
|
|
2681
|
+
|
|
2654
2682
|
function readKiroJsonlTokens(jsonlPath, sinceLineIndex) {
|
|
2655
2683
|
if (!jsonlPath || !fssync.existsSync(jsonlPath)) {
|
|
2656
2684
|
return { rows: [], lineCount: 0, reset: false };
|
|
@@ -2795,6 +2823,14 @@ async function parseKiroIncremental({ dbPath, jsonlPath, cursors, queuePath, onP
|
|
|
2795
2823
|
if (fssync.existsSync(resolvedDbPath)) {
|
|
2796
2824
|
rows = readKiroDbTokens(resolvedDbPath, lastDbId);
|
|
2797
2825
|
usingDb = true;
|
|
2826
|
+
// DB and JSONL are siblings for the same usage events. If the DB ever
|
|
2827
|
+
// disappears (corrupted / wiped) and we fall back to JSONL in a later
|
|
2828
|
+
// run, we must not re-read lines that the DB path already consumed.
|
|
2829
|
+
// Advance the JSONL line cursor to the current file tail.
|
|
2830
|
+
if (fssync.existsSync(resolvedJsonlPath)) {
|
|
2831
|
+
const tailLineCount = countKiroJsonlLines(resolvedJsonlPath);
|
|
2832
|
+
if (tailLineCount > nextJsonlLine) nextJsonlLine = tailLineCount;
|
|
2833
|
+
}
|
|
2798
2834
|
} else if (fssync.existsSync(resolvedJsonlPath)) {
|
|
2799
2835
|
const jsonlResult = readKiroJsonlTokens(resolvedJsonlPath, lastJsonlLine);
|
|
2800
2836
|
rows = jsonlResult.rows;
|
|
@@ -2999,6 +3035,175 @@ async function parseHermesIncremental({ dbPath, cursors, queuePath, onProgress }
|
|
|
2999
3035
|
return { recordsProcessed: rows.length, eventsAggregated, bucketsQueued };
|
|
3000
3036
|
}
|
|
3001
3037
|
|
|
3038
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
3039
|
+
// Kimi — passive JSONL reader (~/.kimi/sessions/**/wire.jsonl)
|
|
3040
|
+
// No hook installation needed; Kimi writes wire.jsonl automatically.
|
|
3041
|
+
|
|
3042
|
+
function resolveKimiDefaultModel(env = process.env) {
|
|
3043
|
+
const fallback = "kimi-for-coding";
|
|
3044
|
+
try {
|
|
3045
|
+
const home = env.HOME || require("node:os").homedir();
|
|
3046
|
+
const cfgPath = path.join(env.KIMI_HOME || path.join(home, ".kimi"), "config.toml");
|
|
3047
|
+
const raw = fssync.readFileSync(cfgPath, "utf8");
|
|
3048
|
+
const defaultMatch = raw.match(/^\s*default_model\s*=\s*"([^"]+)"/m);
|
|
3049
|
+
if (!defaultMatch) return fallback;
|
|
3050
|
+
const sectionKey = defaultMatch[1];
|
|
3051
|
+
const escaped = sectionKey.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
3052
|
+
const sectionRe = new RegExp(
|
|
3053
|
+
`\\[models\\."${escaped}"\\]([\\s\\S]*?)(?:\\n\\[|$)`,
|
|
3054
|
+
);
|
|
3055
|
+
const section = raw.match(sectionRe);
|
|
3056
|
+
if (section) {
|
|
3057
|
+
const modelMatch = section[1].match(/^\s*model\s*=\s*"([^"]+)"/m);
|
|
3058
|
+
if (modelMatch && modelMatch[1]) return modelMatch[1];
|
|
3059
|
+
}
|
|
3060
|
+
if (sectionKey.includes("/")) return sectionKey.split("/").pop();
|
|
3061
|
+
return sectionKey || fallback;
|
|
3062
|
+
} catch {
|
|
3063
|
+
return fallback;
|
|
3064
|
+
}
|
|
3065
|
+
}
|
|
3066
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
3067
|
+
|
|
3068
|
+
function resolveKimiWireFiles(env = process.env) {
|
|
3069
|
+
const home = require("node:os").homedir();
|
|
3070
|
+
const kimiHome = env.KIMI_HOME || path.join(home, ".kimi");
|
|
3071
|
+
const sessionsDir = path.join(kimiHome, "sessions");
|
|
3072
|
+
if (!fssync.existsSync(sessionsDir)) return [];
|
|
3073
|
+
const files = [];
|
|
3074
|
+
try {
|
|
3075
|
+
for (const ws of fssync.readdirSync(sessionsDir)) {
|
|
3076
|
+
const wsDir = path.join(sessionsDir, ws);
|
|
3077
|
+
let wsStat;
|
|
3078
|
+
try { wsStat = fssync.statSync(wsDir); } catch { continue; }
|
|
3079
|
+
if (!wsStat.isDirectory()) continue;
|
|
3080
|
+
for (const sess of fssync.readdirSync(wsDir)) {
|
|
3081
|
+
const wireFile = path.join(wsDir, sess, "wire.jsonl");
|
|
3082
|
+
if (fssync.existsSync(wireFile)) files.push(wireFile);
|
|
3083
|
+
}
|
|
3084
|
+
}
|
|
3085
|
+
} catch { /* ignore */ }
|
|
3086
|
+
return files;
|
|
3087
|
+
}
|
|
3088
|
+
|
|
3089
|
+
async function parseKimiIncremental({ wireFiles, cursors, queuePath, onProgress, env, model } = {}) {
|
|
3090
|
+
await ensureDir(path.dirname(queuePath));
|
|
3091
|
+
const kimiState = cursors.kimi && typeof cursors.kimi === "object" ? cursors.kimi : {};
|
|
3092
|
+
const seenIds = new Set(Array.isArray(kimiState.seenIds) ? kimiState.seenIds : []);
|
|
3093
|
+
const fileOffsets =
|
|
3094
|
+
kimiState.fileOffsets && typeof kimiState.fileOffsets === "object"
|
|
3095
|
+
? { ...kimiState.fileOffsets }
|
|
3096
|
+
: {};
|
|
3097
|
+
|
|
3098
|
+
const files = Array.isArray(wireFiles)
|
|
3099
|
+
? wireFiles
|
|
3100
|
+
: resolveKimiWireFiles(env || process.env);
|
|
3101
|
+
const kimiModel = model || resolveKimiDefaultModel(env || process.env);
|
|
3102
|
+
if (files.length === 0) {
|
|
3103
|
+
cursors.kimi = { ...kimiState, seenIds: Array.from(seenIds), fileOffsets, updatedAt: new Date().toISOString() };
|
|
3104
|
+
return { recordsProcessed: 0, eventsAggregated: 0, bucketsQueued: 0 };
|
|
3105
|
+
}
|
|
3106
|
+
|
|
3107
|
+
const hourlyState = normalizeHourlyState(cursors?.hourly);
|
|
3108
|
+
const touchedBuckets = new Set();
|
|
3109
|
+
const cb = typeof onProgress === "function" ? onProgress : null;
|
|
3110
|
+
let recordsProcessed = 0;
|
|
3111
|
+
let eventsAggregated = 0;
|
|
3112
|
+
|
|
3113
|
+
for (let fileIdx = 0; fileIdx < files.length; fileIdx++) {
|
|
3114
|
+
const filePath = files[fileIdx];
|
|
3115
|
+
let stat;
|
|
3116
|
+
try { stat = fssync.statSync(filePath); } catch { continue; }
|
|
3117
|
+
|
|
3118
|
+
const prevEntry = fileOffsets[filePath] || {};
|
|
3119
|
+
const prevSize = Number(prevEntry.size) || 0;
|
|
3120
|
+
const prevIno = prevEntry.ino;
|
|
3121
|
+
const inodeChanged = typeof prevIno === "number" && prevIno !== stat.ino;
|
|
3122
|
+
const startOffset = stat.size < prevSize || inodeChanged ? 0 : prevSize;
|
|
3123
|
+
if (stat.size <= startOffset) continue;
|
|
3124
|
+
|
|
3125
|
+
let stream;
|
|
3126
|
+
try {
|
|
3127
|
+
stream = fssync.createReadStream(filePath, { encoding: "utf8", start: startOffset });
|
|
3128
|
+
} catch { continue; }
|
|
3129
|
+
const rl = readline.createInterface({ input: stream, crlfDelay: Infinity });
|
|
3130
|
+
|
|
3131
|
+
for await (const line of rl) {
|
|
3132
|
+
if (!line || !line.trim()) continue;
|
|
3133
|
+
let entry;
|
|
3134
|
+
try { entry = JSON.parse(line); } catch { continue; }
|
|
3135
|
+
|
|
3136
|
+
const msg = entry.message;
|
|
3137
|
+
if (!msg || msg.type !== "StatusUpdate") continue;
|
|
3138
|
+
|
|
3139
|
+
const payload = msg.payload;
|
|
3140
|
+
if (!payload) continue;
|
|
3141
|
+
const { token_usage, message_id } = payload;
|
|
3142
|
+
if (!token_usage || !message_id) continue;
|
|
3143
|
+
if (seenIds.has(message_id)) continue;
|
|
3144
|
+
|
|
3145
|
+
recordsProcessed++;
|
|
3146
|
+
|
|
3147
|
+
const input = toNonNegativeInt(token_usage.input_other);
|
|
3148
|
+
const output = toNonNegativeInt(token_usage.output);
|
|
3149
|
+
const cacheRead = toNonNegativeInt(token_usage.input_cache_read);
|
|
3150
|
+
const cacheCreation = toNonNegativeInt(token_usage.input_cache_creation);
|
|
3151
|
+
if (input === 0 && output === 0 && cacheRead === 0 && cacheCreation === 0) {
|
|
3152
|
+
seenIds.add(message_id);
|
|
3153
|
+
continue;
|
|
3154
|
+
}
|
|
3155
|
+
|
|
3156
|
+
const epochSec = entry.timestamp ?? payload.timestamp;
|
|
3157
|
+
if (epochSec == null || !Number.isFinite(Number(epochSec))) continue;
|
|
3158
|
+
const tsIso = new Date(Number(epochSec) * 1000).toISOString();
|
|
3159
|
+
const bucketStart = toUtcHalfHourStart(tsIso);
|
|
3160
|
+
if (!bucketStart) continue;
|
|
3161
|
+
|
|
3162
|
+
const delta = {
|
|
3163
|
+
input_tokens: input,
|
|
3164
|
+
cached_input_tokens: cacheRead,
|
|
3165
|
+
cache_creation_input_tokens: cacheCreation,
|
|
3166
|
+
output_tokens: output,
|
|
3167
|
+
reasoning_output_tokens: 0,
|
|
3168
|
+
total_tokens: input + output + cacheRead + cacheCreation,
|
|
3169
|
+
conversation_count: 1,
|
|
3170
|
+
};
|
|
3171
|
+
|
|
3172
|
+
const bucket = getHourlyBucket(hourlyState, "kimi", kimiModel, bucketStart);
|
|
3173
|
+
addTotals(bucket.totals, delta);
|
|
3174
|
+
touchedBuckets.add(bucketKey("kimi", kimiModel, bucketStart));
|
|
3175
|
+
seenIds.add(message_id);
|
|
3176
|
+
eventsAggregated++;
|
|
3177
|
+
|
|
3178
|
+
if (cb) {
|
|
3179
|
+
cb({
|
|
3180
|
+
index: fileIdx + 1,
|
|
3181
|
+
total: files.length,
|
|
3182
|
+
recordsProcessed,
|
|
3183
|
+
eventsAggregated,
|
|
3184
|
+
bucketsQueued: touchedBuckets.size,
|
|
3185
|
+
});
|
|
3186
|
+
}
|
|
3187
|
+
}
|
|
3188
|
+
|
|
3189
|
+
let postStat = stat;
|
|
3190
|
+
try { postStat = fssync.statSync(filePath); } catch {}
|
|
3191
|
+
fileOffsets[filePath] = { size: postStat.size, mtimeMs: postStat.mtimeMs, ino: postStat.ino };
|
|
3192
|
+
}
|
|
3193
|
+
|
|
3194
|
+
// Cap seenIds to last 10k to bound cursor state size
|
|
3195
|
+
const seenArr = Array.from(seenIds);
|
|
3196
|
+
const cappedSeen = seenArr.length > 10_000 ? seenArr.slice(seenArr.length - 10_000) : seenArr;
|
|
3197
|
+
|
|
3198
|
+
const bucketsQueued = await enqueueTouchedBuckets({ queuePath, hourlyState, touchedBuckets });
|
|
3199
|
+
const updatedAt = new Date().toISOString();
|
|
3200
|
+
hourlyState.updatedAt = updatedAt;
|
|
3201
|
+
cursors.hourly = hourlyState;
|
|
3202
|
+
cursors.kimi = { ...kimiState, seenIds: cappedSeen, fileOffsets, updatedAt };
|
|
3203
|
+
|
|
3204
|
+
return { recordsProcessed, eventsAggregated, bucketsQueued };
|
|
3205
|
+
}
|
|
3206
|
+
|
|
3002
3207
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
3003
3208
|
// GitHub Copilot CLI — OpenTelemetry JSONL exporter
|
|
3004
3209
|
// User must opt in by setting:
|
|
@@ -3209,4 +3414,12 @@ module.exports = {
|
|
|
3209
3414
|
parseKiroIncremental,
|
|
3210
3415
|
parseHermesIncremental,
|
|
3211
3416
|
parseCopilotIncremental,
|
|
3417
|
+
resolveKimiWireFiles,
|
|
3418
|
+
resolveKimiDefaultModel,
|
|
3419
|
+
parseKimiIncremental,
|
|
3420
|
+
// Exposed for regression tests covering cache-token accounting.
|
|
3421
|
+
normalizeGeminiTokens,
|
|
3422
|
+
normalizeOpencodeTokens,
|
|
3423
|
+
sameGeminiTotals,
|
|
3424
|
+
diffGeminiTotals,
|
|
3212
3425
|
};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{r as n,D as e,aA as D,C as H,aC as W,h as Y,j as Z,aE as G,aI as J,B as a,az as L,ax as R,a9 as E,aJ as q,aK as F}from"./main-Vhl9rhYB.js";import{b as B,d as Q,l as V,f as X,e as ee,L as re,g as ae}from"./leaderboard-columns-eDzDr_Xs.js";const y=18;function O(){return e.jsxs("svg",{"aria-hidden":!0,width:y,height:y,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[e.jsx("circle",{cx:"12",cy:"12",r:"4"}),e.jsx("path",{d:"M12 2v2"}),e.jsx("path",{d:"M12 20v2"}),e.jsx("path",{d:"m4.93 4.93 1.41 1.41"}),e.jsx("path",{d:"m17.66 17.66 1.41 1.41"}),e.jsx("path",{d:"M2 12h2"}),e.jsx("path",{d:"M20 12h2"}),e.jsx("path",{d:"m6.34 17.66-1.41 1.41"}),e.jsx("path",{d:"m19.07 4.93-1.41 1.41"})]})}function P(){return e.jsx("svg",{"aria-hidden":!0,width:y,height:y,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:e.jsx("path",{d:"M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z"})})}function te(){return e.jsxs("svg",{"aria-hidden":!0,width:y,height:y,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[e.jsx("rect",{x:"2",y:"3",width:"20",height:"14",rx:"2"}),e.jsx("path",{d:"M8 21h8"}),e.jsx("path",{d:"M12 17v4"})]})}const oe=[{value:"light",label:"Light",Icon:O},{value:"dark",label:"Dark",Icon:P},{value:"system",label:"System",Icon:te}];function se(r){return r==="dark"?P:O}function ne({theme:r,resolvedTheme:s,onSetTheme:b,className:d="",direction:p="down",align:T="right"}){const[c,k]=n.useState(!1),h=n.useRef(null),i=n.useCallback(()=>k(!1),[]);n.useEffect(()=>{if(!c)return;const t=l=>{h.current&&!h.current.contains(l.target)&&i()};return document.addEventListener("mousedown",t),()=>document.removeEventListener("mousedown",t)},[c,i]),n.useEffect(()=>{if(!c)return;const t=l=>{l.key==="Escape"&&i()};return document.addEventListener("keydown",t),()=>document.removeEventListener("keydown",t)},[c,i]);const x=se(s);return e.jsxs("div",{ref:h,className:`relative ${d}`,children:[e.jsx("button",{type:"button","aria-label":"Theme","aria-expanded":c,onClick:()=>k(t=>!t),className:"flex items-center justify-center w-9 h-9 rounded-lg text-oai-gray-600 dark:text-oai-gray-400 hover:bg-oai-gray-100 dark:hover:bg-oai-gray-800 hover:text-oai-black dark:hover:text-white transition-colors",children:e.jsx(x,{})}),c&&e.jsx("div",{className:`absolute z-50 min-w-[140px] py-1 rounded-lg border border-oai-gray-200 dark:border-oai-gray-800 bg-white dark:bg-oai-gray-900 shadow-lg ${p==="up"?"bottom-full mb-1":"top-full mt-1"} ${T==="left"?"left-0":"right-0"}`,children:oe.map(({value:t,label:l,Icon:j})=>{const m=r===t;return e.jsxs("button",{type:"button",onClick:()=>{b(t),i()},className:`flex w-full items-center gap-2.5 px-3 py-2 text-sm transition-colors ${m?"text-oai-black dark:text-white bg-oai-gray-100 dark:bg-oai-gray-800":"text-oai-gray-600 dark:text-oai-gray-400 hover:bg-oai-gray-50 dark:hover:bg-oai-gray-800/60 hover:text-oai-black dark:hover:text-white"}`,children:[e.jsx(j,{}),e.jsx("span",{children:l})]},t)})})]})}function ie(r){if(!r)return a("shared.error.prefix",{error:a("leaderboard.error.unknown")});const s=r?.message||String(r),b=String(s||"").trim()||a("leaderboard.error.unknown");return a("shared.error.prefix",{error:b})}function le(r){return typeof r!="string"?"":r.trim()}function de(r){if(typeof r!="string")return null;const s=r.trim().toLowerCase();return s==="week"||s==="month"||s==="total"?s:null}function me({auth:r,signedIn:s,sessionSoftExpired:b,userId:d}){const p=D(),{theme:T,resolvedTheme:c,setTheme:k}=H(),h=n.useMemo(()=>W(),[]),i=Y(),x=s&&!b,t=n.useMemo(()=>x&&(typeof r=="function"||typeof r=="string"||r&&typeof r=="object")?r:null,[r,x]),l=x?t:null,j=x&&Z(l),m=n.useMemo(()=>{const o=new URLSearchParams(p?.search||"");return de(o.get("period"))||"week"},[p?.search]),_=p?.search||"",[v,w]=n.useState(()=>({loading:!1,error:null,data:null}));n.useEffect(()=>{if(!h&&!i||!d||!i&&(!x||!j))return;let o=!0;return w(f=>({...f,loading:!0,error:null})),(async()=>{const f=await G(l);if(!o)return;if(!f){w({loading:!1,error:null,data:null});return}const $=await J({accessToken:f,userId:d,period:m});o&&w({loading:!1,error:null,data:$})})().catch(f=>{o&&w({loading:!1,error:ie(f),data:null})}),()=>{o=!1}},[x,j,h,l,i,m,d]);const N=v.data,C=N?.from||null,A=N?.to||null,M=N?.generated_at||null,g=N?.entry||null,S=le(g?.display_name)||a("leaderboard.anon_label"),z=a("leaderboard.period.week"),K=a("leaderboard.period.month"),U=a("leaderboard.period.total"),I=m==="month"?K:m==="total"?U:z;let u=null;return d?v.loading?u=e.jsx("div",{className:"px-6 py-12 text-center",children:e.jsx("p",{className:"text-sm text-oai-gray-500 dark:text-oai-gray-400",children:a("leaderboard.loading")})}):v.error?u=e.jsx("div",{className:"px-6 py-12 text-center",children:e.jsx("p",{className:"text-sm text-red-500 dark:text-red-400",children:v.error})}):g?u=e.jsx("div",{className:"w-full overflow-x-auto",children:e.jsxs("table",{className:"min-w-max w-full text-left text-sm",children:[e.jsx("thead",{className:"border-b border-oai-gray-200 dark:border-oai-gray-800",children:e.jsxs("tr",{children:[e.jsx("th",{className:L(re,"font-medium text-oai-gray-500 dark:text-oai-gray-400"),children:a("leaderboard.column.rank")}),e.jsx("th",{className:L(ae,"font-medium text-oai-gray-500 dark:text-oai-gray-400 whitespace-nowrap"),children:a("leaderboard.column.total")}),B.map(o=>e.jsx("th",{className:"px-4 py-4 font-medium text-oai-gray-500 dark:text-oai-gray-400 whitespace-nowrap",children:e.jsx(Q,{iconSrc:o.icon,label:a(o.copyKey)})},o.key))]})}),e.jsx("tbody",{className:"divide-y divide-oai-gray-100 dark:divide-oai-gray-800/50",children:e.jsxs("tr",{className:"transition-colors hover:bg-oai-gray-50 dark:hover:bg-oai-gray-900/60",children:[e.jsx("td",{className:L(V(!1),"font-medium text-oai-gray-500 dark:text-oai-gray-400"),children:g?.rank??a("shared.placeholder.short")}),e.jsx("td",{className:L(X(),"text-oai-gray-700 dark:text-oai-gray-300"),children:R(g?.total_tokens)}),B.map(o=>e.jsx("td",{className:"px-4 py-4 text-oai-gray-500 dark:text-oai-gray-400 whitespace-nowrap",children:R(g?.[o.key])},o.key))]})})]})}):u=e.jsx("div",{className:"px-6 py-12 text-center",children:e.jsx("p",{className:"text-sm text-oai-gray-500 dark:text-oai-gray-400",children:a("leaderboard.empty")})}):u=e.jsx("div",{className:"px-6 py-12 text-center",children:e.jsx("p",{className:"text-sm text-oai-gray-500 dark:text-oai-gray-400",children:a("leaderboard.empty")})}),e.jsxs("div",{className:"flex flex-col min-h-screen bg-oai-white dark:bg-oai-gray-950 text-oai-black dark:text-oai-white font-oai antialiased transition-colors duration-200",children:[e.jsx("header",{className:"sticky top-0 z-50 bg-white/80 dark:bg-oai-gray-950/80 backdrop-blur-md border-b border-oai-gray-200 dark:border-oai-gray-900 transition-colors duration-200",children:e.jsxs("div",{className:"mx-auto flex h-14 max-w-6xl items-center justify-between px-4 sm:px-6",children:[e.jsxs("div",{className:"flex items-center gap-5",children:[e.jsxs(E,{to:"/",className:"flex items-center gap-3 no-underline outline-none rounded focus-visible:ring-2 focus-visible:ring-oai-brand-500 focus-visible:ring-offset-2 dark:ring-offset-oai-gray-950 transition-opacity hover:opacity-80",children:[e.jsx("img",{src:"/app-icon.png",alt:"",width:24,height:24,className:"rounded-md"}),e.jsx("span",{className:"text-sm font-semibold tracking-wide text-oai-black dark:text-white uppercase",children:"Token Tracker"})]}),e.jsx("div",{className:"hidden sm:block",children:e.jsx(q,{})})]}),e.jsxs("div",{className:"flex items-center gap-2 sm:gap-3",children:[e.jsx(E,{to:`/leaderboard${_}`,className:"no-underline inline-flex items-center justify-center h-9 px-5 text-sm font-medium rounded-full shadow-sm ring-1 ring-oai-gray-200 dark:ring-white/10 bg-oai-gray-900 dark:bg-white text-white dark:text-oai-gray-900 hover:bg-oai-gray-800 dark:hover:bg-oai-gray-100 transition-colors",children:a("leaderboard.profile.nav.back")}),e.jsx(ne,{theme:T,resolvedTheme:c,onSetTheme:k}),e.jsx(F,{})]})]})}),e.jsx("main",{className:"flex-1 py-12 sm:py-16",children:e.jsxs("div",{className:"mx-auto max-w-6xl px-4 sm:px-6",children:[e.jsxs("div",{className:"flex flex-col sm:flex-row sm:items-center gap-6 mb-10",children:[e.jsx(ee,{avatarUrl:g?.avatar_url,displayName:S,seed:typeof d=="string"?d:S,size:"lg",className:"shrink-0 ring-2 ring-oai-gray-200 dark:ring-oai-gray-800"}),e.jsxs("div",{className:"min-w-0",children:[e.jsx("h1",{className:"text-3xl sm:text-4xl font-semibold tracking-tight text-oai-black dark:text-white mb-3",children:S}),e.jsxs("p",{className:"text-oai-gray-500 dark:text-oai-gray-400 text-sm sm:text-base",children:[m==="total"?a("leaderboard.range.total"):C&&A?a("leaderboard.range",{period:I,from:C,to:A}):a("leaderboard.range_loading",{period:I}),M&&e.jsx("span",{className:"ml-2 pl-2 border-l border-oai-gray-200 dark:border-oai-gray-800 inline-block text-oai-gray-400 dark:text-oai-gray-500 text-xs",children:a("leaderboard.generated_at",{ts:M})})]})]})]}),e.jsx("div",{className:"rounded-xl border border-oai-gray-200 dark:border-oai-gray-800 overflow-hidden",children:u})]})}),e.jsx("footer",{className:"border-t border-oai-gray-200 dark:border-oai-gray-900 py-8 transition-colors duration-200",children:e.jsxs("div",{className:"mx-auto flex max-w-6xl items-center justify-between px-4 sm:px-6 text-sm text-oai-gray-400 dark:text-oai-gray-500",children:[e.jsx("p",{children:a("landing.v2.footer.line")}),e.jsx(E,{to:`/leaderboard${_}`,className:"text-oai-gray-400 dark:text-oai-gray-500 hover:text-oai-black dark:hover:text-white transition-colors",children:a("leaderboard.profile.nav.back")})]})})]})}export{me as LeaderboardProfilePage};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{ad as l,D as n,az as i}from"./main-Vhl9rhYB.js";function y(r){let e=0;const o=String(r??"");for(let a=0;a<o.length;a+=1)e=Math.imul(31,e)+o.charCodeAt(a)|0;return Math.abs(e)%360}function m(r){const e=String(r??"").trim();if(!e)return"?";const o=e.split(/\s+/).filter(Boolean);if(o.length>=2){const a=o[0][0]||"",t=o[1][0]||"";return`${a}${t}`.toUpperCase()}return e.slice(0,2).toUpperCase()}const g={sm:"h-7 w-7 min-h-7 min-w-7 text-[10px]",md:"h-8 w-8 min-h-8 min-w-8 text-[11px]",lg:"h-14 w-14 min-h-14 min-w-14 text-base"};function h({avatarUrl:r,displayName:e,seed:o,size:a="md",className:t}){const d=g[a]||g.md,b=y(o??e??""),s=typeof r=="string"?r.trim():"",[p,c]=l.useState(!1);return l.useEffect(()=>{c(!1)},[s]),s&&!p?n.jsx("img",{src:s,alt:"",referrerPolicy:"no-referrer",onError:()=>c(!0),className:i("rounded-full object-cover ring-1 ring-white/10",d,t)}):n.jsx("div",{className:i("flex shrink-0 items-center justify-center rounded-full font-semibold text-white ring-1 ring-white/10",d,t),style:{backgroundColor:`hsl(${b} 42% 34%)`},"aria-hidden":!0,children:m(e)})}const u=new Set(["/brand-logos/cursor.svg","/brand-logos/kiro.svg","/brand-logos/copilot.svg"]);function w({iconSrc:r,label:e}){return n.jsxs("span",{className:"inline-flex items-center gap-3",children:[r?n.jsx("img",{src:r,alt:"",width:16,height:16,className:`h-4 w-4 shrink-0 object-contain opacity-90 ${u.has(r)?"dark:invert":""}`}):null,n.jsx("span",{className:"whitespace-nowrap",children:e})]})}const x=[{key:"gpt_tokens",copyKey:"leaderboard.column.codex",icon:"/brand-logos/codex.svg"},{key:"claude_tokens",copyKey:"leaderboard.column.claude",icon:"/brand-logos/claude-code.svg"},{key:"gemini_tokens",copyKey:"leaderboard.column.gemini",icon:"/brand-logos/gemini.svg"},{key:"cursor_tokens",copyKey:"leaderboard.column.cursor",icon:"/brand-logos/cursor.svg"},{key:"kiro_tokens",copyKey:"leaderboard.column.kiro",icon:"/brand-logos/kiro.svg"},{key:"copilot_tokens",copyKey:"leaderboard.column.copilot",icon:"/brand-logos/copilot.svg"},{key:"opencode_tokens",copyKey:"leaderboard.column.opencode",icon:"/brand-logos/opencode.svg"},{key:"openclaw_tokens",copyKey:"leaderboard.column.openclaw",icon:"/brand-logos/openclaw.svg"},{key:"hermes_tokens",copyKey:"leaderboard.column.hermes",icon:null},{key:"other_tokens",copyKey:"leaderboard.column.supplemental",icon:null}],f="sticky left-0 z-40 w-[72px] min-w-[72px] max-w-[72px] border-r border-oai-gray-200 dark:border-oai-gray-800 bg-white dark:bg-oai-gray-950 px-4 py-4 align-middle",_="sticky left-[72px] z-40 min-w-[140px] max-w-[min(180px,35vw)] border-r border-oai-gray-200 dark:border-oai-gray-800 bg-white dark:bg-oai-gray-950 px-4 py-4 align-middle",v="sticky left-[72px] z-40 min-w-[6rem] border-r border-oai-gray-200 dark:border-oai-gray-800 bg-white dark:bg-oai-gray-950 px-4 py-4";function K(r){return i("sticky left-0 z-30 w-[72px] min-w-[72px] max-w-[72px] border-r border-oai-gray-200 dark:border-oai-gray-800 px-4 py-4 whitespace-nowrap",r?"bg-oai-brand-50 dark:bg-emerald-950":"bg-white dark:bg-oai-gray-950 group-hover:bg-oai-gray-50 dark:group-hover:bg-oai-gray-900/60")}function T(r){return i("sticky left-[72px] z-30 min-w-[140px] max-w-[min(180px,35vw)] border-r border-oai-gray-200 dark:border-oai-gray-800 px-4 py-4 min-w-0",r?"bg-oai-brand-50 dark:bg-emerald-950":"bg-white dark:bg-oai-gray-950 group-hover:bg-oai-gray-50 dark:group-hover:bg-oai-gray-900/60")}function S(r){return i("sticky left-[72px] z-30 min-w-[6rem] border-r border-oai-gray-200 dark:border-oai-gray-800 px-4 py-4 whitespace-nowrap","bg-white dark:bg-oai-gray-950")}export{f as L,_ as a,x as b,T as c,w as d,h as e,S as f,v as g,K as l};
|