tokentracker-cli 0.5.99 → 0.5.100
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 +6 -5
- package/README.zh-CN.md +7 -5
- package/dashboard/dist/assets/{main-BhjD_pKB.js → main-BYMjcXxR.js} +169 -168
- package/dashboard/dist/index.html +1 -1
- package/dashboard/dist/share.html +1 -1
- package/package.json +2 -2
- package/src/commands/init.js +12 -0
- package/src/commands/status.js +63 -15
- package/src/commands/sync.js +26 -0
- package/src/lib/pricing/seed-snapshot.json +1 -1
- package/src/lib/rollout.js +259 -0
|
@@ -135,7 +135,7 @@
|
|
|
135
135
|
]
|
|
136
136
|
}
|
|
137
137
|
</script>
|
|
138
|
-
<script type="module" crossorigin src="/assets/main-
|
|
138
|
+
<script type="module" crossorigin src="/assets/main-BYMjcXxR.js"></script>
|
|
139
139
|
<link rel="stylesheet" crossorigin href="/assets/main-HLMqEvtH.css">
|
|
140
140
|
</head>
|
|
141
141
|
<body>
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
"description": "Shareable Token Tracker dashboard snapshot."
|
|
52
52
|
}
|
|
53
53
|
</script>
|
|
54
|
-
<script type="module" crossorigin src="/assets/main-
|
|
54
|
+
<script type="module" crossorigin src="/assets/main-BYMjcXxR.js"></script>
|
|
55
55
|
<link rel="stylesheet" crossorigin href="/assets/main-HLMqEvtH.css">
|
|
56
56
|
</head>
|
|
57
57
|
<body>
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tokentracker-cli",
|
|
3
|
-
"version": "0.5.
|
|
4
|
-
"description": "Token usage tracker for AI agent CLIs (Claude Code, Codex, Cursor,
|
|
3
|
+
"version": "0.5.100",
|
|
4
|
+
"description": "Token usage tracker for AI agent CLIs (Claude Code, Codex, Cursor, Gemini, Kiro, OpenCode, OpenClaw, Every Code, Hermes, GitHub Copilot, Kimi Code, CodeBuddy, oh-my-pi)",
|
|
5
5
|
"main": "src/cli.js",
|
|
6
6
|
"bin": {
|
|
7
7
|
"tokentracker-cli": "bin/tracker.js",
|
package/src/commands/init.js
CHANGED
|
@@ -425,6 +425,18 @@ async function applyIntegrationSetup({ home, trackerDir, notifyPath, notifyOrigi
|
|
|
425
425
|
}
|
|
426
426
|
}
|
|
427
427
|
|
|
428
|
+
// oh-my-pi: passive reader — no hook installation needed.
|
|
429
|
+
// TokenTracker reads ~/.omp/agent/sessions/**/*.jsonl directly.
|
|
430
|
+
{
|
|
431
|
+
const ompHome = process.env.OMP_HOME ||
|
|
432
|
+
(process.env.PI_CONFIG_DIR ? path.join(home, process.env.PI_CONFIG_DIR) : path.join(home, ".omp"));
|
|
433
|
+
const ompAgentDir = process.env.PI_CODING_AGENT_DIR || path.join(ompHome, "agent");
|
|
434
|
+
const ompSessions = path.join(ompAgentDir, "sessions");
|
|
435
|
+
if (fssync.existsSync(ompSessions)) {
|
|
436
|
+
summary.push({ label: "oh-my-pi", status: "detected", detail: "Passive reader (no hook needed)" });
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
|
|
428
440
|
// CodeBuddy: Claude-Code fork. Install the SessionEnd hook so finished
|
|
429
441
|
// sessions trigger notify.cjs → tracker sync; passive scan still runs as a
|
|
430
442
|
// safety net for sessions that don't fire SessionEnd cleanly.
|
package/src/commands/status.js
CHANGED
|
@@ -16,19 +16,31 @@ const {
|
|
|
16
16
|
isGeminiHookConfigured,
|
|
17
17
|
buildGeminiHookCommand,
|
|
18
18
|
} = require("../lib/gemini-config");
|
|
19
|
-
const {
|
|
19
|
+
const {
|
|
20
|
+
resolveOpencodeConfigDir,
|
|
21
|
+
isOpencodePluginInstalled,
|
|
22
|
+
} = require("../lib/opencode-config");
|
|
20
23
|
const { collectLocalSubscriptions } = require("../lib/subscriptions");
|
|
21
|
-
const {
|
|
22
|
-
|
|
24
|
+
const {
|
|
25
|
+
describeCopilotOtelStatus,
|
|
26
|
+
readCopilotOauthToken,
|
|
27
|
+
} = require("../lib/usage-limits");
|
|
28
|
+
const {
|
|
29
|
+
normalizeState: normalizeUploadState,
|
|
30
|
+
} = require("../lib/upload-throttle");
|
|
23
31
|
const { collectTrackerDiagnostics } = require("../lib/diagnostics");
|
|
24
32
|
const { probeOpenclawHookState } = require("../lib/openclaw-hook");
|
|
25
|
-
const {
|
|
33
|
+
const {
|
|
34
|
+
probeOpenclawSessionPluginState,
|
|
35
|
+
} = require("../lib/openclaw-session-plugin");
|
|
26
36
|
const { resolveTrackerPaths } = require("../lib/tracker-paths");
|
|
27
37
|
const {
|
|
28
38
|
resolveKimiWireFiles,
|
|
29
39
|
resolveKiroCliDbPath,
|
|
30
40
|
resolveCodebuddyHome,
|
|
31
41
|
resolveCodebuddyProjectFiles,
|
|
42
|
+
resolveOmpSessionFiles,
|
|
43
|
+
resolveOmpAgentDir,
|
|
32
44
|
} = require("../lib/rollout");
|
|
33
45
|
|
|
34
46
|
async function cmdStatus(argv = []) {
|
|
@@ -60,8 +72,13 @@ async function cmdStatus(argv = []) {
|
|
|
60
72
|
"settings.json",
|
|
61
73
|
);
|
|
62
74
|
const geminiConfigDir = resolveGeminiConfigDir({ home, env: process.env });
|
|
63
|
-
const geminiSettingsPath = resolveGeminiSettingsPath({
|
|
64
|
-
|
|
75
|
+
const geminiSettingsPath = resolveGeminiSettingsPath({
|
|
76
|
+
configDir: geminiConfigDir,
|
|
77
|
+
});
|
|
78
|
+
const opencodeConfigDir = resolveOpencodeConfigDir({
|
|
79
|
+
home,
|
|
80
|
+
env: process.env,
|
|
81
|
+
});
|
|
65
82
|
const notifyPath = path.join(binDir, "notify.cjs");
|
|
66
83
|
const claudeHookCommand = buildClaudeHookCommand(notifyPath);
|
|
67
84
|
const codebuddyHookCommand = buildHookCommand(notifyPath, "codebuddy");
|
|
@@ -70,20 +87,26 @@ async function cmdStatus(argv = []) {
|
|
|
70
87
|
const config = await readJson(configPath);
|
|
71
88
|
const cursors = await readJson(cursorsPath);
|
|
72
89
|
const queueState = (await readJson(queueStatePath)) || { offset: 0 };
|
|
73
|
-
const uploadThrottle = normalizeUploadState(
|
|
90
|
+
const uploadThrottle = normalizeUploadState(
|
|
91
|
+
await readJson(uploadThrottlePath),
|
|
92
|
+
);
|
|
74
93
|
const autoRetry = await readJson(autoRetryPath);
|
|
75
94
|
|
|
76
95
|
const queueSize = await safeStatSize(queuePath);
|
|
77
96
|
const pendingBytes = Math.max(0, queueSize - (queueState.offset || 0));
|
|
78
97
|
|
|
79
98
|
const lastNotify = (await safeReadText(notifySignalPath))?.trim() || null;
|
|
80
|
-
const lastOpenclawSync =
|
|
81
|
-
|
|
99
|
+
const lastOpenclawSync =
|
|
100
|
+
(await safeReadText(openclawSignalPath))?.trim() || null;
|
|
101
|
+
const lastNotifySpawn = parseEpochMsToIso(
|
|
102
|
+
(await safeReadText(throttlePath))?.trim() || null,
|
|
103
|
+
);
|
|
82
104
|
|
|
83
105
|
const codexNotify = await readCodexNotify(codexConfigPath);
|
|
84
106
|
const notifyConfigured = Array.isArray(codexNotify) && codexNotify.length > 0;
|
|
85
107
|
const everyCodeNotify = await readEveryCodeNotify(codeConfigPath);
|
|
86
|
-
const everyCodeConfigured =
|
|
108
|
+
const everyCodeConfigured =
|
|
109
|
+
Array.isArray(everyCodeNotify) && everyCodeNotify.length > 0;
|
|
87
110
|
const claudeHookConfigured = await isClaudeHookConfigured({
|
|
88
111
|
settingsPath: claudeSettingsPath,
|
|
89
112
|
hookCommand: claudeHookCommand,
|
|
@@ -104,7 +127,11 @@ async function cmdStatus(argv = []) {
|
|
|
104
127
|
trackerDir,
|
|
105
128
|
env: process.env,
|
|
106
129
|
});
|
|
107
|
-
const openclawHookState = await probeOpenclawHookState({
|
|
130
|
+
const openclawHookState = await probeOpenclawHookState({
|
|
131
|
+
home,
|
|
132
|
+
trackerDir,
|
|
133
|
+
env: process.env,
|
|
134
|
+
});
|
|
108
135
|
|
|
109
136
|
const lastUpload = uploadThrottle.lastSuccessMs
|
|
110
137
|
? parseEpochMsToIso(uploadThrottle.lastSuccessMs)
|
|
@@ -151,9 +178,17 @@ async function cmdStatus(argv = []) {
|
|
|
151
178
|
? resolveCodebuddyProjectFiles(process.env)
|
|
152
179
|
: [];
|
|
153
180
|
|
|
181
|
+
// oh-my-pi — passive scan only (no hooks).
|
|
182
|
+
const ompAgentDir = resolveOmpAgentDir(process.env);
|
|
183
|
+
const ompInstalled = fssync.existsSync(path.join(ompAgentDir, "sessions"));
|
|
184
|
+
const ompFiles = ompInstalled ? resolveOmpSessionFiles(process.env) : [];
|
|
185
|
+
|
|
154
186
|
const copilotToken = readCopilotOauthToken({ home });
|
|
155
187
|
const copilotOtel = describeCopilotOtelStatus({ home, env: process.env });
|
|
156
|
-
const copilotLines = formatCopilotLines({
|
|
188
|
+
const copilotLines = formatCopilotLines({
|
|
189
|
+
token: copilotToken,
|
|
190
|
+
otel: copilotOtel,
|
|
191
|
+
});
|
|
157
192
|
|
|
158
193
|
process.stdout.write(
|
|
159
194
|
[
|
|
@@ -186,6 +221,9 @@ async function cmdStatus(argv = []) {
|
|
|
186
221
|
codebuddyInstalled
|
|
187
222
|
? `- CodeBuddy hooks: ${codebuddyHookConfigured ? "set" : "unset"} (${codebuddyFiles.length} session jsonl file${codebuddyFiles.length !== 1 ? "s" : ""} found)`
|
|
188
223
|
: null,
|
|
224
|
+
ompInstalled
|
|
225
|
+
? `- oh-my-pi: passive reader (${ompFiles.length} session jsonl file${ompFiles.length !== 1 ? "s" : ""} found)`
|
|
226
|
+
: null,
|
|
189
227
|
...copilotLines,
|
|
190
228
|
...subscriptionLines,
|
|
191
229
|
"",
|
|
@@ -197,7 +235,9 @@ async function cmdStatus(argv = []) {
|
|
|
197
235
|
|
|
198
236
|
function formatCopilotLines({ token, otel }) {
|
|
199
237
|
if (!token && !otel.otel_has_files) return [];
|
|
200
|
-
const limitsState = token
|
|
238
|
+
const limitsState = token
|
|
239
|
+
? "set (via GitHub OAuth)"
|
|
240
|
+
: "unset (no Copilot OAuth token found)";
|
|
201
241
|
const usageState = otel.otel_has_files
|
|
202
242
|
? `set (${otel.otel_path || otel.otel_default_dir})`
|
|
203
243
|
: otel.otel_enabled
|
|
@@ -235,7 +275,11 @@ function formatSubscriptionLine(entry = {}) {
|
|
|
235
275
|
|
|
236
276
|
if (!planType) return null;
|
|
237
277
|
|
|
238
|
-
if (
|
|
278
|
+
if (
|
|
279
|
+
tool === "claude" &&
|
|
280
|
+
provider === "anthropic" &&
|
|
281
|
+
product === "subscription"
|
|
282
|
+
) {
|
|
239
283
|
const suffix = rateLimitTier ? ` (rate limit tier: ${rateLimitTier})` : "";
|
|
240
284
|
return `- ${toolLabel} subscription: ${planType}${suffix}`;
|
|
241
285
|
}
|
|
@@ -249,7 +293,11 @@ function formatSubscriptionLine(entry = {}) {
|
|
|
249
293
|
}
|
|
250
294
|
|
|
251
295
|
function parseArgs(argv) {
|
|
252
|
-
const out = {
|
|
296
|
+
const out = {
|
|
297
|
+
diagnostics: false,
|
|
298
|
+
probeKeychain: false,
|
|
299
|
+
probeKeychainDetails: false,
|
|
300
|
+
};
|
|
253
301
|
|
|
254
302
|
for (let i = 0; i < argv.length; i++) {
|
|
255
303
|
const a = argv[i];
|
package/src/commands/sync.js
CHANGED
|
@@ -27,6 +27,8 @@ const {
|
|
|
27
27
|
parseCopilotIncremental,
|
|
28
28
|
resolveKimiWireFiles,
|
|
29
29
|
parseKimiIncremental,
|
|
30
|
+
resolveOmpSessionFiles,
|
|
31
|
+
parseOmpIncremental,
|
|
30
32
|
resolveCodebuddyProjectFiles,
|
|
31
33
|
parseCodebuddyIncremental,
|
|
32
34
|
resolveKiroCliSessionFiles,
|
|
@@ -447,6 +449,28 @@ async function cmdSync(argv) {
|
|
|
447
449
|
});
|
|
448
450
|
}
|
|
449
451
|
|
|
452
|
+
// ── oh-my-pi (passive ~/.omp/agent/sessions/**/*.jsonl reader) ──
|
|
453
|
+
let ompResult = { recordsProcessed: 0, eventsAggregated: 0, bucketsQueued: 0 };
|
|
454
|
+
const ompFiles = resolveOmpSessionFiles(process.env);
|
|
455
|
+
if (ompFiles.length > 0) {
|
|
456
|
+
if (progress?.enabled) {
|
|
457
|
+
progress.start(`Parsing oh-my-pi ${renderBar(0)} | buckets 0`);
|
|
458
|
+
}
|
|
459
|
+
ompResult = await parseOmpIncremental({
|
|
460
|
+
sessionFiles: ompFiles,
|
|
461
|
+
cursors,
|
|
462
|
+
queuePath,
|
|
463
|
+
env: process.env,
|
|
464
|
+
onProgress: (p) => {
|
|
465
|
+
if (!progress?.enabled) return;
|
|
466
|
+
const pct = p.total > 0 ? p.index / p.total : 1;
|
|
467
|
+
progress.update(
|
|
468
|
+
`Parsing oh-my-pi ${renderBar(pct)} ${formatNumber(p.index)}/${formatNumber(p.total)} files | buckets ${formatNumber(p.bucketsQueued)}`,
|
|
469
|
+
);
|
|
470
|
+
},
|
|
471
|
+
});
|
|
472
|
+
}
|
|
473
|
+
|
|
450
474
|
// ── GitHub Copilot CLI (OTEL JSONL files) ──
|
|
451
475
|
let copilotResult = { recordsProcessed: 0, eventsAggregated: 0, bucketsQueued: 0 };
|
|
452
476
|
const copilotPaths = resolveCopilotOtelPaths(process.env);
|
|
@@ -566,6 +590,7 @@ async function cmdSync(argv) {
|
|
|
566
590
|
hermesResult.recordsProcessed +
|
|
567
591
|
kimiResult.recordsProcessed +
|
|
568
592
|
codebuddyResult.recordsProcessed +
|
|
593
|
+
ompResult.recordsProcessed +
|
|
569
594
|
copilotResult.recordsProcessed;
|
|
570
595
|
const totalBuckets =
|
|
571
596
|
parseResult.bucketsQueued +
|
|
@@ -579,6 +604,7 @@ async function cmdSync(argv) {
|
|
|
579
604
|
hermesResult.bucketsQueued +
|
|
580
605
|
kimiResult.bucketsQueued +
|
|
581
606
|
codebuddyResult.bucketsQueued +
|
|
607
|
+
ompResult.bucketsQueued +
|
|
582
608
|
copilotResult.bucketsQueued;
|
|
583
609
|
process.stdout.write(
|
|
584
610
|
[
|