token-usage-dashboard 1.0.16 → 1.0.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.
Files changed (75) hide show
  1. package/build/adapter-node.js +1 -1
  2. package/build/client/_app/immutable/chunks/BLLqPIda.js +3 -0
  3. package/build/client/_app/immutable/chunks/BLLqPIda.js.br +0 -0
  4. package/build/client/_app/immutable/chunks/BLLqPIda.js.gz +0 -0
  5. package/build/client/_app/immutable/chunks/{B0VWrXPj.js → C2_oK6Yg.js} +1 -1
  6. package/build/client/_app/immutable/chunks/C2_oK6Yg.js.br +0 -0
  7. package/build/client/_app/immutable/chunks/C2_oK6Yg.js.gz +0 -0
  8. package/build/client/_app/immutable/chunks/CRzLMJPS.js +1 -0
  9. package/build/client/_app/immutable/chunks/CRzLMJPS.js.br +0 -0
  10. package/build/client/_app/immutable/chunks/CRzLMJPS.js.gz +0 -0
  11. package/build/client/_app/immutable/chunks/D-Hu4b5U.js +1 -0
  12. package/build/client/_app/immutable/chunks/D-Hu4b5U.js.br +1 -0
  13. package/build/client/_app/immutable/chunks/D-Hu4b5U.js.gz +0 -0
  14. package/build/client/_app/immutable/chunks/{ssd4Rw-g.js → zGlnsnwf.js} +2 -2
  15. package/build/client/_app/immutable/chunks/zGlnsnwf.js.br +0 -0
  16. package/build/client/_app/immutable/chunks/zGlnsnwf.js.gz +0 -0
  17. package/build/client/_app/immutable/entry/{app.ByhTKJxk.js → app.QnEDURra.js} +2 -2
  18. package/build/client/_app/immutable/entry/app.QnEDURra.js.br +0 -0
  19. package/build/client/_app/immutable/entry/app.QnEDURra.js.gz +0 -0
  20. package/build/client/_app/immutable/entry/start.CBYpir1g.js +2 -0
  21. package/build/client/_app/immutable/entry/start.CBYpir1g.js.br +0 -0
  22. package/build/client/_app/immutable/entry/start.CBYpir1g.js.gz +0 -0
  23. package/build/client/_app/immutable/nodes/0.yxxqRuA2.js +1 -0
  24. package/build/client/_app/immutable/nodes/0.yxxqRuA2.js.br +0 -0
  25. package/build/client/_app/immutable/nodes/0.yxxqRuA2.js.gz +0 -0
  26. package/build/client/_app/immutable/nodes/{1.Cy2JV0fN.js → 1.CArPcl3H.js} +1 -1
  27. package/build/client/_app/immutable/nodes/1.CArPcl3H.js.br +1 -0
  28. package/build/client/_app/immutable/nodes/1.CArPcl3H.js.gz +0 -0
  29. package/build/client/_app/immutable/nodes/2.BXzrhQ0D.js +2 -0
  30. package/build/client/_app/immutable/nodes/2.BXzrhQ0D.js.br +0 -0
  31. package/build/client/_app/immutable/nodes/2.BXzrhQ0D.js.gz +0 -0
  32. package/build/client/_app/version.json +1 -1
  33. package/build/client/_app/version.json.br +0 -0
  34. package/build/client/_app/version.json.gz +0 -0
  35. package/build/server/adapter-env.js +1 -2
  36. package/build/server/chunks/instance.js +3 -3
  37. package/build/server/chunks/internal.js +1 -1
  38. package/build/server/chunks/queries.js +41 -49
  39. package/build/server/chunks/range.js +10 -4
  40. package/build/server/entries/pages/_page.svelte.js +29 -10
  41. package/build/server/env.js +1 -2
  42. package/build/server/handler.js +1 -2
  43. package/build/server/manifest-full.js +1 -1
  44. package/build/server/manifest.js +1 -1
  45. package/build/server/nodes/0.js +1 -1
  46. package/build/server/nodes/1.js +1 -1
  47. package/build/server/nodes/2.js +1 -1
  48. package/build/server/server.js +1 -1
  49. package/package.json +1 -1
  50. package/build/client/_app/immutable/chunks/B0VWrXPj.js.br +0 -0
  51. package/build/client/_app/immutable/chunks/B0VWrXPj.js.gz +0 -0
  52. package/build/client/_app/immutable/chunks/BaNbYf_w.js +0 -1
  53. package/build/client/_app/immutable/chunks/BaNbYf_w.js.br +0 -0
  54. package/build/client/_app/immutable/chunks/BaNbYf_w.js.gz +0 -0
  55. package/build/client/_app/immutable/chunks/CbiRHTcG.js +0 -1
  56. package/build/client/_app/immutable/chunks/CbiRHTcG.js.br +0 -0
  57. package/build/client/_app/immutable/chunks/CbiRHTcG.js.gz +0 -0
  58. package/build/client/_app/immutable/chunks/DTingiCe.js +0 -3
  59. package/build/client/_app/immutable/chunks/DTingiCe.js.br +0 -0
  60. package/build/client/_app/immutable/chunks/DTingiCe.js.gz +0 -0
  61. package/build/client/_app/immutable/chunks/ssd4Rw-g.js.br +0 -0
  62. package/build/client/_app/immutable/chunks/ssd4Rw-g.js.gz +0 -0
  63. package/build/client/_app/immutable/entry/app.ByhTKJxk.js.br +0 -0
  64. package/build/client/_app/immutable/entry/app.ByhTKJxk.js.gz +0 -0
  65. package/build/client/_app/immutable/entry/start.CzGx2BYz.js +0 -2
  66. package/build/client/_app/immutable/entry/start.CzGx2BYz.js.br +0 -0
  67. package/build/client/_app/immutable/entry/start.CzGx2BYz.js.gz +0 -0
  68. package/build/client/_app/immutable/nodes/0.BBGTwdwd.js +0 -1
  69. package/build/client/_app/immutable/nodes/0.BBGTwdwd.js.br +0 -0
  70. package/build/client/_app/immutable/nodes/0.BBGTwdwd.js.gz +0 -0
  71. package/build/client/_app/immutable/nodes/1.Cy2JV0fN.js.br +0 -2
  72. package/build/client/_app/immutable/nodes/1.Cy2JV0fN.js.gz +0 -0
  73. package/build/client/_app/immutable/nodes/2.DVE735SW.js +0 -2
  74. package/build/client/_app/immutable/nodes/2.DVE735SW.js.br +0 -0
  75. package/build/client/_app/immutable/nodes/2.DVE735SW.js.gz +0 -0
@@ -1 +1 @@
1
- {"version":"1791567178720"}
1
+ {"version":"1792037128339"}
Binary file
Binary file
@@ -1,2 +1 @@
1
- import { n as timeout_env, t as env } from "./adapter-node-env.js";
2
- export { env, timeout_env };
1
+ export { t as env, n as timeout_env } from "./adapter-node-env.js";
@@ -206,7 +206,7 @@ function server_data_serializer(event, state) {
206
206
  let promise_id = 1;
207
207
  let max_nodes = -1;
208
208
  const iterator = create_async_iterator();
209
- const global = "__sveltekit_1rca8ms";
209
+ const global = "__sveltekit_xmcbry";
210
210
  /** @param {number} index */
211
211
  function get_replacer(index) {
212
212
  /** @param {any} thing */
@@ -1444,7 +1444,7 @@ async function render_response({ branch, fetched, page_config, status, error = n
1444
1444
  "crossorigin"
1445
1445
  ]);
1446
1446
  }
1447
- const global = "__sveltekit_1rca8ms";
1447
+ const global = "__sveltekit_xmcbry";
1448
1448
  const { data, chunks } = data_serializer.get_data(csp);
1449
1449
  if (page_config.ssr && page_config.csr) body += `\n\t\t\t${fetched.map((item) => serialize_data(item, resolve_opts.filterSerializedResponseHeaders, !!(state.prerendering || state.prerender_default === true))).join("\n ")}`;
1450
1450
  if (page_config.csr && client) {
@@ -1468,7 +1468,7 @@ async function render_response({ branch, fetched, page_config, status, error = n
1468
1468
  }
1469
1469
  }
1470
1470
  const blocks = [];
1471
- const properties = [`base: ${base_expression}`, `version: ${s("1791567178720")}`];
1471
+ const properties = [`base: ${base_expression}`, `version: ${s("1792037128339")}`];
1472
1472
  if (assets) properties.push(`assets: ${s(assets)}`);
1473
1473
  if (client.uses_env_dynamic_public) properties.push(`env: ${load_env_eagerly ? "null" : uneval$1(rendered_env)}`);
1474
1474
  if (chunks) {
@@ -2491,7 +2491,7 @@ function redirect_response(status, location) {
2491
2491
  * @param {Response} response
2492
2492
  */
2493
2493
  function with_version_header(response) {
2494
- response.headers.set("x-sveltekit-version", "1791567178720");
2494
+ response.headers.set("x-sveltekit-version", "1792037128339");
2495
2495
  return response;
2496
2496
  }
2497
2497
  /**
@@ -39,6 +39,7 @@ create table if not exists events (
39
39
  output integer not null default 0,
40
40
  cache_read integer not null default 0,
41
41
  cache_write integer not null default 0,
42
+ cache_write_long integer not null default 0,
42
43
  reasoning integer not null default 0,
43
44
  subagent integer
44
45
  );
@@ -82,14 +83,21 @@ function db() {
82
83
  writeMeta("schema", String(SCHEMA));
83
84
  }
84
85
  handle.exec(TABLES);
85
- addSubagent(handle);
86
+ addColumns(handle);
86
87
  rebucket(handle);
87
88
  return handle;
88
89
  }
89
- /** Older databases grow the column in place, then every file is read again to fill it in */
90
- function addSubagent(handle) {
91
- if (handle.prepare("pragma table_info(events)").all().some((column) => column.name === "subagent")) return;
92
- handle.exec("alter table events add column subagent integer; delete from files");
90
+ var ADDED = {
91
+ subagent: "integer",
92
+ cache_write_long: "integer not null default 0"
93
+ };
94
+ /** Older databases grow columns in place, then every file is read again to fill them in */
95
+ function addColumns(handle) {
96
+ const columns = handle.prepare("pragma table_info(events)").all();
97
+ const missing = Object.keys(ADDED).filter((name) => !columns.some((column) => column.name === name));
98
+ if (!missing.length) return;
99
+ const alters = missing.map((name) => `alter table events add column ${name} ${ADDED[name]};`);
100
+ handle.exec(`begin; ${alters.join(" ")} delete from files; commit;`);
93
101
  }
94
102
  var REBUCKET = `
95
103
  update events set
@@ -146,6 +154,7 @@ var claudeCode = {
146
154
  const ts = Date.parse(String(line.timestamp));
147
155
  if (Number.isNaN(ts)) continue;
148
156
  const details = usage.output_tokens_details;
157
+ const written = usage.cache_creation;
149
158
  events.push({
150
159
  id: `claude-code:${message.id}`,
151
160
  model: message.model,
@@ -156,6 +165,7 @@ var claudeCode = {
156
165
  output: num(usage.output_tokens),
157
166
  cache_read: num(usage.cache_read_input_tokens),
158
167
  cache_write: num(usage.cache_creation_input_tokens),
168
+ cache_write_long: num(written?.ephemeral_1h_input_tokens),
159
169
  reasoning: num(details?.thinking_tokens),
160
170
  subagent: line.isSidechain === true
161
171
  });
@@ -315,7 +325,7 @@ async function listFiles(source) {
315
325
  withFileTypes: true
316
326
  })).filter((entry) => entry.isFile() && entry.name.endsWith(source.ext)).map((entry) => join(entry.parentPath, entry.name));
317
327
  }
318
- var INSERT = "insert into events (id, tool, model, session, project, ts, day, dow, hour, input, output, cache_read, cache_write, reasoning, subagent) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) on conflict(id) do update set input = max(input, excluded.input), output = max(output, excluded.output), cache_read = max(cache_read, excluded.cache_read), cache_write = max(cache_write, excluded.cache_write), reasoning = max(reasoning, excluded.reasoning), subagent = coalesce(excluded.subagent, subagent)";
328
+ var INSERT = "insert into events (id, tool, model, session, project, ts, day, dow, hour, input, output, cache_read, cache_write, cache_write_long, reasoning, subagent) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) on conflict(id) do update set input = max(input, excluded.input), output = max(output, excluded.output), cache_read = max(cache_read, excluded.cache_read), cache_write = max(cache_write, excluded.cache_write), cache_write_long = max(cache_write_long, excluded.cache_write_long), reasoning = max(reasoning, excluded.reasoning), subagent = coalesce(excluded.subagent, subagent)";
319
329
  var INSERT_NAME = "insert into names (tool, session, name) values (?, ?, ?) on conflict(tool, session) do update set name = excluded.name";
320
330
  var INSERT_WINDOW = "insert into windows (id, tool, label, used_percent, window_minutes, resets_at, detail, seen_at) values (?, ?, ?, ?, ?, ?, ?, ?) on conflict(id) do update set used_percent = excluded.used_percent, resets_at = excluded.resets_at, detail = excluded.detail, seen_at = excluded.seen_at where excluded.seen_at >= windows.seen_at";
321
331
  async function scanSource(source) {
@@ -363,7 +373,7 @@ async function scanSource(source) {
363
373
  handle.exec("begin");
364
374
  for (const event of parsed.events) {
365
375
  const at = new Date(event.ts);
366
- insert.run(event.id, source.id, event.model, event.session, event.project, event.ts, localDay(at), at.getDay(), at.getHours(), event.input, event.output, event.cache_read, event.cache_write, event.reasoning, event.subagent === void 0 ? null : Number(event.subagent));
376
+ insert.run(event.id, source.id, event.model, event.session, event.project, event.ts, localDay(at), at.getDay(), at.getHours(), event.input, event.output, event.cache_read, event.cache_write, event.cache_write_long ?? 0, event.reasoning, event.subagent === void 0 ? null : Number(event.subagent));
367
377
  }
368
378
  for (const [session, name] of Object.entries(parsed.names ?? {})) insertName.run(source.id, session, name);
369
379
  for (const window of parsed.windows ?? []) insertWindow.run(window.id, source.id, window.label, window.used_percent, window.window_minutes, window.resets_at, window.detail, window.seen_at);
@@ -471,8 +481,18 @@ var empty = () => ({
471
481
  input: 0,
472
482
  output: 0,
473
483
  cache_read: 0,
474
- cache_write: 0
484
+ cache_write: 0,
485
+ cache_write_long: 0
486
+ });
487
+ var tokensOf = (row) => ({
488
+ input: Number(row.input) || 0,
489
+ output: Number(row.output) || 0,
490
+ cache_read: Number(row.cache_read) || 0,
491
+ cache_write: Number(row.cache_write) || 0,
492
+ cache_write_long: Number(row.cache_write_long) || 0
475
493
  });
494
+ /** Adds what can be priced, so one unpriced model doesn't blank out the whole total */
495
+ var plus = (sum, cost) => cost === null ? sum : (sum ?? 0) + cost;
476
496
  function where(filters, dated = true) {
477
497
  const clauses = [];
478
498
  const params = [];
@@ -494,7 +514,7 @@ function where(filters, dated = true) {
494
514
  params
495
515
  };
496
516
  }
497
- var SUMS = "sum(input) input, sum(output) output, sum(cache_read) cache_read, sum(cache_write) cache_write, sum(reasoning) reasoning, count(*) events, count(distinct tool || ':' || session) sessions";
517
+ var SUMS = "sum(input) input, sum(output) output, sum(cache_read) cache_read, sum(cache_write) cache_write, sum(cache_write_long) cache_write_long, sum(reasoning) reasoning, count(*) events, count(distinct tool || ':' || session) sessions";
498
518
  /** Rows arrive split by model so each slice can be priced at its own rate. */
499
519
  function fold(rows, overrides) {
500
520
  const slices = /* @__PURE__ */ new Map();
@@ -508,27 +528,20 @@ function fold(rows, overrides) {
508
528
  tokens: empty(),
509
529
  total: 0,
510
530
  reasoning: 0,
511
- cost: 0,
531
+ cost: null,
512
532
  events: 0,
513
533
  sessions: 0
514
534
  };
515
535
  slices.set(key, slice);
516
536
  sessions.set(key, /* @__PURE__ */ new Set());
517
537
  }
518
- const tokens = {
519
- input: Number(row.input) || 0,
520
- output: Number(row.output) || 0,
521
- cache_read: Number(row.cache_read) || 0,
522
- cache_write: Number(row.cache_write) || 0
523
- };
538
+ const tokens = tokensOf(row);
524
539
  for (const field of Object.keys(tokens)) slice.tokens[field] += tokens[field];
525
540
  slice.total += totalOf(tokens);
526
541
  slice.reasoning += Number(row.reasoning) || 0;
527
542
  slice.events += Number(row.events) || 0;
528
543
  slice.sessions += Number(row.sessions) || 0;
529
- const cost = costOf(String(row.model ?? ""), tokens, overrides);
530
- if (cost === null) slice.cost = null;
531
- else if (slice.cost !== null) slice.cost += cost;
544
+ slice.cost = plus(slice.cost, costOf(String(row.model ?? ""), tokens, overrides));
532
545
  }
533
546
  return slices;
534
547
  }
@@ -562,18 +575,11 @@ function series(filters, column, overrides) {
562
575
  day: String(row.day),
563
576
  key: String(row.key ?? ""),
564
577
  total: 0,
565
- cost: 0
566
- };
567
- const tokens = {
568
- input: Number(row.input) || 0,
569
- output: Number(row.output) || 0,
570
- cache_read: Number(row.cache_read) || 0,
571
- cache_write: Number(row.cache_write) || 0
578
+ cost: null
572
579
  };
580
+ const tokens = tokensOf(row);
573
581
  point.total += totalOf(tokens);
574
- const cost = costOf(String(row.model ?? ""), tokens, overrides);
575
- if (cost === null) point.cost = null;
576
- else if (point.cost !== null) point.cost += cost;
582
+ point.cost = plus(point.cost, costOf(String(row.model ?? ""), tokens, overrides));
577
583
  points.set(id, point);
578
584
  }
579
585
  return [...points.values()];
@@ -588,20 +594,13 @@ function calendar(filters, overrides) {
588
594
  const entry = days.get(day) ?? {
589
595
  day,
590
596
  total: 0,
591
- cost: 0,
597
+ cost: null,
592
598
  events: 0
593
599
  };
594
- const tokens = {
595
- input: Number(row.input) || 0,
596
- output: Number(row.output) || 0,
597
- cache_read: Number(row.cache_read) || 0,
598
- cache_write: Number(row.cache_write) || 0
599
- };
600
+ const tokens = tokensOf(row);
600
601
  entry.total += totalOf(tokens);
601
602
  entry.events += Number(row.events) || 0;
602
- const cost = costOf(String(row.model ?? ""), tokens, overrides);
603
- if (cost === null) entry.cost = null;
604
- else if (entry.cost !== null) entry.cost += cost;
603
+ entry.cost = plus(entry.cost, costOf(String(row.model ?? ""), tokens, overrides));
605
604
  days.set(day, entry);
606
605
  }
607
606
  return [...days.values()];
@@ -630,19 +629,14 @@ function sessions(filters, overrides, limit = 60) {
630
629
  started: Number(row.started),
631
630
  ended: Number(row.ended),
632
631
  total: 0,
633
- cost: 0,
632
+ cost: null,
634
633
  peak: 0,
635
634
  turns: 0,
636
635
  read: 0,
637
636
  fed: 0,
638
637
  side: null
639
638
  };
640
- const tokens = {
641
- input: Number(row.input) || 0,
642
- output: Number(row.output) || 0,
643
- cache_read: Number(row.cache_read) || 0,
644
- cache_write: Number(row.cache_write) || 0
645
- };
639
+ const tokens = tokensOf(row);
646
640
  entry.models.add(String(row.model));
647
641
  entry.started = Math.min(entry.started, Number(row.started));
648
642
  entry.ended = Math.max(entry.ended, Number(row.ended));
@@ -652,9 +646,7 @@ function sessions(filters, overrides, limit = 60) {
652
646
  entry.read += tokens.cache_read;
653
647
  entry.fed += tokens.input + tokens.cache_read + tokens.cache_write;
654
648
  if (Number(row.flagged)) entry.side = (entry.side ?? 0) + (Number(row.side) || 0);
655
- const cost = costOf(String(row.model), tokens, overrides);
656
- if (cost === null) entry.cost = null;
657
- else if (entry.cost !== null) entry.cost += cost;
649
+ entry.cost = plus(entry.cost, costOf(String(row.model), tokens, overrides));
658
650
  merged.set(at, entry);
659
651
  }
660
652
  const name = db().prepare("select name from names where tool = ? and session = ?");
@@ -40,12 +40,14 @@ var THEMES = [
40
40
  //#endregion
41
41
  //#region src/lib/pricing.ts
42
42
  /** Dollars per million. Anthropic bills cache reads at a tenth and 5m writes at 1.25x. */
43
- var anthropic = (input, output) => ({
43
+ var anthropic = (input, output, read = .1) => ({
44
44
  input,
45
45
  output,
46
- cacheRead: input * .1,
46
+ cacheRead: input * read,
47
47
  cacheWrite: input * 1.25
48
48
  });
49
+ /** An hour in the cache costs 2x input, where five minutes is 1.25x */
50
+ var LONG_WRITE = 2 / 1.25;
49
51
  /** OpenAI discounts cached input and charges nothing to put it there. */
50
52
  var openai = (input, output) => ({
51
53
  input,
@@ -54,17 +56,20 @@ var openai = (input, output) => ({
54
56
  cacheWrite: 0
55
57
  });
56
58
  var RATES = {
59
+ "claude-fable-5-1": anthropic(10, 50, .025),
57
60
  "claude-fable-5": anthropic(10, 50),
61
+ "claude-opus-5-5": anthropic(4, 20, .05),
58
62
  "claude-opus-5": anthropic(5, 25),
59
63
  "claude-opus-4-8": anthropic(5, 25),
60
64
  "claude-opus-4-7": anthropic(5, 25),
61
65
  "claude-opus-4-6": anthropic(5, 25),
62
66
  "claude-opus-4-5": anthropic(5, 25),
63
67
  "claude-opus-4-1": anthropic(15, 75),
64
- "claude-sonnet-5": anthropic(3, 15),
68
+ "claude-sonnet-5": anthropic(2, 10),
65
69
  "claude-sonnet-4-6": anthropic(3, 15),
66
70
  "claude-sonnet-4-5": anthropic(3, 15),
67
71
  "claude-sonnet-4": anthropic(3, 15),
72
+ "claude-haiku-5-5": anthropic(.1, .5),
68
73
  "claude-haiku-4-5": anthropic(1, 5),
69
74
  "claude-3-5-haiku": anthropic(.8, 4),
70
75
  "gpt-5.6-sol-pro": openai(2.5, 15),
@@ -96,7 +101,8 @@ function rateFor(model, overrides = {}) {
96
101
  function costOf(model, tokens, overrides = {}) {
97
102
  const rate = rateFor(model, overrides);
98
103
  if (!rate) return null;
99
- return (tokens.input * rate.input + tokens.output * rate.output + tokens.cache_read * rate.cacheRead + tokens.cache_write * rate.cacheWrite) / 1e6;
104
+ const short = tokens.cache_write - tokens.cache_write_long;
105
+ return (tokens.input * rate.input + tokens.output * rate.output + tokens.cache_read * rate.cacheRead + short * rate.cacheWrite + tokens.cache_write_long * rate.cacheWrite * LONG_WRITE) / 1e6;
100
106
  }
101
107
  var totalOf = (tokens) => tokens.input + tokens.output + tokens.cache_read + tokens.cache_write;
102
108
  //#endregion
@@ -139,9 +139,9 @@ function delta(now, before) {
139
139
  //#region src/lib/components/Figures.svelte
140
140
  function Figures($$renderer, $$props) {
141
141
  $$renderer.component(($$renderer) => {
142
- let { totals, previous, activeDays, rangeLabel } = $$props;
142
+ let { totals, previous, activeDays, rangeLabel, unpriced } = $$props;
143
143
  const change = derived(() => delta(totals.total, previous.total));
144
- const costChange = derived(() => delta(totals.cost ?? 0, previous.cost ?? 0));
144
+ const costChange = derived(() => unpriced.length ? null : delta(totals.cost ?? 0, previous.cost ?? 0));
145
145
  const perDay = derived(() => activeDays ? totals.total / activeDays : 0);
146
146
  $$renderer.push(`<div class="figures svelte-l3stpt"><div class="lead svelte-l3stpt"><span class="cap svelte-l3stpt">Tokens, ${escape_html(rangeLabel.toLowerCase())}</span> <strong class="num svelte-l3stpt">${escape_html(compact(totals.total))}</strong> `);
147
147
  if (change()) $$renderer.push(`<!--[0--><span class="delta svelte-l3stpt">${escape_html(change().text)}</span>`);
@@ -149,6 +149,9 @@ function Figures($$renderer, $$props) {
149
149
  $$renderer.push(`<!--]--></div> <dl class="svelte-l3stpt"><div class="svelte-l3stpt"><dt class="svelte-l3stpt">Est. cost</dt> <dd class="num svelte-l3stpt">${escape_html(money(totals.cost))} `);
150
150
  if (costChange()) $$renderer.push(`<!--[0--><i${attr_class(`delta cost ${stringify(costChange().tone)}`, "svelte-l3stpt")}>${escape_html(costChange().text)}</i>`);
151
151
  else $$renderer.push("<!--[-1-->");
152
+ $$renderer.push(`<!--]--> `);
153
+ if (unpriced.length) $$renderer.push(`<!--[0--><i class="delta svelte-l3stpt">${escape_html(unpriced.length)} unpriced<span class="visually-hidden">: ${escape_html(unpriced.join(", "))}</span></i>`);
154
+ else $$renderer.push("<!--[-1-->");
152
155
  $$renderer.push(`<!--]--></dd></div> <div class="svelte-l3stpt"><dt class="svelte-l3stpt">Sessions</dt> <dd class="num svelte-l3stpt">${escape_html(full(totals.sessions))}</dd></div> <div class="svelte-l3stpt"><dt class="svelte-l3stpt">Active days</dt> <dd class="num svelte-l3stpt">${escape_html(full(activeDays))}</dd></div> <div class="svelte-l3stpt"><dt class="svelte-l3stpt">Daily pace</dt> <dd class="num svelte-l3stpt">${escape_html(compact(perDay()))}</dd></div></dl></div>`);
153
156
  });
154
157
  }
@@ -588,6 +591,20 @@ function providerFor(model) {
588
591
  return MATCHES.find(([pattern]) => pattern.test(name.toLowerCase()))?.[1] ?? "unknown";
589
592
  }
590
593
  var providerMeta = (id) => PROVIDERS.find((provider) => provider.id === id) ?? PROVIDERS[PROVIDERS.length - 1];
594
+ var shade = (colour, index) => {
595
+ if (!index) return colour;
596
+ return `color-mix(in oklch, ${colour}, ${index % 2 ? "black" : "white"} ${Math.min(Math.ceil(index / 2) * 18, 72)}%)`;
597
+ };
598
+ /** Each model after a provider's first goes alternately darker and lighter, so siblings differ */
599
+ function modelColours(models) {
600
+ const seen = /* @__PURE__ */ new Map();
601
+ return Object.fromEntries(models.map((model) => {
602
+ const provider = providerFor(model);
603
+ const index = seen.get(provider) ?? 0;
604
+ seen.set(provider, index + 1);
605
+ return [model, shade(providerMeta(provider).colour, index)];
606
+ }));
607
+ }
591
608
  var TOOLS = [
592
609
  {
593
610
  id: "claude-code",
@@ -970,17 +987,18 @@ function _page($$renderer, $$props) {
970
987
  }
971
988
  const toggle = (list, value) => list.includes(value) ? list.filter((item) => item !== value) : [...list, value];
972
989
  const measure = (slice) => metric === "cost" ? slice.cost ?? 0 : slice.total;
973
- const show = (value) => metric === "cost" ? money(value) : compact(value);
990
+ const show = (slice) => metric === "cost" ? money(slice.cost) : compact(slice.total);
974
991
  const activeDays = derived(() => new Set(usage.series.filter((point) => point.total > 0).map((point) => point.day)).size);
975
992
  const toolKeys = derived(() => usage.byTool.map((slice) => ({
976
993
  id: slice.key,
977
994
  label: toolMeta(slice.key).label,
978
995
  colour: toolMeta(slice.key).colour
979
996
  })));
997
+ const colours = derived(() => modelColours(usage.byModel.map((slice) => slice.key)));
980
998
  const modelKeys = derived(() => usage.byModel.map((slice) => ({
981
999
  id: slice.key,
982
1000
  label: modelName(slice.key),
983
- colour: providerMeta(providerFor(slice.key)).colour
1001
+ colour: colours()[slice.key]
984
1002
  })));
985
1003
  const trendKeys = derived(() => trendBy === "tool" ? toolKeys() : modelKeys());
986
1004
  const modelRows = derived(() => usage.byModel.map((slice) => {
@@ -990,8 +1008,8 @@ function _page($$renderer, $$props) {
990
1008
  label: modelName(slice.key),
991
1009
  detail: provider.label,
992
1010
  value: measure(slice),
993
- display: show(measure(slice)),
994
- colour: provider.colour,
1011
+ display: show(slice),
1012
+ colour: colours()[slice.key],
995
1013
  mark: provider.id,
996
1014
  hint: `${slice.key} - ${full(slice.total)} tokens over ${full(slice.events)} requests, ${money(slice.cost)} estimated`
997
1015
  };
@@ -1001,7 +1019,7 @@ function _page($$renderer, $$props) {
1001
1019
  label: projectName(slice.key),
1002
1020
  detail: "",
1003
1021
  value: projectBy === "sessions" ? slice.sessions : measure(slice),
1004
- display: projectBy === "sessions" ? full(slice.sessions) : show(measure(slice)),
1022
+ display: projectBy === "sessions" ? full(slice.sessions) : show(slice),
1005
1023
  colour: "var(--accent)",
1006
1024
  hint: `${slice.key || "unknown"} - ${full(slice.total)} tokens, ${full(slice.sessions)} sessions`
1007
1025
  })));
@@ -1014,7 +1032,7 @@ function _page($$renderer, $$props) {
1014
1032
  label: tool.label,
1015
1033
  detail: slice ? `${full(slice.sessions)} sessions` : "not found",
1016
1034
  value: slice ? measure(slice) : 0,
1017
- display: slice ? show(measure(slice)) : "--",
1035
+ display: slice ? show(slice) : "--",
1018
1036
  colour: tool.colour,
1019
1037
  mark: source.id,
1020
1038
  hint: source.present ? `${full(source.files)} files under ${source.root}` : `Nothing at ${source.root}`
@@ -1148,7 +1166,8 @@ function _page($$renderer, $$props) {
1148
1166
  totals: usage.totals,
1149
1167
  previous: usage.previous,
1150
1168
  activeDays: activeDays(),
1151
- rangeLabel: rangeLabel(usage.filters.range)
1169
+ rangeLabel: rangeLabel(usage.filters.range),
1170
+ unpriced: usage.unpriced
1152
1171
  });
1153
1172
  $$renderer.push(`<!----> <div class="grid svelte-1uha8ag">`);
1154
1173
  Panel($$renderer, {
@@ -1261,7 +1280,7 @@ function _page($$renderer, $$props) {
1261
1280
  colour: row.colour,
1262
1281
  display: row.display
1263
1282
  })),
1264
- centre: show(measure(usage.totals)),
1283
+ centre: show(usage.totals),
1265
1284
  caption: metric === "cost" ? "estimated" : "tokens"
1266
1285
  });
1267
1286
  $$renderer.push(`<!----> <ul class="key svelte-1uha8ag"><!--[-->`);
@@ -1,2 +1 @@
1
- import { a as variables, i as set_env, n as explicit_public_env, r as rendered_env, t as dynamic_private_env } from "./chunks/config.js";
2
- export { dynamic_private_env, explicit_public_env, rendered_env, set_env, variables };
1
+ export { t as dynamic_private_env, n as explicit_public_env, r as rendered_env, i as set_env, a as variables } from "./chunks/config.js";
@@ -1,2 +1 @@
1
- import { t as handler } from "./adapter-node-handler.js";
2
- export { handler };
1
+ export { t as handler } from "./adapter-node-handler.js";
@@ -9,7 +9,7 @@ return {
9
9
  app_path: "_app",
10
10
  assets: new Set(["favicon.svg","robots.txt"]),
11
11
  mime_types: {".svg":"image/svg+xml",".txt":"text/plain"},
12
- client: {start:"_app/immutable/entry/start.CzGx2BYz.js",app:"_app/immutable/entry/app.ByhTKJxk.js",imports:["_app/immutable/entry/start.CzGx2BYz.js","_app/immutable/entry/payload.DSmR2FwN.js","_app/immutable/chunks/BaNbYf_w.js","_app/immutable/chunks/CbiRHTcG.js","_app/immutable/chunks/ssd4Rw-g.js","_app/immutable/chunks/DTingiCe.js","_app/immutable/chunks/B0VWrXPj.js","_app/immutable/entry/app.ByhTKJxk.js"],stylesheets:[],fonts:[],uses_env_dynamic_public:false},
12
+ client: {start:"_app/immutable/entry/start.CBYpir1g.js",app:"_app/immutable/entry/app.QnEDURra.js",imports:["_app/immutable/entry/start.CBYpir1g.js","_app/immutable/entry/payload.DSmR2FwN.js","_app/immutable/chunks/CRzLMJPS.js","_app/immutable/chunks/D-Hu4b5U.js","_app/immutable/chunks/zGlnsnwf.js","_app/immutable/chunks/BLLqPIda.js","_app/immutable/chunks/C2_oK6Yg.js","_app/immutable/entry/app.QnEDURra.js"],stylesheets:[],fonts:[],uses_env_dynamic_public:false},
13
13
 
14
14
  nodes: [
15
15
  __memo(() => import('./nodes/0.js')),
@@ -9,7 +9,7 @@ return {
9
9
  app_path: "_app",
10
10
  assets: new Set(["favicon.svg","robots.txt"]),
11
11
  mime_types: {".svg":"image/svg+xml",".txt":"text/plain"},
12
- client: {start:"_app/immutable/entry/start.CzGx2BYz.js",app:"_app/immutable/entry/app.ByhTKJxk.js",imports:["_app/immutable/entry/start.CzGx2BYz.js","_app/immutable/entry/payload.DSmR2FwN.js","_app/immutable/chunks/BaNbYf_w.js","_app/immutable/chunks/CbiRHTcG.js","_app/immutable/chunks/ssd4Rw-g.js","_app/immutable/chunks/DTingiCe.js","_app/immutable/chunks/B0VWrXPj.js","_app/immutable/entry/app.ByhTKJxk.js"],stylesheets:[],fonts:[],uses_env_dynamic_public:false},
12
+ client: {start:"_app/immutable/entry/start.CBYpir1g.js",app:"_app/immutable/entry/app.QnEDURra.js",imports:["_app/immutable/entry/start.CBYpir1g.js","_app/immutable/entry/payload.DSmR2FwN.js","_app/immutable/chunks/CRzLMJPS.js","_app/immutable/chunks/D-Hu4b5U.js","_app/immutable/chunks/zGlnsnwf.js","_app/immutable/chunks/BLLqPIda.js","_app/immutable/chunks/C2_oK6Yg.js","_app/immutable/entry/app.QnEDURra.js"],stylesheets:[],fonts:[],uses_env_dynamic_public:false},
13
13
 
14
14
  nodes: [
15
15
  __memo(() => import('./nodes/0.js')),
@@ -3,6 +3,6 @@
3
3
  export const index = 0;
4
4
  let component_cache;
5
5
  export const component = async () => component_cache ??= (await import('../entries/pages/_layout.svelte.js')).default;
6
- export const imports = ["_app/immutable/nodes/0.BBGTwdwd.js","_app/immutable/chunks/DTingiCe.js"];
6
+ export const imports = ["_app/immutable/nodes/0.yxxqRuA2.js","_app/immutable/chunks/BLLqPIda.js"];
7
7
  export const stylesheets = ["_app/immutable/assets/0.CZ6VMqH1.css"];
8
8
  export const fonts = [];
@@ -3,6 +3,6 @@
3
3
  export const index = 1;
4
4
  let component_cache;
5
5
  export const component = async () => component_cache ??= (await import('../entries/fallbacks/error.svelte.js')).default;
6
- export const imports = ["_app/immutable/nodes/1.Cy2JV0fN.js","_app/immutable/chunks/DTingiCe.js","_app/immutable/chunks/B0VWrXPj.js","_app/immutable/entry/payload.DSmR2FwN.js"];
6
+ export const imports = ["_app/immutable/nodes/1.CArPcl3H.js","_app/immutable/chunks/BLLqPIda.js","_app/immutable/chunks/C2_oK6Yg.js","_app/immutable/entry/payload.DSmR2FwN.js"];
7
7
  export const stylesheets = [];
8
8
  export const fonts = [];
@@ -5,6 +5,6 @@ let component_cache;
5
5
  export const component = async () => component_cache ??= (await import('../entries/pages/_page.svelte.js')).default;
6
6
  export { server };
7
7
  export const server_id = "src/routes/+page.server.ts";
8
- export const imports = ["_app/immutable/nodes/2.DVE735SW.js","_app/immutable/chunks/DTingiCe.js","_app/immutable/chunks/ssd4Rw-g.js","_app/immutable/entry/payload.DSmR2FwN.js","_app/immutable/chunks/B0VWrXPj.js"];
8
+ export const imports = ["_app/immutable/nodes/2.BXzrhQ0D.js","_app/immutable/chunks/BLLqPIda.js","_app/immutable/chunks/zGlnsnwf.js","_app/immutable/entry/payload.DSmR2FwN.js","_app/immutable/chunks/C2_oK6Yg.js"];
9
9
  export const stylesheets = ["_app/immutable/assets/2.CZocdpCk.css"];
10
10
  export const fonts = [];
@@ -10,7 +10,7 @@ return {
10
10
  app_path: "_app",
11
11
  assets: new Set(["favicon.svg","robots.txt"]),
12
12
  mime_types: {".svg":"image/svg+xml",".txt":"text/plain"},
13
- client: {start:"_app/immutable/entry/start.CzGx2BYz.js",app:"_app/immutable/entry/app.ByhTKJxk.js",imports:["_app/immutable/entry/start.CzGx2BYz.js","_app/immutable/entry/payload.DSmR2FwN.js","_app/immutable/chunks/BaNbYf_w.js","_app/immutable/chunks/CbiRHTcG.js","_app/immutable/chunks/ssd4Rw-g.js","_app/immutable/chunks/DTingiCe.js","_app/immutable/chunks/B0VWrXPj.js","_app/immutable/entry/app.ByhTKJxk.js"],stylesheets:[],fonts:[],uses_env_dynamic_public:false},
13
+ client: {start:"_app/immutable/entry/start.CBYpir1g.js",app:"_app/immutable/entry/app.QnEDURra.js",imports:["_app/immutable/entry/start.CBYpir1g.js","_app/immutable/entry/payload.DSmR2FwN.js","_app/immutable/chunks/CRzLMJPS.js","_app/immutable/chunks/D-Hu4b5U.js","_app/immutable/chunks/zGlnsnwf.js","_app/immutable/chunks/BLLqPIda.js","_app/immutable/chunks/C2_oK6Yg.js","_app/immutable/entry/app.QnEDURra.js"],stylesheets:[],fonts:[],uses_env_dynamic_public:false},
14
14
 
15
15
  nodes: [
16
16
  __memo(() => import('./nodes/0.js')),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "token-usage-dashboard",
3
- "version": "1.0.16",
3
+ "version": "1.0.18",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "dev": "vite dev",
@@ -1 +0,0 @@
1
- var e=function(e,t){return new URL(e,t).href},t={},n=function(e){return e.pathname.endsWith(`.css`)},r=function(r,i,a){let o=Promise.resolve();if(i&&i.length>0){let r,s=document.querySelector(`meta[property=csp-nonce]`),c=s?.nonce||s?.getAttribute(`nonce`);function l(e){return Promise.all(e.map(e=>Promise.resolve(e).then(e=>({status:`fulfilled`,value:e}),e=>({status:`rejected`,reason:e}))))}function u(e){return import.meta.resolve?new URL(import.meta.resolve(e)):new URL(e,import.meta.url)}o=l(i.map(i=>{i=e(i,a);let o=u(i);if(o.href in t)return;t[o.href]=!0;let s=n(o);if(r===void 0){r={all:new Set,styles:new Set};let e=document.getElementsByTagName(`link`);for(let t=e.length-1;t>=0;t--){let n=e[t];r.all.add(n.href),n.rel===`stylesheet`&&r.styles.add(n.href)}}if((s?r.styles:r.all).has(o.href))return;let l=document.createElement(`link`);if(l.rel=s?`stylesheet`:`modulepreload`,s||(l.as=`script`),l.crossOrigin=``,l.href=o.href,c&&l.setAttribute(`nonce`,c),document.head.appendChild(l),s)return new Promise((e,t)=>{l.addEventListener(`load`,e),l.addEventListener(`error`,()=>t(Error(`Unable to preload CSS for ${o}`)))})}).filter(e=>e!==void 0))}function s(e){let t=new Event(`vite:preloadError`,{cancelable:!0});if(t.payload=e,window.dispatchEvent(t),!t.defaultPrevented)throw e}return o.then(e=>{for(let t of e||[])t.status===`rejected`&&s(t.reason);return r().catch(s)})};export{r as t};
@@ -1 +0,0 @@
1
- import{n as e,r as t}from"./ssd4Rw-g.js";export{t as load_css,e as start};