tokmon 0.14.4 → 0.14.5
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/dist/cli.js +80 -44
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -610,9 +610,9 @@ function glyphs() {
|
|
|
610
610
|
// src/app.tsx
|
|
611
611
|
import { spawn } from "child_process";
|
|
612
612
|
import { appendFileSync as appendFileSync2 } from "fs";
|
|
613
|
-
import { useState as useState3, useEffect as useEffect3, useCallback
|
|
613
|
+
import { useState as useState3, useEffect as useEffect3, useCallback, useRef as useRef2, useMemo } from "react";
|
|
614
614
|
import { Box as Box7, Text as Text7, Transform, useInput, useStdout, useApp } from "ink";
|
|
615
|
-
import { useMouse
|
|
615
|
+
import { useMouse } from "@zenobius/ink-mouse";
|
|
616
616
|
|
|
617
617
|
// src/http.ts
|
|
618
618
|
async function readJson(res) {
|
|
@@ -705,7 +705,9 @@ async function detectClaude(homeDir) {
|
|
|
705
705
|
}
|
|
706
706
|
function priceFor(model) {
|
|
707
707
|
for (const key of PRICE_KEYS) {
|
|
708
|
-
if (model.startsWith(key))
|
|
708
|
+
if (!model.startsWith(key)) continue;
|
|
709
|
+
const rest = model.slice(key.length);
|
|
710
|
+
if (rest === "" || rest[0] === "-") return PRICING[key];
|
|
709
711
|
}
|
|
710
712
|
return FALLBACK;
|
|
711
713
|
}
|
|
@@ -1013,10 +1015,15 @@ function subtractClamped(cur, prev) {
|
|
|
1013
1015
|
reasoning_output_tokens: sub(cur.reasoning_output_tokens, prev?.reasoning_output_tokens)
|
|
1014
1016
|
};
|
|
1015
1017
|
}
|
|
1018
|
+
function eventSig(last, total) {
|
|
1019
|
+
const f = (x) => x ? `${x.input_tokens ?? 0},${x.cached_input_tokens ?? 0},${x.output_tokens ?? 0},${x.reasoning_output_tokens ?? 0}` : "-";
|
|
1020
|
+
return `${f(last)}|${f(total)}`;
|
|
1021
|
+
}
|
|
1016
1022
|
async function parseFile2(path) {
|
|
1017
1023
|
const entries = [];
|
|
1018
1024
|
let model = "gpt-5-codex";
|
|
1019
1025
|
let prevTotal = null;
|
|
1026
|
+
let prevSig = null;
|
|
1020
1027
|
const rl = createInterface2({ input: createReadStream2(path), crlfDelay: Infinity });
|
|
1021
1028
|
for await (const rawLine of rl) {
|
|
1022
1029
|
if (!rawLine.includes("token_count") && !rawLine.includes("turn_context")) continue;
|
|
@@ -1032,7 +1039,11 @@ async function parseFile2(path) {
|
|
|
1032
1039
|
if (payloadType !== "token_count") continue;
|
|
1033
1040
|
const info = obj?.payload?.info;
|
|
1034
1041
|
const total = info?.total_token_usage;
|
|
1035
|
-
|
|
1042
|
+
const last = info?.last_token_usage;
|
|
1043
|
+
const sig = eventSig(last, total);
|
|
1044
|
+
if (sig === prevSig) continue;
|
|
1045
|
+
prevSig = sig;
|
|
1046
|
+
let d = last;
|
|
1036
1047
|
if (!d && total) {
|
|
1037
1048
|
const reset = !!prevTotal && (total.input_tokens ?? 0) < (prevTotal.input_tokens ?? 0);
|
|
1038
1049
|
d = reset ? total : subtractClamped(total, prevTotal);
|
|
@@ -1622,9 +1633,10 @@ async function parseFile3(path) {
|
|
|
1622
1633
|
const c = u.cost ?? {};
|
|
1623
1634
|
const costInput = pos(c.input);
|
|
1624
1635
|
const cacheSavings = input > 0 && cacheRead > 0 ? Math.max(0, cacheRead * (costInput / input) - pos(c.cacheRead)) : 0;
|
|
1636
|
+
const model = typeof msg.responseModel === "string" && msg.responseModel || typeof msg.model === "string" && msg.model || "unknown";
|
|
1625
1637
|
entries.push({
|
|
1626
1638
|
ts,
|
|
1627
|
-
model
|
|
1639
|
+
model,
|
|
1628
1640
|
cost: pos(c.total),
|
|
1629
1641
|
input,
|
|
1630
1642
|
output,
|
|
@@ -1915,6 +1927,7 @@ function resetDate(value) {
|
|
|
1915
1927
|
}
|
|
1916
1928
|
function percentMetric2(label, snapshot, reset, primary) {
|
|
1917
1929
|
if (!snapshot || typeof snapshot.percent_remaining !== "number") return null;
|
|
1930
|
+
if (snapshot.unlimited === true || snapshot.entitlement === 0) return null;
|
|
1918
1931
|
const used = Math.min(100, Math.max(0, 100 - snapshot.percent_remaining));
|
|
1919
1932
|
return { label, used, limit: 100, format: { kind: "percent" }, resetsAt: reset, primary };
|
|
1920
1933
|
}
|
|
@@ -2670,9 +2683,9 @@ function saveSnapshot(stats) {
|
|
|
2670
2683
|
|
|
2671
2684
|
// src/ui/shared.tsx
|
|
2672
2685
|
import { appendFileSync } from "fs";
|
|
2673
|
-
import {
|
|
2686
|
+
import { useEffect, useRef, useState } from "react";
|
|
2674
2687
|
import { Box, Text } from "ink";
|
|
2675
|
-
import { useOnMouseClick
|
|
2688
|
+
import { useOnMouseClick } from "@zenobius/ink-mouse";
|
|
2676
2689
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2677
2690
|
function truncateName(s, n) {
|
|
2678
2691
|
const ell = glyphs().ellipsis;
|
|
@@ -2685,40 +2698,72 @@ function ClickableBox({ onClick, children, ...props }) {
|
|
|
2685
2698
|
});
|
|
2686
2699
|
return /* @__PURE__ */ jsx(Box, { ref, ...props, children });
|
|
2687
2700
|
}
|
|
2688
|
-
|
|
2689
|
-
|
|
2690
|
-
|
|
2691
|
-
|
|
2692
|
-
const
|
|
2693
|
-
|
|
2701
|
+
var SGR_PRESS = /\x1b\[<(\d+);(\d+);(\d+)M/g;
|
|
2702
|
+
var linkHits = /* @__PURE__ */ new Set();
|
|
2703
|
+
function dispatchLinkClicks(chunk) {
|
|
2704
|
+
if (linkHits.size === 0) return;
|
|
2705
|
+
const s = typeof chunk === "string" ? chunk : chunk.toString("utf8");
|
|
2706
|
+
SGR_PRESS.lastIndex = 0;
|
|
2707
|
+
let m;
|
|
2708
|
+
while ((m = SGR_PRESS.exec(s)) !== null) {
|
|
2709
|
+
const code = Number(m[1]);
|
|
2710
|
+
if (code & 64 || code & 32) continue;
|
|
2711
|
+
const mx = Number(m[2]) - 1;
|
|
2712
|
+
const my = Number(m[3]) - 1;
|
|
2694
2713
|
if (process.env.TOKMON_LINKDEBUG) {
|
|
2695
2714
|
try {
|
|
2696
|
-
appendFileSync(process.env.TOKMON_LINKDEBUG, `
|
|
2715
|
+
appendFileSync(process.env.TOKMON_LINKDEBUG, `DISPATCH code=${code} mx=${mx} my=${my} hits=${linkHits.size}
|
|
2697
2716
|
`);
|
|
2698
2717
|
} catch {
|
|
2699
2718
|
}
|
|
2700
2719
|
}
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
|
|
2720
|
+
for (const hit of [...linkHits]) {
|
|
2721
|
+
if (hit(mx, my)) break;
|
|
2722
|
+
}
|
|
2723
|
+
}
|
|
2724
|
+
}
|
|
2725
|
+
function nodeBox(node) {
|
|
2726
|
+
const yn = node?.yogaNode;
|
|
2727
|
+
if (!yn) return null;
|
|
2728
|
+
const l = yn.getComputedLayout();
|
|
2729
|
+
let left = l.left, top = l.top;
|
|
2730
|
+
let p = node?.parentNode;
|
|
2731
|
+
while (p) {
|
|
2732
|
+
const pn = p.yogaNode;
|
|
2733
|
+
if (!pn) break;
|
|
2734
|
+
const pl = pn.getComputedLayout();
|
|
2735
|
+
left += pl.left;
|
|
2736
|
+
top += pl.top;
|
|
2737
|
+
p = p.parentNode;
|
|
2738
|
+
}
|
|
2739
|
+
return { left, top, width: l.width, height: l.height };
|
|
2740
|
+
}
|
|
2741
|
+
function LinkBox({ onClick, children, ...props }) {
|
|
2742
|
+
const ref = useRef(null);
|
|
2743
|
+
const onClickRef = useRef(onClick);
|
|
2744
|
+
onClickRef.current = onClick;
|
|
2708
2745
|
useEffect(() => {
|
|
2709
|
-
const
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
|
|
2746
|
+
const hit = (mx, my) => {
|
|
2747
|
+
const box = nodeBox(ref.current);
|
|
2748
|
+
if (process.env.TOKMON_LINKDEBUG) {
|
|
2749
|
+
try {
|
|
2750
|
+
appendFileSync(process.env.TOKMON_LINKDEBUG, `HIT? mx=${mx} my=${my} box=${box ? `${box.left},${box.top} ${box.width}x${box.height}` : "null"}
|
|
2713
2751
|
`);
|
|
2714
|
-
|
|
2752
|
+
} catch {
|
|
2753
|
+
}
|
|
2715
2754
|
}
|
|
2716
|
-
|
|
2717
|
-
|
|
2755
|
+
if (!box || box.width <= 0 || box.height <= 0) return false;
|
|
2756
|
+
if (mx >= box.left && mx < box.left + box.width && my >= box.top && my < box.top + box.height) {
|
|
2757
|
+
onClickRef.current();
|
|
2758
|
+
return true;
|
|
2759
|
+
}
|
|
2760
|
+
return false;
|
|
2761
|
+
};
|
|
2762
|
+
linkHits.add(hit);
|
|
2718
2763
|
return () => {
|
|
2719
|
-
|
|
2764
|
+
linkHits.delete(hit);
|
|
2720
2765
|
};
|
|
2721
|
-
}, [
|
|
2766
|
+
}, []);
|
|
2722
2767
|
return /* @__PURE__ */ jsx(Box, { ref, ...props, children });
|
|
2723
2768
|
}
|
|
2724
2769
|
function Spinner({ label }) {
|
|
@@ -4245,12 +4290,12 @@ function App({ interval: cliInterval, initialConfig }) {
|
|
|
4245
4290
|
useEffect3(() => {
|
|
4246
4291
|
setDashPage((p) => Math.min(p, dashPageCount - 1));
|
|
4247
4292
|
}, [dashPageCount]);
|
|
4248
|
-
const resetView =
|
|
4293
|
+
const resetView = useCallback(() => {
|
|
4249
4294
|
setCursor(0);
|
|
4250
4295
|
setExpanded(-1);
|
|
4251
4296
|
}, []);
|
|
4252
4297
|
const clampRow = (n) => Math.max(0, Math.min(rowCountRef.current - 1, n));
|
|
4253
|
-
const mouse =
|
|
4298
|
+
const mouse = useMouse();
|
|
4254
4299
|
useEffect3(() => {
|
|
4255
4300
|
if (!IS_TTY) return;
|
|
4256
4301
|
mouse.enable();
|
|
@@ -4263,20 +4308,11 @@ function App({ interval: cliInterval, initialConfig }) {
|
|
|
4263
4308
|
}
|
|
4264
4309
|
};
|
|
4265
4310
|
mouse.events.on("scroll", onScroll);
|
|
4266
|
-
|
|
4267
|
-
|
|
4268
|
-
onClickDbg = (p, a) => {
|
|
4269
|
-
try {
|
|
4270
|
-
appendFileSync2(process.env.TOKMON_LINKDEBUG, `APP click p=${p.x},${p.y} a=${a}
|
|
4271
|
-
`);
|
|
4272
|
-
} catch {
|
|
4273
|
-
}
|
|
4274
|
-
};
|
|
4275
|
-
mouse.events.on("click", onClickDbg);
|
|
4276
|
-
}
|
|
4311
|
+
const onData = (d) => dispatchLinkClicks(d);
|
|
4312
|
+
process.stdin.on("data", onData);
|
|
4277
4313
|
return () => {
|
|
4278
4314
|
mouse.events.off("scroll", onScroll);
|
|
4279
|
-
|
|
4315
|
+
process.stdin.off("data", onData);
|
|
4280
4316
|
};
|
|
4281
4317
|
}, [tab]);
|
|
4282
4318
|
function updateConfig(fn) {
|