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.
@@ -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-CjKIAPGE.js"></script>
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-CjKIAPGE.js"></script>
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.12.1",
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",
@@ -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.
@@ -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
  "",
@@ -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:",