@tokz/cli 0.2.1 → 0.2.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.
@@ -16,7 +16,7 @@ import {
16
16
  sanitizeProjectPath,
17
17
  shortModel,
18
18
  usd
19
- } from "./chunk-MO4Y7IF6.js";
19
+ } from "./chunk-JAZOB7NC.js";
20
20
 
21
21
  // src/ui/Root.tsx
22
22
  import { useEffect as useEffect2, useState as useState6 } from "react";
@@ -147,7 +147,7 @@ async function loadProjects(home = homedir(), onProgress) {
147
147
  byDir.set(dir, list);
148
148
  }
149
149
  const realMap = await realPathsBySanitized(home);
150
- const seenMessageIds = /* @__PURE__ */ new Set();
150
+ const seenMessageIds = /* @__PURE__ */ new Map();
151
151
  const seenToolIds = /* @__PURE__ */ new Set();
152
152
  let parsed = 0;
153
153
  const out = [];
@@ -7,7 +7,8 @@ var PRICES = {
7
7
  "claude-opus-4-8": { inputPerMTok: 5, outputPerMTok: 25 },
8
8
  "claude-opus-4-7": { inputPerMTok: 5, outputPerMTok: 25 },
9
9
  "claude-opus-4-6": { inputPerMTok: 5, outputPerMTok: 25 },
10
- "claude-sonnet-5": { inputPerMTok: 3, outputPerMTok: 15 },
10
+ // introductory pricing ($2/$10) through 2026-08-31; sticker is $3/$15 after
11
+ "claude-sonnet-5": { inputPerMTok: 2, outputPerMTok: 10 },
11
12
  "claude-sonnet-4-6": { inputPerMTok: 3, outputPerMTok: 15 },
12
13
  "claude-haiku-4-5": { inputPerMTok: 1, outputPerMTok: 5 },
13
14
  // OpenAI (no cache-write charge; cached input 0.1x)
@@ -43,13 +44,16 @@ function resolvePrice(modelId) {
43
44
  function emptyUsage() {
44
45
  return { inputTokens: 0, cacheReadTokens: 0, cacheCreationTokens: 0, outputTokens: 0, turns: 0 };
45
46
  }
47
+ var CACHE_WRITE_1H_MULT = 2;
46
48
  function costUsd(usage, modelId) {
47
49
  const p = resolvePrice(modelId);
48
50
  const readMult = p.cacheReadMult ?? DEFAULT_CACHE_READ_MULT;
49
51
  const writeMult = p.cacheWriteMult ?? DEFAULT_CACHE_WRITE_MULT;
50
52
  const input = usage.inputTokens / 1e6 * p.inputPerMTok;
51
53
  const cacheRead = usage.cacheReadTokens / 1e6 * p.inputPerMTok * readMult;
52
- const cacheWrite = usage.cacheCreationTokens / 1e6 * p.inputPerMTok * writeMult;
54
+ const write1h = Math.min(usage.cacheCreation1hTokens ?? 0, usage.cacheCreationTokens);
55
+ const write5m = usage.cacheCreationTokens - write1h;
56
+ const cacheWrite = write5m / 1e6 * p.inputPerMTok * writeMult + write1h / 1e6 * p.inputPerMTok * (p.cacheWriteMult ?? CACHE_WRITE_1H_MULT);
53
57
  const output = usage.outputTokens / 1e6 * p.outputPerMTok;
54
58
  return { input, cacheRead, cacheWrite, output, total: input + cacheRead + cacheWrite + output };
55
59
  }
@@ -60,6 +64,7 @@ function addUsage(acc, u) {
60
64
  acc.inputTokens += u.inputTokens;
61
65
  acc.cacheReadTokens += u.cacheReadTokens;
62
66
  acc.cacheCreationTokens += u.cacheCreationTokens;
67
+ acc.cacheCreation1hTokens = (acc.cacheCreation1hTokens ?? 0) + (u.cacheCreation1hTokens ?? 0);
63
68
  acc.outputTokens += u.outputTokens;
64
69
  acc.turns += u.turns;
65
70
  }
@@ -279,12 +284,16 @@ var AssistantLine = z.object({
279
284
  input_tokens: z.number().catch(0).default(0),
280
285
  cache_creation_input_tokens: z.number().catch(0).default(0),
281
286
  cache_read_input_tokens: z.number().catch(0).default(0),
282
- output_tokens: z.number().catch(0).default(0)
287
+ output_tokens: z.number().catch(0).default(0),
288
+ cache_creation: z.object({
289
+ ephemeral_5m_input_tokens: z.number().catch(0).default(0),
290
+ ephemeral_1h_input_tokens: z.number().catch(0).default(0)
291
+ }).nullish()
283
292
  }).optional(),
284
293
  content: z.array(z.object({ type: z.string(), id: z.string().optional(), name: z.string().optional() }).passthrough()).optional()
285
294
  })
286
295
  });
287
- async function parseTranscript(file, seenMessageIds = /* @__PURE__ */ new Set(), seenToolIds = /* @__PURE__ */ new Set()) {
296
+ async function parseTranscript(file, seenMessages = /* @__PURE__ */ new Map(), seenToolIds = /* @__PURE__ */ new Set()) {
288
297
  const stats = { file, usageByModel: {}, toolCalls: {}, toolCostUsd: {}, dailyUsage: {} };
289
298
  const rl = createInterface({ input: createReadStream(file, "utf8"), crlfDelay: Infinity });
290
299
  for await (const line of rl) {
@@ -304,32 +313,51 @@ async function parseTranscript(file, seenMessageIds = /* @__PURE__ */ new Set(),
304
313
  stats.lastTs = timestamp;
305
314
  }
306
315
  const model = message.model ?? "unknown";
307
- const firstSeen = !message.id || !seenMessageIds.has(message.id);
308
- if (message.id) seenMessageIds.add(message.id);
309
316
  let turnCost = 0;
310
- if (message.usage && firstSeen && model !== "<synthetic>") {
311
- const accs = [stats.usageByModel[model] ??= emptyUsage()];
312
- if (timestamp) {
313
- const day = stats.dailyUsage[timestamp.slice(0, 10)] ??= {};
314
- accs.push(day[model] ??= emptyUsage());
317
+ if (message.usage && model !== "<synthetic>") {
318
+ const u = message.usage;
319
+ const cur = {
320
+ input: u.input_tokens,
321
+ cacheRead: u.cache_read_input_tokens,
322
+ cacheWrite: u.cache_creation_input_tokens,
323
+ cacheWrite1h: u.cache_creation?.ephemeral_1h_input_tokens ?? 0,
324
+ output: u.output_tokens
325
+ };
326
+ const prev = message.id ? seenMessages.get(message.id) : void 0;
327
+ const delta = {
328
+ inputTokens: Math.max(0, cur.input - (prev?.input ?? 0)),
329
+ cacheReadTokens: Math.max(0, cur.cacheRead - (prev?.cacheRead ?? 0)),
330
+ cacheCreationTokens: Math.max(0, cur.cacheWrite - (prev?.cacheWrite ?? 0)),
331
+ cacheCreation1hTokens: Math.max(0, cur.cacheWrite1h - (prev?.cacheWrite1h ?? 0)),
332
+ outputTokens: Math.max(0, cur.output - (prev?.output ?? 0)),
333
+ turns: prev ? 0 : 1
334
+ };
335
+ if (message.id) {
336
+ seenMessages.set(message.id, {
337
+ input: Math.max(cur.input, prev?.input ?? 0),
338
+ cacheRead: Math.max(cur.cacheRead, prev?.cacheRead ?? 0),
339
+ cacheWrite: Math.max(cur.cacheWrite, prev?.cacheWrite ?? 0),
340
+ cacheWrite1h: Math.max(cur.cacheWrite1h, prev?.cacheWrite1h ?? 0),
341
+ output: Math.max(cur.output, prev?.output ?? 0)
342
+ });
315
343
  }
316
- for (const u of accs) {
317
- u.inputTokens += message.usage.input_tokens;
318
- u.cacheCreationTokens += message.usage.cache_creation_input_tokens;
319
- u.cacheReadTokens += message.usage.cache_read_input_tokens;
320
- u.outputTokens += message.usage.output_tokens;
321
- u.turns += 1;
344
+ const hasDelta = delta.inputTokens + delta.cacheReadTokens + delta.cacheCreationTokens + delta.outputTokens > 0 || delta.turns > 0;
345
+ if (hasDelta) {
346
+ const accs = [stats.usageByModel[model] ??= emptyUsage()];
347
+ if (timestamp) {
348
+ const day = stats.dailyUsage[timestamp.slice(0, 10)] ??= {};
349
+ accs.push(day[model] ??= emptyUsage());
350
+ }
351
+ for (const acc of accs) {
352
+ acc.inputTokens += delta.inputTokens;
353
+ acc.cacheReadTokens += delta.cacheReadTokens;
354
+ acc.cacheCreationTokens += delta.cacheCreationTokens;
355
+ acc.cacheCreation1hTokens = (acc.cacheCreation1hTokens ?? 0) + (delta.cacheCreation1hTokens ?? 0);
356
+ acc.outputTokens += delta.outputTokens;
357
+ acc.turns += delta.turns;
358
+ }
359
+ turnCost = costUsd(delta, model).total;
322
360
  }
323
- turnCost = costUsd(
324
- {
325
- inputTokens: message.usage.input_tokens,
326
- cacheCreationTokens: message.usage.cache_creation_input_tokens,
327
- cacheReadTokens: message.usage.cache_read_input_tokens,
328
- outputTokens: message.usage.output_tokens,
329
- turns: 1
330
- },
331
- model
332
- ).total;
333
361
  }
334
362
  const turnTools = [];
335
363
  for (const block of message.content ?? []) {
package/dist/cli.js CHANGED
@@ -7,7 +7,7 @@ import {
7
7
  pct1,
8
8
  tok,
9
9
  usd
10
- } from "./chunk-MO4Y7IF6.js";
10
+ } from "./chunk-JAZOB7NC.js";
11
11
 
12
12
  // src/cli.ts
13
13
  import { createRequire } from "module";
@@ -71,7 +71,7 @@ program.command("audit").argument("[project]", "project path (default: current d
71
71
  process.exitCode = 1;
72
72
  return;
73
73
  }
74
- const seenMessageIds = /* @__PURE__ */ new Set();
74
+ const seenMessageIds = /* @__PURE__ */ new Map();
75
75
  const seenToolIds = /* @__PURE__ */ new Set();
76
76
  const sessions = await Promise.all(
77
77
  transcripts.map((f) => parseTranscript(f, seenMessageIds, seenToolIds))
@@ -91,7 +91,7 @@ program.action(async () => {
91
91
  process.exitCode = 1;
92
92
  return;
93
93
  }
94
- const seenMessageIds = /* @__PURE__ */ new Set();
94
+ const seenMessageIds = /* @__PURE__ */ new Map();
95
95
  const seenToolIds = /* @__PURE__ */ new Set();
96
96
  const sessions = await Promise.all(
97
97
  transcripts.map((f) => parseTranscript(f, seenMessageIds, seenToolIds))
@@ -102,7 +102,7 @@ program.action(async () => {
102
102
  const [{ render }, React, { Root }, { Fullscreen }] = await Promise.all([
103
103
  import("ink"),
104
104
  import("react"),
105
- import("./Root-T6AZELSZ.js"),
105
+ import("./Root-6SZ5FQDN.js"),
106
106
  import("./Fullscreen-GK2ZYXHV.js")
107
107
  ]);
108
108
  render(React.createElement(Fullscreen, null, React.createElement(Root)));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tokz/cli",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "description": "Audit where your coding agent's context window and API dollars go.",
5
5
  "type": "module",
6
6
  "license": "MIT",