@tokz/cli 0.2.16 → 0.2.18
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.
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
sanitizeProjectPath,
|
|
21
21
|
shortModel,
|
|
22
22
|
usd
|
|
23
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-T5J7LVH6.js";
|
|
24
24
|
|
|
25
25
|
// src/ui/Root.tsx
|
|
26
26
|
import { useEffect as useEffect2, useState as useState6 } from "react";
|
|
@@ -766,9 +766,6 @@ function parseLine(raw) {
|
|
|
766
766
|
obj: o
|
|
767
767
|
};
|
|
768
768
|
}
|
|
769
|
-
function tokenCountInfo(p) {
|
|
770
|
-
return p.type === "event_msg" && p.payload?.type === "token_count" ? asDict(p.payload.info) : void 0;
|
|
771
|
-
}
|
|
772
769
|
function headlessUsage(o) {
|
|
773
770
|
const usage = rawUsage(asDict(o.usage)) ?? rawUsage(asDict(asDict(o.data)?.usage)) ?? rawUsage(asDict(asDict(o.result)?.usage)) ?? rawUsage(asDict(asDict(o.response)?.usage));
|
|
774
771
|
if (!usage) return void 0;
|
|
@@ -784,6 +781,43 @@ function headlessTimestamp(o, pick) {
|
|
|
784
781
|
const fromFields = (f) => f ? pick(f.timestamp) ?? pick(f.created_at) ?? pick(f.createdAt) : void 0;
|
|
785
782
|
return fromFields(o) ?? fromFields(asDict(o.data)) ?? fromFields(asDict(o.result)) ?? fromFields(asDict(o.response));
|
|
786
783
|
}
|
|
784
|
+
function detectReplaySecond(content, lines) {
|
|
785
|
+
const encoder = new TextEncoder();
|
|
786
|
+
let byteLen = 0;
|
|
787
|
+
let charLimit = 0;
|
|
788
|
+
for (let i = 0; i < content.length; i++) {
|
|
789
|
+
const code = content.charCodeAt(i);
|
|
790
|
+
if (code <= 127) byteLen += 1;
|
|
791
|
+
else if (code <= 2047) byteLen += 2;
|
|
792
|
+
else if (code >= 55296 && code <= 57343) {
|
|
793
|
+
byteLen += 4;
|
|
794
|
+
i++;
|
|
795
|
+
} else byteLen += 3;
|
|
796
|
+
if (byteLen > 16384) break;
|
|
797
|
+
charLimit = i + 1;
|
|
798
|
+
}
|
|
799
|
+
const head = content.slice(0, charLimit);
|
|
800
|
+
if (!head.includes("thread_spawn") && !head.includes("forked_from_id")) return void 0;
|
|
801
|
+
let firstSecond;
|
|
802
|
+
for (const p of lines) {
|
|
803
|
+
if (p.type !== "event_msg" || p.payload?.type !== "token_count") continue;
|
|
804
|
+
const info = p.payload.info;
|
|
805
|
+
if (!info) continue;
|
|
806
|
+
if (!asDict(info.last_token_usage) && !asDict(info.total_token_usage)) continue;
|
|
807
|
+
const ts = p.timestamp;
|
|
808
|
+
if (!ts || typeof ts !== "string" || ts.length < 19) continue;
|
|
809
|
+
const sec = ts.slice(0, 19);
|
|
810
|
+
if (firstSecond === void 0) {
|
|
811
|
+
firstSecond = sec;
|
|
812
|
+
} else {
|
|
813
|
+
if (firstSecond === sec) {
|
|
814
|
+
return sec;
|
|
815
|
+
}
|
|
816
|
+
return void 0;
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
return void 0;
|
|
820
|
+
}
|
|
787
821
|
async function parseCodexRollout(file, seen = /* @__PURE__ */ new Set()) {
|
|
788
822
|
const stats = { file, usageByModel: {}, toolCalls: {}, toolCostUsd: {}, dailyUsage: {} };
|
|
789
823
|
const content = await readFile4(file, "utf8").catch(() => "");
|
|
@@ -793,6 +827,8 @@ async function parseCodexRollout(file, seen = /* @__PURE__ */ new Set()) {
|
|
|
793
827
|
const parsed = parseLine(raw);
|
|
794
828
|
if (parsed) lines.push(parsed);
|
|
795
829
|
}
|
|
830
|
+
const replaySecond = detectReplaySecond(content, lines);
|
|
831
|
+
let skipReplay = replaySecond !== void 0;
|
|
796
832
|
const modelState = { currentIsFallback: false };
|
|
797
833
|
let prev;
|
|
798
834
|
let turnTools = [];
|
|
@@ -812,12 +848,14 @@ async function parseCodexRollout(file, seen = /* @__PURE__ */ new Set()) {
|
|
|
812
848
|
}
|
|
813
849
|
seen.add(dedupKey);
|
|
814
850
|
const delta = {
|
|
815
|
-
// Codex's input_tokens INCLUDES cached tokens; split them out.
|
|
816
851
|
inputTokens: Math.max(0, usage.input - cached),
|
|
817
852
|
cacheReadTokens: cached,
|
|
818
853
|
cacheCreationTokens: 0,
|
|
819
854
|
outputTokens: usage.output,
|
|
820
|
-
turns: 1
|
|
855
|
+
turns: 1,
|
|
856
|
+
longContextInputTokens: usage.input > 272e3 ? Math.max(0, usage.input - cached) : 0,
|
|
857
|
+
longContextCacheReadTokens: usage.input > 272e3 ? cached : 0,
|
|
858
|
+
longContextOutputTokens: usage.input > 272e3 ? usage.output : 0
|
|
821
859
|
};
|
|
822
860
|
const accs = [stats.usageByModel[model] ??= emptyUsage()];
|
|
823
861
|
if (timestamp) {
|
|
@@ -829,6 +867,9 @@ async function parseCodexRollout(file, seen = /* @__PURE__ */ new Set()) {
|
|
|
829
867
|
u.cacheReadTokens += delta.cacheReadTokens;
|
|
830
868
|
u.outputTokens += delta.outputTokens;
|
|
831
869
|
u.turns += 1;
|
|
870
|
+
u.longContextInputTokens = (u.longContextInputTokens ?? 0) + (delta.longContextInputTokens ?? 0);
|
|
871
|
+
u.longContextCacheReadTokens = (u.longContextCacheReadTokens ?? 0) + (delta.longContextCacheReadTokens ?? 0);
|
|
872
|
+
u.longContextOutputTokens = (u.longContextOutputTokens ?? 0) + (delta.longContextOutputTokens ?? 0);
|
|
832
873
|
}
|
|
833
874
|
const turnCost = costUsd(delta, model).total;
|
|
834
875
|
if (turnCost > 0 && turnTools.length > 0) {
|
|
@@ -862,33 +903,34 @@ async function parseCodexRollout(file, seen = /* @__PURE__ */ new Set()) {
|
|
|
862
903
|
}
|
|
863
904
|
continue;
|
|
864
905
|
}
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
906
|
+
if (type === "event_msg" && payload2?.type === "token_count") {
|
|
907
|
+
const info = asDict(payload2.info);
|
|
908
|
+
if (replaySecond !== void 0 && skipReplay) {
|
|
909
|
+
const ts = timestamp ?? parsed.obj.timestamp;
|
|
910
|
+
const matchesReplay = typeof ts === "string" && ts.length >= 19 && ts.slice(0, 19) === replaySecond;
|
|
911
|
+
if (matchesReplay) {
|
|
912
|
+
const totals = rawUsage(info?.total_token_usage);
|
|
913
|
+
if (totals) prev = totals;
|
|
914
|
+
turnTools = [];
|
|
873
915
|
continue;
|
|
874
916
|
}
|
|
875
|
-
|
|
876
|
-
usage2 = last ?? totals;
|
|
877
|
-
} else {
|
|
878
|
-
usage2 = subtractUsage(totals, prev);
|
|
879
|
-
}
|
|
880
|
-
prev = totals;
|
|
881
|
-
} else {
|
|
882
|
-
usage2 = last;
|
|
917
|
+
skipReplay = false;
|
|
883
918
|
}
|
|
884
|
-
if (
|
|
919
|
+
if (info) {
|
|
920
|
+
const totals = rawUsage(info.total_token_usage);
|
|
921
|
+
const last = rawUsage(info.last_token_usage);
|
|
922
|
+
if (!last && !totals) continue;
|
|
923
|
+
const usage2 = last ?? subtractUsage(totals, prev);
|
|
924
|
+
if (totals) prev = totals;
|
|
925
|
+
if (usage2.input === 0 && usage2.cached === 0 && usage2.output === 0 && usage2.reasoning === 0) {
|
|
926
|
+
continue;
|
|
927
|
+
}
|
|
928
|
+
const ts = nonEmpty(timestamp) ?? normalizeTimestamp(parsed.obj.timestamp);
|
|
929
|
+
const parsedModel = modelFromParts(payload2) ?? modelFromParts(info);
|
|
930
|
+
const model2 = resolveModel(parsedModel, ts ?? "", modelState);
|
|
931
|
+
accumulate(usage2, model2, ts);
|
|
885
932
|
continue;
|
|
886
933
|
}
|
|
887
|
-
const ts = nonEmpty(timestamp) ?? normalizeTimestamp(parsed.obj.timestamp);
|
|
888
|
-
const parsedModel = modelFromParts(payload2) ?? modelFromParts(info);
|
|
889
|
-
const model2 = resolveModel(parsedModel, ts ?? "", modelState);
|
|
890
|
-
accumulate(usage2, model2, ts);
|
|
891
|
-
continue;
|
|
892
934
|
}
|
|
893
935
|
if (type === "event_msg" || payload2?.type === "turn_context") continue;
|
|
894
936
|
const usage = headlessUsage(parsed.obj);
|
|
@@ -68,13 +68,25 @@ function costUsd(usage, modelId) {
|
|
|
68
68
|
const p = resolvePrice(modelId);
|
|
69
69
|
const readMult = p.cacheReadMult ?? DEFAULT_CACHE_READ_MULT;
|
|
70
70
|
const writeMult = p.cacheWriteMult ?? DEFAULT_CACHE_WRITE_MULT;
|
|
71
|
-
const
|
|
72
|
-
const
|
|
71
|
+
const regInputTokens = usage.inputTokens - (usage.longContextInputTokens ?? 0);
|
|
72
|
+
const regCacheReadTokens = usage.cacheReadTokens - (usage.longContextCacheReadTokens ?? 0);
|
|
73
|
+
const regOutputTokens = usage.outputTokens - (usage.longContextOutputTokens ?? 0);
|
|
74
|
+
let input = regInputTokens / 1e6 * p.inputPerMTok;
|
|
75
|
+
let cacheRead = regCacheReadTokens / 1e6 * p.inputPerMTok * readMult;
|
|
76
|
+
let output = regOutputTokens / 1e6 * p.outputPerMTok;
|
|
77
|
+
if (usage.longContextInputTokens) {
|
|
78
|
+
input += usage.longContextInputTokens / 1e6 * (p.inputPerMTok * 2);
|
|
79
|
+
}
|
|
80
|
+
if (usage.longContextCacheReadTokens) {
|
|
81
|
+
cacheRead += usage.longContextCacheReadTokens / 1e6 * (p.inputPerMTok * 2) * readMult;
|
|
82
|
+
}
|
|
83
|
+
if (usage.longContextOutputTokens) {
|
|
84
|
+
output += usage.longContextOutputTokens / 1e6 * (p.outputPerMTok * 2);
|
|
85
|
+
}
|
|
73
86
|
const write1h = Math.min(usage.cacheCreation1hTokens ?? 0, usage.cacheCreationTokens);
|
|
74
87
|
const write5m = usage.cacheCreationTokens - write1h;
|
|
75
88
|
const write1hMult = p.cacheWrite1hMult ?? (p.cacheWriteMult === 0 ? 0 : CACHE_WRITE_1H_MULT);
|
|
76
89
|
const cacheWrite = write5m / 1e6 * p.inputPerMTok * writeMult + write1h / 1e6 * p.inputPerMTok * write1hMult;
|
|
77
|
-
const output = usage.outputTokens / 1e6 * p.outputPerMTok;
|
|
78
90
|
return { input, cacheRead, cacheWrite, output, total: input + cacheRead + cacheWrite + output };
|
|
79
91
|
}
|
|
80
92
|
|
package/dist/cli.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
buildBlocks,
|
|
4
4
|
renderBlocksReport
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-VXWHRHQU.js";
|
|
6
6
|
import {
|
|
7
7
|
findMcpServers
|
|
8
8
|
} from "./chunk-65BQE6TI.js";
|
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
setTimezone,
|
|
18
18
|
tok,
|
|
19
19
|
usd
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-T5J7LVH6.js";
|
|
21
21
|
|
|
22
22
|
// src/cli.ts
|
|
23
23
|
import { createRequire } from "module";
|
|
@@ -234,7 +234,7 @@ program.command("blocks").description("Claude usage grouped into rolling 5-hour
|
|
|
234
234
|
});
|
|
235
235
|
program.command("statusline").description("compact usage line for Claude Code's statusLine hook (reads hook JSON on stdin)").argument("[action]", '"enable" writes the hook into ~/.claude/settings.json, "disable" removes it').option("--cost-source <mode>", "session cost source: auto | cc | calc | both", "auto").action(async (action, opts) => {
|
|
236
236
|
const globals = applyGlobals();
|
|
237
|
-
const sl = await import("./statusline-
|
|
237
|
+
const sl = await import("./statusline-4UN2Q6BT.js");
|
|
238
238
|
if (action === "enable" || action === "disable") {
|
|
239
239
|
try {
|
|
240
240
|
console.log(action === "enable" ? await sl.enableStatusline() : await sl.disableStatusline());
|
|
@@ -276,7 +276,7 @@ program.action(async () => {
|
|
|
276
276
|
const [{ render }, React, { Root }, { Fullscreen }] = await Promise.all([
|
|
277
277
|
import("ink"),
|
|
278
278
|
import("react"),
|
|
279
|
-
import("./Root-
|
|
279
|
+
import("./Root-IVPGDV7M.js"),
|
|
280
280
|
import("./Fullscreen-GK2ZYXHV.js")
|
|
281
281
|
]);
|
|
282
282
|
render(React.createElement(Fullscreen, null, React.createElement(Root)));
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
buildBlocks,
|
|
4
4
|
burnRate,
|
|
5
5
|
fmtMs
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-VXWHRHQU.js";
|
|
7
7
|
import {
|
|
8
8
|
compact,
|
|
9
9
|
costUsd,
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
parseTranscript,
|
|
13
13
|
shortModel,
|
|
14
14
|
usd
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-T5J7LVH6.js";
|
|
16
16
|
|
|
17
17
|
// src/statusline.ts
|
|
18
18
|
import { mkdir, readFile, stat, writeFile } from "fs/promises";
|