tokentracker-cli 0.77.1 → 0.78.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.
Files changed (83) hide show
  1. package/README.de.md +24 -3
  2. package/README.ja.md +3 -3
  3. package/README.ko.md +3 -3
  4. package/README.md +24 -3
  5. package/README.zh-CN.md +3 -3
  6. package/dashboard/dist/assets/ActivityHeatmap-5352XxLR.js +42 -0
  7. package/dashboard/dist/assets/{Card-DP2HT77t.js → Card-Ca_hYHhx.js} +1 -1
  8. package/dashboard/dist/assets/{ClawdAnimated-ScYRJSG0.js → ClawdAnimated-DSgOS5ND.js} +1 -1
  9. package/dashboard/dist/assets/{CommunityStatsModal-CU46JMkg.js → CommunityStatsModal-o8uQVQxu.js} +1 -1
  10. package/dashboard/dist/assets/ConfirmModal-D1hi9XUf.js +1 -0
  11. package/dashboard/dist/assets/Controls-CwnKP56V.js +1 -0
  12. package/dashboard/dist/assets/DashboardPage-CDv0TIOL.js +19 -0
  13. package/dashboard/dist/assets/{DevicePage-BL9ew9-m.js → DevicePage-BlfIHcZX.js} +1 -1
  14. package/dashboard/dist/assets/DialogClose-CismfYwe.js +1 -0
  15. package/dashboard/dist/assets/DialogDescription-DWKp1yez.js +1 -0
  16. package/dashboard/dist/assets/{DialogTitle-Oqnn_dIL.js → DialogTitle-DuuTVbUb.js} +1 -1
  17. package/dashboard/dist/assets/{FadeIn-CFLwnHqt.js → FadeIn-DpnitRKo.js} +1 -1
  18. package/dashboard/dist/assets/{HeaderGithubStar-B397ELF4.js → HeaderGithubStar-D6zy-ADl.js} +1 -1
  19. package/dashboard/dist/assets/{IpCheckPage-CamsHe6o.js → IpCheckPage-yUNp0VNe.js} +1 -1
  20. package/dashboard/dist/assets/LandingPage-BvmpAaVn.js +4314 -0
  21. package/dashboard/dist/assets/LeaderboardAvatar-2WTIeXye.js +1 -0
  22. package/dashboard/dist/assets/LeaderboardPage-Bq3-VO7w.js +2 -0
  23. package/dashboard/dist/assets/{LeaderboardProfileModal-BIe6gBNu.js → LeaderboardProfileModal-DH0EEK6q.js} +3 -3
  24. package/dashboard/dist/assets/{LeaderboardProfilePage-DeVBEYtg.js → LeaderboardProfilePage-uJAng2JE.js} +3 -3
  25. package/dashboard/dist/assets/{LimitsPage-6I5EU7qe.js → LimitsPage-D8UohgJm.js} +2 -2
  26. package/dashboard/dist/assets/{LocalOnlyNotice-AyYKZloH.js → LocalOnlyNotice-Dv_BnDVV.js} +1 -1
  27. package/dashboard/dist/assets/{LoginPage-D8smF1gU.js → LoginPage-D6b6DZU3.js} +1 -1
  28. package/dashboard/dist/assets/PetPage-DfpBkuCa.js +1 -0
  29. package/dashboard/dist/assets/{PopoverPopup-DRWhz-bY.js → PopoverPopup-CjzdZn-9.js} +1 -1
  30. package/dashboard/dist/assets/{ResetPasswordPage-CzSqJfuA.js → ResetPasswordPage-BnOCFkwe.js} +1 -1
  31. package/dashboard/dist/assets/Select-CHtQAiLD.js +1 -0
  32. package/dashboard/dist/assets/{SelectItemText-DEYadcIK.js → SelectItemText-Vjqvf8wO.js} +1 -1
  33. package/dashboard/dist/assets/SettingsPage-B-iHGL4q.js +1 -0
  34. package/dashboard/dist/assets/SkillsPage-DtG2aV-q.js +1 -0
  35. package/dashboard/dist/assets/WidgetsPage-4kqTtWfK.js +1 -0
  36. package/dashboard/dist/assets/{WrappedPage-BuP9KXqF.js → WrappedPage-DMMRpani.js} +1 -1
  37. package/dashboard/dist/assets/agent-logos-D0vYkEpX.js +1 -0
  38. package/dashboard/dist/assets/{arrow-up-right-cFMBPEVS.js → arrow-up-right-BAQYGZkR.js} +1 -1
  39. package/dashboard/dist/assets/check-C3RPBZiS.js +1 -0
  40. package/dashboard/dist/assets/{copy-DYx8X3ZO.js → copy-gG_BLBs8.js} +1 -1
  41. package/dashboard/dist/assets/{download-B-hXZWKj.js → download-BQOcg3gT.js} +1 -1
  42. package/dashboard/dist/assets/{format-tokens-CngV51wN.js → format-tokens-CGK6lQAf.js} +1 -1
  43. package/dashboard/dist/assets/{info-qVF2hV50.js → info-C_BrDrcq.js} +1 -1
  44. package/dashboard/dist/assets/{link-2-DR-yGZFS.js → link-2-DFwCBbIZ.js} +1 -1
  45. package/dashboard/dist/assets/{loader-circle-0k9uueb5.js → loader-circle-BMFI_BJ8.js} +1 -1
  46. package/dashboard/dist/assets/{main-B8lT0e78.css → main-Dy8Y_qst.css} +1 -1
  47. package/dashboard/dist/assets/main-w0hAaCsy.js +1190 -0
  48. package/dashboard/dist/assets/{trash-2-DpxBaV_1.js → trash-2-GeZ6IzgV.js} +1 -1
  49. package/dashboard/dist/assets/{use-community-stats-Cbij-V8j.js → use-community-stats-pC8cmVof.js} +1 -1
  50. package/dashboard/dist/assets/{use-limits-display-prefs-q0TuryM0.js → use-limits-display-prefs-DnFpPcA3.js} +1 -1
  51. package/dashboard/dist/assets/use-native-settings-CvcOSUhn.js +1 -0
  52. package/dashboard/dist/assets/{use-ordered-list-CH-J7c04.js → use-ordered-list-CbMroVZ8.js} +2 -2
  53. package/dashboard/dist/assets/{use-quality-per-dollar-pref-DKLmkwxe.js → use-quality-per-dollar-pref-Bn3Al6yX.js} +1 -1
  54. package/dashboard/dist/assets/{use-usage-limits-DrmF6I_t.js → use-usage-limits-D08q_Dr8.js} +1 -1
  55. package/dashboard/dist/assets/{useCurrency-DwygZqrs.js → useCurrency-h3kqF52v.js} +1 -1
  56. package/dashboard/dist/assets/{useScrollLock-DVCKuErg.js → useScrollLock-9au2731u.js} +1 -1
  57. package/dashboard/dist/index.html +2 -2
  58. package/dashboard/dist/share.html +2 -2
  59. package/package.json +1 -1
  60. package/src/commands/status.js +293 -30
  61. package/src/commands/sync.js +494 -104
  62. package/src/lib/install-resolver.js +1 -0
  63. package/src/lib/local-api.js +202 -56
  64. package/src/lib/pricing/seed-snapshot.json +1 -1
  65. package/src/lib/rollout.js +1329 -40
  66. package/dashboard/dist/assets/ActivityHeatmap-DTZh551Z.js +0 -42
  67. package/dashboard/dist/assets/ConfirmModal-BYvz0dzg.js +0 -1
  68. package/dashboard/dist/assets/Controls-DPElSq0S.js +0 -1
  69. package/dashboard/dist/assets/DashboardPage-CN0buIso.js +0 -19
  70. package/dashboard/dist/assets/DialogClose-cqXrG903.js +0 -1
  71. package/dashboard/dist/assets/DialogDescription-Bo0iWtYz.js +0 -1
  72. package/dashboard/dist/assets/LandingPage-D4ygTHwO.js +0 -4312
  73. package/dashboard/dist/assets/LeaderboardAvatar-B39rNGCV.js +0 -1
  74. package/dashboard/dist/assets/LeaderboardPage-BFUOxX6P.js +0 -2
  75. package/dashboard/dist/assets/PetPage-BlMYvJn2.js +0 -1
  76. package/dashboard/dist/assets/Select-Cb8n7kQO.js +0 -1
  77. package/dashboard/dist/assets/SettingsPage-DlHXcFdJ.js +0 -1
  78. package/dashboard/dist/assets/SkillsPage--Kcv1pxG.js +0 -1
  79. package/dashboard/dist/assets/WidgetsPage-DwtJ9CKU.js +0 -1
  80. package/dashboard/dist/assets/agent-logos-DbwDXgg1.js +0 -1
  81. package/dashboard/dist/assets/check-t_ltRp2A.js +0 -1
  82. package/dashboard/dist/assets/main-CU04bNYH.js +0 -1172
  83. package/dashboard/dist/assets/use-native-settings-BCzogs1L.js +0 -1
@@ -60,22 +60,26 @@ const {
60
60
  resolveGrokBuildSessions,
61
61
  resolveHermesPath,
62
62
  resolveHermesDbPath,
63
+ resolveCopilotSessionStorePaths,
64
+ describeCopilotSessionStoreDb,
63
65
  resolveCopilotAppDbPath,
64
66
  resolveCopilotAppDbPaths,
65
67
  probeWslDistros,
66
68
  } = require("../lib/rollout");
67
69
  const wsl = require("../lib/wsl-probe");
68
- const { getWslMode, isInvalidWslMode, shouldProbeWsl } = wsl;
70
+ const { getWslMode, isInvalidWslMode, shouldProbeWsl, discoverWslHome } = wsl;
69
71
  const { resolveInstallPaths } = require("../lib/install-resolver");
70
72
  const { probeGrokHookState, resolveGrokHome } = require("../lib/grok-hook");
71
73
 
72
74
  function formatResolvedPaths(paths, filename) {
73
75
  const active = [];
74
76
  if (paths.native) {
75
- active.push(`native: ${filename ? path.join(paths.native, filename) : paths.native}`);
77
+ const file = filename ? path.join(paths.native, filename) : paths.native;
78
+ try { if (fssync.existsSync(file)) active.push(`native: ${file}`); } catch (_e) {}
76
79
  }
77
80
  if (paths.wsl) {
78
- active.push(`WSL: ${filename ? path.join(paths.wsl, filename) : paths.wsl}`);
81
+ const file = filename ? path.join(paths.wsl, filename) : paths.wsl;
82
+ try { if (fssync.existsSync(file)) active.push(`WSL: ${file}`); } catch (_e) {}
79
83
  }
80
84
  return active;
81
85
  }
@@ -105,11 +109,11 @@ async function cmdStatus(argv = []) {
105
109
  const codeConfigPath = path.join(codeHome, "config.toml");
106
110
  const claudeSettingsPath = path.join(home, ".claude", "settings.json");
107
111
  const codebuddySettingsPath = path.join(
108
- process.env.CODEBUDDY_HOME || path.join(home, ".codebuddy"),
112
+ resolveCodebuddyHome(process.env) || path.join(home, ".codebuddy"),
109
113
  "settings.json",
110
114
  );
111
115
  const workbuddySettingsPath = path.join(
112
- process.env.WORKBUDDY_HOME || path.join(home, ".workbuddy"),
116
+ resolveWorkbuddyHome(process.env) || path.join(home, ".workbuddy"),
113
117
  "settings.json",
114
118
  );
115
119
  const geminiConfigDir = resolveGeminiConfigDir({ home, env: process.env });
@@ -224,7 +228,7 @@ async function cmdStatus(argv = []) {
224
228
  // CodeBuddy — passive scan only (no hooks). Surface the file count so
225
229
  // operators can confirm JSONL sessions and extension logs are discovered.
226
230
  const codebuddyHome = resolveCodebuddyHome(process.env);
227
- const codebuddyInstalled = fssync.existsSync(codebuddyHome);
231
+ const codebuddyInstalled = Boolean(codebuddyHome && fssync.existsSync(codebuddyHome));
228
232
  const codebuddyFiles = codebuddyInstalled
229
233
  ? resolveCodebuddyProjectFiles(process.env)
230
234
  : [];
@@ -232,7 +236,7 @@ async function cmdStatus(argv = []) {
232
236
  // WorkBuddy — passive scan (sibling Claude-Code fork). Surface both the
233
237
  // recursive JSONL count and SQLite fallback so operators can confirm coverage.
234
238
  const workbuddyHome = resolveWorkbuddyHome(process.env);
235
- const workbuddyInstalled = fssync.existsSync(workbuddyHome);
239
+ const workbuddyInstalled = Boolean(workbuddyHome && fssync.existsSync(workbuddyHome));
236
240
  const workbuddyFiles = workbuddyInstalled
237
241
  ? resolveWorkbuddyProjectFiles(process.env)
238
242
  : [];
@@ -254,7 +258,7 @@ async function cmdStatus(argv = []) {
254
258
 
255
259
  // Craft Agents — passive scan only (no hooks).
256
260
  const craftConfigDir = resolveCraftConfigDir(process.env);
257
- const craftInstalled = fssync.existsSync(craftConfigDir);
261
+ const craftInstalled = Boolean(craftConfigDir && fssync.existsSync(craftConfigDir));
258
262
  const craftFiles = craftInstalled ? resolveCraftSessionFiles(process.env) : [];
259
263
 
260
264
  // Kilo CLI (kilo.ai @kilocode/plugin) — passive scan of kilo.db.
@@ -297,6 +301,87 @@ async function cmdStatus(argv = []) {
297
301
  const zcodeInstalled = zcodeActive.length > 0;
298
302
  const zcodeDbPath = zcodeActive.join(" | ");
299
303
 
304
+ // OpenCode (JSON files + SQLite DB) — passive scan of storage/message/ and opencode.db.
305
+ const opencodeStorageNativeValue = process.env.OPENCODE_HOME || path.join(xdgDataHome, "opencode");
306
+ const wslOpencodeStorageDir = process.platform === "win32" && shouldProbeWsl(process.env)
307
+ ? discoverWslHome(".local/share/opencode")
308
+ : null;
309
+ const opencodeStoragePaths = resolveInstallPaths({
310
+ nativeValue: opencodeStorageNativeValue,
311
+ wslValue: wslOpencodeStorageDir,
312
+ });
313
+ const opencodeStorageActive = formatResolvedPaths(opencodeStoragePaths);
314
+
315
+ const opencodeDbNativeValue = process.env.OPENCODE_HOME || path.join(xdgDataHome, "opencode");
316
+ const wslOpencodeDbDir = process.platform === "win32" && shouldProbeWsl(process.env)
317
+ ? discoverWslHome(".local/share/opencode")
318
+ : null;
319
+ const opencodeDbPaths = resolveInstallPaths({
320
+ nativeValue: opencodeDbNativeValue,
321
+ wslValue: wslOpencodeDbDir,
322
+ });
323
+ const opencodeDbActive = formatResolvedPaths(opencodeDbPaths, "opencode.db");
324
+ const opencodeInstalled = opencodeStorageActive.length > 0 || opencodeDbActive.length > 0;
325
+
326
+ // Every Code (passive sessions scan)
327
+ const codePaths = resolveInstallPaths({
328
+ nativeValue: process.env.CODE_HOME || path.join(home, ".code"),
329
+ wslDir: ".code",
330
+ });
331
+ const codeActive = formatResolvedPaths(codePaths, "sessions");
332
+ const codeInstalled = codeActive.length > 0;
333
+
334
+ // Gemini CLI & Antigravity (shared home)
335
+ const geminiPaths = resolveInstallPaths({
336
+ nativeValue: process.env.GEMINI_HOME || path.join(home, ".gemini"),
337
+ wslDir: ".gemini",
338
+ });
339
+ const geminiActive = formatResolvedPaths(geminiPaths);
340
+ const geminiInstalledStatus = geminiActive.length > 0;
341
+
342
+ // Gemini CLI (passive sessions scan)
343
+ const geminiCliActive = formatResolvedPaths(geminiPaths, "tmp");
344
+ const geminiCliInstalled = geminiCliActive.length > 0;
345
+
346
+ // Antigravity (passive brains scan)
347
+ const antigravityActive = [];
348
+ if (geminiPaths.native) {
349
+ const dirs = [
350
+ path.join(geminiPaths.native, "antigravity", "brain"),
351
+ path.join(geminiPaths.native, "antigravity-ide", "brain"),
352
+ path.join(geminiPaths.native, "antigravity-cli", "brain"),
353
+ ];
354
+ if (dirs.some(d => { try { return fssync.existsSync(d); } catch (_) { return false; } })) {
355
+ antigravityActive.push(`native: ${geminiPaths.native}`);
356
+ }
357
+ }
358
+ if (geminiPaths.wsl) {
359
+ const dirs = [
360
+ path.join(geminiPaths.wsl, "antigravity", "brain"),
361
+ path.join(geminiPaths.wsl, "antigravity-ide", "brain"),
362
+ path.join(geminiPaths.wsl, "antigravity-cli", "brain"),
363
+ ];
364
+ if (dirs.some(d => { try { return fssync.existsSync(d); } catch (_) { return false; } })) {
365
+ antigravityActive.push(`WSL: ${geminiPaths.wsl}`);
366
+ }
367
+ }
368
+ const antigravityInstalled = antigravityActive.length > 0;
369
+
370
+ // Codex CLI (passive sessions scan)
371
+ const codexPaths = resolveInstallPaths({
372
+ nativeValue: process.env.CODEX_HOME || path.join(home, ".codex"),
373
+ wslDir: ".codex",
374
+ });
375
+ const codexActive = formatResolvedPaths(codexPaths, "sessions");
376
+ const codexInstalledStatus = codexActive.length > 0;
377
+
378
+ // Kimi (passive sessions scan)
379
+ const kimiPaths = resolveInstallPaths({
380
+ nativeValue: path.join(home, ".kimi"),
381
+ wslDir: ".kimi",
382
+ });
383
+ const kimiActive = formatResolvedPaths(kimiPaths, "sessions");
384
+
300
385
  // Kilo Code VS Code extension — passive scan of all VS Code-family
301
386
  // globalStorage/kilocode.kilo-code/tasks/ ui_messages.json files.
302
387
  const kilocodeTaskFiles = resolveKilocodeTaskFiles(process.env);
@@ -338,9 +423,15 @@ async function cmdStatus(argv = []) {
338
423
  // install / WSL auto-discovery. Surface the resolved path (UNC included) and,
339
424
  // on Windows, the discovered distros so WSL users can debug "why no sync"
340
425
  // without guessing the right UNC alias (#87).
341
- const hermesPath = resolveHermesPath();
342
- const hermesDbPath = resolveHermesDbPath();
343
- const hermesInstalled = Boolean(hermesDbPath && fssync.existsSync(hermesDbPath));
426
+ const hermesPaths = resolveInstallPaths({
427
+ nativeValue: process.env.TOKENTRACKER_HERMES_HOME || (process.platform === "win32" && typeof process.env.LOCALAPPDATA === "string"
428
+ ? path.join(process.env.LOCALAPPDATA.trim(), "hermes")
429
+ : path.join(home, ".hermes")),
430
+ wslDir: ".hermes",
431
+ });
432
+ const hermesActive = formatResolvedPaths(hermesPaths, "state.db");
433
+ const hermesInstalled = hermesActive.length > 0;
434
+ const hermesPath = hermesActive.join(" | ");
344
435
  const wslDistros = process.platform === "win32" && shouldProbeWsl(process.env) ? probeWslDistros() : [];
345
436
 
346
437
  const copilotToken = readCopilotOauthToken({ home });
@@ -349,14 +440,123 @@ async function cmdStatus(argv = []) {
349
440
  const copilotAppExistingPaths = copilotAppDbPaths.filter((p) => {
350
441
  try { return fssync.existsSync(p); } catch (_e) { return false; }
351
442
  });
443
+ const copilotStorePaths = Array.from(
444
+ new Set([
445
+ ...resolveCopilotSessionStorePaths(process.env),
446
+ ...Object.keys(cursors?.copilotStore?.dbs || {}),
447
+ ]),
448
+ );
449
+ const copilotStoreExistingPaths = copilotStorePaths.filter((p) => {
450
+ try { return fssync.existsSync(p); } catch (_e) { return false; }
451
+ });
452
+ const copilotStoreDetails = [];
453
+ const copilotStoreInspectionErrors = [];
454
+ for (const storePath of copilotStoreExistingPaths) {
455
+ try {
456
+ copilotStoreDetails.push(describeCopilotSessionStoreDb(storePath));
457
+ } catch (err) {
458
+ copilotStoreInspectionErrors.push(
459
+ `${storePath}: ${err && err.message ? err.message : String(err)}`,
460
+ );
461
+ }
462
+ }
463
+ const copilotStoreCursor =
464
+ cursors?.copilotStore && typeof cursors.copilotStore === "object"
465
+ ? cursors.copilotStore
466
+ : {};
467
+ const copilotStoreDbStates =
468
+ copilotStoreCursor.dbs && typeof copilotStoreCursor.dbs === "object"
469
+ ? copilotStoreCursor.dbs
470
+ : {};
471
+ const copilotStatusPathKey = (dbPath) => {
472
+ const normalized = path.normalize(dbPath);
473
+ return process.platform === "win32" ? normalized.toLowerCase() : normalized;
474
+ };
475
+ const existingCopilotStoreKeys = new Set(
476
+ copilotStoreExistingPaths.map(copilotStatusPathKey),
477
+ );
478
+ const adoptedCopilotStores = Object.entries(copilotStoreDbStates).filter(
479
+ ([, state]) => state?.adoptedAt,
480
+ );
481
+ const missingAdoptedCopilotStores = adoptedCopilotStores
482
+ .map(([dbPath]) => dbPath)
483
+ .filter((dbPath) => !existingCopilotStoreKeys.has(copilotStatusPathKey(dbPath)));
484
+ const copilotStoreDegradedReasons = [
485
+ ...missingAdoptedCopilotStores.map(
486
+ (dbPath) => `canonical store unavailable: ${dbPath}`,
487
+ ),
488
+ ...copilotStoreInspectionErrors.map(
489
+ (message) => `store inspection failed: ${message}`,
490
+ ),
491
+ ...Object.entries(copilotStoreDbStates)
492
+ .filter(([, state]) => state?.lastError)
493
+ .map(([dbPath, state]) => `${dbPath}: ${state.lastError}`),
494
+ ];
495
+ const malformedCopilotEvents = Object.values(copilotStoreDbStates).reduce(
496
+ (sum, state) => sum + Math.max(0, Number(state?.malformedEventCount) || 0),
497
+ 0,
498
+ );
499
+ if (malformedCopilotEvents > 0) {
500
+ copilotStoreDegradedReasons.push(
501
+ `${malformedCopilotEvents} event${malformedCopilotEvents === 1 ? "" : "s"} lack a valid timestamp`,
502
+ );
503
+ }
504
+ const copilotResetGapEvents = Object.values(copilotStoreDbStates).reduce(
505
+ (sum, state) => sum + Math.max(0, Number(state?.resetGapEventCount) || 0),
506
+ 0,
507
+ );
508
+ if (copilotResetGapEvents > 0) {
509
+ copilotStoreDegradedReasons.push(
510
+ `${copilotResetGapEvents} event${copilotResetGapEvents === 1 ? "" : "s"} were baselined during a legacy cursor/reset race`,
511
+ );
512
+ }
513
+ const copilotStoreCanonical =
514
+ copilotStoreCursor.active === true && adoptedCopilotStores.length > 0;
515
+ const copilotStoreDegraded = copilotStoreDegradedReasons.length > 0;
516
+ const copilotStoreStatus = {
517
+ store_paths: copilotStoreExistingPaths,
518
+ store_path: copilotStorePaths[0] || null,
519
+ store_has_file: copilotStoreExistingPaths.length > 0,
520
+ store_details: copilotStoreDetails.map((detail) => ({
521
+ path: detail.path,
522
+ schema_version: detail.schemaVersion,
523
+ event_count: detail.eventCount,
524
+ last_event_id: detail.lastEventId,
525
+ last_event_at: detail.lastEventAt,
526
+ })),
527
+ canonical: copilotStoreCanonical,
528
+ source_mode: copilotStoreCanonical
529
+ ? copilotStoreDegraded
530
+ ? "canonical-degraded"
531
+ : "canonical"
532
+ : copilotStoreExistingPaths.length > 0
533
+ ? "awaiting-adoption"
534
+ : "legacy",
535
+ precision: copilotStoreCanonical
536
+ ? "exact-post-adoption; aggregate-pre-adoption"
537
+ : "aggregate",
538
+ coverage: copilotStoreCanonical
539
+ ? "per-request-post-adoption; legacy-aggregate-pre-adoption"
540
+ : "legacy-aggregate",
541
+ malformed_event_count: malformedCopilotEvents,
542
+ reset_gap_event_count: copilotResetGapEvents,
543
+ degraded: copilotStoreDegraded,
544
+ degraded_reasons: copilotStoreDegradedReasons,
545
+ recommended_action: copilotStoreDegraded
546
+ ? "Restore or repair the Copilot session store, then run `tokentracker sync`."
547
+ : null,
548
+ };
549
+ const copilotAppStatus = {
550
+ app_db_path: resolveCopilotAppDbPath(process.env),
551
+ app_db_paths: copilotAppExistingPaths,
552
+ app_db_has_file: copilotAppExistingPaths.length > 0,
553
+ app_db_mode: copilotStoreCanonical ? "observe-only" : "legacy-writer",
554
+ };
352
555
  const copilotLines = formatCopilotLines({
353
556
  token: copilotToken,
354
557
  otel: copilotOtel,
355
- appDb: {
356
- app_db_path: resolveCopilotAppDbPath(process.env),
357
- app_db_paths: copilotAppExistingPaths,
358
- app_db_has_file: copilotAppExistingPaths.length > 0,
359
- },
558
+ sessionStore: copilotStoreStatus,
559
+ appDb: copilotAppStatus,
360
560
  });
361
561
 
362
562
  // Detect passive-mode providers exactly once — both the JSON/light path
@@ -473,9 +673,8 @@ async function cmdStatus(argv = []) {
473
673
  otel_has_files: Boolean(copilotOtel.otel_has_files),
474
674
  otel_path: copilotOtel.otel_path || null,
475
675
  otel_enabled: Boolean(copilotOtel.otel_enabled),
476
- app_db_has_file: copilotAppExistingPaths.length > 0,
477
- app_db_path: resolveCopilotAppDbPath(process.env),
478
- app_db_paths: copilotAppExistingPaths,
676
+ ...copilotStoreStatus,
677
+ ...copilotAppStatus,
479
678
  },
480
679
  passive_mode: {
481
680
  active: isPassiveModeActive(passiveProviders),
@@ -524,7 +723,7 @@ async function cmdStatus(argv = []) {
524
723
  `- OpenClaw session plugin conversation access: ${openclawSessionPluginState?.conversationAccess ? "set" : "unset"}`,
525
724
  `- OpenClaw hook (legacy): ${openclawHookState?.configured ? "set" : "unset"}`,
526
725
  kimiInstalled || kimiCodeInstalled
527
- ? `- Kimi Code: passive reader (${kimiWireFiles.length + kimiCodeWireFiles.length} wire.jsonl file${(kimiWireFiles.length + kimiCodeWireFiles.length) !== 1 ? "s" : ""} found)`
726
+ ? `- Kimi Code: passive reader (${kimiWireFiles.length + kimiCodeWireFiles.length} wire.jsonl file${(kimiWireFiles.length + kimiCodeWireFiles.length) !== 1 ? "s" : ""} found, directories: ${kimiActive.join(" | ") || "none"})`
528
727
  : null,
529
728
  kiroCliInstalled
530
729
  ? `- Kiro CLI: SQLite data.sqlite3 found (tokens approximated from char lengths, merged under 'kiro' source)`
@@ -553,6 +752,24 @@ async function cmdStatus(argv = []) {
553
752
  zcodeInstalled
554
753
  ? `- ZCode: passive reader (${zcodeDbPath})`
555
754
  : null,
755
+ opencodeInstalled
756
+ ? `- OpenCode: passive reader (storage: ${opencodeStorageActive.join(" | ") || "not found"}, DB: ${opencodeDbActive.join(" | ") || "not found"})`
757
+ : null,
758
+ codeInstalled
759
+ ? `- Every Code: sessions found (${codeActive.join(" | ")})`
760
+ : null,
761
+ geminiCliInstalled
762
+ ? `- Gemini CLI: sessions found (${geminiCliActive.join(" | ")})`
763
+ : null,
764
+ antigravityInstalled
765
+ ? `- Antigravity: brain found (${antigravityActive.join(" | ")})`
766
+ : null,
767
+ (!geminiCliInstalled && !antigravityInstalled && geminiInstalledStatus)
768
+ ? `- Gemini CLI / Antigravity: home found (${geminiActive.join(" | ")})`
769
+ : null,
770
+ codexInstalledStatus
771
+ ? `- Codex CLI: sessions found (${codexActive.join(" | ")})`
772
+ : null,
556
773
  kilocodeInstalled
557
774
  ? `- 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" : ""})`
558
775
  : null,
@@ -607,13 +824,30 @@ async function cmdStatus(argv = []) {
607
824
  );
608
825
  }
609
826
 
610
- function formatCopilotLines({ token, otel, appDb }) {
611
- if (!token && !otel.otel_has_files && !appDb?.app_db_has_file) return [];
827
+ function formatCopilotStoreDetail(detail) {
828
+ return `${detail.path} (schema ${detail.schema_version ?? "?"}, ${detail.event_count ?? 0} events, last id ${detail.last_event_id ?? 0}${detail.last_event_at ? ` at ${detail.last_event_at}` : ""})`;
829
+ }
830
+
831
+ function formatCopilotLines({ token, otel, sessionStore, appDb }) {
832
+ if (
833
+ !token &&
834
+ !otel.otel_has_files &&
835
+ !sessionStore?.store_has_file &&
836
+ !appDb?.app_db_has_file
837
+ ) {
838
+ return [];
839
+ }
612
840
  const limitsState = token
613
841
  ? "set (via GitHub OAuth)"
614
842
  : "unset (no Copilot OAuth token found)";
843
+ const storeDetail = (sessionStore?.store_details || [])
844
+ .map(formatCopilotStoreDetail)
845
+ .join(", ");
846
+ const storeState = sessionStore?.store_has_file
847
+ ? `${sessionStore.source_mode || "set"} (${storeDetail || (sessionStore.store_paths || []).join(", ")}; precision ${sessionStore.precision || "unknown"}; coverage ${sessionStore.coverage || "unknown"})`
848
+ : `not found (${sessionStore?.store_path || "unknown"})`;
615
849
  const appDbState = appDb?.app_db_has_file
616
- ? `set (${(appDb.app_db_paths || []).join(", ")})`
850
+ ? `${appDb.app_db_mode || "set"} (${(appDb.app_db_paths || []).join(", ")})`
617
851
  : `not found (${appDb?.app_db_path || "unknown"})`;
618
852
  const usageState = otel.otel_has_files
619
853
  ? `set (${otel.otel_path || otel.otel_default_dir})`
@@ -622,12 +856,19 @@ function formatCopilotLines({ token, otel, appDb }) {
622
856
  : "unset (OTEL export not enabled)";
623
857
  const lines = [
624
858
  `- GitHub Copilot limits: ${limitsState}`,
625
- `- GitHub Copilot usage (App DB): ${appDbState}`,
626
- `- GitHub Copilot usage (OTEL CLI/Chat extension): ${usageState}`,
859
+ `- GitHub Copilot usage (App/CLI store): ${storeState}`,
860
+ `- GitHub Copilot usage (App DB legacy baseline): ${appDbState}`,
861
+ `- GitHub Copilot usage (OTEL Chat/legacy CLI): ${usageState}`,
627
862
  ];
628
- if (!otel.otel_has_files) {
863
+ for (const reason of sessionStore?.degraded_reasons || []) {
864
+ lines.push(` Degraded: ${reason}`);
865
+ }
866
+ if (sessionStore?.recommended_action) {
867
+ lines.push(` Action: ${sessionStore.recommended_action}`);
868
+ }
869
+ if (!sessionStore?.store_has_file && !otel.otel_has_files) {
629
870
  lines.push(
630
- " To track Copilot CLI / Chat extension token usage, add to your shell profile:",
871
+ " To track older Copilot CLI / Chat extension token usage, add to your shell profile:",
631
872
  " export COPILOT_OTEL_ENABLED=true",
632
873
  " export COPILOT_OTEL_EXPORTER_TYPE=file",
633
874
  ` export COPILOT_OTEL_FILE_EXPORTER_PATH="${otel.otel_default_dir}/copilot-otel-$(date +%Y%m%d).jsonl"`,
@@ -745,22 +986,44 @@ function renderLightTable(summary) {
745
986
  (summary.copilot.token_set ||
746
987
  summary.copilot.otel_enabled ||
747
988
  summary.copilot.otel_has_files ||
989
+ summary.copilot.store_has_file ||
748
990
  summary.copilot.app_db_has_file);
749
991
  if (copilotDetected) {
750
992
  push(
751
- "Copilot App DB",
993
+ "Copilot App/CLI store",
994
+ summary.copilot.store_has_file
995
+ ? `${summary.copilot.source_mode || "set"}: ${
996
+ (summary.copilot.store_details || [])
997
+ .map(formatCopilotStoreDetail)
998
+ .join(", ") ||
999
+ (summary.copilot.store_paths || [summary.copilot.store_path])
1000
+ .filter(Boolean)
1001
+ .join(", ")
1002
+ }`
1003
+ : `not found (${summary.copilot.store_path || "unknown"})`,
1004
+ );
1005
+ push(
1006
+ "Copilot App DB legacy baseline",
752
1007
  summary.copilot.app_db_has_file
753
- ? (summary.copilot.app_db_paths || [summary.copilot.app_db_path]).filter(Boolean).join(", ")
1008
+ ? `${summary.copilot.app_db_mode || "set"}: ${(summary.copilot.app_db_paths || [summary.copilot.app_db_path]).filter(Boolean).join(", ")}`
754
1009
  : `not found (${summary.copilot.app_db_path || "unknown"})`,
755
1010
  );
756
1011
  push(
757
- "Copilot OTEL",
1012
+ "Copilot OTEL Chat/legacy CLI",
758
1013
  summary.copilot.otel_has_files
759
1014
  ? summary.copilot.otel_path || "files found"
760
1015
  : summary.copilot.otel_enabled
761
1016
  ? "enabled, no files"
762
1017
  : "not enabled",
763
1018
  );
1019
+ push("Copilot precision", summary.copilot.precision);
1020
+ push("Copilot coverage", summary.copilot.coverage);
1021
+ for (const reason of summary.copilot.degraded_reasons || []) {
1022
+ push("Copilot degraded", reason);
1023
+ }
1024
+ if (summary.copilot.recommended_action) {
1025
+ push("Copilot action", summary.copilot.recommended_action);
1026
+ }
764
1027
  }
765
1028
 
766
1029
  if (summary.passive_mode) {