tokentracker-cli 0.12.1 → 0.13.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 +4 -2
- package/dashboard/dist/assets/{main-CjKIAPGE.js → main-Dc116CZl.js} +3 -1
- package/dashboard/dist/brand-logos/kilo.svg +4 -0
- package/dashboard/dist/index.html +1 -1
- package/dashboard/dist/share.html +1 -1
- package/package.json +2 -2
- package/src/commands/init.js +28 -0
- package/src/commands/status.js +18 -0
- package/src/commands/sync.js +66 -2
- package/src/lib/pricing/seed-snapshot.json +1 -1
- package/src/lib/rollout.js +251 -2
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
<svg width="512" height="512" viewBox="0 0 512 512" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<path d="M512 0H0V512H512V0Z" fill="black"/>
|
|
3
|
+
<path d="M512 512H0V0H512V512ZM322.783 322.784H278.261V392.747L308.472 422.958H378.435V378.437H322.782L322.783 322.784ZM422.957 308.474L392.746 278.263H322.783V322.784H378.435L378.435 378.437H422.957L422.957 308.474ZM233.739 278.263H189.217V322.784H233.739V278.263ZM89.0435 392.747L119.254 422.958H233.739V378.437H133.565V278.263H89.043L89.0435 392.747ZM372.538 189.217V119.254L342.327 89.0435H278.261V133.565H328.017V189.217H278.261V233.739H422.957V189.217H372.538ZM133.565 89.0435H89.0435V233.739H133.565V183.652H189.218V233.739H233.74V183.652L189.218 139.13H133.565V89.0435ZM233.739 89.0435H189.217L189.218 139.13H233.739V89.0435Z" fill="#FAF74F"/>
|
|
4
|
+
</svg>
|
|
@@ -210,7 +210,7 @@
|
|
|
210
210
|
]
|
|
211
211
|
}
|
|
212
212
|
</script>
|
|
213
|
-
<script type="module" crossorigin src="/assets/main-
|
|
213
|
+
<script type="module" crossorigin src="/assets/main-Dc116CZl.js"></script>
|
|
214
214
|
<link rel="stylesheet" crossorigin href="/assets/main-B-qohcBn.css">
|
|
215
215
|
</head>
|
|
216
216
|
<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-Dc116CZl.js"></script>
|
|
55
55
|
<link rel="stylesheet" crossorigin href="/assets/main-B-qohcBn.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.
|
|
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, pi, Craft Agents)",
|
|
3
|
+
"version": "0.13.0",
|
|
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, pi, Craft Agents, Kilo CLI, Kilo Code)",
|
|
5
5
|
"main": "src/cli.js",
|
|
6
6
|
"bin": {
|
|
7
7
|
"tokentracker-cli": "bin/tracker.js",
|
package/src/commands/init.js
CHANGED
|
@@ -459,6 +459,34 @@ async function applyIntegrationSetup({ home, trackerDir, notifyPath, notifyOrigi
|
|
|
459
459
|
}
|
|
460
460
|
}
|
|
461
461
|
|
|
462
|
+
// Kilo CLI (kilo.ai @kilocode/plugin): passive reader — no hook installation
|
|
463
|
+
// needed. Reuses OpenCode-fork SQLite schema at ~/.local/share/kilo/kilo.db
|
|
464
|
+
// (override via KILO_HOME).
|
|
465
|
+
{
|
|
466
|
+
const xdgDataHome = process.env.XDG_DATA_HOME || path.join(home, ".local", "share");
|
|
467
|
+
const kiloHome = process.env.KILO_HOME || path.join(xdgDataHome, "kilo");
|
|
468
|
+
const kiloDbPath = path.join(kiloHome, "kilo.db");
|
|
469
|
+
if (fssync.existsSync(kiloDbPath)) {
|
|
470
|
+
summary.push({ label: "Kilo CLI", status: "detected", detail: "Passive reader (no hook needed)" });
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
// Kilo Code VS Code extension (kilocode.kilo-code): passive reader — no hook
|
|
475
|
+
// installation needed. Scans ui_messages.json under every detected VS Code-
|
|
476
|
+
// family install (Code, Cursor, CodeBuddy, Windsurf, …).
|
|
477
|
+
{
|
|
478
|
+
const { resolveKilocodeTaskFiles } = require("../lib/rollout");
|
|
479
|
+
const taskFiles = resolveKilocodeTaskFiles(process.env);
|
|
480
|
+
if (taskFiles.length > 0) {
|
|
481
|
+
const ides = Array.from(new Set(taskFiles.map((t) => t.ide))).join(", ");
|
|
482
|
+
summary.push({
|
|
483
|
+
label: "Kilo Code (VS Code extension)",
|
|
484
|
+
status: "detected",
|
|
485
|
+
detail: `Passive reader · ${taskFiles.length} task${taskFiles.length !== 1 ? "s" : ""} in ${ides}`,
|
|
486
|
+
});
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
|
|
462
490
|
// CodeBuddy: Claude-Code fork. Install the SessionEnd hook so finished
|
|
463
491
|
// sessions trigger notify.cjs → tracker sync; passive scan still runs as a
|
|
464
492
|
// safety net for sessions that don't fire SessionEnd cleanly.
|
package/src/commands/status.js
CHANGED
|
@@ -46,6 +46,7 @@ const {
|
|
|
46
46
|
piAgentDirCollidesWithOmp,
|
|
47
47
|
resolveCraftSessionFiles,
|
|
48
48
|
resolveCraftConfigDir,
|
|
49
|
+
resolveKilocodeTaskFiles,
|
|
49
50
|
} = require("../lib/rollout");
|
|
50
51
|
|
|
51
52
|
async function cmdStatus(argv = []) {
|
|
@@ -200,6 +201,17 @@ async function cmdStatus(argv = []) {
|
|
|
200
201
|
const craftInstalled = fssync.existsSync(craftConfigDir);
|
|
201
202
|
const craftFiles = craftInstalled ? resolveCraftSessionFiles(process.env) : [];
|
|
202
203
|
|
|
204
|
+
// Kilo CLI (kilo.ai @kilocode/plugin) — passive scan of kilo.db.
|
|
205
|
+
const xdgDataHome = process.env.XDG_DATA_HOME || path.join(home, ".local", "share");
|
|
206
|
+
const kiloHome = process.env.KILO_HOME || path.join(xdgDataHome, "kilo");
|
|
207
|
+
const kiloDbPath = path.join(kiloHome, "kilo.db");
|
|
208
|
+
const kiloInstalled = fssync.existsSync(kiloDbPath);
|
|
209
|
+
|
|
210
|
+
// Kilo Code VS Code extension — passive scan of all VS Code-family
|
|
211
|
+
// globalStorage/kilocode.kilo-code/tasks/ ui_messages.json files.
|
|
212
|
+
const kilocodeTaskFiles = resolveKilocodeTaskFiles(process.env);
|
|
213
|
+
const kilocodeInstalled = kilocodeTaskFiles.length > 0;
|
|
214
|
+
|
|
203
215
|
const copilotToken = readCopilotOauthToken({ home });
|
|
204
216
|
const copilotOtel = describeCopilotOtelStatus({ home, env: process.env });
|
|
205
217
|
const copilotLines = formatCopilotLines({
|
|
@@ -247,6 +259,12 @@ async function cmdStatus(argv = []) {
|
|
|
247
259
|
craftInstalled
|
|
248
260
|
? `- Craft Agents: passive reader (${craftFiles.length} session jsonl file${craftFiles.length !== 1 ? "s" : ""} found)`
|
|
249
261
|
: null,
|
|
262
|
+
kiloInstalled
|
|
263
|
+
? `- Kilo CLI: passive reader (${kiloDbPath})`
|
|
264
|
+
: null,
|
|
265
|
+
kilocodeInstalled
|
|
266
|
+
? `- Kilo Code (VS Code extension): passive reader (${kilocodeTaskFiles.length} task${kilocodeTaskFiles.length !== 1 ? "s" : ""} across ${new Set(kilocodeTaskFiles.map((t) => t.ide)).size} IDE${new Set(kilocodeTaskFiles.map((t) => t.ide)).size !== 1 ? "s" : ""})`
|
|
267
|
+
: null,
|
|
250
268
|
...copilotLines,
|
|
251
269
|
...subscriptionLines,
|
|
252
270
|
"",
|
package/src/commands/sync.js
CHANGED
|
@@ -40,6 +40,8 @@ const {
|
|
|
40
40
|
resolveKiroCliSessionFiles,
|
|
41
41
|
resolveKiroCliDbPath,
|
|
42
42
|
parseKiroCliIncremental,
|
|
43
|
+
resolveKilocodeTaskFiles,
|
|
44
|
+
parseKilocodeIncremental,
|
|
43
45
|
bucketKey,
|
|
44
46
|
totalsKey,
|
|
45
47
|
groupBucketKey,
|
|
@@ -133,6 +135,7 @@ async function cmdSync(argv) {
|
|
|
133
135
|
const xdgDataHome = process.env.XDG_DATA_HOME || path.join(home, ".local", "share");
|
|
134
136
|
const opencodeHome = process.env.OPENCODE_HOME || path.join(xdgDataHome, "opencode");
|
|
135
137
|
const opencodeStorageDir = path.join(opencodeHome, "storage");
|
|
138
|
+
const kiloHome = process.env.KILO_HOME || path.join(xdgDataHome, "kilo");
|
|
136
139
|
|
|
137
140
|
// OpenClaw hook integration: allow a hook to request incremental parsing for a single session jsonl.
|
|
138
141
|
// We still parse all regular sources so model/source attribution stays complete (e.g. Kimi sessions).
|
|
@@ -324,6 +327,63 @@ async function cmdSync(argv) {
|
|
|
324
327
|
opencodeResult.bucketsQueued += opencodeDbResult.bucketsQueued;
|
|
325
328
|
}
|
|
326
329
|
|
|
330
|
+
// ── Kilo CLI (kilo.ai @kilocode/plugin — OpenCode-fork SQLite) ──
|
|
331
|
+
// Uses the exact same `message` table schema as OpenCode v1.2+. We reuse
|
|
332
|
+
// the OpenCode DB reader/parser, just with a separate cursor namespace so
|
|
333
|
+
// the message indexes don't collide.
|
|
334
|
+
const kiloDbPath = path.join(kiloHome, "kilo.db");
|
|
335
|
+
let kiloResult = { messagesProcessed: 0, eventsAggregated: 0, bucketsQueued: 0 };
|
|
336
|
+
const kiloDbMessages = readOpencodeDbMessages(kiloDbPath);
|
|
337
|
+
if (kiloDbMessages.length > 0) {
|
|
338
|
+
if (progress?.enabled) {
|
|
339
|
+
progress.start(
|
|
340
|
+
`Parsing Kilo CLI ${renderBar(0)} 0/${formatNumber(kiloDbMessages.length)} msgs | buckets 0`,
|
|
341
|
+
);
|
|
342
|
+
}
|
|
343
|
+
kiloResult = await parseOpencodeDbIncremental({
|
|
344
|
+
dbMessages: kiloDbMessages,
|
|
345
|
+
cursors,
|
|
346
|
+
queuePath,
|
|
347
|
+
projectQueuePath,
|
|
348
|
+
onProgress: (p) => {
|
|
349
|
+
if (!progress?.enabled) return;
|
|
350
|
+
const pct = p.total > 0 ? p.index / p.total : 1;
|
|
351
|
+
progress.update(
|
|
352
|
+
`Parsing Kilo CLI ${renderBar(pct)} ${formatNumber(p.index)}/${formatNumber(
|
|
353
|
+
p.total,
|
|
354
|
+
)} msgs | buckets ${formatNumber(p.bucketsQueued)}`,
|
|
355
|
+
);
|
|
356
|
+
},
|
|
357
|
+
source: "kilo-cli",
|
|
358
|
+
cursorKey: "kiloCli",
|
|
359
|
+
});
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
// ── Kilo Code VS Code extension (Cline-style ui_messages.json) ──
|
|
363
|
+
const kilocodeTaskFiles = resolveKilocodeTaskFiles(process.env);
|
|
364
|
+
let kilocodeResult = { recordsProcessed: 0, eventsAggregated: 0, bucketsQueued: 0 };
|
|
365
|
+
if (kilocodeTaskFiles.length > 0) {
|
|
366
|
+
if (progress?.enabled) {
|
|
367
|
+
progress.start(
|
|
368
|
+
`Parsing Kilo Code ${renderBar(0)} 0/${formatNumber(kilocodeTaskFiles.length)} tasks | buckets 0`,
|
|
369
|
+
);
|
|
370
|
+
}
|
|
371
|
+
kilocodeResult = await parseKilocodeIncremental({
|
|
372
|
+
taskFiles: kilocodeTaskFiles,
|
|
373
|
+
cursors,
|
|
374
|
+
queuePath,
|
|
375
|
+
onProgress: (p) => {
|
|
376
|
+
if (!progress?.enabled) return;
|
|
377
|
+
const pct = p.total > 0 ? p.index / p.total : 1;
|
|
378
|
+
progress.update(
|
|
379
|
+
`Parsing Kilo Code ${renderBar(pct)} ${formatNumber(p.index)}/${formatNumber(
|
|
380
|
+
p.total,
|
|
381
|
+
)} tasks | buckets ${formatNumber(p.bucketsQueued)}`,
|
|
382
|
+
);
|
|
383
|
+
},
|
|
384
|
+
});
|
|
385
|
+
}
|
|
386
|
+
|
|
327
387
|
// ── Cursor (API-based) ──
|
|
328
388
|
// One-time migration: earlier CLI versions mis-parsed the Cursor CSV after
|
|
329
389
|
// Cursor inserted new "Cloud Agent ID"/"Automation ID" columns, writing
|
|
@@ -689,7 +749,9 @@ async function cmdSync(argv) {
|
|
|
689
749
|
ompResult.recordsProcessed +
|
|
690
750
|
piResult.recordsProcessed +
|
|
691
751
|
craftResult.recordsProcessed +
|
|
692
|
-
copilotResult.recordsProcessed
|
|
752
|
+
copilotResult.recordsProcessed +
|
|
753
|
+
kiloResult.messagesProcessed +
|
|
754
|
+
kilocodeResult.recordsProcessed;
|
|
693
755
|
const totalBuckets =
|
|
694
756
|
parseResult.bucketsQueued +
|
|
695
757
|
openclawResult.bucketsQueued +
|
|
@@ -705,7 +767,9 @@ async function cmdSync(argv) {
|
|
|
705
767
|
ompResult.bucketsQueued +
|
|
706
768
|
piResult.bucketsQueued +
|
|
707
769
|
craftResult.bucketsQueued +
|
|
708
|
-
copilotResult.bucketsQueued
|
|
770
|
+
copilotResult.bucketsQueued +
|
|
771
|
+
kiloResult.bucketsQueued +
|
|
772
|
+
kilocodeResult.bucketsQueued;
|
|
709
773
|
process.stdout.write(
|
|
710
774
|
[
|
|
711
775
|
"Sync finished:",
|