tokmon 0.3.2 → 0.3.4

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 (2) hide show
  1. package/dist/cli.js +56 -50
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -3,6 +3,39 @@
3
3
  // src/cli.tsx
4
4
  import { render } from "ink";
5
5
 
6
+ // src/config.ts
7
+ import { readFile, writeFile, mkdir } from "fs/promises";
8
+ import { join } from "path";
9
+ import { homedir } from "os";
10
+ var DEFAULTS = { interval: 2, clearScreen: true };
11
+ function configDir() {
12
+ if (process.platform === "win32") {
13
+ return join(process.env.APPDATA ?? join(homedir(), "AppData", "Roaming"), "tokmon");
14
+ }
15
+ const xdg = process.env.XDG_CONFIG_HOME ?? join(homedir(), ".config");
16
+ return join(xdg, "tokmon");
17
+ }
18
+ function configPath() {
19
+ return join(configDir(), "config.json");
20
+ }
21
+ async function loadConfig() {
22
+ try {
23
+ const raw = await readFile(configPath(), "utf-8");
24
+ const parsed = JSON.parse(raw);
25
+ return { ...DEFAULTS, ...parsed };
26
+ } catch {
27
+ return { ...DEFAULTS };
28
+ }
29
+ }
30
+ async function saveConfig(config2) {
31
+ const dir = configDir();
32
+ await mkdir(dir, { recursive: true });
33
+ await writeFile(configPath(), JSON.stringify(config2, null, 2) + "\n");
34
+ }
35
+ function configLocation() {
36
+ return configPath();
37
+ }
38
+
6
39
  // src/app.tsx
7
40
  import { useState, useEffect, useRef } from "react";
8
41
  import { Box, Text, useInput, useStdout, useApp } from "ink";
@@ -11,8 +44,8 @@ import { Box, Text, useInput, useStdout, useApp } from "ink";
11
44
  import { readdir, stat as fsStat } from "fs/promises";
12
45
  import { createReadStream } from "fs";
13
46
  import { createInterface } from "readline";
14
- import { join } from "path";
15
- import { homedir } from "os";
47
+ import { join as join2 } from "path";
48
+ import { homedir as homedir2 } from "os";
16
49
 
17
50
  // src/format.ts
18
51
  function currency(value) {
@@ -56,19 +89,19 @@ var PRICING = {
56
89
  var FALLBACK = PRICING["claude-opus-4"];
57
90
  var fileCache = /* @__PURE__ */ new Map();
58
91
  function getClaudeDirs() {
59
- const home = homedir();
60
- const dirs = [join(home, ".claude", "projects")];
92
+ const home = homedir2();
93
+ const dirs = [join2(home, ".claude", "projects")];
61
94
  if (process.env.XDG_CONFIG_HOME) {
62
- dirs.push(join(process.env.XDG_CONFIG_HOME, "claude", "projects"));
95
+ dirs.push(join2(process.env.XDG_CONFIG_HOME, "claude", "projects"));
63
96
  } else if (process.platform !== "win32") {
64
- dirs.push(join(home, ".config", "claude", "projects"));
97
+ dirs.push(join2(home, ".config", "claude", "projects"));
65
98
  }
66
99
  if (process.env.APPDATA) {
67
- dirs.push(join(process.env.APPDATA, "claude", "projects"));
100
+ dirs.push(join2(process.env.APPDATA, "claude", "projects"));
68
101
  }
69
102
  if (process.env.CLAUDE_CONFIG_DIR) {
70
103
  for (const p of process.env.CLAUDE_CONFIG_DIR.split(process.platform === "win32" ? ";" : ",")) {
71
- dirs.push(join(p.trim(), "projects"));
104
+ dirs.push(join2(p.trim(), "projects"));
72
105
  }
73
106
  }
74
107
  return dirs;
@@ -123,7 +156,7 @@ async function loadEntries(since) {
123
156
  }
124
157
  const files = listing.filter((f) => f.endsWith(".jsonl"));
125
158
  await Promise.all(files.map(async (f) => {
126
- const path = join(dir, f);
159
+ const path = join2(dir, f);
127
160
  if (seen.has(path)) return;
128
161
  seen.add(path);
129
162
  try {
@@ -232,39 +265,6 @@ async function fetchTable() {
232
265
  };
233
266
  }
234
267
 
235
- // src/config.ts
236
- import { readFile, writeFile, mkdir } from "fs/promises";
237
- import { join as join2 } from "path";
238
- import { homedir as homedir2 } from "os";
239
- var DEFAULTS = { interval: 2, clearScreen: true };
240
- function configDir() {
241
- if (process.platform === "win32") {
242
- return join2(process.env.APPDATA ?? join2(homedir2(), "AppData", "Roaming"), "tokmon");
243
- }
244
- const xdg = process.env.XDG_CONFIG_HOME ?? join2(homedir2(), ".config");
245
- return join2(xdg, "tokmon");
246
- }
247
- function configPath() {
248
- return join2(configDir(), "config.json");
249
- }
250
- async function loadConfig() {
251
- try {
252
- const raw = await readFile(configPath(), "utf-8");
253
- const parsed = JSON.parse(raw);
254
- return { ...DEFAULTS, ...parsed };
255
- } catch {
256
- return { ...DEFAULTS };
257
- }
258
- }
259
- async function saveConfig(config) {
260
- const dir = configDir();
261
- await mkdir(dir, { recursive: true });
262
- await writeFile(configPath(), JSON.stringify(config, null, 2) + "\n");
263
- }
264
- function configLocation() {
265
- return configPath();
266
- }
267
-
268
268
  // src/app.tsx
269
269
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
270
270
  var TABS = ["Dashboard", "Table"];
@@ -279,20 +279,22 @@ function App({ interval: cliInterval }) {
279
279
  const [view, setView] = useState(0);
280
280
  const [scroll, setScroll] = useState(0);
281
281
  const [showSettings, setShowSettings] = useState(false);
282
- const [config, setConfig] = useState(null);
282
+ const [config2, setConfig] = useState(null);
283
283
  const [settingsCursor, setSettingsCursor] = useState(0);
284
284
  const tableLoadedOnce = useRef(false);
285
285
  const { stdout } = useStdout();
286
286
  const rows = stdout?.rows ?? 24;
287
287
  const cols = stdout?.columns ?? 80;
288
- const interval2 = cliInterval ?? (config?.interval ?? 2) * 1e3;
288
+ const interval2 = cliInterval ?? (config2?.interval ?? 2) * 1e3;
289
289
  useEffect(() => {
290
290
  loadConfig().then((c) => {
291
291
  if (cliInterval) c = { ...c, interval: cliInterval / 1e3 };
292
292
  setConfig(c);
293
- if (c.clearScreen && stdout) stdout.write("\x1B[2J\x1B[H");
294
293
  });
295
294
  }, []);
295
+ useEffect(() => {
296
+ if (stdout) stdout.write("\x1B[2J\x1B[H");
297
+ }, [tab, view, showSettings]);
296
298
  useEffect(() => {
297
299
  let active = true;
298
300
  const load = async () => {
@@ -350,7 +352,7 @@ function App({ interval: cliInterval }) {
350
352
  const { exit } = useApp();
351
353
  const isTTY = process.stdin.isTTY === true;
352
354
  const settingsItems = 2;
353
- const cfg = config ?? { interval: 2, clearScreen: true };
355
+ const cfg = config2 ?? { interval: 2, clearScreen: true };
354
356
  useInput((input, key) => {
355
357
  if (showSettings) {
356
358
  if (key.escape || input === "s") setShowSettings(false);
@@ -504,7 +506,7 @@ function ViewBar({ views, active }) {
504
506
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: " d/w/m or \u2190\u2192" })
505
507
  ] });
506
508
  }
507
- function SettingsView({ config, cursor }) {
509
+ function SettingsView({ config: config2, cursor }) {
508
510
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
509
511
  /* @__PURE__ */ jsx(Text, { bold: true, children: "Settings" }),
510
512
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: configLocation() }),
@@ -520,7 +522,7 @@ function SettingsView({ config, cursor }) {
520
522
  " "
521
523
  ] }),
522
524
  /* @__PURE__ */ jsxs(Text, { bold: true, color: "yellow", children: [
523
- config.interval,
525
+ config2.interval,
524
526
  "s"
525
527
  ] }),
526
528
  /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
@@ -534,7 +536,7 @@ function SettingsView({ config, cursor }) {
534
536
  " "
535
537
  ] }),
536
538
  /* @__PURE__ */ jsx(Text, { children: "Clear screen " }),
537
- /* @__PURE__ */ jsx(Text, { bold: true, color: config.clearScreen ? "green" : "red", children: config.clearScreen ? "on" : "off" })
539
+ /* @__PURE__ */ jsx(Text, { bold: true, color: config2.clearScreen ? "green" : "red", children: config2.clearScreen ? "on" : "off" })
538
540
  ] }),
539
541
  /* @__PURE__ */ jsx(Box, { height: 1 }),
540
542
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2191\u2193 select \u2190\u2192 adjust s/Esc close" })
@@ -723,9 +725,13 @@ for (let i = 0; i < args.length; i++) {
723
725
  console.log(" \u2191\u2193 Scroll table");
724
726
  console.log(" 1-2 Jump to view");
725
727
  console.log(" s Settings");
726
- console.log(" Ctrl+C Quit");
728
+ console.log(" q Quit");
727
729
  process.exit(0);
728
730
  }
729
731
  }
732
+ var config = await loadConfig();
733
+ if (config.clearScreen && process.stdout.isTTY) {
734
+ process.stdout.write("\x1B[2J\x1B[H");
735
+ }
730
736
  var { waitUntilExit } = render(/* @__PURE__ */ jsx2(App, { interval }));
731
737
  await waitUntilExit();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tokmon",
3
- "version": "0.3.2",
3
+ "version": "0.3.4",
4
4
  "description": "Terminal dashboard for Claude Code usage and costs",
5
5
  "type": "module",
6
6
  "bin": {