tokentracker-cli 0.19.0 → 0.20.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 +2 -2
- package/README.zh-CN.md +2 -2
- package/dashboard/dist/assets/{Card-ANC9ZmIT.js → Card-jA08WeEw.js} +1 -1
- package/dashboard/dist/assets/{DashboardPage-DpZaCksZ.js → DashboardPage-chDVOYmG.js} +1 -1
- package/dashboard/dist/assets/{FadeIn-WXGyOn0H.js → FadeIn-DqSYXuUL.js} +1 -1
- package/dashboard/dist/assets/{HeaderGithubStar-DUkE0Dwd.js → HeaderGithubStar-C11rWv0B.js} +1 -1
- package/dashboard/dist/assets/{IpCheckPage-BPF8eGpg.js → IpCheckPage-CkEZ9yLK.js} +1 -1
- package/dashboard/dist/assets/{LandingPage-0uTpqpAU.js → LandingPage-BgckTHRQ.js} +1 -1
- package/dashboard/dist/assets/{LeaderboardPage-DzxRJEzb.js → LeaderboardPage-BCNW7UWp.js} +1 -1
- package/dashboard/dist/assets/{LeaderboardProfilePage-C3_oUxhG.js → LeaderboardProfilePage-BLATxMt-.js} +1 -1
- package/dashboard/dist/assets/{LimitsPage-BVuvoeY9.js → LimitsPage-arF--WgR.js} +1 -1
- package/dashboard/dist/assets/{LoginPage-CfkNRmT6.js → LoginPage-DpoFP0va.js} +1 -1
- package/dashboard/dist/assets/{PopoverPopup-CfxiYbJm.js → PopoverPopup-kdgc2H6C.js} +1 -1
- package/dashboard/dist/assets/{ProviderIcon-DiPzAed2.js → ProviderIcon-DV5r9qqP.js} +1 -1
- package/dashboard/dist/assets/{SettingsPage-Devu7beE.js → SettingsPage-Bb22ORmU.js} +1 -1
- package/dashboard/dist/assets/{SkillsPage-CSe8fW4V.js → SkillsPage-xhtBqVKC.js} +1 -1
- package/dashboard/dist/assets/{WidgetsPage-BrLp5YLk.js → WidgetsPage-CUoSVDET.js} +1 -1
- package/dashboard/dist/assets/{chevron-down-nFF6Yj_r.js → chevron-down-DYb2EChD.js} +1 -1
- package/dashboard/dist/assets/{download-DhSZ--68.js → download-C-_8o6dh.js} +1 -1
- package/dashboard/dist/assets/{leaderboard-columns-CvFdXrw5.js → leaderboard-columns-BgzBlYo7.js} +1 -1
- package/dashboard/dist/assets/{main-DtrPNYb7.js → main-11hApDak.js} +3 -3
- package/dashboard/dist/assets/{use-limits-display-prefs-Yy8t7tbB.js → use-limits-display-prefs-BeGKWUuk.js} +1 -1
- package/dashboard/dist/assets/{use-native-settings-uemf9RSH.js → use-native-settings-nTTHktn0.js} +1 -1
- package/dashboard/dist/assets/{use-reduced-motion-DH8DxE18.js → use-reduced-motion-DU8Gm6j1.js} +1 -1
- package/dashboard/dist/assets/{use-usage-limits-C3vUT6PH.js → use-usage-limits-DTPmEB8Y.js} +1 -1
- package/dashboard/dist/index.html +1 -1
- package/dashboard/dist/share.html +1 -1
- package/package.json +1 -1
- package/src/commands/init.js +9 -5
- package/src/commands/serve.js +0 -12
- package/src/commands/sync.js +370 -7
- package/src/lib/grok-hook.js +86 -7
- package/src/lib/pricing/curated-overrides.json +1 -1
- package/src/lib/pricing/seed-snapshot.json +1 -1
- package/src/lib/rollout.js +403 -140
- package/src/lib/subscriptions.js +92 -40
- package/src/lib/usage-limits.js +1 -1
package/src/lib/grok-hook.js
CHANGED
|
@@ -94,14 +94,15 @@ function buildGrokSessionEndHandler({ trackerDir }) {
|
|
|
94
94
|
// It must be self-contained enough or rely on the copied runtime.
|
|
95
95
|
// For simplicity and reliability we write a small script that:
|
|
96
96
|
// 1. Reads GROK_SESSION_ID + GROK_WORKSPACE_ROOT from env
|
|
97
|
-
// 2. Locates the
|
|
98
|
-
// 3. Extracts usage
|
|
97
|
+
// 2. Locates the session metadata files
|
|
98
|
+
// 3. Extracts usage metadata only
|
|
99
99
|
// 4. Writes a signal file under trackerDir that sync.js will pick up on next run
|
|
100
100
|
|
|
101
101
|
return `#!/usr/bin/env node
|
|
102
102
|
const fs = require('node:fs');
|
|
103
103
|
const path = require('node:path');
|
|
104
104
|
const os = require('node:os');
|
|
105
|
+
const readline = require('node:readline');
|
|
105
106
|
|
|
106
107
|
const GROK_HOME = process.env.TOKENTRACKER_GROK_HOME || process.env.GROK_HOME || path.join(os.homedir(), '.grok');
|
|
107
108
|
const SESSION_ID = process.env.GROK_SESSION_ID;
|
|
@@ -120,14 +121,17 @@ const encodedCwd = encodeGrokCwd(WORKSPACE_ROOT);
|
|
|
120
121
|
const sessionDir = path.join(GROK_HOME, 'sessions', encodedCwd, SESSION_ID);
|
|
121
122
|
const signalsPath = path.join(sessionDir, 'signals.json');
|
|
122
123
|
const summaryPath = path.join(sessionDir, 'summary.json');
|
|
124
|
+
const updatesPath = path.join(sessionDir, 'updates.jsonl');
|
|
123
125
|
|
|
124
|
-
let signals =
|
|
126
|
+
let signals = {};
|
|
125
127
|
try {
|
|
126
128
|
const raw = fs.readFileSync(signalsPath, 'utf8');
|
|
127
129
|
signals = JSON.parse(raw);
|
|
128
130
|
} catch (err) {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
+
signals = {};
|
|
132
|
+
}
|
|
133
|
+
if (!signals || typeof signals !== 'object') {
|
|
134
|
+
signals = {};
|
|
131
135
|
}
|
|
132
136
|
|
|
133
137
|
const summary = (() => {
|
|
@@ -143,10 +147,74 @@ function toNonNegativeFiniteNumber(value) {
|
|
|
143
147
|
return Number.isFinite(number) && number > 0 ? number : 0;
|
|
144
148
|
}
|
|
145
149
|
|
|
146
|
-
|
|
150
|
+
function timestampToIso(value) {
|
|
151
|
+
if (value == null) return null;
|
|
152
|
+
if (typeof value === 'number') {
|
|
153
|
+
if (!Number.isFinite(value) || value <= 0) return null;
|
|
154
|
+
const millis = value < 10000000000 ? value * 1000 : value;
|
|
155
|
+
const dt = new Date(millis);
|
|
156
|
+
return Number.isFinite(dt.getTime()) ? dt.toISOString() : null;
|
|
157
|
+
}
|
|
158
|
+
if (typeof value === 'string') {
|
|
159
|
+
const trimmed = value.trim();
|
|
160
|
+
if (!trimmed) return null;
|
|
161
|
+
if (/^[0-9]+(?:\\.[0-9]+)?$/.test(trimmed)) return timestampToIso(Number(trimmed));
|
|
162
|
+
const dt = new Date(trimmed);
|
|
163
|
+
return Number.isFinite(dt.getTime()) ? dt.toISOString() : null;
|
|
164
|
+
}
|
|
165
|
+
return null;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
async function readUpdateTelemetry(filePath) {
|
|
169
|
+
let totalTokens = 0;
|
|
170
|
+
let lastEventId = null;
|
|
171
|
+
let lastEventTimestamp = null;
|
|
172
|
+
let lineNumber = 0;
|
|
173
|
+
|
|
174
|
+
try {
|
|
175
|
+
const input = fs.createReadStream(filePath, { encoding: 'utf8' });
|
|
176
|
+
const rl = readline.createInterface({ input, crlfDelay: Infinity });
|
|
177
|
+
try {
|
|
178
|
+
for await (const line of rl) {
|
|
179
|
+
lineNumber += 1;
|
|
180
|
+
if (!line || !line.trim()) continue;
|
|
181
|
+
let record = null;
|
|
182
|
+
try {
|
|
183
|
+
record = JSON.parse(line);
|
|
184
|
+
} catch {
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
const meta = record && record.params && record.params._meta ? record.params._meta : record && record._meta;
|
|
188
|
+
if (!meta || typeof meta !== 'object') continue;
|
|
189
|
+
const nextTotal = toNonNegativeFiniteNumber(meta.totalTokens);
|
|
190
|
+
if (nextTotal <= 0) continue;
|
|
191
|
+
totalTokens = Math.max(totalTokens, nextTotal);
|
|
192
|
+
lastEventId = meta.eventId != null ? String(meta.eventId) : String(lineNumber);
|
|
193
|
+
lastEventTimestamp =
|
|
194
|
+
timestampToIso(meta.agentTimestampMs) ||
|
|
195
|
+
timestampToIso(meta.timestampMs) ||
|
|
196
|
+
timestampToIso(record.timestamp_ms) ||
|
|
197
|
+
timestampToIso(record.timestamp) ||
|
|
198
|
+
lastEventTimestamp;
|
|
199
|
+
}
|
|
200
|
+
} finally {
|
|
201
|
+
rl.close();
|
|
202
|
+
}
|
|
203
|
+
} catch {
|
|
204
|
+
return { totalTokens, lastEventId, lastEventTimestamp };
|
|
205
|
+
}
|
|
206
|
+
return { totalTokens, lastEventId, lastEventTimestamp };
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
async function main() {
|
|
210
|
+
const contextTokensUsed = toNonNegativeFiniteNumber(signals.contextTokensUsed ?? signals.totalTokens);
|
|
211
|
+
const totalTokensBeforeCompaction = toNonNegativeFiniteNumber(signals.totalTokensBeforeCompaction);
|
|
212
|
+
const signalTotalTokens = totalTokensBeforeCompaction + contextTokensUsed;
|
|
213
|
+
const updateTelemetry = await readUpdateTelemetry(updatesPath);
|
|
214
|
+
const totalTokens = Math.max(updateTelemetry.totalTokens, signalTotalTokens);
|
|
147
215
|
const messageCount = toNonNegativeFiniteNumber(signals.assistantMessageCount || signals.num_chat_messages);
|
|
148
216
|
const model = signals.primaryModelId || (Array.isArray(signals.modelsUsed) ? signals.modelsUsed[0] : 'grok-build');
|
|
149
|
-
const lastActive = signals.lastActiveAt || summary.updated_at || new Date().toISOString();
|
|
217
|
+
const lastActive = signals.lastActiveAt || updateTelemetry.lastEventTimestamp || summary.updated_at || new Date().toISOString();
|
|
150
218
|
|
|
151
219
|
if (totalTokens <= 0) {
|
|
152
220
|
process.exit(0);
|
|
@@ -163,8 +231,16 @@ const signal = {
|
|
|
163
231
|
cwd: WORKSPACE_ROOT,
|
|
164
232
|
model,
|
|
165
233
|
totalTokens,
|
|
234
|
+
contextTokensUsed,
|
|
235
|
+
totalTokensBeforeCompaction,
|
|
166
236
|
messageCount,
|
|
167
237
|
lastActive,
|
|
238
|
+
sessionDir,
|
|
239
|
+
updatesPath,
|
|
240
|
+
signalsPath,
|
|
241
|
+
summaryPath,
|
|
242
|
+
lastEventId: updateTelemetry.lastEventId,
|
|
243
|
+
lastEventTimestamp: updateTelemetry.lastEventTimestamp,
|
|
168
244
|
capturedAt: new Date().toISOString()
|
|
169
245
|
};
|
|
170
246
|
|
|
@@ -177,6 +253,9 @@ try {
|
|
|
177
253
|
} catch {}
|
|
178
254
|
|
|
179
255
|
process.exit(0);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
main().catch(() => process.exit(0));
|
|
180
259
|
`;
|
|
181
260
|
}
|
|
182
261
|
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"deepseek-v4-flash":{ "input": 0.14, "output": 0.28, "cache_read": 0.0028, "cache_write": 0.14 },
|
|
19
19
|
"deepseek-v4-pro": { "input": 0.435,"output": 0.87, "cache_read": 0.003625, "cache_write": 0.435 },
|
|
20
20
|
"deepseek-chat": { "input": 0.14, "output": 0.28, "cache_read": 0.0028, "cache_write": 0.14 },
|
|
21
|
-
"grok-build": { "input": 1.25, "output": 2.50, "cache_read": 0.20, "note": "Grok Build TUI estimate.
|
|
21
|
+
"grok-build": { "input": 1.25, "output": 2.50, "cache_read": 0.20, "note": "Grok Build TUI estimate. Local telemetry currently exposes totalTokens without a stable prompt/output/cache split, so TokenTracker estimates input/output split until Grok exposes per-call usage details." },
|
|
22
22
|
"grok-4-0709": { "input": 3.00, "output": 15.00, "cache_read": 0.75 },
|
|
23
23
|
"grok-4": { "input": 3.00, "output": 15.00, "cache_read": 0.75 },
|
|
24
24
|
"grok-4-latest": { "input": 3.00, "output": 15.00, "cache_read": 0.75 },
|