tokmon 0.20.2 → 0.20.3

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.
@@ -18,7 +18,7 @@ import {
18
18
  systemTimezone,
19
19
  time,
20
20
  tokens
21
- } from "./chunk-7HJIP4U6.js";
21
+ } from "./chunk-ANCKHLJV.js";
22
22
  import {
23
23
  COLOR_PALETTE,
24
24
  DEFAULTS,
@@ -3194,7 +3194,7 @@ function App({ interval: cliInterval, initialConfig, baseUrl = null, wsToken = n
3194
3194
  if (webStartingRef.current) return;
3195
3195
  webStartingRef.current = true;
3196
3196
  try {
3197
- const { startWebServer } = await import("./server-BXMRN774.js");
3197
+ const { startWebServer } = await import("./server-R6Z6W4CN.js");
3198
3198
  const ctrl = await startWebServer({ config: cfg, log: false });
3199
3199
  webRef.current = ctrl;
3200
3200
  openUrl(ctrl.url);
@@ -2554,14 +2554,127 @@ var antigravityProvider = {
2554
2554
  };
2555
2555
 
2556
2556
  // src/providers/gemini/billing.ts
2557
- import { access as access8, readFile as readFile6 } from "fs/promises";
2557
+ import { access as access8, readFile as readFile6, readdir as readdir9 } from "fs/promises";
2558
+ import { join as join14 } from "path";
2559
+ import { homedir as homedir12 } from "os";
2560
+
2561
+ // src/providers/gemini/usage.ts
2562
+ import { readdir as readdir8, stat as fsStat5 } from "fs/promises";
2563
+ import { createReadStream as createReadStream5 } from "fs";
2564
+ import { createInterface as createInterface5 } from "readline";
2558
2565
  import { join as join13 } from "path";
2559
2566
  import { homedir as homedir11 } from "os";
2567
+ var PRICING3 = {
2568
+ "gemini-3.1-pro-preview": { in: 2e-6, out: 12e-6, cr: 2e-7 },
2569
+ "gemini-3.1-pro": { in: 2e-6, out: 12e-6, cr: 2e-7 },
2570
+ "gemini-3-pro-preview": { in: 2e-6, out: 12e-6, cr: 2e-7 },
2571
+ "gemini-3-pro": { in: 2e-6, out: 12e-6, cr: 2e-7 },
2572
+ "gemini-3.5-flash": { in: 15e-7, out: 9e-6, cr: 15e-8 },
2573
+ "gemini-3-flash-preview": { in: 15e-7, out: 9e-6, cr: 15e-8 },
2574
+ "gemini-3-flash": { in: 15e-7, out: 9e-6, cr: 15e-8 },
2575
+ "gemini-2.5-flash-lite": { in: 1e-7, out: 4e-7, cr: 1e-8 },
2576
+ "gemini-3.1-flash-lite": { in: 1e-7, out: 4e-7, cr: 1e-8 },
2577
+ "gemini-2.5-flash": { in: 3e-7, out: 25e-7, cr: 3e-8 },
2578
+ "gemini-2.5-pro": { in: 125e-8, out: 1e-5, cr: 125e-9 },
2579
+ "gemini-2.0-flash": { in: 1e-7, out: 4e-7, cr: 25e-9 }
2580
+ };
2581
+ var PRICE_KEYS3 = Object.keys(PRICING3).sort((a, b) => b.length - a.length);
2582
+ var ZERO_PRICE3 = { in: 0, out: 0, cr: 0 };
2583
+ function geminiTmpDir(homeDir) {
2584
+ return join13(homeDir ?? homedir11(), ".gemini", "tmp");
2585
+ }
2586
+ function priceFor3(model) {
2587
+ const m = model.toLowerCase().trim();
2588
+ for (const key of PRICE_KEYS3) {
2589
+ if (!m.startsWith(key)) continue;
2590
+ const rest = m.slice(key.length);
2591
+ if (rest === "" || rest[0] === "-") return PRICING3[key];
2592
+ }
2593
+ return ZERO_PRICE3;
2594
+ }
2595
+ function shortModel2(model) {
2596
+ return model.replace(/(-preview|-customtools)+$/, "");
2597
+ }
2598
+ function isGeminiSessionFile(path) {
2599
+ return /(^|[\\/])chats[\\/]session-.*\.jsonl$/.test(path) || /(^|[\\/])chats[\\/]session-.*\.json$/.test(path);
2600
+ }
2601
+ async function parseFile4(path) {
2602
+ const entries = [];
2603
+ const rl = createInterface5({ input: createReadStream5(path), crlfDelay: Infinity });
2604
+ for await (const line of rl) {
2605
+ try {
2606
+ const obj = JSON.parse(line.charCodeAt(0) === 65279 ? line.slice(1) : line);
2607
+ if (obj.sessionId && obj.kind || obj.$set || obj.$rewindTo) continue;
2608
+ if (obj.type !== "gemini" || !obj.tokens) continue;
2609
+ const ts = Date.parse(obj.timestamp ?? "");
2610
+ if (!Number.isFinite(ts)) continue;
2611
+ const t = obj.tokens;
2612
+ const input = Math.max(0, safeNum(t.input) + safeNum(t.tool) - safeNum(t.cached));
2613
+ const output = safeNum(t.output) + safeNum(t.thoughts);
2614
+ const cacheRead = safeNum(t.cached);
2615
+ if (input + output + cacheRead === 0) continue;
2616
+ const model = typeof obj.model === "string" && obj.model ? obj.model : "unknown";
2617
+ const p = priceFor3(model);
2618
+ entries.push({
2619
+ id: typeof obj.id === "string" ? obj.id : void 0,
2620
+ ts,
2621
+ model: shortModel2(model),
2622
+ cost: input * p.in + cacheRead * p.cr + output * p.out,
2623
+ input,
2624
+ output,
2625
+ cacheCreate: 0,
2626
+ cacheRead,
2627
+ cacheSavings: cacheRead * (p.in - p.cr)
2628
+ });
2629
+ } catch {
2630
+ }
2631
+ }
2632
+ return entries;
2633
+ }
2634
+ async function loadEntries5(since, homeDir) {
2635
+ const files = [];
2636
+ const seen = /* @__PURE__ */ new Set();
2637
+ const seenIno = /* @__PURE__ */ new Set();
2638
+ let listing;
2639
+ try {
2640
+ listing = await readdir8(geminiTmpDir(homeDir), { recursive: true });
2641
+ } catch {
2642
+ return [];
2643
+ }
2644
+ for (const f of listing) {
2645
+ if (!isGeminiSessionFile(f)) continue;
2646
+ const path = join13(geminiTmpDir(homeDir), f);
2647
+ if (seen.has(path)) continue;
2648
+ seen.add(path);
2649
+ try {
2650
+ const s = await fsStat5(path);
2651
+ if (s.mtimeMs < since) continue;
2652
+ if (s.ino && process.platform !== "win32") {
2653
+ const idn = `${s.dev}:${s.ino}`;
2654
+ if (seenIno.has(idn)) continue;
2655
+ seenIno.add(idn);
2656
+ }
2657
+ files.push({ path, mtimeMs: s.mtimeMs, size: s.size });
2658
+ } catch {
2659
+ }
2660
+ }
2661
+ return loadCachedEntries(files, parseFile4, since);
2662
+ }
2663
+ async function geminiDashboard(tz, homeDir) {
2664
+ const entries = await loadEntries5(dashboardSince(tz), homeDir);
2665
+ return summarize(entries, tz);
2666
+ }
2667
+ async function geminiTable(tz, homeDir) {
2668
+ const entries = await loadEntries5(tableSince(tz), homeDir);
2669
+ return tabulate(entries, tz);
2670
+ }
2671
+
2672
+ // src/providers/gemini/billing.ts
2560
2673
  function geminiCredsPath(homeDir) {
2561
- return join13(homeDir ?? homedir11(), ".gemini", "oauth_creds.json");
2674
+ return join14(homeDir ?? homedir12(), ".gemini", "oauth_creds.json");
2562
2675
  }
2563
2676
  function geminiDir(homeDir) {
2564
- return join13(homeDir ?? homedir11(), ".gemini");
2677
+ return join14(homeDir ?? homedir12(), ".gemini");
2565
2678
  }
2566
2679
  function authTypeFromSettings(settings) {
2567
2680
  const raw = settings?.security?.auth?.selectedType ?? settings?.selectedAuthType;
@@ -2574,7 +2687,7 @@ function authTypeFromSettings(settings) {
2574
2687
  }
2575
2688
  async function authMethodFromSettings(homeDir) {
2576
2689
  try {
2577
- const raw = await readFile6(join13(geminiDir(homeDir), "settings.json"), "utf8");
2690
+ const raw = await readFile6(join14(geminiDir(homeDir), "settings.json"), "utf8");
2578
2691
  return authTypeFromSettings(JSON.parse(raw));
2579
2692
  } catch {
2580
2693
  return "none";
@@ -2582,12 +2695,12 @@ async function authMethodFromSettings(homeDir) {
2582
2695
  }
2583
2696
  async function hasGeminiApiKeyFile(homeDir) {
2584
2697
  try {
2585
- await access8(join13(geminiDir(homeDir), "api_key"));
2698
+ await access8(join14(geminiDir(homeDir), "api_key"));
2586
2699
  return true;
2587
2700
  } catch {
2588
2701
  }
2589
2702
  try {
2590
- const env = await readFile6(join13(geminiDir(homeDir), ".env"), "utf8");
2703
+ const env = await readFile6(join14(geminiDir(homeDir), ".env"), "utf8");
2591
2704
  return /^\s*GEMINI_API_KEY\s*=/m.test(env);
2592
2705
  } catch {
2593
2706
  return false;
@@ -2606,12 +2719,22 @@ async function noOAuthAuthMessage(homeDir) {
2606
2719
  return "Not signed in \u2014 run gemini and log in with Google";
2607
2720
  }
2608
2721
  async function detectGemini(homeDir) {
2722
+ let oauthOk = false;
2609
2723
  try {
2610
2724
  await access8(geminiCredsPath(homeDir));
2611
- return true;
2725
+ oauthOk = true;
2726
+ } catch {
2727
+ }
2728
+ return oauthOk || await hasGeminiChatSessions(homeDir);
2729
+ }
2730
+ async function hasGeminiChatSessions(homeDir) {
2731
+ let listing;
2732
+ try {
2733
+ listing = await readdir9(geminiTmpDir(homeDir), { recursive: true });
2612
2734
  } catch {
2613
2735
  return false;
2614
2736
  }
2737
+ return listing.some((path) => /(^|[\\/])chats[\\/]session-.*\.jsonl$/.test(path));
2615
2738
  }
2616
2739
  function decodeBase64UrlJson2(segment) {
2617
2740
  try {
@@ -2666,34 +2789,36 @@ var geminiProvider = {
2666
2789
  id: "gemini",
2667
2790
  name: "Gemini",
2668
2791
  color: "greenBright",
2669
- hasUsage: false,
2792
+ hasUsage: true,
2670
2793
  hasBilling: true,
2671
2794
  detect: (homeDir) => detectGemini(homeDir),
2795
+ fetchSummary: (account, tz) => geminiDashboard(tz, account.homeDir),
2796
+ fetchTable: (account, tz) => geminiTable(tz, account.homeDir),
2672
2797
  fetchBilling: (account) => geminiBilling(account)
2673
2798
  };
2674
2799
 
2675
2800
  // src/providers/detect.ts
2676
2801
  import { accessSync, constants } from "fs";
2677
- import { join as join14, delimiter, isAbsolute as isAbsolute2 } from "path";
2678
- import { homedir as homedir12 } from "os";
2802
+ import { join as join15, delimiter, isAbsolute as isAbsolute2 } from "path";
2803
+ import { homedir as homedir13 } from "os";
2679
2804
  function searchDirs() {
2680
- const home = homedir12();
2805
+ const home = homedir13();
2681
2806
  const fromEnv = (process.env.PATH ?? "").split(delimiter).filter(Boolean);
2682
2807
  const extra = process.platform === "win32" ? [
2683
- process.env.APPDATA && join14(process.env.APPDATA, "npm"),
2684
- process.env.LOCALAPPDATA && join14(process.env.LOCALAPPDATA, "pnpm"),
2685
- join14(home, "scoop", "shims")
2808
+ process.env.APPDATA && join15(process.env.APPDATA, "npm"),
2809
+ process.env.LOCALAPPDATA && join15(process.env.LOCALAPPDATA, "pnpm"),
2810
+ join15(home, "scoop", "shims")
2686
2811
  ] : [
2687
2812
  "/opt/homebrew/bin",
2688
2813
  "/usr/local/bin",
2689
2814
  "/usr/bin",
2690
2815
  "/bin",
2691
2816
  "/opt/local/bin",
2692
- join14(home, ".local", "bin"),
2693
- join14(home, "bin"),
2694
- join14(home, ".npm-global", "bin"),
2695
- join14(home, ".bun", "bin"),
2696
- join14(home, ".local", "share", "pnpm")
2817
+ join15(home, ".local", "bin"),
2818
+ join15(home, "bin"),
2819
+ join15(home, ".npm-global", "bin"),
2820
+ join15(home, ".bun", "bin"),
2821
+ join15(home, ".local", "share", "pnpm")
2697
2822
  ];
2698
2823
  return [.../* @__PURE__ */ new Set([...fromEnv, ...extra.filter((d) => !!d)])];
2699
2824
  }
@@ -2710,7 +2835,7 @@ function onPath(names) {
2710
2835
  for (const dir of searchDirs()) {
2711
2836
  for (const n of names) {
2712
2837
  for (const e of exts) {
2713
- if (isExec(join14(dir, n + e))) return true;
2838
+ if (isExec(join15(dir, n + e))) return true;
2714
2839
  }
2715
2840
  }
2716
2841
  }
@@ -2720,7 +2845,7 @@ function anyExists(paths) {
2720
2845
  return paths.some((p) => !!p && isExec(p));
2721
2846
  }
2722
2847
  function installSignals(id) {
2723
- const home = homedir12();
2848
+ const home = homedir13();
2724
2849
  const pf = process.env.ProgramFiles;
2725
2850
  const pf86 = process.env["ProgramFiles(x86)"];
2726
2851
  const lad = process.env.LOCALAPPDATA;
@@ -2728,8 +2853,8 @@ function installSignals(id) {
2728
2853
  case "claude":
2729
2854
  return onPath(["claude"]) || anyExists([
2730
2855
  "/Applications/Claude.app",
2731
- join14(home, "Applications", "Claude.app"),
2732
- lad && join14(lad, "Programs", "claude", "Claude.exe")
2856
+ join15(home, "Applications", "Claude.app"),
2857
+ lad && join15(lad, "Programs", "claude", "Claude.exe")
2733
2858
  ]);
2734
2859
  case "codex": {
2735
2860
  const bin = process.env.CODEX_BIN;
@@ -2739,10 +2864,10 @@ function installSignals(id) {
2739
2864
  case "cursor":
2740
2865
  return onPath(["cursor", "cursor-agent"]) || anyExists([
2741
2866
  "/Applications/Cursor.app",
2742
- join14(home, "Applications", "Cursor.app"),
2743
- lad && join14(lad, "Programs", "cursor", "Cursor.exe"),
2744
- pf && join14(pf, "Cursor", "Cursor.exe"),
2745
- pf86 && join14(pf86, "Cursor", "Cursor.exe"),
2867
+ join15(home, "Applications", "Cursor.app"),
2868
+ lad && join15(lad, "Programs", "cursor", "Cursor.exe"),
2869
+ pf && join15(pf, "Cursor", "Cursor.exe"),
2870
+ pf86 && join15(pf86, "Cursor", "Cursor.exe"),
2746
2871
  "/opt/Cursor/cursor",
2747
2872
  "/usr/share/cursor/cursor",
2748
2873
  "/usr/bin/cursor"
@@ -2756,8 +2881,8 @@ function installSignals(id) {
2756
2881
  case "antigravity":
2757
2882
  return onPath(["antigravity"]) || anyExists([
2758
2883
  "/Applications/Antigravity.app",
2759
- join14(home, "Applications", "Antigravity.app"),
2760
- lad && join14(lad, "Programs", "Antigravity", "Antigravity.exe")
2884
+ join15(home, "Applications", "Antigravity.app"),
2885
+ lad && join15(lad, "Programs", "Antigravity", "Antigravity.exe")
2761
2886
  ]);
2762
2887
  case "gemini":
2763
2888
  return onPath(["gemini"]);
@@ -2794,10 +2919,10 @@ async function detectProviders() {
2794
2919
 
2795
2920
  // src/accounts.ts
2796
2921
  import { existsSync, readdirSync, readFileSync, statSync } from "fs";
2797
- import { homedir as homedir13 } from "os";
2798
- import { basename, join as join15, resolve } from "path";
2922
+ import { homedir as homedir14 } from "os";
2923
+ import { basename, join as join16, resolve } from "path";
2799
2924
  function accountKey(providerId, homeDir) {
2800
- return `${providerId}:${homeDir ? resolve(expandHome(homeDir)) : homedir13()}`;
2925
+ return `${providerId}:${homeDir ? resolve(expandHome(homeDir)) : homedir14()}`;
2801
2926
  }
2802
2927
  function uniqueId(base, used) {
2803
2928
  let id = slugify(base) || "account";
@@ -2818,7 +2943,7 @@ function uniqueId(base, used) {
2818
2943
  }
2819
2944
  function readClaudeIdentity2(homeDir) {
2820
2945
  try {
2821
- const parsed = JSON.parse(readFileSync(join15(homeDir, ".claude.json"), "utf-8"));
2946
+ const parsed = JSON.parse(readFileSync(join16(homeDir, ".claude.json"), "utf-8"));
2822
2947
  const oauth = parsed?.oauthAccount;
2823
2948
  return {
2824
2949
  email: typeof oauth?.emailAddress === "string" && oauth.emailAddress.trim() ? oauth.emailAddress.trim() : void 0,
@@ -2829,10 +2954,10 @@ function readClaudeIdentity2(homeDir) {
2829
2954
  }
2830
2955
  }
2831
2956
  function hasClaudeState(homeDir) {
2832
- return existsSync(join15(homeDir, ".claude.json")) || existsSync(join15(homeDir, ".claude", ".credentials.json")) || existsSync(join15(homeDir, ".claude", "projects")) || existsSync(join15(homeDir, ".config", "claude", ".credentials.json")) || existsSync(join15(homeDir, ".config", "claude", "projects"));
2957
+ return existsSync(join16(homeDir, ".claude.json")) || existsSync(join16(homeDir, ".claude", ".credentials.json")) || existsSync(join16(homeDir, ".claude", "projects")) || existsSync(join16(homeDir, ".config", "claude", ".credentials.json")) || existsSync(join16(homeDir, ".config", "claude", "projects"));
2833
2958
  }
2834
2959
  function candidateAlternateHomes(prefix) {
2835
- const home = homedir13();
2960
+ const home = homedir14();
2836
2961
  let entries;
2837
2962
  try {
2838
2963
  entries = readdirSync(home);
@@ -2843,7 +2968,7 @@ function candidateAlternateHomes(prefix) {
2843
2968
  const pattern = new RegExp(`^\\.${prefix}[_-]`);
2844
2969
  for (const name of entries) {
2845
2970
  if (!pattern.test(name)) continue;
2846
- const path = join15(home, name);
2971
+ const path = join16(home, name);
2847
2972
  try {
2848
2973
  if (!statSync(path).isDirectory()) continue;
2849
2974
  out.push(path);
@@ -2869,7 +2994,7 @@ function decodeBase64UrlJson3(segment) {
2869
2994
  }
2870
2995
  }
2871
2996
  function codexAuthPaths(homeDir) {
2872
- return [join15(homeDir, ".codex", "auth.json"), join15(homeDir, "auth.json")];
2997
+ return [join16(homeDir, ".codex", "auth.json"), join16(homeDir, "auth.json")];
2873
2998
  }
2874
2999
  function readCodexIdentity(homeDir) {
2875
3000
  for (const path of codexAuthPaths(homeDir)) {
@@ -8,7 +8,7 @@ import {
8
8
  detectProviders,
9
9
  fetchPeak,
10
10
  resolveTimezone
11
- } from "./chunk-7HJIP4U6.js";
11
+ } from "./chunk-ANCKHLJV.js";
12
12
  import {
13
13
  cacheDir,
14
14
  expandHome,
package/dist/cli.js CHANGED
@@ -14,12 +14,12 @@ process.emitWarning = ((warning, ...rest) => {
14
14
  var args = process.argv.slice(2);
15
15
  var subcommand = args[0]?.toLowerCase();
16
16
  if (subcommand === "__daemon") {
17
- const { runDaemon } = await import("./daemon-NVWX3RRK.js");
17
+ const { runDaemon } = await import("./daemon-BUYFTSED.js");
18
18
  await runDaemon(args.slice(1), { foreground: false });
19
19
  process.exit(typeof process.exitCode === "number" ? process.exitCode : 0);
20
20
  }
21
21
  if (subcommand === "serve" || subcommand === "web") {
22
- const { runDaemon } = await import("./daemon-NVWX3RRK.js");
22
+ const { runDaemon } = await import("./daemon-BUYFTSED.js");
23
23
  await runDaemon(args.slice(1), { foreground: true });
24
24
  process.exit(typeof process.exitCode === "number" ? process.exitCode : 0);
25
25
  }
@@ -68,5 +68,5 @@ setGlyphs(resolveGlyphs({
68
68
  }));
69
69
  var daemon = await attachOrSpawn();
70
70
  var mode = daemon.kind === "spawned" ? "connected" : "degraded";
71
- var { bootstrapInk } = await import("./bootstrap-ink-KWHXVQYS.js");
71
+ var { bootstrapInk } = await import("./bootstrap-ink-F3JFQ3ON.js");
72
72
  await bootstrapInk({ interval, config, daemon, mode });
@@ -2,10 +2,10 @@
2
2
  import {
3
3
  appVersion,
4
4
  startWebServer
5
- } from "./chunk-5IHAR2RZ.js";
5
+ } from "./chunk-M3RGQIOW.js";
6
6
  import {
7
7
  flushDisk
8
- } from "./chunk-7HJIP4U6.js";
8
+ } from "./chunk-ANCKHLJV.js";
9
9
  import {
10
10
  cacheDir,
11
11
  loadConfig
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  startWebServer
4
- } from "./chunk-5IHAR2RZ.js";
5
- import "./chunk-7HJIP4U6.js";
4
+ } from "./chunk-M3RGQIOW.js";
5
+ import "./chunk-ANCKHLJV.js";
6
6
  import "./chunk-XQEJ4WQ5.js";
7
7
  export {
8
8
  startWebServer
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tokmon",
3
- "version": "0.20.2",
3
+ "version": "0.20.3",
4
4
  "description": "Terminal + web dashboard for Claude Code, Codex, Cursor, opencode, pi, Copilot, Gemini & more — usage, limits, and costs",
5
5
  "type": "module",
6
6
  "bin": {