llm-usage-metrics 0.10.1 → 0.11.0

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 (3) hide show
  1. package/README.md +11 -4
  2. package/dist/index.js +1643 -471
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -48,12 +48,16 @@ function normalizeSkippedRowReasons(value) {
48
48
  }
49
49
 
50
50
  // src/domain/normalization.ts
51
+ import { stripVTControlCharacters } from "util";
51
52
  var CONTROL_CHARACTER_CLASS = String.raw`[\u0000-\u001F\u007F-\u009F\u061C\u200E\u200F\u2028-\u202E\u2066-\u2069]`;
52
53
  var CONTROL_CHARACTERS_PATTERN = new RegExp(CONTROL_CHARACTER_CLASS, "gu");
53
54
  var CONTROL_CHARACTER_TEST_PATTERN = new RegExp(CONTROL_CHARACTER_CLASS, "u");
54
55
  function stripControlCharacters(value) {
55
56
  return value.replace(CONTROL_CHARACTERS_PATTERN, "");
56
57
  }
58
+ function toTerminalLine(value) {
59
+ return stripControlCharacters(stripVTControlCharacters(value).replaceAll(/\s+/gu, " ")).trim();
60
+ }
57
61
  function hasControlCharacters(value) {
58
62
  return CONTROL_CHARACTER_TEST_PATTERN.test(value);
59
63
  }
@@ -287,6 +291,10 @@ function createUsageEvent(input) {
287
291
  const reasoningTokens = normalizeNonNegativeInteger(input.reasoningTokens);
288
292
  const cacheReadTokens = normalizeNonNegativeInteger(input.cacheReadTokens);
289
293
  const cacheWriteTokens = normalizeNonNegativeInteger(input.cacheWriteTokens);
294
+ const cacheWrite1hTokens = Math.min(
295
+ cacheWriteTokens,
296
+ normalizeNonNegativeInteger(input.cacheWrite1hTokens)
297
+ );
290
298
  const declaredTotalTokens = normalizeNonNegativeInteger(input.totalTokens);
291
299
  const componentTotalTokens = inputTokens + outputTokens + reasoningTokens + cacheReadTokens + cacheWriteTokens;
292
300
  const totalTokens = input.totalTokens === void 0 ? componentTotalTokens : declaredTotalTokens;
@@ -304,6 +312,7 @@ function createUsageEvent(input) {
304
312
  reasoningTokens,
305
313
  cacheReadTokens,
306
314
  cacheWriteTokens,
315
+ cacheWrite1hTokens,
307
316
  totalTokens,
308
317
  costUsd,
309
318
  costMode
@@ -555,6 +564,7 @@ function slowNormalizeStoredEvent(row) {
555
564
  reasoningTokens: toNonNegativeInteger(row.reasoning_tokens),
556
565
  cacheReadTokens: toNonNegativeInteger(row.cache_read_tokens),
557
566
  cacheWriteTokens: toNonNegativeInteger(row.cache_write_tokens),
567
+ cacheWrite1hTokens: toNonNegativeInteger(row.cache_write_1h_tokens),
558
568
  totalTokens: toNonNegativeInteger(row.total_tokens),
559
569
  costUsd: toNonNegativeNumber(row.cost_usd),
560
570
  costMode
@@ -578,6 +588,7 @@ function fastMaterializeStoredEvent(row) {
578
588
  row.reasoning_tokens,
579
589
  row.cache_read_tokens,
580
590
  row.cache_write_tokens,
591
+ row.cache_write_1h_tokens,
581
592
  row.total_tokens,
582
593
  row.cost_usd,
583
594
  row.cost_mode
@@ -600,12 +611,13 @@ function normalizeStoredEventTuple(row) {
600
611
  reasoning_tokens: row[8],
601
612
  cache_read_tokens: row[9],
602
613
  cache_write_tokens: row[10],
603
- total_tokens: row[11],
604
- cost_usd: row[12],
605
- cost_mode: row[13]
614
+ cache_write_1h_tokens: row[11],
615
+ total_tokens: row[12],
616
+ cost_usd: row[13],
617
+ cost_mode: row[14]
606
618
  });
607
619
  }
608
- function materializeStoredEvent(sourceValue, sessionIdValue, timestampValue, modelValue, providerValue, repoRootValue, inputTokensValue, outputTokensValue, reasoningTokensValue, cacheReadTokensValue, cacheWriteTokensValue, totalTokensValue, costUsdValue, costModeValue) {
620
+ function materializeStoredEvent(sourceValue, sessionIdValue, timestampValue, modelValue, providerValue, repoRootValue, inputTokensValue, outputTokensValue, reasoningTokensValue, cacheReadTokensValue, cacheWriteTokensValue, cacheWrite1hTokensValue, totalTokensValue, costUsdValue, costModeValue) {
609
621
  const costMode = costModeValue === "explicit" || costModeValue === "estimated" ? costModeValue : void 0;
610
622
  if (!costMode) {
611
623
  return void 0;
@@ -621,9 +633,10 @@ function materializeStoredEvent(sourceValue, sessionIdValue, timestampValue, mod
621
633
  const reasoningTokens = toStoredNonNegativeInteger(reasoningTokensValue);
622
634
  const cacheReadTokens = toStoredNonNegativeInteger(cacheReadTokensValue);
623
635
  const cacheWriteTokens = toStoredNonNegativeInteger(cacheWriteTokensValue);
636
+ const cacheWrite1hTokens = toStoredNonNegativeInteger(cacheWrite1hTokensValue);
624
637
  const totalTokens = toStoredNonNegativeInteger(totalTokensValue);
625
638
  const costUsd = toStoredCostUsd(costUsdValue, costMode);
626
- if (!source || !sessionId || !timestamp || repoRoot === FAST_PATH_REJECT || provider === FAST_PATH_REJECT || model === FAST_PATH_REJECT || inputTokens === void 0 || outputTokens === void 0 || reasoningTokens === void 0 || cacheReadTokens === void 0 || cacheWriteTokens === void 0 || totalTokens === void 0 || costUsd === FAST_PATH_REJECT) {
639
+ if (!source || !sessionId || !timestamp || repoRoot === FAST_PATH_REJECT || provider === FAST_PATH_REJECT || model === FAST_PATH_REJECT || inputTokens === void 0 || outputTokens === void 0 || reasoningTokens === void 0 || cacheReadTokens === void 0 || cacheWriteTokens === void 0 || cacheWrite1hTokens === void 0 || cacheWrite1hTokens > cacheWriteTokens || totalTokens === void 0 || costUsd === FAST_PATH_REJECT) {
627
640
  return void 0;
628
641
  }
629
642
  if (provider && normalizeProviderToBillingEntity(provider) !== provider) {
@@ -644,6 +657,7 @@ function materializeStoredEvent(sourceValue, sessionIdValue, timestampValue, mod
644
657
  reasoningTokens,
645
658
  cacheReadTokens,
646
659
  cacheWriteTokens,
660
+ cacheWrite1hTokens,
647
661
  totalTokens,
648
662
  costUsd,
649
663
  costMode
@@ -717,6 +731,8 @@ function computeEventContentHash(event) {
717
731
  event.reasoningTokens,
718
732
  event.cacheReadTokens,
719
733
  event.cacheWriteTokens,
734
+ // cacheWrite1hTokens is left out: it only splits cacheWriteTokens, and leaving it out
735
+ // keeps events stored before it existed matching their reparsed copies.
720
736
  event.totalTokens,
721
737
  event.costMode,
722
738
  event.costUsd ?? ""
@@ -752,6 +768,9 @@ CREATE TEMP TABLE IF NOT EXISTS history_departed_files (
752
768
  file_path TEXT NOT NULL,
753
769
  PRIMARY KEY (source, file_path)
754
770
  );
771
+ CREATE TEMP TABLE IF NOT EXISTS history_departed_hashes (
772
+ content_hash TEXT PRIMARY KEY
773
+ );
755
774
  CREATE TEMP TABLE IF NOT EXISTS history_served_files (
756
775
  source TEXT NOT NULL,
757
776
  file_path TEXT NOT NULL,
@@ -761,6 +780,7 @@ CREATE TEMP TABLE IF NOT EXISTS history_served_files (
761
780
  DELETE FROM history_selected_sources;
762
781
  DELETE FROM history_discovered_files;
763
782
  DELETE FROM history_departed_files;
783
+ DELETE FROM history_departed_hashes;
764
784
  DELETE FROM history_served_files;
765
785
  `);
766
786
  }
@@ -837,6 +857,36 @@ function addHashCount(target, hash, count) {
837
857
  target.set(hash, (target.get(hash) ?? 0) + count);
838
858
  }
839
859
  function readLiveHashCounts(store) {
860
+ store.database.prepare(
861
+ [
862
+ "INSERT OR IGNORE INTO history_departed_hashes (content_hash)",
863
+ "SELECT events.content_hash",
864
+ "FROM history_departed_files AS departed",
865
+ "CROSS JOIN events",
866
+ "WHERE events.source = departed.source",
867
+ " AND events.file_path = departed.file_path",
868
+ " AND events.content_hash IS NOT NULL"
869
+ ].join("\n")
870
+ ).run();
871
+ store.database.prepare(
872
+ [
873
+ "INSERT OR IGNORE INTO history_departed_hashes (content_hash)",
874
+ "SELECT events.content_hash",
875
+ "FROM history_discovered_files AS discovered",
876
+ "CROSS JOIN events",
877
+ "WHERE events.source = discovered.source",
878
+ " AND events.file_path = discovered.file_path",
879
+ " AND discovered.counted = 1",
880
+ " AND events.content_hash IS NOT NULL",
881
+ " AND EXISTS (",
882
+ " SELECT 1 FROM history_departed_files AS departed",
883
+ " CROSS JOIN events AS departed_events",
884
+ " WHERE departed_events.source = departed.source",
885
+ " AND departed_events.file_path = departed.file_path",
886
+ " AND departed_events.content_hash IS NULL",
887
+ " )"
888
+ ].join("\n")
889
+ ).run();
840
890
  const rows = store.database.prepare(
841
891
  [
842
892
  "SELECT content_hash,",
@@ -845,15 +895,16 @@ function readLiveHashCounts(store) {
845
895
  "FROM (",
846
896
  " SELECT events.content_hash AS content_hash,",
847
897
  " selected.repeats_events AS repeats_events, COUNT(*) AS file_count",
848
- " FROM history_discovered_files AS discovered",
849
- " JOIN history_selected_sources AS selected",
850
- " ON discovered.source = selected.source",
898
+ " FROM history_departed_hashes AS departed",
851
899
  " CROSS JOIN events",
852
- " WHERE discovered.counted = 1",
853
- " AND events.source = discovered.source",
854
- " AND events.file_path = discovered.file_path",
855
- " AND events.content_hash IS NOT NULL",
856
- " GROUP BY discovered.source, discovered.file_path, events.content_hash",
900
+ " JOIN history_discovered_files AS discovered",
901
+ " ON discovered.source = events.source",
902
+ " AND discovered.file_path = events.file_path",
903
+ " JOIN history_selected_sources AS selected",
904
+ " ON selected.source = events.source",
905
+ " WHERE events.content_hash = departed.content_hash",
906
+ " AND discovered.counted = 1",
907
+ " GROUP BY events.source, events.file_path, events.content_hash",
857
908
  ")",
858
909
  "GROUP BY content_hash"
859
910
  ].join("\n")
@@ -1014,7 +1065,8 @@ function loadServedEvents(store, servedFiles, liveHashCounts) {
1014
1065
  "SELECT events.source, events.session_id, events.timestamp, events.model,",
1015
1066
  " events.provider, events.repo_root, events.input_tokens, events.output_tokens,",
1016
1067
  " events.reasoning_tokens, events.cache_read_tokens, events.cache_write_tokens,",
1017
- " events.total_tokens, events.cost_usd, events.cost_mode, served.ordinal",
1068
+ " events.cache_write_1h_tokens, events.total_tokens, events.cost_usd, events.cost_mode,",
1069
+ " served.ordinal",
1018
1070
  "FROM history_served_files AS served",
1019
1071
  "CROSS JOIN events",
1020
1072
  "WHERE events.source = served.source",
@@ -1043,10 +1095,10 @@ function classifyAgainstLiveFiles(store, input) {
1043
1095
  if (selectedSources.size === 0) {
1044
1096
  return { classifiedFiles: [], liveHashCounts: /* @__PURE__ */ new Map() };
1045
1097
  }
1046
- const liveHashCounts = readLiveHashCounts(store);
1047
- const servedHashCounts = new Map(liveHashCounts);
1048
1098
  const departedFiles = readDepartedFiles(store);
1049
1099
  const departedHashMultisets = readDepartedHashMultisets(store);
1100
+ const liveHashCounts = readLiveHashCounts(store);
1101
+ const servedHashCounts = new Map(liveHashCounts);
1050
1102
  const classifiedFiles = [];
1051
1103
  for (const departedFile of departedFiles) {
1052
1104
  const fileHashCounts = departedHashMultisets.get(
@@ -1083,7 +1135,7 @@ function loadHistoryEvents(store, input) {
1083
1135
  }
1084
1136
 
1085
1137
  // src/persistence/event-store-schema.ts
1086
- var EVENT_STORE_SCHEMA_VERSION = "3";
1138
+ var EVENT_STORE_SCHEMA_VERSION = "4";
1087
1139
  var MIGRATION_BATCH_SIZE = 5e3;
1088
1140
  var EventStoreSchemaVersionError = class extends Error {
1089
1141
  schemaVersion;
@@ -1126,6 +1178,7 @@ CREATE TABLE IF NOT EXISTS events (
1126
1178
  reasoning_tokens INTEGER NOT NULL,
1127
1179
  cache_read_tokens INTEGER NOT NULL,
1128
1180
  cache_write_tokens INTEGER NOT NULL,
1181
+ cache_write_1h_tokens INTEGER NOT NULL DEFAULT 0,
1129
1182
  total_tokens INTEGER NOT NULL,
1130
1183
  content_hash TEXT,
1131
1184
  cost_usd REAL,
@@ -1133,8 +1186,22 @@ CREATE TABLE IF NOT EXISTS events (
1133
1186
  );
1134
1187
  CREATE INDEX IF NOT EXISTS events_file ON events(source, file_path, event_index);
1135
1188
  CREATE INDEX IF NOT EXISTS events_content_hash ON events(content_hash);
1189
+ ${createOverrideOnlyFilesSql()}
1136
1190
  `;
1137
1191
  }
1192
+ function createOverrideOnlyFilesSql() {
1193
+ return `
1194
+ CREATE TABLE IF NOT EXISTS override_only_files (
1195
+ source TEXT NOT NULL,
1196
+ file_path TEXT NOT NULL,
1197
+ PRIMARY KEY (source, file_path)
1198
+ );`;
1199
+ }
1200
+ function ensureOverrideOnlyFilesTable(database) {
1201
+ if (!listUserTableNames(database).includes("override_only_files")) {
1202
+ database.exec(createOverrideOnlyFilesSql());
1203
+ }
1204
+ }
1138
1205
  function listUserTableNames(database) {
1139
1206
  return database.prepare(
1140
1207
  [
@@ -1167,7 +1234,7 @@ function migrateSchemaV1ToV2(database) {
1167
1234
  [
1168
1235
  "SELECT id, source, session_id, timestamp, model, provider, repo_root,",
1169
1236
  " input_tokens, output_tokens, reasoning_tokens, cache_read_tokens,",
1170
- " cache_write_tokens, total_tokens, cost_usd, cost_mode",
1237
+ " cache_write_tokens, 0 AS cache_write_1h_tokens, total_tokens, cost_usd, cost_mode",
1171
1238
  "FROM events",
1172
1239
  "WHERE id > ?",
1173
1240
  "ORDER BY id ASC",
@@ -1207,7 +1274,7 @@ function migrateSchemaV2ToV3(database) {
1207
1274
  [
1208
1275
  "SELECT id, source, session_id, timestamp, model, provider, repo_root,",
1209
1276
  " input_tokens, output_tokens, reasoning_tokens, cache_read_tokens,",
1210
- " cache_write_tokens, total_tokens, cost_usd, cost_mode",
1277
+ " cache_write_tokens, 0 AS cache_write_1h_tokens, total_tokens, cost_usd, cost_mode",
1211
1278
  "FROM events",
1212
1279
  "WHERE id > ?",
1213
1280
  "ORDER BY id ASC",
@@ -1234,8 +1301,17 @@ function migrateSchemaV2ToV3(database) {
1234
1301
  database.prepare("UPDATE meta SET value = ? WHERE key = 'schemaVersion'").run("3");
1235
1302
  });
1236
1303
  }
1304
+ function migrateSchemaV3ToV4(database) {
1305
+ runTransaction(database, () => {
1306
+ if (readSchemaVersion(database) !== "3") {
1307
+ return;
1308
+ }
1309
+ database.exec("ALTER TABLE events ADD COLUMN cache_write_1h_tokens INTEGER NOT NULL DEFAULT 0");
1310
+ database.prepare("UPDATE meta SET value = ? WHERE key = 'schemaVersion'").run("4");
1311
+ });
1312
+ }
1237
1313
  function isSupportedSchemaVersion(schemaVersion) {
1238
- return schemaVersion === EVENT_STORE_SCHEMA_VERSION || schemaVersion === "1" || schemaVersion === "2";
1314
+ return schemaVersion === EVENT_STORE_SCHEMA_VERSION || schemaVersion === "1" || schemaVersion === "2" || schemaVersion === "3";
1239
1315
  }
1240
1316
  function assertSupportedSchemaVersion(database) {
1241
1317
  const schemaVersion = readSchemaVersion(database);
@@ -1244,6 +1320,10 @@ function assertSupportedSchemaVersion(database) {
1244
1320
  }
1245
1321
  }
1246
1322
  function initializeSchema(database) {
1323
+ createOrMigrateSchema(database);
1324
+ ensureOverrideOnlyFilesTable(database);
1325
+ }
1326
+ function createOrMigrateSchema(database) {
1247
1327
  if (listUserTableNames(database).length === 0) {
1248
1328
  const createdSchema = runTransaction(database, () => {
1249
1329
  if (listUserTableNames(database).length > 0) {
@@ -1263,10 +1343,16 @@ function initializeSchema(database) {
1263
1343
  if (schemaVersion === "1") {
1264
1344
  migrateSchemaV1ToV2(database);
1265
1345
  migrateSchemaV2ToV3(database);
1346
+ migrateSchemaV3ToV4(database);
1266
1347
  return;
1267
1348
  }
1268
1349
  if (schemaVersion === "2") {
1269
1350
  migrateSchemaV2ToV3(database);
1351
+ migrateSchemaV3ToV4(database);
1352
+ return;
1353
+ }
1354
+ if (schemaVersion === "3") {
1355
+ migrateSchemaV3ToV4(database);
1270
1356
  return;
1271
1357
  }
1272
1358
  throw new EventStoreSchemaVersionError(schemaVersion);
@@ -1573,6 +1659,21 @@ function readMetaValues(database) {
1573
1659
  }
1574
1660
  return meta;
1575
1661
  }
1662
+ var WIDE_WINDOW_ROW_SHARE = 0.15;
1663
+ function isWideWindow(database, fromTimestamp, toTimestamp) {
1664
+ const rowCount = toNonNegativeInteger(
1665
+ database.prepare("SELECT count(*) AS count FROM events").get()?.count
1666
+ );
1667
+ const threshold = Math.ceil((rowCount ?? 0) * WIDE_WINDOW_ROW_SHARE);
1668
+ const row = database.prepare(
1669
+ [
1670
+ "SELECT count(*) AS count FROM (",
1671
+ " SELECT 1 FROM events WHERE timestamp >= ? AND timestamp < ? LIMIT ?",
1672
+ ")"
1673
+ ].join("\n")
1674
+ ).get(fromTimestamp, toTimestamp, threshold);
1675
+ return (toNonNegativeInteger(row?.count) ?? 0) >= threshold;
1676
+ }
1576
1677
  async function readEventStoreEvents(filePath, window = {}, loadSqliteModule = loadEventStoreSqliteModule) {
1577
1678
  const sqliteModule = await loadSqliteModule();
1578
1679
  if (!isEventStoreSqliteModule(sqliteModule)) {
@@ -1584,21 +1685,22 @@ async function readEventStoreEvents(filePath, window = {}, loadSqliteModule = lo
1584
1685
  });
1585
1686
  try {
1586
1687
  assertSupportedSchemaVersion(database);
1688
+ const meta = readMetaValues(database);
1689
+ const cacheWrite1hColumn = meta.get("schemaVersion") === EVENT_STORE_SCHEMA_VERSION ? "cache_write_1h_tokens" : "0 AS cache_write_1h_tokens";
1690
+ const fromTimestamp = window.fromTimestamp ?? "";
1691
+ const toTimestamp = window.toTimestamp ?? "\uFFFF";
1587
1692
  const statement = database.prepare(
1588
1693
  [
1589
1694
  "SELECT source, session_id, timestamp, model, provider, repo_root,",
1590
1695
  " input_tokens, output_tokens, reasoning_tokens, cache_read_tokens,",
1591
- " cache_write_tokens, total_tokens, cost_usd, cost_mode",
1592
- "FROM events",
1696
+ ` cache_write_tokens, ${cacheWrite1hColumn}, total_tokens, cost_usd, cost_mode`,
1697
+ isWideWindow(database, fromTimestamp, toTimestamp) ? "FROM events INDEXED BY events_file" : "FROM events",
1593
1698
  "WHERE timestamp >= ? AND timestamp < ?",
1594
1699
  "ORDER BY source, file_path, event_index"
1595
1700
  ].join("\n")
1596
1701
  );
1597
1702
  statement.setReturnArrays(true);
1598
- const rows = statement.all(
1599
- window.fromTimestamp ?? "",
1600
- window.toTimestamp ?? "\uFFFF"
1601
- );
1703
+ const rows = statement.all(fromTimestamp, toTimestamp);
1602
1704
  const events = [];
1603
1705
  for (const row of rows) {
1604
1706
  const event = normalizeStoredEventTuple(row);
@@ -1606,7 +1708,7 @@ async function readEventStoreEvents(filePath, window = {}, loadSqliteModule = lo
1606
1708
  events.push(event);
1607
1709
  }
1608
1710
  }
1609
- return { meta: readMetaValues(database), events };
1711
+ return { meta, events };
1610
1712
  } finally {
1611
1713
  database.close();
1612
1714
  }
@@ -1647,7 +1749,7 @@ function selectFileEventRows(store, source, filePath) {
1647
1749
  [
1648
1750
  "SELECT source, session_id, timestamp, model, provider, repo_root,",
1649
1751
  " input_tokens, output_tokens, reasoning_tokens, cache_read_tokens,",
1650
- " cache_write_tokens, total_tokens, cost_usd, cost_mode",
1752
+ " cache_write_tokens, cache_write_1h_tokens, total_tokens, cost_usd, cost_mode",
1651
1753
  "FROM events",
1652
1754
  "WHERE source = ? AND file_path = ?",
1653
1755
  "ORDER BY event_index ASC"
@@ -1745,11 +1847,15 @@ function deleteStoredFiles(store, files) {
1745
1847
  const deleteFile = store.database.prepare(
1746
1848
  "DELETE FROM files WHERE source = ? AND file_path = ?"
1747
1849
  );
1850
+ const deleteOverrideOnlyFile = store.database.prepare(
1851
+ "DELETE FROM override_only_files WHERE source = ? AND file_path = ?"
1852
+ );
1748
1853
  for (const file of normalizedFiles) {
1749
1854
  result.deletedEventCount += countMatchingRows(store, "events", file.source, file.filePath);
1750
1855
  result.deletedFileCount += countMatchingRows(store, "files", file.source, file.filePath);
1751
1856
  deleteEvents.run(file.source, file.filePath);
1752
1857
  deleteFile.run(file.source, file.filePath);
1858
+ deleteOverrideOnlyFile.run(file.source, file.filePath);
1753
1859
  }
1754
1860
  });
1755
1861
  return result;
@@ -1768,7 +1874,8 @@ function replaceFilesEvents(store, inputs) {
1768
1874
  skippedRows: toNonNegativeInteger(input.skippedRows) ?? 0,
1769
1875
  skippedRowReasons: stringifySkippedRowReasons(input.skippedRowReasons),
1770
1876
  ingestedAt: Math.max(0, Math.trunc(input.now)),
1771
- events: input.events.map((event) => createUsageEvent(event))
1877
+ events: input.events.map((event) => createUsageEvent(event)),
1878
+ overrideOnly: input.overrideOnly === true
1772
1879
  }));
1773
1880
  const deleteFileEvents = store.statements.deleteFileEvents ??= store.database.prepare(
1774
1881
  "DELETE FROM events WHERE source = ? AND file_path = ?"
@@ -1778,8 +1885,9 @@ function replaceFilesEvents(store, inputs) {
1778
1885
  "INSERT INTO events (",
1779
1886
  " source, file_path, event_index, session_id, timestamp, model, provider, repo_root,",
1780
1887
  " input_tokens, output_tokens, reasoning_tokens, cache_read_tokens,",
1781
- " cache_write_tokens, total_tokens, content_hash, cost_usd, cost_mode",
1782
- ") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
1888
+ " cache_write_tokens, cache_write_1h_tokens, total_tokens, content_hash, cost_usd,",
1889
+ " cost_mode",
1890
+ ") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
1783
1891
  ].join("\n")
1784
1892
  );
1785
1893
  const upsertFile = store.statements.upsertFile ??= store.database.prepare(
@@ -1794,10 +1902,19 @@ function replaceFilesEvents(store, inputs) {
1794
1902
  " ingested_at = excluded.ingested_at"
1795
1903
  ].join("\n")
1796
1904
  );
1905
+ const markOverrideOnlyFile = store.statements.markOverrideOnlyFile ??= store.database.prepare(
1906
+ [
1907
+ "INSERT OR IGNORE INTO override_only_files (source, file_path)",
1908
+ "SELECT ?, ? WHERE NOT EXISTS (SELECT 1 FROM files WHERE source = ? AND file_path = ?)"
1909
+ ].join("\n")
1910
+ );
1797
1911
  runTransaction(store.database, () => {
1798
1912
  for (const write of writes) {
1799
1913
  const { source, filePath } = write;
1800
1914
  deleteFileEvents.run(source, filePath);
1915
+ if (write.overrideOnly) {
1916
+ markOverrideOnlyFile.run(source, filePath, source, filePath);
1917
+ }
1801
1918
  write.events.forEach((event, eventIndex) => {
1802
1919
  insertEvent.run(
1803
1920
  source,
@@ -1813,6 +1930,7 @@ function replaceFilesEvents(store, inputs) {
1813
1930
  event.reasoningTokens,
1814
1931
  event.cacheReadTokens,
1815
1932
  event.cacheWriteTokens,
1933
+ event.cacheWrite1hTokens,
1816
1934
  event.totalTokens,
1817
1935
  computeEventContentHash(event),
1818
1936
  event.costUsd ?? null,
@@ -1830,6 +1948,41 @@ function replaceFilesEvents(store, inputs) {
1830
1948
  }
1831
1949
  });
1832
1950
  }
1951
+ function readOverrideOnlyFiles(store) {
1952
+ const rows = store.database.prepare("SELECT source, file_path FROM override_only_files ORDER BY source, file_path").all();
1953
+ const files = [];
1954
+ for (const row of rows) {
1955
+ const source = toText(row.source);
1956
+ const filePath = toText(row.file_path);
1957
+ if (source && filePath) {
1958
+ files.push({ source, filePath });
1959
+ }
1960
+ }
1961
+ return files;
1962
+ }
1963
+ function claimOverrideOnlyFiles(store, files) {
1964
+ const overrideOnlyKeys = new Set(
1965
+ readOverrideOnlyFiles(store).map((file) => `${file.source}\0${file.filePath}`)
1966
+ );
1967
+ if (overrideOnlyKeys.size === 0) {
1968
+ return;
1969
+ }
1970
+ const claimedFiles = files.map((file) => ({
1971
+ source: normalizeStoreSource(file.source),
1972
+ filePath: normalizeStoreFilePath(file.filePath)
1973
+ })).filter((file) => overrideOnlyKeys.has(`${file.source}\0${file.filePath}`));
1974
+ if (claimedFiles.length === 0) {
1975
+ return;
1976
+ }
1977
+ runTransaction(store.database, () => {
1978
+ const deleteOverrideOnlyFile = store.database.prepare(
1979
+ "DELETE FROM override_only_files WHERE source = ? AND file_path = ?"
1980
+ );
1981
+ for (const file of claimedFiles) {
1982
+ deleteOverrideOnlyFile.run(file.source, file.filePath);
1983
+ }
1984
+ });
1985
+ }
1833
1986
  function closeEventStore(store) {
1834
1987
  store.database.close();
1835
1988
  }
@@ -3787,7 +3940,7 @@ function exitQuietlyOnBrokenPipe(stream, exit = () => process.exit()) {
3787
3940
  }
3788
3941
 
3789
3942
  // src/cli/create-cli.ts
3790
- import { Command as Command6 } from "commander";
3943
+ import { Command as Command6, Help } from "commander";
3791
3944
 
3792
3945
  // src/utils/suggest-closest.ts
3793
3946
  function editDistance(left, right4) {
@@ -3830,7 +3983,7 @@ function suggestClosest(input, candidates) {
3830
3983
  }
3831
3984
 
3832
3985
  // src/cli/report-definitions/report-definitions.ts
3833
- import { Command } from "commander";
3986
+ import { Argument, Command, Option as Option2 } from "commander";
3834
3987
 
3835
3988
  // src/utils/time-buckets.ts
3836
3989
  var DAY_MS3 = 24 * 60 * 60 * 1e3;
@@ -3855,7 +4008,7 @@ function getDateTimeFormatter(timezone) {
3855
4008
  dateTimeFormatterCache.set(timezone, formatter);
3856
4009
  return formatter;
3857
4010
  }
3858
- var MAX_MEMOIZED_TIMESTAMPS = 1e5;
4011
+ var MAX_MEMOIZED_TIMESTAMPS = 1e6;
3859
4012
  var localDatePartsByTimestamp = /* @__PURE__ */ new Map();
3860
4013
  function extractLocalDateParts(timestampIso, timezone) {
3861
4014
  let partsByTimestamp = localDatePartsByTimestamp.get(timezone);
@@ -3918,7 +4071,8 @@ function coversTimestamp(window, timestampMs) {
3918
4071
  function createLocalDateWindow(dayIndex, timestampMs, offsetMs, timezone, localDateTime) {
3919
4072
  const startMs = dayIndex * DAY_MS3 - offsetMs;
3920
4073
  const endMs = startMs + DAY_MS3;
3921
- const parts = toLocalDateParts(localDateTime);
4074
+ const localDate = toLocalDateParts(localDateTime);
4075
+ const parts = { ...localDate, dateKey: formatLocalDateParts(localDate) };
3922
4076
  if (hasStableOffsetWindow(startMs, endMs, offsetMs, timezone)) {
3923
4077
  return { startMs, endMs, parts };
3924
4078
  }
@@ -4023,7 +4177,7 @@ function getIsoWeekParts(localDate) {
4023
4177
  function getPeriodKey(timestampIso, granularity, timezone) {
4024
4178
  const localDate = extractLocalDateParts(timestampIso, timezone);
4025
4179
  if (granularity === "daily") {
4026
- return formatLocalDateParts(localDate);
4180
+ return localDate.dateKey;
4027
4181
  }
4028
4182
  if (granularity === "monthly") {
4029
4183
  return `${localDate.year}-${String(localDate.month).padStart(2, "0")}`;
@@ -4042,15 +4196,13 @@ function getIsoDayOfWeekFromDateKey(localDateKey) {
4042
4196
  return toIsoDayOfWeek(createUtcDate(parseLocalDateKey(localDateKey)));
4043
4197
  }
4044
4198
  function getCurrentLocalDateKey(timezone, now = /* @__PURE__ */ new Date()) {
4045
- return formatLocalDateParts(extractLocalDateParts(now.toISOString(), timezone));
4199
+ return extractLocalDateParts(now.toISOString(), timezone).dateKey;
4046
4200
  }
4047
4201
  function shiftLocalDateKey(localDateKey, days) {
4048
- return formatLocalDateParts(
4049
- extractLocalDateParts(
4050
- addDays(createUtcDate(parseLocalDateKey(localDateKey)), days).toISOString(),
4051
- "UTC"
4052
- )
4053
- );
4202
+ return extractLocalDateParts(
4203
+ addDays(createUtcDate(parseLocalDateKey(localDateKey)), days).toISOString(),
4204
+ "UTC"
4205
+ ).dateKey;
4054
4206
  }
4055
4207
  function getLocalDateKeyRange(from, to) {
4056
4208
  if (from > to) {
@@ -5692,6 +5844,9 @@ function parseUsage(usage) {
5692
5844
  const cacheWriteTokens = normalizeNonNegativeInteger(
5693
5845
  toNumberLike(usage.cache_creation_input_tokens)
5694
5846
  );
5847
+ const cacheWrite1hTokens = normalizeNonNegativeInteger(
5848
+ toNumberLike(asRecord(usage.cache_creation)?.ephemeral_1h_input_tokens)
5849
+ );
5695
5850
  const thinkingTokens = normalizeNonNegativeInteger(
5696
5851
  toNumberLike(asRecord(usage.output_tokens_details)?.thinking_tokens)
5697
5852
  );
@@ -5705,6 +5860,7 @@ function parseUsage(usage) {
5705
5860
  reasoningTokens: Math.min(outputTokens, thinkingTokens),
5706
5861
  cacheReadTokens,
5707
5862
  cacheWriteTokens,
5863
+ cacheWrite1hTokens: Math.min(cacheWriteTokens, cacheWrite1hTokens),
5708
5864
  totalTokens
5709
5865
  };
5710
5866
  }
@@ -5727,8 +5883,11 @@ function comparePendingEvents(left, right4) {
5727
5883
  }
5728
5884
  var ClaudeSourceAdapter = class {
5729
5885
  id = "claude";
5730
- parserVersion = 3;
5731
- capabilities = { eventsPrecedeFileMtime: true };
5886
+ parserVersion = 4;
5887
+ capabilities = {
5888
+ eventsPrecedeFileMtime: true,
5889
+ sessionsCopyEvents: true
5890
+ };
5732
5891
  rootDirs;
5733
5892
  requireDir;
5734
5893
  // Sibling forks share a parent; read its message keys once per parent version.
@@ -9450,7 +9609,7 @@ function createDefaultAdapters(options) {
9450
9609
  // src/cli/build-usage-data-inputs.ts
9451
9610
  function validateDateInput(value, flagName) {
9452
9611
  if (!/^\d{4}-\d{2}-\d{2}$/u.test(value)) {
9453
- throw new Error(`${flagName} must use format YYYY-MM-DD`);
9612
+ throw new Error(`${flagName} "${value}" is not a date; use YYYY-MM-DD`);
9454
9613
  }
9455
9614
  const parsed = /* @__PURE__ */ new Date(`${value}T00:00:00.000Z`);
9456
9615
  if (Number.isNaN(parsed.getTime()) || parsed.toISOString().slice(0, 10) !== value) {
@@ -9744,6 +9903,101 @@ function formatEnvVarOverrides(overrides) {
9744
9903
  return lines;
9745
9904
  }
9746
9905
 
9906
+ // src/render/format-model-list.ts
9907
+ function limitNamedModels(models, limit) {
9908
+ if (models.length <= limit) {
9909
+ return [...models];
9910
+ }
9911
+ return [...models.slice(0, limit), `+${models.length - limit} more`];
9912
+ }
9913
+
9914
+ // src/cli/count-copied-session-events-once.ts
9915
+ function getCopyIdentity(event) {
9916
+ return [
9917
+ event.timestamp,
9918
+ event.provider ?? "",
9919
+ event.model ?? "",
9920
+ event.inputTokens,
9921
+ event.outputTokens,
9922
+ event.reasoningTokens,
9923
+ event.cacheReadTokens,
9924
+ event.cacheWriteTokens,
9925
+ event.cacheWrite1hTokens,
9926
+ event.totalTokens
9927
+ ].join("\0");
9928
+ }
9929
+ function isCopyOf(left, right4) {
9930
+ return left.totalTokens === right4.totalTokens && left.timestamp === right4.timestamp && left.model === right4.model && left.provider === right4.provider && left.inputTokens === right4.inputTokens && left.outputTokens === right4.outputTokens && left.reasoningTokens === right4.reasoningTokens && left.cacheReadTokens === right4.cacheReadTokens && left.cacheWriteTokens === right4.cacheWriteTokens && left.cacheWrite1hTokens === right4.cacheWrite1hTokens;
9931
+ }
9932
+ function findEventsOtherSessionsHold(events) {
9933
+ const firstByTimestamp = /* @__PURE__ */ new Map();
9934
+ const sameTimestampGroups = /* @__PURE__ */ new Map();
9935
+ for (const event of events) {
9936
+ const first = firstByTimestamp.get(event.timestamp);
9937
+ if (first === void 0) {
9938
+ firstByTimestamp.set(event.timestamp, event);
9939
+ continue;
9940
+ }
9941
+ const group = sameTimestampGroups.get(event.timestamp);
9942
+ if (group) {
9943
+ group.push(event);
9944
+ } else {
9945
+ sameTimestampGroups.set(event.timestamp, [first, event]);
9946
+ }
9947
+ }
9948
+ const candidates = /* @__PURE__ */ new Set();
9949
+ for (const group of sameTimestampGroups.values()) {
9950
+ for (let left = 0; left < group.length; left += 1) {
9951
+ for (let right4 = left + 1; right4 < group.length; right4 += 1) {
9952
+ if (group[left].sessionId !== group[right4].sessionId && isCopyOf(group[left], group[right4])) {
9953
+ candidates.add(group[left]);
9954
+ candidates.add(group[right4]);
9955
+ }
9956
+ }
9957
+ }
9958
+ }
9959
+ return candidates;
9960
+ }
9961
+ function countCopiedSessionEventsOnce(events) {
9962
+ const candidates = findEventsOtherSessionsHold(events);
9963
+ if (candidates.size === 0) {
9964
+ return [...events];
9965
+ }
9966
+ const sessionStarts = /* @__PURE__ */ new Map();
9967
+ const candidatesBySession = /* @__PURE__ */ new Map();
9968
+ for (const event of events) {
9969
+ const start = sessionStarts.get(event.sessionId);
9970
+ if (start === void 0 || compareByCodePoint(event.timestamp, start) < 0) {
9971
+ sessionStarts.set(event.sessionId, event.timestamp);
9972
+ }
9973
+ if (candidates.has(event)) {
9974
+ const sessionCandidates = candidatesBySession.get(event.sessionId) ?? [];
9975
+ sessionCandidates.push(event);
9976
+ candidatesBySession.set(event.sessionId, sessionCandidates);
9977
+ }
9978
+ }
9979
+ const sessionsOldestFirst = [...candidatesBySession.keys()].sort(
9980
+ (left, right4) => compareByCodePoint(sessionStarts.get(left) ?? "", sessionStarts.get(right4) ?? "") || compareByCodePoint(left, right4)
9981
+ );
9982
+ const countedIdentities = /* @__PURE__ */ new Map();
9983
+ const copies = /* @__PURE__ */ new Set();
9984
+ for (const sessionId of sessionsOldestFirst) {
9985
+ const sessionCounts = /* @__PURE__ */ new Map();
9986
+ for (const event of candidatesBySession.get(sessionId) ?? []) {
9987
+ const identity = getCopyIdentity(event);
9988
+ const seen = (sessionCounts.get(identity) ?? 0) + 1;
9989
+ sessionCounts.set(identity, seen);
9990
+ if (seen <= (countedIdentities.get(identity) ?? 0)) {
9991
+ copies.add(event);
9992
+ }
9993
+ }
9994
+ for (const [identity, count] of sessionCounts) {
9995
+ countedIdentities.set(identity, Math.max(count, countedIdentities.get(identity) ?? 0));
9996
+ }
9997
+ }
9998
+ return events.filter((event) => !copies.has(event));
9999
+ }
10000
+
9747
10001
  // src/cli/history-live-files.ts
9748
10002
  import { stat as stat4 } from "fs/promises";
9749
10003
  var MAX_CONCURRENT_STATS = 32;
@@ -9845,12 +10099,33 @@ function writeParsedFilesToEventStore(context, files) {
9845
10099
  const now = context.now();
9846
10100
  context.replaceFilesEvents(
9847
10101
  context.store,
9848
- files.map((file) => ({ ...file, now }))
10102
+ files.map((file) => ({
10103
+ ...file,
10104
+ now,
10105
+ overrideOnly: context.overrideSourceIds.has(file.source.toLowerCase())
10106
+ }))
9849
10107
  );
9850
10108
  } catch (error) {
9851
10109
  recordEventStoreFailure(context.failureState, error);
9852
10110
  }
9853
10111
  }
10112
+ function claimFilesInUsualLocations(context, files) {
10113
+ if (context.failureState.disabled) {
10114
+ return void 0;
10115
+ }
10116
+ const usualLocationFiles = files.filter(
10117
+ (file) => !context.overrideSourceIds.has(file.source.toLowerCase())
10118
+ );
10119
+ if (usualLocationFiles.length === 0) {
10120
+ return void 0;
10121
+ }
10122
+ try {
10123
+ context.claimOverrideOnlyFiles(context.store, usualLocationFiles);
10124
+ return void 0;
10125
+ } catch (error) {
10126
+ return `Event store could not record files found in their usual location: ${getErrorReason(error)}`;
10127
+ }
10128
+ }
9854
10129
 
9855
10130
  // src/cli/parse/parse-budget.ts
9856
10131
  function createParseBudget(maxParallelFileParsing) {
@@ -10551,14 +10826,17 @@ async function parseSelectedAdapters(adaptersToParse, maxParallelFileParsing, op
10551
10826
  getFileEntry: options.eventStoreDeps?.getFileEntry ?? getFileEntry,
10552
10827
  readFileEvents: options.eventStoreDeps?.readFileEvents ?? readFileEvents,
10553
10828
  replaceFilesEvents: options.eventStoreDeps?.replaceFilesEvents ?? replaceFilesEvents,
10829
+ claimOverrideOnlyFiles: options.eventStoreDeps?.claimOverrideOnlyFiles ?? claimOverrideOnlyFiles,
10554
10830
  now: options.now ?? Date.now,
10555
- failureState: eventStoreFailureState
10831
+ failureState: eventStoreFailureState,
10832
+ overrideSourceIds: options.overrideSourceIds ?? /* @__PURE__ */ new Set()
10556
10833
  };
10557
10834
  } catch (error) {
10558
10835
  recordEventStoreFailure(eventStoreFailureState, error);
10559
10836
  }
10560
10837
  }
10561
10838
  let parseResults;
10839
+ let claimWarning;
10562
10840
  try {
10563
10841
  parseResults = await Promise.allSettled(
10564
10842
  adaptersToParse.map(
@@ -10584,6 +10862,17 @@ async function parseSelectedAdapters(adaptersToParse, maxParallelFileParsing, op
10584
10862
  )
10585
10863
  )
10586
10864
  );
10865
+ if (eventStoreContext) {
10866
+ claimWarning = claimFilesInUsualLocations(
10867
+ eventStoreContext,
10868
+ parseResults.flatMap(
10869
+ (parseResult) => parseResult.status === "fulfilled" ? parseResult.value.filePaths.map((filePath) => ({
10870
+ source: parseResult.value.source,
10871
+ filePath
10872
+ })) : []
10873
+ )
10874
+ );
10875
+ }
10587
10876
  } finally {
10588
10877
  if (eventStoreContext && ownsEventStore) {
10589
10878
  try {
@@ -10618,7 +10907,9 @@ async function parseSelectedAdapters(adaptersToParse, maxParallelFileParsing, op
10618
10907
  failedFiles,
10619
10908
  eventStoreAvailable: Boolean(options.eventStore?.enabled) && !eventStoreFailureState.disabled,
10620
10909
  sourceFailures,
10621
- warnings: eventStoreFailureState.warning ? [eventStoreFailureState.warning] : []
10910
+ warnings: [eventStoreFailureState.warning, claimWarning].filter(
10911
+ (warning) => warning !== void 0
10912
+ )
10622
10913
  };
10623
10914
  }
10624
10915
  function throwOnExplicitSourceFailures(sourceFailures, explicitSourceIds) {
@@ -10670,16 +10961,46 @@ function filterByModelRules(events, modelFilter) {
10670
10961
  const modelFilterRules = resolveModelFilterRules(events, modelFilter);
10671
10962
  return events.filter((event) => matchesModel(event.model, modelFilterRules));
10672
10963
  }
10964
+ function shiftUtcDate(date, days) {
10965
+ const shifted = /* @__PURE__ */ new Date(`${date}T00:00:00.000Z`);
10966
+ shifted.setUTCDate(shifted.getUTCDate() + days);
10967
+ return shifted.toISOString();
10968
+ }
10969
+ function createDateWindowPrefilter(since, until) {
10970
+ const outsideBefore = since ? shiftUtcDate(since, -1) : void 0;
10971
+ const insideFrom = since ? shiftUtcDate(since, 1) : void 0;
10972
+ const insideBefore = until ? shiftUtcDate(until, 0) : void 0;
10973
+ const outsideFrom = until ? shiftUtcDate(until, 2) : void 0;
10974
+ if ([outsideBefore, insideFrom, insideBefore, outsideFrom].some(
10975
+ (bound) => bound !== void 0 && bound.length !== 24
10976
+ )) {
10977
+ return () => "near-edge";
10978
+ }
10979
+ return (timestamp) => {
10980
+ if (timestamp.length !== 24) {
10981
+ return "near-edge";
10982
+ }
10983
+ if (outsideBefore && timestamp < outsideBefore || outsideFrom && timestamp >= outsideFrom) {
10984
+ return "outside";
10985
+ }
10986
+ return (!insideFrom || timestamp >= insideFrom) && (!insideBefore || timestamp < insideBefore) ? "inside" : "near-edge";
10987
+ };
10988
+ }
10673
10989
  function collectProviderAndDateFilteredEvents(eventGroups, options) {
10674
10990
  const filteredEvents = [];
10675
10991
  const hasDateRange = Boolean(options.since ?? options.until);
10992
+ const prefilterDate = createDateWindowPrefilter(options.since, options.until);
10676
10993
  const dateByTimestamp = /* @__PURE__ */ new Map();
10677
10994
  for (const events of eventGroups) {
10678
10995
  for (const event of events) {
10679
10996
  if (!matchesCanonicalProviderFilter(event.provider, options.providerFilter)) {
10680
10997
  continue;
10681
10998
  }
10682
- if (hasDateRange) {
10999
+ const datePosition = hasDateRange ? prefilterDate(event.timestamp) : "inside";
11000
+ if (datePosition === "outside") {
11001
+ continue;
11002
+ }
11003
+ if (datePosition === "near-edge") {
10683
11004
  let eventDate = dateByTimestamp.get(event.timestamp);
10684
11005
  if (!eventDate) {
10685
11006
  eventDate = getPeriodKey(event.timestamp, "daily", options.timezone);
@@ -10834,6 +11155,7 @@ function toUsageEventInput(value) {
10834
11155
  reasoningTokens: optionalCount(record, "reasoningTokens"),
10835
11156
  cacheReadTokens: optionalCount(record, "cacheReadTokens"),
10836
11157
  cacheWriteTokens: optionalCount(record, "cacheWriteTokens"),
11158
+ cacheWrite1hTokens: optionalCount(record, "cacheWrite1hTokens"),
10837
11159
  totalTokens: optionalCount(record, "totalTokens"),
10838
11160
  costUsd: optionalCount(record, "costUsd"),
10839
11161
  costMode
@@ -11039,6 +11361,9 @@ function applyMachineExport(cache, bundle, now) {
11039
11361
  function recordMachineSyncFailure(cache, reason, now) {
11040
11362
  writeEventStoreMeta(cache, { attemptedAt: String(now), lastError: reason });
11041
11363
  }
11364
+ function toStoredError(value) {
11365
+ return value === void 0 ? void 0 : toTerminalLine(value);
11366
+ }
11042
11367
  function toEpochMs(value) {
11043
11368
  const parsed = value === void 0 ? Number.NaN : Number(value);
11044
11369
  return Number.isSafeInteger(parsed) && parsed >= 0 ? parsed : void 0;
@@ -11049,7 +11374,7 @@ function toSyncState(readMeta) {
11049
11374
  cliVersion: readMeta("cliVersion"),
11050
11375
  syncedAt: toEpochMs(readMeta("syncedAt")),
11051
11376
  attemptedAt: toEpochMs(readMeta("attemptedAt")),
11052
- lastError: readMeta("lastError")
11377
+ lastError: toStoredError(readMeta("lastError"))
11053
11378
  };
11054
11379
  }
11055
11380
  function readMachineSyncState(cache) {
@@ -11230,7 +11555,7 @@ async function loadMachineUsage(params) {
11230
11555
  // src/machines/machine-ssh.ts
11231
11556
  import { spawn } from "child_process";
11232
11557
  import { createInterface } from "readline";
11233
- import { stripVTControlCharacters } from "util";
11558
+ import { stripVTControlCharacters as stripVTControlCharacters2 } from "util";
11234
11559
  var DEFAULT_MACHINE_COMMAND = "llm-usage";
11235
11560
  var MACHINE_EXPORT_TIMEOUT_MARK = "timed out";
11236
11561
  var STDERR_TAIL_BYTES = 4096;
@@ -11323,7 +11648,7 @@ async function detectRemoteCommand(target, options = {}) {
11323
11648
  }
11324
11649
  function readStderrTail(chunks) {
11325
11650
  const text2 = Buffer.concat(chunks).toString("utf8").slice(-STDERR_TAIL_BYTES);
11326
- return stripControlCharacters(stripVTControlCharacters(text2).replaceAll(/\s+/gu, " ")).trim();
11651
+ return toTerminalLine(text2);
11327
11652
  }
11328
11653
  function describeExportFailure(machine, exitCode, stderr) {
11329
11654
  const command = machine.command ?? DEFAULT_MACHINE_COMMAND;
@@ -11417,11 +11742,15 @@ async function fetchMachineExport(machine, knownFiles, options = {}) {
11417
11742
  cause: readError
11418
11743
  });
11419
11744
  }
11420
- const remoteWarnings = Buffer.concat(stderrChunks).toString("utf8").slice(-STDERR_TAIL_BYTES).split("\n").map((line) => stripControlCharacters(stripVTControlCharacters(line)).trim()).filter((line) => line.length > 0);
11745
+ const remoteWarnings = Buffer.concat(stderrChunks).toString("utf8").slice(-STDERR_TAIL_BYTES).split("\n").map((line) => stripControlCharacters(stripVTControlCharacters2(line)).trim()).filter((line) => line.length > 0);
11421
11746
  return { bundle, remoteWarnings };
11422
11747
  }
11423
11748
 
11424
11749
  // src/render/render-machines.ts
11750
+ var MAX_REASON_LENGTH = 300;
11751
+ function formatReason(error) {
11752
+ return error.length > MAX_REASON_LENGTH ? `${error.slice(0, MAX_REASON_LENGTH)}\u2026` : error;
11753
+ }
11425
11754
  var integerFormat = new Intl.NumberFormat("en-US");
11426
11755
  function formatAge(ageMs) {
11427
11756
  const minutes = Math.floor(Math.max(0, ageMs) / 6e4);
@@ -11456,7 +11785,7 @@ function renderSyncOutcome(outcome, now) {
11456
11785
  ];
11457
11786
  }
11458
11787
  const cacheNote = outcome.state.syncedAt === void 0 ? "nothing cached yet" : `reports keep its usage from ${formatAge(now - outcome.state.syncedAt)}`;
11459
- return [`\u2717 ${outcome.name}: ${outcome.error} (${cacheNote})`];
11788
+ return [`\u2717 ${outcome.name}: ${formatReason(outcome.error)} (${cacheNote})`];
11460
11789
  }
11461
11790
  function describeMachineStatus(entry, now) {
11462
11791
  const { state } = entry;
@@ -11464,11 +11793,11 @@ function describeMachineStatus(entry, now) {
11464
11793
  return "disabled (cached usage stays in reports)";
11465
11794
  }
11466
11795
  if (state?.syncedAt === void 0) {
11467
- return state?.lastError ? `never synced: ${state.lastError}` : "never synced";
11796
+ return state?.lastError ? `never synced: ${formatReason(state.lastError)}` : "never synced";
11468
11797
  }
11469
11798
  const synced = `synced ${formatAge(now - state.syncedAt)}, ${formatCachedTotals(entry.fileCount, entry.eventCount)}`;
11470
11799
  if (state.lastError && (state.attemptedAt ?? 0) >= state.syncedAt) {
11471
- return `${synced}; last attempt failed ${formatAge(now - (state.attemptedAt ?? 0))}: ${state.lastError}`;
11800
+ return `${synced}; last attempt failed ${formatAge(now - (state.attemptedAt ?? 0))}: ${formatReason(state.lastError)}`;
11472
11801
  }
11473
11802
  return synced;
11474
11803
  }
@@ -11488,12 +11817,9 @@ function describeIncludedMachine(machine, now, localVersion) {
11488
11817
  return state?.syncedAt === void 0 ? `${machine.name} (disabled, nothing cached)` : `${machine.name} (disabled, usage from ${formatAge(now - state.syncedAt)})`;
11489
11818
  }
11490
11819
  if (state?.syncedAt === void 0) {
11491
- return `${machine.name} (never synced; run llm-usage sync ${machine.name})`;
11820
+ return state?.lastError === void 0 ? `${machine.name} (never synced; run llm-usage sync ${machine.name})` : `${machine.name} (never synced)`;
11492
11821
  }
11493
11822
  const details = [`synced ${formatAge(now - state.syncedAt)}`];
11494
- if (state.lastError !== void 0 && (state.attemptedAt ?? 0) >= state.syncedAt) {
11495
- details.push("last sync failed");
11496
- }
11497
11823
  if (state.cliVersion && state.cliVersion !== localVersion) {
11498
11824
  details.push(
11499
11825
  `llm-usage-metrics ${state.cliVersion} there; shared sessions may count twice until both run the same version`
@@ -11514,16 +11840,35 @@ function formatRefreshFailure(outcome, now) {
11514
11840
  const { syncedAt } = outcome.state;
11515
11841
  if (syncedAt === void 0) {
11516
11842
  return {
11517
- text: `Could not sync ${outcome.name} (${outcome.error}); it has no usage cached yet.`,
11843
+ text: `Could not sync ${outcome.name} (${formatReason(outcome.error)}); it has no usage cached yet.`,
11518
11844
  stale: true
11519
11845
  };
11520
11846
  }
11521
11847
  const hint = outcome.error.endsWith(`(${MACHINE_EXPORT_TIMEOUT_MARK})`) ? ` Run llm-usage sync ${outcome.name} to wait for it.` : "";
11522
11848
  return {
11523
- text: `Could not sync ${outcome.name} (${outcome.error}); using its usage from ${formatAge(now - syncedAt)}.${hint}`,
11849
+ text: `Could not sync ${outcome.name} (${formatReason(outcome.error)}); using its usage from ${formatAge(now - syncedAt)}.${hint}`,
11524
11850
  stale: now - syncedAt >= STALE_CACHE_MS
11525
11851
  };
11526
11852
  }
11853
+ function formatStoredSyncFailure(machine, now) {
11854
+ const { state } = machine;
11855
+ if (!machine.enabled || state?.lastError === void 0) {
11856
+ return void 0;
11857
+ }
11858
+ if (state.syncedAt === void 0) {
11859
+ return {
11860
+ text: `${machine.name}: never synced (${formatReason(state.lastError)}). Run llm-usage sync ${machine.name} to retry.`,
11861
+ stale: true
11862
+ };
11863
+ }
11864
+ if ((state.attemptedAt ?? 0) < state.syncedAt) {
11865
+ return void 0;
11866
+ }
11867
+ return {
11868
+ text: `${machine.name}: last sync failed (${formatReason(state.lastError)}); using its usage from ${formatAge(now - state.syncedAt)}. Run llm-usage sync ${machine.name} to retry.`,
11869
+ stale: now - state.syncedAt >= STALE_CACHE_MS
11870
+ };
11871
+ }
11527
11872
 
11528
11873
  // src/machines/sync-machine.ts
11529
11874
  async function syncMachine(name, machine, options = {}) {
@@ -11554,7 +11899,7 @@ async function syncMachine(name, machine, options = {}) {
11554
11899
  const result = applyMachineExport(cache, bundle, now());
11555
11900
  return { name, ok: true, result, remoteWarnings, state: readMachineSyncState(cache) };
11556
11901
  } catch (error) {
11557
- const reason = getErrorReason(error);
11902
+ const reason = toTerminalLine(getErrorReason(error));
11558
11903
  let state = {};
11559
11904
  try {
11560
11905
  if (!options.signal?.aborted) {
@@ -11671,7 +12016,13 @@ function calculateEstimatedCostUsd(event, pricing) {
11671
12016
  const inputCost = estimateTokenGroupCost(event.inputTokens, pricing.inputPer1MUsd);
11672
12017
  const outputCost = estimateTokenGroupCost(billedOutput.outputTokens, pricing.outputPer1MUsd);
11673
12018
  const cacheReadCost = estimateTokenGroupCost(event.cacheReadTokens, pricing.cacheReadPer1MUsd);
11674
- const cacheWriteCost = estimateTokenGroupCost(event.cacheWriteTokens, pricing.cacheWritePer1MUsd);
12019
+ const cacheWriteCost = estimateTokenGroupCost(
12020
+ event.cacheWriteTokens - event.cacheWrite1hTokens,
12021
+ pricing.cacheWritePer1MUsd
12022
+ ) + estimateTokenGroupCost(
12023
+ event.cacheWrite1hTokens,
12024
+ pricing.cacheWrite1hPer1MUsd ?? pricing.cacheWritePer1MUsd
12025
+ );
11675
12026
  const reasoningCost = estimateTokenGroupCost(
11676
12027
  billedOutput.reasoningTokens,
11677
12028
  pricing.reasoningPer1MUsd
@@ -11760,7 +12111,12 @@ function applyPricingToEvents(events, pricingSource) {
11760
12111
 
11761
12112
  // src/pricing/pricing-override-source.ts
11762
12113
  var requiredRateKeys = ["inputPer1MUsd", "outputPer1MUsd"];
11763
- var optionalRateKeys = ["cacheReadPer1MUsd", "cacheWritePer1MUsd", "reasoningPer1MUsd"];
12114
+ var optionalRateKeys = [
12115
+ "cacheReadPer1MUsd",
12116
+ "cacheWritePer1MUsd",
12117
+ "cacheWrite1hPer1MUsd",
12118
+ "reasoningPer1MUsd"
12119
+ ];
11764
12120
  var knownOverrideKeys = /* @__PURE__ */ new Set([
11765
12121
  ...requiredRateKeys,
11766
12122
  ...optionalRateKeys,
@@ -11807,6 +12163,7 @@ function normalizePricingOverride(raw, problems) {
11807
12163
  const outputPer1MUsd = readRate(raw, "outputPer1MUsd", true, problems);
11808
12164
  const cacheReadPer1MUsd = readRate(raw, "cacheReadPer1MUsd", false, problems);
11809
12165
  const cacheWritePer1MUsd = readRate(raw, "cacheWritePer1MUsd", false, problems);
12166
+ const cacheWrite1hPer1MUsd = readRate(raw, "cacheWrite1hPer1MUsd", false, problems);
11810
12167
  const reasoningPer1MUsd = readRate(raw, "reasoningPer1MUsd", false, problems);
11811
12168
  const reasoningBilling = normalizeReasoningBilling(raw.reasoningBilling);
11812
12169
  if (raw.reasoningBilling !== void 0 && reasoningBilling === void 0) {
@@ -11820,6 +12177,7 @@ function normalizePricingOverride(raw, problems) {
11820
12177
  outputPer1MUsd,
11821
12178
  ...cacheReadPer1MUsd !== void 0 ? { cacheReadPer1MUsd } : {},
11822
12179
  ...cacheWritePer1MUsd !== void 0 ? { cacheWritePer1MUsd } : {},
12180
+ ...cacheWrite1hPer1MUsd !== void 0 ? { cacheWrite1hPer1MUsd } : {},
11823
12181
  ...reasoningPer1MUsd !== void 0 ? { reasoningPer1MUsd } : {},
11824
12182
  ...reasoningBilling !== void 0 ? { reasoningBilling } : {}
11825
12183
  };
@@ -12774,31 +13132,36 @@ var litellm_pricing_snapshot_default = {
12774
13132
  inputPer1MUsd: 10,
12775
13133
  outputPer1MUsd: 50,
12776
13134
  cacheReadPer1MUsd: 1,
12777
- cacheWritePer1MUsd: 12.5
13135
+ cacheWritePer1MUsd: 12.5,
13136
+ cacheWrite1hPer1MUsd: 20
12778
13137
  },
12779
13138
  "anthropic.claude-fable-5-1": {
12780
13139
  inputPer1MUsd: 10,
12781
13140
  outputPer1MUsd: 50,
12782
13141
  cacheReadPer1MUsd: 0.25,
12783
- cacheWritePer1MUsd: 12.5
13142
+ cacheWritePer1MUsd: 12.5,
13143
+ cacheWrite1hPer1MUsd: 20
12784
13144
  },
12785
13145
  "anthropic.claude-haiku-4-5-20251001-v1:0": {
12786
13146
  inputPer1MUsd: 1,
12787
13147
  outputPer1MUsd: 5,
12788
13148
  cacheReadPer1MUsd: 0.09999999999999999,
12789
- cacheWritePer1MUsd: 1.25
13149
+ cacheWritePer1MUsd: 1.25,
13150
+ cacheWrite1hPer1MUsd: 2
12790
13151
  },
12791
13152
  "anthropic.claude-haiku-4-5@20251001": {
12792
13153
  inputPer1MUsd: 1,
12793
13154
  outputPer1MUsd: 5,
12794
13155
  cacheReadPer1MUsd: 0.09999999999999999,
12795
- cacheWritePer1MUsd: 1.25
13156
+ cacheWritePer1MUsd: 1.25,
13157
+ cacheWrite1hPer1MUsd: 2
12796
13158
  },
12797
13159
  "anthropic.claude-haiku-5-5": {
12798
13160
  inputPer1MUsd: 0.09999999999999999,
12799
13161
  outputPer1MUsd: 0.5,
12800
13162
  cacheReadPer1MUsd: 0.01,
12801
- cacheWritePer1MUsd: 0.125
13163
+ cacheWritePer1MUsd: 0.125,
13164
+ cacheWrite1hPer1MUsd: 0.19999999999999998
12802
13165
  },
12803
13166
  "anthropic.claude-instant-v1": {
12804
13167
  inputPer1MUsd: 0.7999999999999999,
@@ -12808,13 +13171,15 @@ var litellm_pricing_snapshot_default = {
12808
13171
  inputPer1MUsd: 10,
12809
13172
  outputPer1MUsd: 50,
12810
13173
  cacheReadPer1MUsd: 0.25,
12811
- cacheWritePer1MUsd: 12.5
13174
+ cacheWritePer1MUsd: 12.5,
13175
+ cacheWrite1hPer1MUsd: 20
12812
13176
  },
12813
13177
  "anthropic.claude-mythos-preview": {
12814
13178
  inputPer1MUsd: 27.5,
12815
13179
  outputPer1MUsd: 137.5,
12816
13180
  cacheReadPer1MUsd: 2.75,
12817
- cacheWritePer1MUsd: 34.375
13181
+ cacheWritePer1MUsd: 34.375,
13182
+ cacheWrite1hPer1MUsd: 55
12818
13183
  },
12819
13184
  "anthropic.claude-opus-4-1-20250805-v1:0": {
12820
13185
  inputPer1MUsd: 15,
@@ -12832,37 +13197,43 @@ var litellm_pricing_snapshot_default = {
12832
13197
  inputPer1MUsd: 5,
12833
13198
  outputPer1MUsd: 25,
12834
13199
  cacheReadPer1MUsd: 0.5,
12835
- cacheWritePer1MUsd: 6.25
13200
+ cacheWritePer1MUsd: 6.25,
13201
+ cacheWrite1hPer1MUsd: 10
12836
13202
  },
12837
13203
  "anthropic.claude-opus-4-6-v1": {
12838
13204
  inputPer1MUsd: 5,
12839
13205
  outputPer1MUsd: 25,
12840
13206
  cacheReadPer1MUsd: 0.5,
12841
- cacheWritePer1MUsd: 6.25
13207
+ cacheWritePer1MUsd: 6.25,
13208
+ cacheWrite1hPer1MUsd: 10
12842
13209
  },
12843
13210
  "anthropic.claude-opus-4-7": {
12844
13211
  inputPer1MUsd: 5,
12845
13212
  outputPer1MUsd: 25,
12846
13213
  cacheReadPer1MUsd: 0.5,
12847
- cacheWritePer1MUsd: 6.25
13214
+ cacheWritePer1MUsd: 6.25,
13215
+ cacheWrite1hPer1MUsd: 10
12848
13216
  },
12849
13217
  "anthropic.claude-opus-4-8": {
12850
13218
  inputPer1MUsd: 5,
12851
13219
  outputPer1MUsd: 25,
12852
13220
  cacheReadPer1MUsd: 0.5,
12853
- cacheWritePer1MUsd: 6.25
13221
+ cacheWritePer1MUsd: 6.25,
13222
+ cacheWrite1hPer1MUsd: 10
12854
13223
  },
12855
13224
  "anthropic.claude-opus-5": {
12856
13225
  inputPer1MUsd: 5,
12857
13226
  outputPer1MUsd: 25,
12858
13227
  cacheReadPer1MUsd: 0.5,
12859
- cacheWritePer1MUsd: 6.25
13228
+ cacheWritePer1MUsd: 6.25,
13229
+ cacheWrite1hPer1MUsd: 10
12860
13230
  },
12861
13231
  "anthropic.claude-opus-5-5": {
12862
13232
  inputPer1MUsd: 4,
12863
13233
  outputPer1MUsd: 20,
12864
13234
  cacheReadPer1MUsd: 0.19999999999999998,
12865
- cacheWritePer1MUsd: 5
13235
+ cacheWritePer1MUsd: 5,
13236
+ cacheWrite1hPer1MUsd: 8
12866
13237
  },
12867
13238
  "anthropic.claude-sonnet-4-20250514-v1:0": {
12868
13239
  inputPer1MUsd: 3,
@@ -12874,25 +13245,29 @@ var litellm_pricing_snapshot_default = {
12874
13245
  inputPer1MUsd: 3,
12875
13246
  outputPer1MUsd: 15,
12876
13247
  cacheReadPer1MUsd: 0.3,
12877
- cacheWritePer1MUsd: 3.75
13248
+ cacheWritePer1MUsd: 3.75,
13249
+ cacheWrite1hPer1MUsd: 6
12878
13250
  },
12879
13251
  "anthropic.claude-sonnet-4-6": {
12880
13252
  inputPer1MUsd: 3,
12881
13253
  outputPer1MUsd: 15,
12882
13254
  cacheReadPer1MUsd: 0.3,
12883
- cacheWritePer1MUsd: 3.75
13255
+ cacheWritePer1MUsd: 3.75,
13256
+ cacheWrite1hPer1MUsd: 6
12884
13257
  },
12885
13258
  "anthropic.claude-sonnet-5": {
12886
13259
  inputPer1MUsd: 2,
12887
13260
  outputPer1MUsd: 10,
12888
13261
  cacheReadPer1MUsd: 0.19999999999999998,
12889
- cacheWritePer1MUsd: 2.5
13262
+ cacheWritePer1MUsd: 2.5,
13263
+ cacheWrite1hPer1MUsd: 4
12890
13264
  },
12891
13265
  "anthropic.claude-sonnet-5-5": {
12892
13266
  inputPer1MUsd: 2,
12893
13267
  outputPer1MUsd: 10,
12894
13268
  cacheReadPer1MUsd: 0.19999999999999998,
12895
- cacheWritePer1MUsd: 2.5
13269
+ cacheWritePer1MUsd: 2.5,
13270
+ cacheWrite1hPer1MUsd: 4
12896
13271
  },
12897
13272
  "anthropic.claude-v1": {
12898
13273
  inputPer1MUsd: 8,
@@ -12979,7 +13354,8 @@ var litellm_pricing_snapshot_default = {
12979
13354
  inputPer1MUsd: 11,
12980
13355
  outputPer1MUsd: 55,
12981
13356
  cacheReadPer1MUsd: 1.1,
12982
- cacheWritePer1MUsd: 13.75
13357
+ cacheWritePer1MUsd: 13.75,
13358
+ cacheWrite1hPer1MUsd: 22
12983
13359
  },
12984
13360
  "apac.anthropic.claude-haiku-4-5-20251001-v1:0": {
12985
13361
  inputPer1MUsd: 1.1,
@@ -12991,37 +13367,43 @@ var litellm_pricing_snapshot_default = {
12991
13367
  inputPer1MUsd: 0.11,
12992
13368
  outputPer1MUsd: 0.55,
12993
13369
  cacheReadPer1MUsd: 0.011,
12994
- cacheWritePer1MUsd: 0.1375
13370
+ cacheWritePer1MUsd: 0.1375,
13371
+ cacheWrite1hPer1MUsd: 0.22
12995
13372
  },
12996
13373
  "apac.anthropic.claude-mythos-preview": {
12997
13374
  inputPer1MUsd: 27.5,
12998
13375
  outputPer1MUsd: 137.5,
12999
13376
  cacheReadPer1MUsd: 2.75,
13000
- cacheWritePer1MUsd: 34.375
13377
+ cacheWritePer1MUsd: 34.375,
13378
+ cacheWrite1hPer1MUsd: 55
13001
13379
  },
13002
13380
  "apac.anthropic.claude-opus-4-7": {
13003
13381
  inputPer1MUsd: 5.5,
13004
13382
  outputPer1MUsd: 27.5,
13005
13383
  cacheReadPer1MUsd: 0.55,
13006
- cacheWritePer1MUsd: 6.875
13384
+ cacheWritePer1MUsd: 6.875,
13385
+ cacheWrite1hPer1MUsd: 11
13007
13386
  },
13008
13387
  "apac.anthropic.claude-opus-4-8": {
13009
13388
  inputPer1MUsd: 5.5,
13010
13389
  outputPer1MUsd: 27.5,
13011
13390
  cacheReadPer1MUsd: 0.55,
13012
- cacheWritePer1MUsd: 6.875
13391
+ cacheWritePer1MUsd: 6.875,
13392
+ cacheWrite1hPer1MUsd: 11
13013
13393
  },
13014
13394
  "apac.anthropic.claude-opus-5": {
13015
13395
  inputPer1MUsd: 5.5,
13016
13396
  outputPer1MUsd: 27.5,
13017
13397
  cacheReadPer1MUsd: 0.55,
13018
- cacheWritePer1MUsd: 6.875
13398
+ cacheWritePer1MUsd: 6.875,
13399
+ cacheWrite1hPer1MUsd: 11
13019
13400
  },
13020
13401
  "apac.anthropic.claude-opus-5-5": {
13021
13402
  inputPer1MUsd: 4.4,
13022
13403
  outputPer1MUsd: 22,
13023
13404
  cacheReadPer1MUsd: 0.22,
13024
- cacheWritePer1MUsd: 5.5
13405
+ cacheWritePer1MUsd: 5.5,
13406
+ cacheWrite1hPer1MUsd: 8.8
13025
13407
  },
13026
13408
  "apac.anthropic.claude-sonnet-4-20250514-v1:0": {
13027
13409
  inputPer1MUsd: 3,
@@ -13033,97 +13415,113 @@ var litellm_pricing_snapshot_default = {
13033
13415
  inputPer1MUsd: 3.3000000000000003,
13034
13416
  outputPer1MUsd: 16.5,
13035
13417
  cacheReadPer1MUsd: 0.33,
13036
- cacheWritePer1MUsd: 4.125
13418
+ cacheWritePer1MUsd: 4.125,
13419
+ cacheWrite1hPer1MUsd: 6.6000000000000005
13037
13420
  },
13038
13421
  "apac.anthropic.claude-sonnet-5": {
13039
13422
  inputPer1MUsd: 2.2,
13040
13423
  outputPer1MUsd: 11,
13041
13424
  cacheReadPer1MUsd: 0.22,
13042
- cacheWritePer1MUsd: 2.75
13425
+ cacheWritePer1MUsd: 2.75,
13426
+ cacheWrite1hPer1MUsd: 4.4
13043
13427
  },
13044
13428
  "apac.anthropic.claude-sonnet-5-5": {
13045
13429
  inputPer1MUsd: 2.2,
13046
13430
  outputPer1MUsd: 11,
13047
13431
  cacheReadPer1MUsd: 0.22,
13048
- cacheWritePer1MUsd: 2.75
13432
+ cacheWritePer1MUsd: 2.75,
13433
+ cacheWrite1hPer1MUsd: 4.4
13049
13434
  },
13050
13435
  "au.anthropic.claude-fable-5": {
13051
13436
  inputPer1MUsd: 11,
13052
13437
  outputPer1MUsd: 55,
13053
13438
  cacheReadPer1MUsd: 1.1,
13054
- cacheWritePer1MUsd: 13.75
13439
+ cacheWritePer1MUsd: 13.75,
13440
+ cacheWrite1hPer1MUsd: 22
13055
13441
  },
13056
13442
  "au.anthropic.claude-haiku-4-5-20251001-v1:0": {
13057
13443
  inputPer1MUsd: 1.1,
13058
13444
  outputPer1MUsd: 5.5,
13059
13445
  cacheReadPer1MUsd: 0.11,
13060
- cacheWritePer1MUsd: 1.375
13446
+ cacheWritePer1MUsd: 1.375,
13447
+ cacheWrite1hPer1MUsd: 2.2
13061
13448
  },
13062
13449
  "au.anthropic.claude-haiku-5-5": {
13063
13450
  inputPer1MUsd: 0.11,
13064
13451
  outputPer1MUsd: 0.55,
13065
13452
  cacheReadPer1MUsd: 0.011,
13066
- cacheWritePer1MUsd: 0.1375
13453
+ cacheWritePer1MUsd: 0.1375,
13454
+ cacheWrite1hPer1MUsd: 0.22
13067
13455
  },
13068
13456
  "au.anthropic.claude-mythos-preview": {
13069
13457
  inputPer1MUsd: 27.5,
13070
13458
  outputPer1MUsd: 137.5,
13071
13459
  cacheReadPer1MUsd: 2.75,
13072
- cacheWritePer1MUsd: 34.375
13460
+ cacheWritePer1MUsd: 34.375,
13461
+ cacheWrite1hPer1MUsd: 55
13073
13462
  },
13074
13463
  "au.anthropic.claude-opus-4-6-v1": {
13075
13464
  inputPer1MUsd: 5.5,
13076
13465
  outputPer1MUsd: 27.5,
13077
13466
  cacheReadPer1MUsd: 0.55,
13078
- cacheWritePer1MUsd: 6.875
13467
+ cacheWritePer1MUsd: 6.875,
13468
+ cacheWrite1hPer1MUsd: 11
13079
13469
  },
13080
13470
  "au.anthropic.claude-opus-4-7": {
13081
13471
  inputPer1MUsd: 5.5,
13082
13472
  outputPer1MUsd: 27.5,
13083
13473
  cacheReadPer1MUsd: 0.55,
13084
- cacheWritePer1MUsd: 6.875
13474
+ cacheWritePer1MUsd: 6.875,
13475
+ cacheWrite1hPer1MUsd: 11
13085
13476
  },
13086
13477
  "au.anthropic.claude-opus-4-8": {
13087
13478
  inputPer1MUsd: 5.5,
13088
13479
  outputPer1MUsd: 27.5,
13089
13480
  cacheReadPer1MUsd: 0.55,
13090
- cacheWritePer1MUsd: 6.875
13481
+ cacheWritePer1MUsd: 6.875,
13482
+ cacheWrite1hPer1MUsd: 11
13091
13483
  },
13092
13484
  "au.anthropic.claude-opus-5": {
13093
13485
  inputPer1MUsd: 5.5,
13094
13486
  outputPer1MUsd: 27.5,
13095
13487
  cacheReadPer1MUsd: 0.55,
13096
- cacheWritePer1MUsd: 6.875
13488
+ cacheWritePer1MUsd: 6.875,
13489
+ cacheWrite1hPer1MUsd: 11
13097
13490
  },
13098
13491
  "au.anthropic.claude-opus-5-5": {
13099
13492
  inputPer1MUsd: 4.4,
13100
13493
  outputPer1MUsd: 22,
13101
13494
  cacheReadPer1MUsd: 0.22,
13102
- cacheWritePer1MUsd: 5.5
13495
+ cacheWritePer1MUsd: 5.5,
13496
+ cacheWrite1hPer1MUsd: 8.8
13103
13497
  },
13104
13498
  "au.anthropic.claude-sonnet-4-5-20250929-v1:0": {
13105
13499
  inputPer1MUsd: 3.3000000000000003,
13106
13500
  outputPer1MUsd: 16.5,
13107
13501
  cacheReadPer1MUsd: 0.33,
13108
- cacheWritePer1MUsd: 4.125
13502
+ cacheWritePer1MUsd: 4.125,
13503
+ cacheWrite1hPer1MUsd: 6.6000000000000005
13109
13504
  },
13110
13505
  "au.anthropic.claude-sonnet-4-6": {
13111
13506
  inputPer1MUsd: 3.3000000000000003,
13112
13507
  outputPer1MUsd: 16.5,
13113
13508
  cacheReadPer1MUsd: 0.33,
13114
- cacheWritePer1MUsd: 4.125
13509
+ cacheWritePer1MUsd: 4.125,
13510
+ cacheWrite1hPer1MUsd: 6.6000000000000005
13115
13511
  },
13116
13512
  "au.anthropic.claude-sonnet-5": {
13117
13513
  inputPer1MUsd: 2.2,
13118
13514
  outputPer1MUsd: 11,
13119
13515
  cacheReadPer1MUsd: 0.22,
13120
- cacheWritePer1MUsd: 2.75
13516
+ cacheWritePer1MUsd: 2.75,
13517
+ cacheWrite1hPer1MUsd: 4.4
13121
13518
  },
13122
13519
  "au.anthropic.claude-sonnet-5-5": {
13123
13520
  inputPer1MUsd: 2.2,
13124
13521
  outputPer1MUsd: 11,
13125
13522
  cacheReadPer1MUsd: 0.22,
13126
- cacheWritePer1MUsd: 2.75
13523
+ cacheWritePer1MUsd: 2.75,
13524
+ cacheWrite1hPer1MUsd: 4.4
13127
13525
  },
13128
13526
  "azure/ada": {
13129
13527
  inputPer1MUsd: 0.09999999999999999,
@@ -14407,85 +14805,99 @@ var litellm_pricing_snapshot_default = {
14407
14805
  inputPer1MUsd: 10,
14408
14806
  outputPer1MUsd: 50,
14409
14807
  cacheReadPer1MUsd: 1,
14410
- cacheWritePer1MUsd: 12.5
14808
+ cacheWritePer1MUsd: 12.5,
14809
+ cacheWrite1hPer1MUsd: 20
14411
14810
  },
14412
14811
  "azure_ai/claude-fable-5-1": {
14413
14812
  inputPer1MUsd: 10,
14414
14813
  outputPer1MUsd: 50,
14415
14814
  cacheReadPer1MUsd: 0.25,
14416
- cacheWritePer1MUsd: 12.5
14815
+ cacheWritePer1MUsd: 12.5,
14816
+ cacheWrite1hPer1MUsd: 20
14417
14817
  },
14418
14818
  "azure_ai/claude-haiku-4-5": {
14419
14819
  inputPer1MUsd: 1,
14420
14820
  outputPer1MUsd: 5,
14421
14821
  cacheReadPer1MUsd: 0.09999999999999999,
14422
- cacheWritePer1MUsd: 1.25
14822
+ cacheWritePer1MUsd: 1.25,
14823
+ cacheWrite1hPer1MUsd: 2
14423
14824
  },
14424
14825
  "azure_ai/claude-haiku-5-5": {
14425
14826
  inputPer1MUsd: 0.09999999999999999,
14426
14827
  outputPer1MUsd: 0.5,
14427
14828
  cacheReadPer1MUsd: 0.01,
14428
- cacheWritePer1MUsd: 0.125
14829
+ cacheWritePer1MUsd: 0.125,
14830
+ cacheWrite1hPer1MUsd: 0.19999999999999998
14429
14831
  },
14430
14832
  "azure_ai/claude-opus-4-5": {
14431
14833
  inputPer1MUsd: 5,
14432
14834
  outputPer1MUsd: 25,
14433
14835
  cacheReadPer1MUsd: 0.5,
14434
- cacheWritePer1MUsd: 6.25
14836
+ cacheWritePer1MUsd: 6.25,
14837
+ cacheWrite1hPer1MUsd: 10
14435
14838
  },
14436
14839
  "azure_ai/claude-opus-4-6": {
14437
14840
  inputPer1MUsd: 5,
14438
14841
  outputPer1MUsd: 25,
14439
14842
  cacheReadPer1MUsd: 0.5,
14440
- cacheWritePer1MUsd: 6.25
14843
+ cacheWritePer1MUsd: 6.25,
14844
+ cacheWrite1hPer1MUsd: 10
14441
14845
  },
14442
14846
  "azure_ai/claude-opus-4-7": {
14443
14847
  inputPer1MUsd: 5,
14444
14848
  outputPer1MUsd: 25,
14445
14849
  cacheReadPer1MUsd: 0.5,
14446
- cacheWritePer1MUsd: 6.25
14850
+ cacheWritePer1MUsd: 6.25,
14851
+ cacheWrite1hPer1MUsd: 10
14447
14852
  },
14448
14853
  "azure_ai/claude-opus-4-8": {
14449
14854
  inputPer1MUsd: 5,
14450
14855
  outputPer1MUsd: 25,
14451
14856
  cacheReadPer1MUsd: 0.5,
14452
- cacheWritePer1MUsd: 6.25
14857
+ cacheWritePer1MUsd: 6.25,
14858
+ cacheWrite1hPer1MUsd: 10
14453
14859
  },
14454
14860
  "azure_ai/claude-opus-5": {
14455
14861
  inputPer1MUsd: 5,
14456
14862
  outputPer1MUsd: 25,
14457
14863
  cacheReadPer1MUsd: 0.5,
14458
- cacheWritePer1MUsd: 6.25
14864
+ cacheWritePer1MUsd: 6.25,
14865
+ cacheWrite1hPer1MUsd: 10
14459
14866
  },
14460
14867
  "azure_ai/claude-opus-5-5": {
14461
14868
  inputPer1MUsd: 4,
14462
14869
  outputPer1MUsd: 20,
14463
14870
  cacheReadPer1MUsd: 0.19999999999999998,
14464
- cacheWritePer1MUsd: 5
14871
+ cacheWritePer1MUsd: 5,
14872
+ cacheWrite1hPer1MUsd: 8
14465
14873
  },
14466
14874
  "azure_ai/claude-sonnet-4-5": {
14467
14875
  inputPer1MUsd: 3,
14468
14876
  outputPer1MUsd: 15,
14469
14877
  cacheReadPer1MUsd: 0.3,
14470
- cacheWritePer1MUsd: 3.75
14878
+ cacheWritePer1MUsd: 3.75,
14879
+ cacheWrite1hPer1MUsd: 6
14471
14880
  },
14472
14881
  "azure_ai/claude-sonnet-4-6": {
14473
14882
  inputPer1MUsd: 3,
14474
14883
  outputPer1MUsd: 15,
14475
14884
  cacheReadPer1MUsd: 0.3,
14476
- cacheWritePer1MUsd: 3.75
14885
+ cacheWritePer1MUsd: 3.75,
14886
+ cacheWrite1hPer1MUsd: 6
14477
14887
  },
14478
14888
  "azure_ai/claude-sonnet-5": {
14479
14889
  inputPer1MUsd: 2,
14480
14890
  outputPer1MUsd: 10,
14481
14891
  cacheReadPer1MUsd: 0.19999999999999998,
14482
- cacheWritePer1MUsd: 2.5
14892
+ cacheWritePer1MUsd: 2.5,
14893
+ cacheWrite1hPer1MUsd: 4
14483
14894
  },
14484
14895
  "azure_ai/claude-sonnet-5-5": {
14485
14896
  inputPer1MUsd: 2,
14486
14897
  outputPer1MUsd: 10,
14487
14898
  cacheReadPer1MUsd: 0.19999999999999998,
14488
- cacheWritePer1MUsd: 2.5
14899
+ cacheWritePer1MUsd: 2.5,
14900
+ cacheWrite1hPer1MUsd: 4
14489
14901
  },
14490
14902
  "azure_ai/codestral-2501": {
14491
14903
  inputPer1MUsd: 0.3,
@@ -15507,61 +15919,71 @@ var litellm_pricing_snapshot_default = {
15507
15919
  inputPer1MUsd: 12,
15508
15920
  outputPer1MUsd: 60,
15509
15921
  cacheReadPer1MUsd: 0.3,
15510
- cacheWritePer1MUsd: 15
15922
+ cacheWritePer1MUsd: 15,
15923
+ cacheWrite1hPer1MUsd: 24
15511
15924
  },
15512
15925
  "bedrock/us-gov-east-1/anthropic.claude-haiku-4-5-20251001-v1:0": {
15513
15926
  inputPer1MUsd: 1.2,
15514
15927
  outputPer1MUsd: 6,
15515
15928
  cacheReadPer1MUsd: 0.12,
15516
- cacheWritePer1MUsd: 1.5
15929
+ cacheWritePer1MUsd: 1.5,
15930
+ cacheWrite1hPer1MUsd: 2.4
15517
15931
  },
15518
15932
  "bedrock/us-gov-east-1/anthropic.claude-haiku-5-5": {
15519
15933
  inputPer1MUsd: 0.12,
15520
15934
  outputPer1MUsd: 0.6,
15521
15935
  cacheReadPer1MUsd: 0.012,
15522
- cacheWritePer1MUsd: 0.15
15936
+ cacheWritePer1MUsd: 0.15,
15937
+ cacheWrite1hPer1MUsd: 0.24
15523
15938
  },
15524
15939
  "bedrock/us-gov-east-1/anthropic.claude-opus-4-8": {
15525
15940
  inputPer1MUsd: 6,
15526
15941
  outputPer1MUsd: 30,
15527
15942
  cacheReadPer1MUsd: 0.6,
15528
- cacheWritePer1MUsd: 7.5
15943
+ cacheWritePer1MUsd: 7.5,
15944
+ cacheWrite1hPer1MUsd: 12
15529
15945
  },
15530
15946
  "bedrock/us-gov-east-1/anthropic.claude-opus-5": {
15531
15947
  inputPer1MUsd: 6,
15532
15948
  outputPer1MUsd: 30,
15533
15949
  cacheReadPer1MUsd: 0.6,
15534
- cacheWritePer1MUsd: 7.5
15950
+ cacheWritePer1MUsd: 7.5,
15951
+ cacheWrite1hPer1MUsd: 12
15535
15952
  },
15536
15953
  "bedrock/us-gov-east-1/anthropic.claude-opus-5-5": {
15537
15954
  inputPer1MUsd: 4.8,
15538
15955
  outputPer1MUsd: 24,
15539
15956
  cacheReadPer1MUsd: 0.24,
15540
- cacheWritePer1MUsd: 6
15957
+ cacheWritePer1MUsd: 6,
15958
+ cacheWrite1hPer1MUsd: 9.6
15541
15959
  },
15542
15960
  "bedrock/us-gov-east-1/anthropic.claude-sonnet-4-5-20250929-v1:0": {
15543
15961
  inputPer1MUsd: 3.5999999999999996,
15544
15962
  outputPer1MUsd: 18,
15545
15963
  cacheReadPer1MUsd: 0.36,
15546
- cacheWritePer1MUsd: 4.5
15964
+ cacheWritePer1MUsd: 4.5,
15965
+ cacheWrite1hPer1MUsd: 7.199999999999999
15547
15966
  },
15548
15967
  "bedrock/us-gov-east-1/anthropic.claude-sonnet-5": {
15549
15968
  inputPer1MUsd: 2.4,
15550
15969
  outputPer1MUsd: 12,
15551
15970
  cacheReadPer1MUsd: 0.24,
15552
- cacheWritePer1MUsd: 3
15971
+ cacheWritePer1MUsd: 3,
15972
+ cacheWrite1hPer1MUsd: 4.8
15553
15973
  },
15554
15974
  "bedrock/us-gov-east-1/anthropic.claude-sonnet-5-5": {
15555
15975
  inputPer1MUsd: 2.4,
15556
15976
  outputPer1MUsd: 12,
15557
15977
  cacheReadPer1MUsd: 0.24,
15558
- cacheWritePer1MUsd: 3
15978
+ cacheWritePer1MUsd: 3,
15979
+ cacheWrite1hPer1MUsd: 4.8
15559
15980
  },
15560
15981
  "bedrock/us-gov-east-1/claude-sonnet-4-5-20250929-v1:0": {
15561
15982
  inputPer1MUsd: 3.5999999999999996,
15562
15983
  outputPer1MUsd: 18,
15563
15984
  cacheReadPer1MUsd: 0.36,
15564
- cacheWritePer1MUsd: 4.5
15985
+ cacheWritePer1MUsd: 4.5,
15986
+ cacheWrite1hPer1MUsd: 7.199999999999999
15565
15987
  },
15566
15988
  "bedrock/us-gov-east-1/meta.llama3-70b-instruct-v1:0": {
15567
15989
  inputPer1MUsd: 2.65,
@@ -15638,61 +16060,71 @@ var litellm_pricing_snapshot_default = {
15638
16060
  inputPer1MUsd: 12,
15639
16061
  outputPer1MUsd: 60,
15640
16062
  cacheReadPer1MUsd: 0.3,
15641
- cacheWritePer1MUsd: 15
16063
+ cacheWritePer1MUsd: 15,
16064
+ cacheWrite1hPer1MUsd: 24
15642
16065
  },
15643
16066
  "bedrock/us-gov-west-1/anthropic.claude-haiku-4-5-20251001-v1:0": {
15644
16067
  inputPer1MUsd: 1.2,
15645
16068
  outputPer1MUsd: 6,
15646
16069
  cacheReadPer1MUsd: 0.12,
15647
- cacheWritePer1MUsd: 1.5
16070
+ cacheWritePer1MUsd: 1.5,
16071
+ cacheWrite1hPer1MUsd: 2.4
15648
16072
  },
15649
16073
  "bedrock/us-gov-west-1/anthropic.claude-haiku-5-5": {
15650
16074
  inputPer1MUsd: 0.12,
15651
16075
  outputPer1MUsd: 0.6,
15652
16076
  cacheReadPer1MUsd: 0.012,
15653
- cacheWritePer1MUsd: 0.15
16077
+ cacheWritePer1MUsd: 0.15,
16078
+ cacheWrite1hPer1MUsd: 0.24
15654
16079
  },
15655
16080
  "bedrock/us-gov-west-1/anthropic.claude-opus-4-8": {
15656
16081
  inputPer1MUsd: 6,
15657
16082
  outputPer1MUsd: 30,
15658
16083
  cacheReadPer1MUsd: 0.6,
15659
- cacheWritePer1MUsd: 7.5
16084
+ cacheWritePer1MUsd: 7.5,
16085
+ cacheWrite1hPer1MUsd: 12
15660
16086
  },
15661
16087
  "bedrock/us-gov-west-1/anthropic.claude-opus-5": {
15662
16088
  inputPer1MUsd: 6,
15663
16089
  outputPer1MUsd: 30,
15664
16090
  cacheReadPer1MUsd: 0.6,
15665
- cacheWritePer1MUsd: 7.5
16091
+ cacheWritePer1MUsd: 7.5,
16092
+ cacheWrite1hPer1MUsd: 12
15666
16093
  },
15667
16094
  "bedrock/us-gov-west-1/anthropic.claude-opus-5-5": {
15668
16095
  inputPer1MUsd: 4.8,
15669
16096
  outputPer1MUsd: 24,
15670
16097
  cacheReadPer1MUsd: 0.24,
15671
- cacheWritePer1MUsd: 6
16098
+ cacheWritePer1MUsd: 6,
16099
+ cacheWrite1hPer1MUsd: 9.6
15672
16100
  },
15673
16101
  "bedrock/us-gov-west-1/anthropic.claude-sonnet-4-5-20250929-v1:0": {
15674
16102
  inputPer1MUsd: 3.5999999999999996,
15675
16103
  outputPer1MUsd: 18,
15676
16104
  cacheReadPer1MUsd: 0.36,
15677
- cacheWritePer1MUsd: 4.5
16105
+ cacheWritePer1MUsd: 4.5,
16106
+ cacheWrite1hPer1MUsd: 7.199999999999999
15678
16107
  },
15679
16108
  "bedrock/us-gov-west-1/anthropic.claude-sonnet-5": {
15680
16109
  inputPer1MUsd: 2.4,
15681
16110
  outputPer1MUsd: 12,
15682
16111
  cacheReadPer1MUsd: 0.24,
15683
- cacheWritePer1MUsd: 3
16112
+ cacheWritePer1MUsd: 3,
16113
+ cacheWrite1hPer1MUsd: 4.8
15684
16114
  },
15685
16115
  "bedrock/us-gov-west-1/anthropic.claude-sonnet-5-5": {
15686
16116
  inputPer1MUsd: 2.4,
15687
16117
  outputPer1MUsd: 12,
15688
16118
  cacheReadPer1MUsd: 0.24,
15689
- cacheWritePer1MUsd: 3
16119
+ cacheWritePer1MUsd: 3,
16120
+ cacheWrite1hPer1MUsd: 4.8
15690
16121
  },
15691
16122
  "bedrock/us-gov-west-1/claude-sonnet-4-5-20250929-v1:0": {
15692
16123
  inputPer1MUsd: 3.5999999999999996,
15693
16124
  outputPer1MUsd: 18,
15694
16125
  cacheReadPer1MUsd: 0.36,
15695
- cacheWritePer1MUsd: 4.5
16126
+ cacheWritePer1MUsd: 4.5,
16127
+ cacheWrite1hPer1MUsd: 7.199999999999999
15696
16128
  },
15697
16129
  "bedrock/us-gov-west-1/meta.llama3-70b-instruct-v1:0": {
15698
16130
  inputPer1MUsd: 2.65,
@@ -15796,25 +16228,29 @@ var litellm_pricing_snapshot_default = {
15796
16228
  inputPer1MUsd: 1,
15797
16229
  outputPer1MUsd: 5,
15798
16230
  cacheReadPer1MUsd: 0.09999999999999999,
15799
- cacheWritePer1MUsd: 1.25
16231
+ cacheWritePer1MUsd: 1.25,
16232
+ cacheWrite1hPer1MUsd: 2
15800
16233
  },
15801
16234
  "bedrock_mantle/anthropic.claude-haiku-5-5": {
15802
16235
  inputPer1MUsd: 0.11,
15803
16236
  outputPer1MUsd: 0.55,
15804
16237
  cacheReadPer1MUsd: 0.011,
15805
- cacheWritePer1MUsd: 0.1375
16238
+ cacheWritePer1MUsd: 0.1375,
16239
+ cacheWrite1hPer1MUsd: 0.22
15806
16240
  },
15807
16241
  "bedrock_mantle/anthropic.claude-opus-5-5": {
15808
16242
  inputPer1MUsd: 4.4,
15809
16243
  outputPer1MUsd: 22,
15810
16244
  cacheReadPer1MUsd: 0.22,
15811
- cacheWritePer1MUsd: 5.5
16245
+ cacheWritePer1MUsd: 5.5,
16246
+ cacheWrite1hPer1MUsd: 8.8
15812
16247
  },
15813
16248
  "bedrock_mantle/anthropic.claude-sonnet-5-5": {
15814
16249
  inputPer1MUsd: 2.2,
15815
16250
  outputPer1MUsd: 11,
15816
16251
  cacheReadPer1MUsd: 0.22,
15817
- cacheWritePer1MUsd: 2.75
16252
+ cacheWritePer1MUsd: 2.75,
16253
+ cacheWrite1hPer1MUsd: 4.4
15818
16254
  },
15819
16255
  "bedrock_mantle/deepseek.v3.1": {
15820
16256
  inputPer1MUsd: 0.58,
@@ -15962,19 +16398,22 @@ var litellm_pricing_snapshot_default = {
15962
16398
  inputPer1MUsd: 0.12,
15963
16399
  outputPer1MUsd: 0.6,
15964
16400
  cacheReadPer1MUsd: 0.012,
15965
- cacheWritePer1MUsd: 0.15
16401
+ cacheWritePer1MUsd: 0.15,
16402
+ cacheWrite1hPer1MUsd: 0.24
15966
16403
  },
15967
16404
  "bedrock_mantle/us-gov-west-1/anthropic.claude-opus-5-5": {
15968
16405
  inputPer1MUsd: 4.8,
15969
16406
  outputPer1MUsd: 24,
15970
16407
  cacheReadPer1MUsd: 0.24,
15971
- cacheWritePer1MUsd: 6
16408
+ cacheWritePer1MUsd: 6,
16409
+ cacheWrite1hPer1MUsd: 9.6
15972
16410
  },
15973
16411
  "bedrock_mantle/us-gov-west-1/anthropic.claude-sonnet-5-5": {
15974
16412
  inputPer1MUsd: 2.4,
15975
16413
  outputPer1MUsd: 12,
15976
16414
  cacheReadPer1MUsd: 0.24,
15977
- cacheWritePer1MUsd: 3
16415
+ cacheWritePer1MUsd: 3,
16416
+ cacheWrite1hPer1MUsd: 4.8
15978
16417
  },
15979
16418
  "bedrock_mantle/us-gov-west-1/google.gemma-4-26b-a4b": {
15980
16419
  inputPer1MUsd: 0.156,
@@ -16095,139 +16534,162 @@ var litellm_pricing_snapshot_default = {
16095
16534
  inputPer1MUsd: 10,
16096
16535
  outputPer1MUsd: 50,
16097
16536
  cacheReadPer1MUsd: 1,
16098
- cacheWritePer1MUsd: 12.5
16537
+ cacheWritePer1MUsd: 12.5,
16538
+ cacheWrite1hPer1MUsd: 20
16099
16539
  },
16100
16540
  "claude-fable-5-1": {
16101
16541
  inputPer1MUsd: 10,
16102
16542
  outputPer1MUsd: 50,
16103
16543
  cacheReadPer1MUsd: 0.25,
16104
- cacheWritePer1MUsd: 12.5
16544
+ cacheWritePer1MUsd: 12.5,
16545
+ cacheWrite1hPer1MUsd: 20
16105
16546
  },
16106
16547
  "claude-haiku-4-5": {
16107
16548
  inputPer1MUsd: 1,
16108
16549
  outputPer1MUsd: 5,
16109
16550
  cacheReadPer1MUsd: 0.09999999999999999,
16110
- cacheWritePer1MUsd: 1.25
16551
+ cacheWritePer1MUsd: 1.25,
16552
+ cacheWrite1hPer1MUsd: 2
16111
16553
  },
16112
16554
  "claude-haiku-4-5-20251001": {
16113
16555
  inputPer1MUsd: 1,
16114
16556
  outputPer1MUsd: 5,
16115
16557
  cacheReadPer1MUsd: 0.09999999999999999,
16116
- cacheWritePer1MUsd: 1.25
16558
+ cacheWritePer1MUsd: 1.25,
16559
+ cacheWrite1hPer1MUsd: 2
16117
16560
  },
16118
16561
  "claude-haiku-5-5": {
16119
16562
  inputPer1MUsd: 0.09999999999999999,
16120
16563
  outputPer1MUsd: 0.5,
16121
16564
  cacheReadPer1MUsd: 0.01,
16122
- cacheWritePer1MUsd: 0.125
16565
+ cacheWritePer1MUsd: 0.125,
16566
+ cacheWrite1hPer1MUsd: 0.19999999999999998
16123
16567
  },
16124
16568
  "claude-mythos-5": {
16125
16569
  inputPer1MUsd: 10,
16126
16570
  outputPer1MUsd: 50,
16127
16571
  cacheReadPer1MUsd: 1,
16128
- cacheWritePer1MUsd: 12.5
16572
+ cacheWritePer1MUsd: 12.5,
16573
+ cacheWrite1hPer1MUsd: 20
16129
16574
  },
16130
16575
  "claude-mythos-5-1": {
16131
16576
  inputPer1MUsd: 10,
16132
16577
  outputPer1MUsd: 50,
16133
16578
  cacheReadPer1MUsd: 0.25,
16134
- cacheWritePer1MUsd: 12.5
16579
+ cacheWritePer1MUsd: 12.5,
16580
+ cacheWrite1hPer1MUsd: 20
16135
16581
  },
16136
16582
  "claude-mythos-preview": {
16137
16583
  inputPer1MUsd: 10,
16138
16584
  outputPer1MUsd: 50,
16139
16585
  cacheReadPer1MUsd: 1,
16140
- cacheWritePer1MUsd: 12.5
16586
+ cacheWritePer1MUsd: 12.5,
16587
+ cacheWrite1hPer1MUsd: 20
16141
16588
  },
16142
16589
  "claude-opus-4-5": {
16143
16590
  inputPer1MUsd: 5,
16144
16591
  outputPer1MUsd: 25,
16145
16592
  cacheReadPer1MUsd: 0.5,
16146
- cacheWritePer1MUsd: 6.25
16593
+ cacheWritePer1MUsd: 6.25,
16594
+ cacheWrite1hPer1MUsd: 10
16147
16595
  },
16148
16596
  "claude-opus-4-5-20251101": {
16149
16597
  inputPer1MUsd: 5,
16150
16598
  outputPer1MUsd: 25,
16151
16599
  cacheReadPer1MUsd: 0.5,
16152
- cacheWritePer1MUsd: 6.25
16600
+ cacheWritePer1MUsd: 6.25,
16601
+ cacheWrite1hPer1MUsd: 10
16153
16602
  },
16154
16603
  "claude-opus-4-6": {
16155
16604
  inputPer1MUsd: 5,
16156
16605
  outputPer1MUsd: 25,
16157
16606
  cacheReadPer1MUsd: 0.5,
16158
- cacheWritePer1MUsd: 6.25
16607
+ cacheWritePer1MUsd: 6.25,
16608
+ cacheWrite1hPer1MUsd: 10
16159
16609
  },
16160
16610
  "claude-opus-4-6-20260205": {
16161
16611
  inputPer1MUsd: 5,
16162
16612
  outputPer1MUsd: 25,
16163
16613
  cacheReadPer1MUsd: 0.5,
16164
- cacheWritePer1MUsd: 6.25
16614
+ cacheWritePer1MUsd: 6.25,
16615
+ cacheWrite1hPer1MUsd: 10
16165
16616
  },
16166
16617
  "claude-opus-4-7": {
16167
16618
  inputPer1MUsd: 5,
16168
16619
  outputPer1MUsd: 25,
16169
16620
  cacheReadPer1MUsd: 0.5,
16170
- cacheWritePer1MUsd: 6.25
16621
+ cacheWritePer1MUsd: 6.25,
16622
+ cacheWrite1hPer1MUsd: 10
16171
16623
  },
16172
16624
  "claude-opus-4-7-20260416": {
16173
16625
  inputPer1MUsd: 5,
16174
16626
  outputPer1MUsd: 25,
16175
16627
  cacheReadPer1MUsd: 0.5,
16176
- cacheWritePer1MUsd: 6.25
16628
+ cacheWritePer1MUsd: 6.25,
16629
+ cacheWrite1hPer1MUsd: 10
16177
16630
  },
16178
16631
  "claude-opus-4-8": {
16179
16632
  inputPer1MUsd: 5,
16180
16633
  outputPer1MUsd: 25,
16181
16634
  cacheReadPer1MUsd: 0.5,
16182
- cacheWritePer1MUsd: 6.25
16635
+ cacheWritePer1MUsd: 6.25,
16636
+ cacheWrite1hPer1MUsd: 10
16183
16637
  },
16184
16638
  "claude-opus-5": {
16185
16639
  inputPer1MUsd: 5,
16186
16640
  outputPer1MUsd: 25,
16187
16641
  cacheReadPer1MUsd: 0.5,
16188
- cacheWritePer1MUsd: 6.25
16642
+ cacheWritePer1MUsd: 6.25,
16643
+ cacheWrite1hPer1MUsd: 10
16189
16644
  },
16190
16645
  "claude-opus-5-5": {
16191
16646
  inputPer1MUsd: 4,
16192
16647
  outputPer1MUsd: 20,
16193
16648
  cacheReadPer1MUsd: 0.19999999999999998,
16194
- cacheWritePer1MUsd: 5
16649
+ cacheWritePer1MUsd: 5,
16650
+ cacheWrite1hPer1MUsd: 8
16195
16651
  },
16196
16652
  "claude-sonnet-4-5": {
16197
16653
  inputPer1MUsd: 3,
16198
16654
  outputPer1MUsd: 15,
16199
16655
  cacheReadPer1MUsd: 0.3,
16200
- cacheWritePer1MUsd: 3.75
16656
+ cacheWritePer1MUsd: 3.75,
16657
+ cacheWrite1hPer1MUsd: 6
16201
16658
  },
16202
16659
  "claude-sonnet-4-5-20250929": {
16203
16660
  inputPer1MUsd: 3,
16204
16661
  outputPer1MUsd: 15,
16205
16662
  cacheReadPer1MUsd: 0.3,
16206
- cacheWritePer1MUsd: 3.75
16663
+ cacheWritePer1MUsd: 3.75,
16664
+ cacheWrite1hPer1MUsd: 6
16207
16665
  },
16208
16666
  "claude-sonnet-4-5-20250929-v1:0": {
16209
16667
  inputPer1MUsd: 3,
16210
16668
  outputPer1MUsd: 15,
16211
16669
  cacheReadPer1MUsd: 0.3,
16212
- cacheWritePer1MUsd: 3.75
16670
+ cacheWritePer1MUsd: 3.75,
16671
+ cacheWrite1hPer1MUsd: 6
16213
16672
  },
16214
16673
  "claude-sonnet-4-6": {
16215
16674
  inputPer1MUsd: 3,
16216
16675
  outputPer1MUsd: 15,
16217
16676
  cacheReadPer1MUsd: 0.3,
16218
- cacheWritePer1MUsd: 3.75
16677
+ cacheWritePer1MUsd: 3.75,
16678
+ cacheWrite1hPer1MUsd: 6
16219
16679
  },
16220
16680
  "claude-sonnet-5": {
16221
16681
  inputPer1MUsd: 2,
16222
16682
  outputPer1MUsd: 10,
16223
16683
  cacheReadPer1MUsd: 0.19999999999999998,
16224
- cacheWritePer1MUsd: 2.5
16684
+ cacheWritePer1MUsd: 2.5,
16685
+ cacheWrite1hPer1MUsd: 4
16225
16686
  },
16226
16687
  "claude-sonnet-5-5": {
16227
16688
  inputPer1MUsd: 2,
16228
16689
  outputPer1MUsd: 10,
16229
16690
  cacheReadPer1MUsd: 0.09999999999999999,
16230
- cacheWritePer1MUsd: 2.5
16691
+ cacheWritePer1MUsd: 2.5,
16692
+ cacheWrite1hPer1MUsd: 4
16231
16693
  },
16232
16694
  "cloudflare/@cf/aisingapore/gemma-sea-lion-v4-27b-it": {
16233
16695
  inputPer1MUsd: 0.351,
@@ -16690,7 +17152,8 @@ var litellm_pricing_snapshot_default = {
16690
17152
  inputPer1MUsd: 4.00001,
16691
17153
  outputPer1MUsd: 19.99998,
16692
17154
  cacheReadPer1MUsd: 0.19999,
16693
- cacheWritePer1MUsd: 5.00003
17155
+ cacheWritePer1MUsd: 5.00003,
17156
+ cacheWrite1hPer1MUsd: 8.00002
16694
17157
  },
16695
17158
  "databricks/databricks-claude-sonnet-4": {
16696
17159
  inputPer1MUsd: 2.9999900000000004,
@@ -17780,25 +18243,29 @@ var litellm_pricing_snapshot_default = {
17780
18243
  inputPer1MUsd: 11,
17781
18244
  outputPer1MUsd: 55,
17782
18245
  cacheReadPer1MUsd: 1.1,
17783
- cacheWritePer1MUsd: 13.75
18246
+ cacheWritePer1MUsd: 13.75,
18247
+ cacheWrite1hPer1MUsd: 22
17784
18248
  },
17785
18249
  "eu.anthropic.claude-fable-5-1": {
17786
18250
  inputPer1MUsd: 11,
17787
18251
  outputPer1MUsd: 55,
17788
18252
  cacheReadPer1MUsd: 0.275,
17789
- cacheWritePer1MUsd: 13.75
18253
+ cacheWritePer1MUsd: 13.75,
18254
+ cacheWrite1hPer1MUsd: 22
17790
18255
  },
17791
18256
  "eu.anthropic.claude-haiku-4-5-20251001-v1:0": {
17792
18257
  inputPer1MUsd: 1.1,
17793
18258
  outputPer1MUsd: 5.5,
17794
18259
  cacheReadPer1MUsd: 0.11,
17795
- cacheWritePer1MUsd: 1.375
18260
+ cacheWritePer1MUsd: 1.375,
18261
+ cacheWrite1hPer1MUsd: 2.2
17796
18262
  },
17797
18263
  "eu.anthropic.claude-haiku-5-5": {
17798
18264
  inputPer1MUsd: 0.11,
17799
18265
  outputPer1MUsd: 0.55,
17800
18266
  cacheReadPer1MUsd: 0.011,
17801
- cacheWritePer1MUsd: 0.1375
18267
+ cacheWritePer1MUsd: 0.1375,
18268
+ cacheWrite1hPer1MUsd: 0.22
17802
18269
  },
17803
18270
  "eu.anthropic.claude-opus-4-1-20250805-v1:0": {
17804
18271
  inputPer1MUsd: 15,
@@ -17816,37 +18283,43 @@ var litellm_pricing_snapshot_default = {
17816
18283
  inputPer1MUsd: 5.5,
17817
18284
  outputPer1MUsd: 27.5,
17818
18285
  cacheReadPer1MUsd: 0.55,
17819
- cacheWritePer1MUsd: 6.875
18286
+ cacheWritePer1MUsd: 6.875,
18287
+ cacheWrite1hPer1MUsd: 11
17820
18288
  },
17821
18289
  "eu.anthropic.claude-opus-4-6-v1": {
17822
18290
  inputPer1MUsd: 5.5,
17823
18291
  outputPer1MUsd: 27.5,
17824
18292
  cacheReadPer1MUsd: 0.55,
17825
- cacheWritePer1MUsd: 6.875
18293
+ cacheWritePer1MUsd: 6.875,
18294
+ cacheWrite1hPer1MUsd: 11
17826
18295
  },
17827
18296
  "eu.anthropic.claude-opus-4-7": {
17828
18297
  inputPer1MUsd: 5.5,
17829
18298
  outputPer1MUsd: 27.5,
17830
18299
  cacheReadPer1MUsd: 0.55,
17831
- cacheWritePer1MUsd: 6.875
18300
+ cacheWritePer1MUsd: 6.875,
18301
+ cacheWrite1hPer1MUsd: 11
17832
18302
  },
17833
18303
  "eu.anthropic.claude-opus-4-8": {
17834
18304
  inputPer1MUsd: 5.5,
17835
18305
  outputPer1MUsd: 27.5,
17836
18306
  cacheReadPer1MUsd: 0.55,
17837
- cacheWritePer1MUsd: 6.875
18307
+ cacheWritePer1MUsd: 6.875,
18308
+ cacheWrite1hPer1MUsd: 11
17838
18309
  },
17839
18310
  "eu.anthropic.claude-opus-5": {
17840
18311
  inputPer1MUsd: 5.5,
17841
18312
  outputPer1MUsd: 27.5,
17842
18313
  cacheReadPer1MUsd: 0.55,
17843
- cacheWritePer1MUsd: 6.875
18314
+ cacheWritePer1MUsd: 6.875,
18315
+ cacheWrite1hPer1MUsd: 11
17844
18316
  },
17845
18317
  "eu.anthropic.claude-opus-5-5": {
17846
18318
  inputPer1MUsd: 4.4,
17847
18319
  outputPer1MUsd: 22,
17848
18320
  cacheReadPer1MUsd: 0.22,
17849
- cacheWritePer1MUsd: 5.5
18321
+ cacheWritePer1MUsd: 5.5,
18322
+ cacheWrite1hPer1MUsd: 8.8
17850
18323
  },
17851
18324
  "eu.anthropic.claude-sonnet-4-20250514-v1:0": {
17852
18325
  inputPer1MUsd: 3,
@@ -17858,25 +18331,29 @@ var litellm_pricing_snapshot_default = {
17858
18331
  inputPer1MUsd: 3.3000000000000003,
17859
18332
  outputPer1MUsd: 16.5,
17860
18333
  cacheReadPer1MUsd: 0.33,
17861
- cacheWritePer1MUsd: 4.125
18334
+ cacheWritePer1MUsd: 4.125,
18335
+ cacheWrite1hPer1MUsd: 6.6000000000000005
17862
18336
  },
17863
18337
  "eu.anthropic.claude-sonnet-4-6": {
17864
18338
  inputPer1MUsd: 3.3000000000000003,
17865
18339
  outputPer1MUsd: 16.5,
17866
18340
  cacheReadPer1MUsd: 0.33,
17867
- cacheWritePer1MUsd: 4.125
18341
+ cacheWritePer1MUsd: 4.125,
18342
+ cacheWrite1hPer1MUsd: 6.6000000000000005
17868
18343
  },
17869
18344
  "eu.anthropic.claude-sonnet-5": {
17870
18345
  inputPer1MUsd: 2.2,
17871
18346
  outputPer1MUsd: 11,
17872
18347
  cacheReadPer1MUsd: 0.22,
17873
- cacheWritePer1MUsd: 2.75
18348
+ cacheWritePer1MUsd: 2.75,
18349
+ cacheWrite1hPer1MUsd: 4.4
17874
18350
  },
17875
18351
  "eu.anthropic.claude-sonnet-5-5": {
17876
18352
  inputPer1MUsd: 2.2,
17877
18353
  outputPer1MUsd: 11,
17878
18354
  cacheReadPer1MUsd: 0.22,
17879
- cacheWritePer1MUsd: 2.75
18355
+ cacheWritePer1MUsd: 2.75,
18356
+ cacheWrite1hPer1MUsd: 4.4
17880
18357
  },
17881
18358
  "eu.deepseek.v3.2": {
17882
18359
  inputPer1MUsd: 0.74,
@@ -20051,67 +20528,78 @@ var litellm_pricing_snapshot_default = {
20051
20528
  inputPer1MUsd: 10,
20052
20529
  outputPer1MUsd: 50,
20053
20530
  cacheReadPer1MUsd: 1,
20054
- cacheWritePer1MUsd: 12.5
20531
+ cacheWritePer1MUsd: 12.5,
20532
+ cacheWrite1hPer1MUsd: 20
20055
20533
  },
20056
20534
  "global.anthropic.claude-fable-5-1": {
20057
20535
  inputPer1MUsd: 10,
20058
20536
  outputPer1MUsd: 50,
20059
20537
  cacheReadPer1MUsd: 0.25,
20060
- cacheWritePer1MUsd: 12.5
20538
+ cacheWritePer1MUsd: 12.5,
20539
+ cacheWrite1hPer1MUsd: 20
20061
20540
  },
20062
20541
  "global.anthropic.claude-haiku-4-5-20251001-v1:0": {
20063
20542
  inputPer1MUsd: 1,
20064
20543
  outputPer1MUsd: 5,
20065
20544
  cacheReadPer1MUsd: 0.09999999999999999,
20066
- cacheWritePer1MUsd: 1.25
20545
+ cacheWritePer1MUsd: 1.25,
20546
+ cacheWrite1hPer1MUsd: 2
20067
20547
  },
20068
20548
  "global.anthropic.claude-haiku-5-5": {
20069
20549
  inputPer1MUsd: 0.09999999999999999,
20070
20550
  outputPer1MUsd: 0.5,
20071
20551
  cacheReadPer1MUsd: 0.01,
20072
- cacheWritePer1MUsd: 0.125
20552
+ cacheWritePer1MUsd: 0.125,
20553
+ cacheWrite1hPer1MUsd: 0.19999999999999998
20073
20554
  },
20074
20555
  "global.anthropic.claude-mythos-5-1": {
20075
20556
  inputPer1MUsd: 10,
20076
20557
  outputPer1MUsd: 50,
20077
20558
  cacheReadPer1MUsd: 0.25,
20078
- cacheWritePer1MUsd: 12.5
20559
+ cacheWritePer1MUsd: 12.5,
20560
+ cacheWrite1hPer1MUsd: 20
20079
20561
  },
20080
20562
  "global.anthropic.claude-opus-4-5-20251101-v1:0": {
20081
20563
  inputPer1MUsd: 5,
20082
20564
  outputPer1MUsd: 25,
20083
20565
  cacheReadPer1MUsd: 0.5,
20084
- cacheWritePer1MUsd: 6.25
20566
+ cacheWritePer1MUsd: 6.25,
20567
+ cacheWrite1hPer1MUsd: 10
20085
20568
  },
20086
20569
  "global.anthropic.claude-opus-4-6-v1": {
20087
20570
  inputPer1MUsd: 5,
20088
20571
  outputPer1MUsd: 25,
20089
20572
  cacheReadPer1MUsd: 0.5,
20090
- cacheWritePer1MUsd: 6.25
20573
+ cacheWritePer1MUsd: 6.25,
20574
+ cacheWrite1hPer1MUsd: 10
20091
20575
  },
20092
20576
  "global.anthropic.claude-opus-4-7": {
20093
20577
  inputPer1MUsd: 5,
20094
20578
  outputPer1MUsd: 25,
20095
20579
  cacheReadPer1MUsd: 0.5,
20096
- cacheWritePer1MUsd: 6.25
20580
+ cacheWritePer1MUsd: 6.25,
20581
+ cacheWrite1hPer1MUsd: 10
20097
20582
  },
20098
20583
  "global.anthropic.claude-opus-4-8": {
20099
20584
  inputPer1MUsd: 5,
20100
20585
  outputPer1MUsd: 25,
20101
20586
  cacheReadPer1MUsd: 0.5,
20102
- cacheWritePer1MUsd: 6.25
20587
+ cacheWritePer1MUsd: 6.25,
20588
+ cacheWrite1hPer1MUsd: 10
20103
20589
  },
20104
20590
  "global.anthropic.claude-opus-5": {
20105
20591
  inputPer1MUsd: 5,
20106
20592
  outputPer1MUsd: 25,
20107
20593
  cacheReadPer1MUsd: 0.5,
20108
- cacheWritePer1MUsd: 6.25
20594
+ cacheWritePer1MUsd: 6.25,
20595
+ cacheWrite1hPer1MUsd: 10
20109
20596
  },
20110
20597
  "global.anthropic.claude-opus-5-5": {
20111
20598
  inputPer1MUsd: 4,
20112
20599
  outputPer1MUsd: 20,
20113
20600
  cacheReadPer1MUsd: 0.19999999999999998,
20114
- cacheWritePer1MUsd: 5
20601
+ cacheWritePer1MUsd: 5,
20602
+ cacheWrite1hPer1MUsd: 8
20115
20603
  },
20116
20604
  "global.anthropic.claude-sonnet-4-20250514-v1:0": {
20117
20605
  inputPer1MUsd: 3,
@@ -20123,25 +20611,29 @@ var litellm_pricing_snapshot_default = {
20123
20611
  inputPer1MUsd: 3,
20124
20612
  outputPer1MUsd: 15,
20125
20613
  cacheReadPer1MUsd: 0.3,
20126
- cacheWritePer1MUsd: 3.75
20614
+ cacheWritePer1MUsd: 3.75,
20615
+ cacheWrite1hPer1MUsd: 6
20127
20616
  },
20128
20617
  "global.anthropic.claude-sonnet-4-6": {
20129
20618
  inputPer1MUsd: 3,
20130
20619
  outputPer1MUsd: 15,
20131
20620
  cacheReadPer1MUsd: 0.3,
20132
- cacheWritePer1MUsd: 3.75
20621
+ cacheWritePer1MUsd: 3.75,
20622
+ cacheWrite1hPer1MUsd: 6
20133
20623
  },
20134
20624
  "global.anthropic.claude-sonnet-5": {
20135
20625
  inputPer1MUsd: 2,
20136
20626
  outputPer1MUsd: 10,
20137
20627
  cacheReadPer1MUsd: 0.19999999999999998,
20138
- cacheWritePer1MUsd: 2.5
20628
+ cacheWritePer1MUsd: 2.5,
20629
+ cacheWrite1hPer1MUsd: 4
20139
20630
  },
20140
20631
  "global.anthropic.claude-sonnet-5-5": {
20141
20632
  inputPer1MUsd: 2,
20142
20633
  outputPer1MUsd: 10,
20143
20634
  cacheReadPer1MUsd: 0.19999999999999998,
20144
- cacheWritePer1MUsd: 2.5
20635
+ cacheWritePer1MUsd: 2.5,
20636
+ cacheWrite1hPer1MUsd: 4
20145
20637
  },
20146
20638
  "global.cohere.embed-v4:0": {
20147
20639
  inputPer1MUsd: 0.12,
@@ -20999,61 +21491,71 @@ var litellm_pricing_snapshot_default = {
20999
21491
  inputPer1MUsd: 1.1,
21000
21492
  outputPer1MUsd: 5.5,
21001
21493
  cacheReadPer1MUsd: 0.11,
21002
- cacheWritePer1MUsd: 1.375
21494
+ cacheWritePer1MUsd: 1.375,
21495
+ cacheWrite1hPer1MUsd: 2.2
21003
21496
  },
21004
21497
  "jp.anthropic.claude-haiku-5-5": {
21005
21498
  inputPer1MUsd: 0.11,
21006
21499
  outputPer1MUsd: 0.55,
21007
21500
  cacheReadPer1MUsd: 0.011,
21008
- cacheWritePer1MUsd: 0.1375
21501
+ cacheWritePer1MUsd: 0.1375,
21502
+ cacheWrite1hPer1MUsd: 0.22
21009
21503
  },
21010
21504
  "jp.anthropic.claude-opus-4-7": {
21011
21505
  inputPer1MUsd: 5.5,
21012
21506
  outputPer1MUsd: 27.5,
21013
21507
  cacheReadPer1MUsd: 0.55,
21014
- cacheWritePer1MUsd: 6.875
21508
+ cacheWritePer1MUsd: 6.875,
21509
+ cacheWrite1hPer1MUsd: 11
21015
21510
  },
21016
21511
  "jp.anthropic.claude-opus-4-8": {
21017
21512
  inputPer1MUsd: 5.5,
21018
21513
  outputPer1MUsd: 27.5,
21019
21514
  cacheReadPer1MUsd: 0.55,
21020
- cacheWritePer1MUsd: 6.875
21515
+ cacheWritePer1MUsd: 6.875,
21516
+ cacheWrite1hPer1MUsd: 11
21021
21517
  },
21022
21518
  "jp.anthropic.claude-opus-5": {
21023
21519
  inputPer1MUsd: 5.5,
21024
21520
  outputPer1MUsd: 27.5,
21025
21521
  cacheReadPer1MUsd: 0.55,
21026
- cacheWritePer1MUsd: 6.875
21522
+ cacheWritePer1MUsd: 6.875,
21523
+ cacheWrite1hPer1MUsd: 11
21027
21524
  },
21028
21525
  "jp.anthropic.claude-opus-5-5": {
21029
21526
  inputPer1MUsd: 4.4,
21030
21527
  outputPer1MUsd: 22,
21031
21528
  cacheReadPer1MUsd: 0.22,
21032
- cacheWritePer1MUsd: 5.5
21529
+ cacheWritePer1MUsd: 5.5,
21530
+ cacheWrite1hPer1MUsd: 8.8
21033
21531
  },
21034
21532
  "jp.anthropic.claude-sonnet-4-5-20250929-v1:0": {
21035
21533
  inputPer1MUsd: 3.3000000000000003,
21036
21534
  outputPer1MUsd: 16.5,
21037
21535
  cacheReadPer1MUsd: 0.33,
21038
- cacheWritePer1MUsd: 4.125
21536
+ cacheWritePer1MUsd: 4.125,
21537
+ cacheWrite1hPer1MUsd: 6.6000000000000005
21039
21538
  },
21040
21539
  "jp.anthropic.claude-sonnet-4-6": {
21041
21540
  inputPer1MUsd: 3.3000000000000003,
21042
21541
  outputPer1MUsd: 16.5,
21043
21542
  cacheReadPer1MUsd: 0.33,
21044
- cacheWritePer1MUsd: 4.125
21543
+ cacheWritePer1MUsd: 4.125,
21544
+ cacheWrite1hPer1MUsd: 6.6000000000000005
21045
21545
  },
21046
21546
  "jp.anthropic.claude-sonnet-5": {
21047
21547
  inputPer1MUsd: 2.2,
21048
21548
  outputPer1MUsd: 11,
21049
21549
  cacheReadPer1MUsd: 0.22,
21050
- cacheWritePer1MUsd: 2.75
21550
+ cacheWritePer1MUsd: 2.75,
21551
+ cacheWrite1hPer1MUsd: 4.4
21051
21552
  },
21052
21553
  "jp.anthropic.claude-sonnet-5-5": {
21053
21554
  inputPer1MUsd: 2.2,
21054
21555
  outputPer1MUsd: 11,
21055
21556
  cacheReadPer1MUsd: 0.22,
21056
- cacheWritePer1MUsd: 2.75
21557
+ cacheWritePer1MUsd: 2.75,
21558
+ cacheWrite1hPer1MUsd: 4.4
21057
21559
  },
21058
21560
  "kimi-k2-thinking-251104": {
21059
21561
  inputPer1MUsd: 0,
@@ -27256,49 +27758,57 @@ var litellm_pricing_snapshot_default = {
27256
27758
  inputPer1MUsd: 12,
27257
27759
  outputPer1MUsd: 60,
27258
27760
  cacheReadPer1MUsd: 0.3,
27259
- cacheWritePer1MUsd: 15
27761
+ cacheWritePer1MUsd: 15,
27762
+ cacheWrite1hPer1MUsd: 24
27260
27763
  },
27261
27764
  "us-gov.anthropic.claude-haiku-5-5": {
27262
27765
  inputPer1MUsd: 0.12,
27263
27766
  outputPer1MUsd: 0.6,
27264
27767
  cacheReadPer1MUsd: 0.012,
27265
- cacheWritePer1MUsd: 0.15
27768
+ cacheWritePer1MUsd: 0.15,
27769
+ cacheWrite1hPer1MUsd: 0.24
27266
27770
  },
27267
27771
  "us-gov.anthropic.claude-opus-4-8": {
27268
27772
  inputPer1MUsd: 6,
27269
27773
  outputPer1MUsd: 30,
27270
27774
  cacheReadPer1MUsd: 0.6,
27271
- cacheWritePer1MUsd: 7.5
27775
+ cacheWritePer1MUsd: 7.5,
27776
+ cacheWrite1hPer1MUsd: 12
27272
27777
  },
27273
27778
  "us-gov.anthropic.claude-opus-5": {
27274
27779
  inputPer1MUsd: 6,
27275
27780
  outputPer1MUsd: 30,
27276
27781
  cacheReadPer1MUsd: 0.6,
27277
- cacheWritePer1MUsd: 7.5
27782
+ cacheWritePer1MUsd: 7.5,
27783
+ cacheWrite1hPer1MUsd: 12
27278
27784
  },
27279
27785
  "us-gov.anthropic.claude-opus-5-5": {
27280
27786
  inputPer1MUsd: 4.8,
27281
27787
  outputPer1MUsd: 24,
27282
27788
  cacheReadPer1MUsd: 0.24,
27283
- cacheWritePer1MUsd: 6
27789
+ cacheWritePer1MUsd: 6,
27790
+ cacheWrite1hPer1MUsd: 9.6
27284
27791
  },
27285
27792
  "us-gov.anthropic.claude-sonnet-4-5-20250929-v1:0": {
27286
27793
  inputPer1MUsd: 3.5999999999999996,
27287
27794
  outputPer1MUsd: 18,
27288
27795
  cacheReadPer1MUsd: 0.36,
27289
- cacheWritePer1MUsd: 4.5
27796
+ cacheWritePer1MUsd: 4.5,
27797
+ cacheWrite1hPer1MUsd: 7.199999999999999
27290
27798
  },
27291
27799
  "us-gov.anthropic.claude-sonnet-5": {
27292
27800
  inputPer1MUsd: 2.4,
27293
27801
  outputPer1MUsd: 12,
27294
27802
  cacheReadPer1MUsd: 0.24,
27295
- cacheWritePer1MUsd: 3
27803
+ cacheWritePer1MUsd: 3,
27804
+ cacheWrite1hPer1MUsd: 4.8
27296
27805
  },
27297
27806
  "us-gov.anthropic.claude-sonnet-5-5": {
27298
27807
  inputPer1MUsd: 2.4,
27299
27808
  outputPer1MUsd: 12,
27300
27809
  cacheReadPer1MUsd: 0.24,
27301
- cacheWritePer1MUsd: 3
27810
+ cacheWritePer1MUsd: 3,
27811
+ cacheWrite1hPer1MUsd: 4.8
27302
27812
  },
27303
27813
  "us-gov.nvidia.nemotron-nano-12b-v2": {
27304
27814
  inputPer1MUsd: 0.24,
@@ -27388,43 +27898,50 @@ var litellm_pricing_snapshot_default = {
27388
27898
  inputPer1MUsd: 11,
27389
27899
  outputPer1MUsd: 55,
27390
27900
  cacheReadPer1MUsd: 1.1,
27391
- cacheWritePer1MUsd: 13.75
27901
+ cacheWritePer1MUsd: 13.75,
27902
+ cacheWrite1hPer1MUsd: 22
27392
27903
  },
27393
27904
  "us.anthropic.claude-fable-5-1": {
27394
27905
  inputPer1MUsd: 11,
27395
27906
  outputPer1MUsd: 55,
27396
27907
  cacheReadPer1MUsd: 0.275,
27397
- cacheWritePer1MUsd: 13.75
27908
+ cacheWritePer1MUsd: 13.75,
27909
+ cacheWrite1hPer1MUsd: 22
27398
27910
  },
27399
27911
  "us.anthropic.claude-haiku-4-5-20251001-v1:0": {
27400
27912
  inputPer1MUsd: 1.1,
27401
27913
  outputPer1MUsd: 5.5,
27402
27914
  cacheReadPer1MUsd: 0.11,
27403
- cacheWritePer1MUsd: 1.375
27915
+ cacheWritePer1MUsd: 1.375,
27916
+ cacheWrite1hPer1MUsd: 2.2
27404
27917
  },
27405
27918
  "us.anthropic.claude-haiku-5-5": {
27406
27919
  inputPer1MUsd: 0.11,
27407
27920
  outputPer1MUsd: 0.55,
27408
27921
  cacheReadPer1MUsd: 0.011,
27409
- cacheWritePer1MUsd: 0.1375
27922
+ cacheWritePer1MUsd: 0.1375,
27923
+ cacheWrite1hPer1MUsd: 0.22
27410
27924
  },
27411
27925
  "us.anthropic.claude-mythos-5": {
27412
27926
  inputPer1MUsd: 11,
27413
27927
  outputPer1MUsd: 55,
27414
27928
  cacheReadPer1MUsd: 1.1,
27415
- cacheWritePer1MUsd: 13.75
27929
+ cacheWritePer1MUsd: 13.75,
27930
+ cacheWrite1hPer1MUsd: 22
27416
27931
  },
27417
27932
  "us.anthropic.claude-mythos-5-1": {
27418
27933
  inputPer1MUsd: 11,
27419
27934
  outputPer1MUsd: 55,
27420
27935
  cacheReadPer1MUsd: 0.275,
27421
- cacheWritePer1MUsd: 13.75
27936
+ cacheWritePer1MUsd: 13.75,
27937
+ cacheWrite1hPer1MUsd: 22
27422
27938
  },
27423
27939
  "us.anthropic.claude-mythos-preview": {
27424
27940
  inputPer1MUsd: 27.5,
27425
27941
  outputPer1MUsd: 137.5,
27426
27942
  cacheReadPer1MUsd: 2.75,
27427
- cacheWritePer1MUsd: 34.375
27943
+ cacheWritePer1MUsd: 34.375,
27944
+ cacheWrite1hPer1MUsd: 55
27428
27945
  },
27429
27946
  "us.anthropic.claude-opus-4-1-20250805-v1:0": {
27430
27947
  inputPer1MUsd: 15,
@@ -27442,37 +27959,43 @@ var litellm_pricing_snapshot_default = {
27442
27959
  inputPer1MUsd: 5.5,
27443
27960
  outputPer1MUsd: 27.5,
27444
27961
  cacheReadPer1MUsd: 0.55,
27445
- cacheWritePer1MUsd: 6.875
27962
+ cacheWritePer1MUsd: 6.875,
27963
+ cacheWrite1hPer1MUsd: 11
27446
27964
  },
27447
27965
  "us.anthropic.claude-opus-4-6-v1": {
27448
27966
  inputPer1MUsd: 5.5,
27449
27967
  outputPer1MUsd: 27.5,
27450
27968
  cacheReadPer1MUsd: 0.55,
27451
- cacheWritePer1MUsd: 6.875
27969
+ cacheWritePer1MUsd: 6.875,
27970
+ cacheWrite1hPer1MUsd: 11
27452
27971
  },
27453
27972
  "us.anthropic.claude-opus-4-7": {
27454
27973
  inputPer1MUsd: 5.5,
27455
27974
  outputPer1MUsd: 27.5,
27456
27975
  cacheReadPer1MUsd: 0.55,
27457
- cacheWritePer1MUsd: 6.875
27976
+ cacheWritePer1MUsd: 6.875,
27977
+ cacheWrite1hPer1MUsd: 11
27458
27978
  },
27459
27979
  "us.anthropic.claude-opus-4-8": {
27460
27980
  inputPer1MUsd: 5.5,
27461
27981
  outputPer1MUsd: 27.5,
27462
27982
  cacheReadPer1MUsd: 0.55,
27463
- cacheWritePer1MUsd: 6.875
27983
+ cacheWritePer1MUsd: 6.875,
27984
+ cacheWrite1hPer1MUsd: 11
27464
27985
  },
27465
27986
  "us.anthropic.claude-opus-5": {
27466
27987
  inputPer1MUsd: 5.5,
27467
27988
  outputPer1MUsd: 27.5,
27468
27989
  cacheReadPer1MUsd: 0.55,
27469
- cacheWritePer1MUsd: 6.875
27990
+ cacheWritePer1MUsd: 6.875,
27991
+ cacheWrite1hPer1MUsd: 11
27470
27992
  },
27471
27993
  "us.anthropic.claude-opus-5-5": {
27472
27994
  inputPer1MUsd: 4.4,
27473
27995
  outputPer1MUsd: 22,
27474
27996
  cacheReadPer1MUsd: 0.22,
27475
- cacheWritePer1MUsd: 5.5
27997
+ cacheWritePer1MUsd: 5.5,
27998
+ cacheWrite1hPer1MUsd: 8.8
27476
27999
  },
27477
28000
  "us.anthropic.claude-sonnet-4-20250514-v1:0": {
27478
28001
  inputPer1MUsd: 3,
@@ -27484,25 +28007,29 @@ var litellm_pricing_snapshot_default = {
27484
28007
  inputPer1MUsd: 3.3000000000000003,
27485
28008
  outputPer1MUsd: 16.5,
27486
28009
  cacheReadPer1MUsd: 0.33,
27487
- cacheWritePer1MUsd: 4.125
28010
+ cacheWritePer1MUsd: 4.125,
28011
+ cacheWrite1hPer1MUsd: 6.6000000000000005
27488
28012
  },
27489
28013
  "us.anthropic.claude-sonnet-4-6": {
27490
28014
  inputPer1MUsd: 3.3000000000000003,
27491
28015
  outputPer1MUsd: 16.5,
27492
28016
  cacheReadPer1MUsd: 0.33,
27493
- cacheWritePer1MUsd: 4.125
28017
+ cacheWritePer1MUsd: 4.125,
28018
+ cacheWrite1hPer1MUsd: 6.6000000000000005
27494
28019
  },
27495
28020
  "us.anthropic.claude-sonnet-5": {
27496
28021
  inputPer1MUsd: 2.2,
27497
28022
  outputPer1MUsd: 11,
27498
28023
  cacheReadPer1MUsd: 0.22,
27499
- cacheWritePer1MUsd: 2.75
28024
+ cacheWritePer1MUsd: 2.75,
28025
+ cacheWrite1hPer1MUsd: 4.4
27500
28026
  },
27501
28027
  "us.anthropic.claude-sonnet-5-5": {
27502
28028
  inputPer1MUsd: 2.2,
27503
28029
  outputPer1MUsd: 11,
27504
28030
  cacheReadPer1MUsd: 0.22,
27505
- cacheWritePer1MUsd: 2.75
28031
+ cacheWritePer1MUsd: 2.75,
28032
+ cacheWrite1hPer1MUsd: 4.4
27506
28033
  },
27507
28034
  "us.cohere.embed-v4:0": {
27508
28035
  inputPer1MUsd: 0.12,
@@ -28149,169 +28676,197 @@ var litellm_pricing_snapshot_default = {
28149
28676
  inputPer1MUsd: 10,
28150
28677
  outputPer1MUsd: 50,
28151
28678
  cacheReadPer1MUsd: 1,
28152
- cacheWritePer1MUsd: 12.5
28679
+ cacheWritePer1MUsd: 12.5,
28680
+ cacheWrite1hPer1MUsd: 20
28153
28681
  },
28154
28682
  "vertex_ai/claude-fable-5-1": {
28155
28683
  inputPer1MUsd: 10,
28156
28684
  outputPer1MUsd: 50,
28157
28685
  cacheReadPer1MUsd: 0.25,
28158
- cacheWritePer1MUsd: 12.5
28686
+ cacheWritePer1MUsd: 12.5,
28687
+ cacheWrite1hPer1MUsd: 20
28159
28688
  },
28160
28689
  "vertex_ai/claude-fable-5-1@default": {
28161
28690
  inputPer1MUsd: 10,
28162
28691
  outputPer1MUsd: 50,
28163
28692
  cacheReadPer1MUsd: 0.25,
28164
- cacheWritePer1MUsd: 12.5
28693
+ cacheWritePer1MUsd: 12.5,
28694
+ cacheWrite1hPer1MUsd: 20
28165
28695
  },
28166
28696
  "vertex_ai/claude-fable-5@default": {
28167
28697
  inputPer1MUsd: 10,
28168
28698
  outputPer1MUsd: 50,
28169
28699
  cacheReadPer1MUsd: 1,
28170
- cacheWritePer1MUsd: 12.5
28700
+ cacheWritePer1MUsd: 12.5,
28701
+ cacheWrite1hPer1MUsd: 20
28171
28702
  },
28172
28703
  "vertex_ai/claude-haiku-4-5": {
28173
28704
  inputPer1MUsd: 1,
28174
28705
  outputPer1MUsd: 5,
28175
28706
  cacheReadPer1MUsd: 0.09999999999999999,
28176
- cacheWritePer1MUsd: 1.25
28707
+ cacheWritePer1MUsd: 1.25,
28708
+ cacheWrite1hPer1MUsd: 2
28177
28709
  },
28178
28710
  "vertex_ai/claude-haiku-4-5@20251001": {
28179
28711
  inputPer1MUsd: 1,
28180
28712
  outputPer1MUsd: 5,
28181
28713
  cacheReadPer1MUsd: 0.09999999999999999,
28182
- cacheWritePer1MUsd: 1.25
28714
+ cacheWritePer1MUsd: 1.25,
28715
+ cacheWrite1hPer1MUsd: 2
28183
28716
  },
28184
28717
  "vertex_ai/claude-haiku-5-5": {
28185
28718
  inputPer1MUsd: 0.09999999999999999,
28186
28719
  outputPer1MUsd: 0.5,
28187
28720
  cacheReadPer1MUsd: 0.01,
28188
- cacheWritePer1MUsd: 0.125
28721
+ cacheWritePer1MUsd: 0.125,
28722
+ cacheWrite1hPer1MUsd: 0.19999999999999998
28189
28723
  },
28190
28724
  "vertex_ai/claude-haiku-5-5@default": {
28191
28725
  inputPer1MUsd: 0.09999999999999999,
28192
28726
  outputPer1MUsd: 0.5,
28193
28727
  cacheReadPer1MUsd: 0.01,
28194
- cacheWritePer1MUsd: 0.125
28728
+ cacheWritePer1MUsd: 0.125,
28729
+ cacheWrite1hPer1MUsd: 0.19999999999999998
28195
28730
  },
28196
28731
  "vertex_ai/claude-opus-4-5": {
28197
28732
  inputPer1MUsd: 5,
28198
28733
  outputPer1MUsd: 25,
28199
28734
  cacheReadPer1MUsd: 0.5,
28200
- cacheWritePer1MUsd: 6.25
28735
+ cacheWritePer1MUsd: 6.25,
28736
+ cacheWrite1hPer1MUsd: 10
28201
28737
  },
28202
28738
  "vertex_ai/claude-opus-4-5@20251101": {
28203
28739
  inputPer1MUsd: 5,
28204
28740
  outputPer1MUsd: 25,
28205
28741
  cacheReadPer1MUsd: 0.5,
28206
- cacheWritePer1MUsd: 6.25
28742
+ cacheWritePer1MUsd: 6.25,
28743
+ cacheWrite1hPer1MUsd: 10
28207
28744
  },
28208
28745
  "vertex_ai/claude-opus-4-6": {
28209
28746
  inputPer1MUsd: 5,
28210
28747
  outputPer1MUsd: 25,
28211
28748
  cacheReadPer1MUsd: 0.5,
28212
- cacheWritePer1MUsd: 6.25
28749
+ cacheWritePer1MUsd: 6.25,
28750
+ cacheWrite1hPer1MUsd: 10
28213
28751
  },
28214
28752
  "vertex_ai/claude-opus-4-6@default": {
28215
28753
  inputPer1MUsd: 5,
28216
28754
  outputPer1MUsd: 25,
28217
28755
  cacheReadPer1MUsd: 0.5,
28218
- cacheWritePer1MUsd: 6.25
28756
+ cacheWritePer1MUsd: 6.25,
28757
+ cacheWrite1hPer1MUsd: 10
28219
28758
  },
28220
28759
  "vertex_ai/claude-opus-4-7": {
28221
28760
  inputPer1MUsd: 5,
28222
28761
  outputPer1MUsd: 25,
28223
28762
  cacheReadPer1MUsd: 0.5,
28224
- cacheWritePer1MUsd: 6.25
28763
+ cacheWritePer1MUsd: 6.25,
28764
+ cacheWrite1hPer1MUsd: 10
28225
28765
  },
28226
28766
  "vertex_ai/claude-opus-4-7@default": {
28227
28767
  inputPer1MUsd: 5,
28228
28768
  outputPer1MUsd: 25,
28229
28769
  cacheReadPer1MUsd: 0.5,
28230
- cacheWritePer1MUsd: 6.25
28770
+ cacheWritePer1MUsd: 6.25,
28771
+ cacheWrite1hPer1MUsd: 10
28231
28772
  },
28232
28773
  "vertex_ai/claude-opus-4-8": {
28233
28774
  inputPer1MUsd: 5,
28234
28775
  outputPer1MUsd: 25,
28235
28776
  cacheReadPer1MUsd: 0.5,
28236
- cacheWritePer1MUsd: 6.25
28777
+ cacheWritePer1MUsd: 6.25,
28778
+ cacheWrite1hPer1MUsd: 10
28237
28779
  },
28238
28780
  "vertex_ai/claude-opus-4-8@default": {
28239
28781
  inputPer1MUsd: 5,
28240
28782
  outputPer1MUsd: 25,
28241
28783
  cacheReadPer1MUsd: 0.5,
28242
- cacheWritePer1MUsd: 6.25
28784
+ cacheWritePer1MUsd: 6.25,
28785
+ cacheWrite1hPer1MUsd: 10
28243
28786
  },
28244
28787
  "vertex_ai/claude-opus-5": {
28245
28788
  inputPer1MUsd: 5,
28246
28789
  outputPer1MUsd: 25,
28247
28790
  cacheReadPer1MUsd: 0.5,
28248
- cacheWritePer1MUsd: 6.25
28791
+ cacheWritePer1MUsd: 6.25,
28792
+ cacheWrite1hPer1MUsd: 10
28249
28793
  },
28250
28794
  "vertex_ai/claude-opus-5-5": {
28251
28795
  inputPer1MUsd: 4,
28252
28796
  outputPer1MUsd: 20,
28253
28797
  cacheReadPer1MUsd: 0.19999999999999998,
28254
- cacheWritePer1MUsd: 5
28798
+ cacheWritePer1MUsd: 5,
28799
+ cacheWrite1hPer1MUsd: 8
28255
28800
  },
28256
28801
  "vertex_ai/claude-opus-5-5@default": {
28257
28802
  inputPer1MUsd: 4,
28258
28803
  outputPer1MUsd: 20,
28259
28804
  cacheReadPer1MUsd: 0.19999999999999998,
28260
- cacheWritePer1MUsd: 5
28805
+ cacheWritePer1MUsd: 5,
28806
+ cacheWrite1hPer1MUsd: 8
28261
28807
  },
28262
28808
  "vertex_ai/claude-opus-5@default": {
28263
28809
  inputPer1MUsd: 5,
28264
28810
  outputPer1MUsd: 25,
28265
28811
  cacheReadPer1MUsd: 0.5,
28266
- cacheWritePer1MUsd: 6.25
28812
+ cacheWritePer1MUsd: 6.25,
28813
+ cacheWrite1hPer1MUsd: 10
28267
28814
  },
28268
28815
  "vertex_ai/claude-sonnet-4-5": {
28269
28816
  inputPer1MUsd: 3,
28270
28817
  outputPer1MUsd: 15,
28271
28818
  cacheReadPer1MUsd: 0.3,
28272
- cacheWritePer1MUsd: 3.75
28819
+ cacheWritePer1MUsd: 3.75,
28820
+ cacheWrite1hPer1MUsd: 6
28273
28821
  },
28274
28822
  "vertex_ai/claude-sonnet-4-5@20250929": {
28275
28823
  inputPer1MUsd: 3,
28276
28824
  outputPer1MUsd: 15,
28277
28825
  cacheReadPer1MUsd: 0.3,
28278
- cacheWritePer1MUsd: 3.75
28826
+ cacheWritePer1MUsd: 3.75,
28827
+ cacheWrite1hPer1MUsd: 6
28279
28828
  },
28280
28829
  "vertex_ai/claude-sonnet-4-6": {
28281
28830
  inputPer1MUsd: 3,
28282
28831
  outputPer1MUsd: 15,
28283
28832
  cacheReadPer1MUsd: 0.3,
28284
- cacheWritePer1MUsd: 3.75
28833
+ cacheWritePer1MUsd: 3.75,
28834
+ cacheWrite1hPer1MUsd: 6
28285
28835
  },
28286
28836
  "vertex_ai/claude-sonnet-4-6@default": {
28287
28837
  inputPer1MUsd: 3,
28288
28838
  outputPer1MUsd: 15,
28289
28839
  cacheReadPer1MUsd: 0.3,
28290
- cacheWritePer1MUsd: 3.75
28840
+ cacheWritePer1MUsd: 3.75,
28841
+ cacheWrite1hPer1MUsd: 6
28291
28842
  },
28292
28843
  "vertex_ai/claude-sonnet-5": {
28293
28844
  inputPer1MUsd: 2,
28294
28845
  outputPer1MUsd: 10,
28295
28846
  cacheReadPer1MUsd: 0.19999999999999998,
28296
- cacheWritePer1MUsd: 2.5
28847
+ cacheWritePer1MUsd: 2.5,
28848
+ cacheWrite1hPer1MUsd: 4
28297
28849
  },
28298
28850
  "vertex_ai/claude-sonnet-5-5": {
28299
28851
  inputPer1MUsd: 2,
28300
28852
  outputPer1MUsd: 10,
28301
28853
  cacheReadPer1MUsd: 0.09999999999999999,
28302
- cacheWritePer1MUsd: 2.5
28854
+ cacheWritePer1MUsd: 2.5,
28855
+ cacheWrite1hPer1MUsd: 4
28303
28856
  },
28304
28857
  "vertex_ai/claude-sonnet-5-5@default": {
28305
28858
  inputPer1MUsd: 2,
28306
28859
  outputPer1MUsd: 10,
28307
28860
  cacheReadPer1MUsd: 0.09999999999999999,
28308
- cacheWritePer1MUsd: 2.5
28861
+ cacheWritePer1MUsd: 2.5,
28862
+ cacheWrite1hPer1MUsd: 4
28309
28863
  },
28310
28864
  "vertex_ai/claude-sonnet-5@default": {
28311
28865
  inputPer1MUsd: 2,
28312
28866
  outputPer1MUsd: 10,
28313
28867
  cacheReadPer1MUsd: 0.19999999999999998,
28314
- cacheWritePer1MUsd: 2.5
28868
+ cacheWritePer1MUsd: 2.5,
28869
+ cacheWrite1hPer1MUsd: 4
28315
28870
  },
28316
28871
  "vertex_ai/codestral-2": {
28317
28872
  inputPer1MUsd: 0.3,
@@ -30628,6 +31183,7 @@ var DEFAULT_FETCH_RETRY_COUNT2 = 2;
30628
31183
  var DEFAULT_FETCH_RETRY_DELAY_MS2 = 200;
30629
31184
  var MAX_LITELLM_PRICING_RESPONSE_BYTES = 33554432;
30630
31185
  var DEFAULT_LITELLM_PRICING_URL = "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json";
31186
+ var CACHE_FORMAT_VERSION = 2;
30631
31187
  var RetryableLiteLLMFetchError = class extends Error {
30632
31188
  constructor(message) {
30633
31189
  super(message);
@@ -30680,6 +31236,9 @@ function normalizeModelPricing(rawModelPricing) {
30680
31236
  }
30681
31237
  const cacheReadPerToken = toNonNegativeNumber3(rawModelPricing.cache_read_input_token_cost) ?? toNonNegativeNumber3(rawModelPricing.cache_read_input_token_cost_priority);
30682
31238
  const cacheWritePerToken = toNonNegativeNumber3(rawModelPricing.cache_creation_input_token_cost) ?? toNonNegativeNumber3(rawModelPricing.cache_creation_input_token_cost_priority);
31239
+ const cacheWrite1hPerToken = toNonNegativeNumber3(
31240
+ rawModelPricing.cache_creation_input_token_cost_above_1hr
31241
+ );
30683
31242
  const reasoningPerToken = toNonNegativeNumber3(rawModelPricing.output_cost_per_reasoning_token);
30684
31243
  const modelPricing = {
30685
31244
  inputPer1MUsd: inputPerToken * ONE_MILLION2,
@@ -30691,6 +31250,9 @@ function normalizeModelPricing(rawModelPricing) {
30691
31250
  if (cacheWritePerToken !== void 0) {
30692
31251
  modelPricing.cacheWritePer1MUsd = cacheWritePerToken * ONE_MILLION2;
30693
31252
  }
31253
+ if (cacheWrite1hPerToken !== void 0) {
31254
+ modelPricing.cacheWrite1hPer1MUsd = cacheWrite1hPerToken * ONE_MILLION2;
31255
+ }
30694
31256
  if (reasoningPerToken !== void 0) {
30695
31257
  modelPricing.reasoningPer1MUsd = reasoningPerToken * ONE_MILLION2;
30696
31258
  modelPricing.reasoningBilling = "separate";
@@ -30741,6 +31303,10 @@ function normalizeCachedPricing(rawPricing) {
30741
31303
  if (cacheWritePer1MUsd !== void 0) {
30742
31304
  modelPricing.cacheWritePer1MUsd = cacheWritePer1MUsd;
30743
31305
  }
31306
+ const cacheWrite1hPer1MUsd = toNonNegativeNumber3(pricingRecord.cacheWrite1hPer1MUsd);
31307
+ if (cacheWrite1hPer1MUsd !== void 0) {
31308
+ modelPricing.cacheWrite1hPer1MUsd = cacheWrite1hPer1MUsd;
31309
+ }
30744
31310
  const reasoningPer1MUsd = toNonNegativeNumber3(pricingRecord.reasoningPer1MUsd);
30745
31311
  if (reasoningPer1MUsd !== void 0) {
30746
31312
  modelPricing.reasoningPer1MUsd = reasoningPer1MUsd;
@@ -30985,7 +31551,7 @@ var LiteLLMPricingFetcher = class {
30985
31551
  return false;
30986
31552
  }
30987
31553
  const nowTimestamp = this.now();
30988
- const isStale = cacheFileContent.fetchedAt > nowTimestamp || nowTimestamp - cacheFileContent.fetchedAt > this.cacheTtlMs;
31554
+ const isStale = cacheFileContent.formatVersion !== CACHE_FORMAT_VERSION || cacheFileContent.fetchedAt > nowTimestamp || nowTimestamp - cacheFileContent.fetchedAt > this.cacheTtlMs;
30989
31555
  if (isStale && !options.allowStale) {
30990
31556
  return false;
30991
31557
  }
@@ -31050,12 +31616,14 @@ var LiteLLMPricingFetcher = class {
31050
31616
  } catch {
31051
31617
  return void 0;
31052
31618
  }
31053
- return normalizeLiteLLMCachePayload(parsedPayload);
31619
+ const payload = normalizeLiteLLMCachePayload(parsedPayload);
31620
+ return payload && { ...payload, formatVersion: asRecord(parsedPayload)?.formatVersion };
31054
31621
  }
31055
31622
  async writeCache() {
31056
31623
  const directoryPath = path33.dirname(this.cacheFilePath);
31057
31624
  await ensureDirectory(directoryPath);
31058
31625
  const payload = {
31626
+ formatVersion: CACHE_FORMAT_VERSION,
31059
31627
  fetchedAt: this.now(),
31060
31628
  sourceUrl: this.sourceUrl,
31061
31629
  pricingByModel: Object.fromEntries(this.pricingByModel.entries())
@@ -31176,6 +31744,11 @@ async function resolveAndApplyPricingToEvents(events, options, runtimeConfig = g
31176
31744
  }
31177
31745
 
31178
31746
  // src/sources/source-adapter.ts
31747
+ function getSessionCopyingSourceIds(adapters) {
31748
+ return new Set(
31749
+ adapters.filter((adapter) => adapter.capabilities?.sessionsCopyEvents).map((adapter) => adapter.id)
31750
+ );
31751
+ }
31179
31752
  function getRepeatingSourceIds(adapters) {
31180
31753
  return adapters.filter((adapter) => adapter.capabilities?.eventsRepeatAcrossFiles).map((adapter) => adapter.id);
31181
31754
  }
@@ -31249,6 +31822,23 @@ function findUnmatchedFilterWarnings(input) {
31249
31822
  ...findUnmatchedModelWarnings(eventsInRange, input.modelFilter, scope)
31250
31823
  ];
31251
31824
  }
31825
+ function hasValue(value) {
31826
+ return Array.isArray(value) ? value.length > 0 : Boolean(value);
31827
+ }
31828
+ function hasCliFilters(options) {
31829
+ return [
31830
+ options.source,
31831
+ options.provider,
31832
+ options.model,
31833
+ options.machine,
31834
+ options.since,
31835
+ options.until,
31836
+ options.last,
31837
+ options.vsSince,
31838
+ options.vsUntil,
31839
+ options.id
31840
+ ].some(hasValue);
31841
+ }
31252
31842
 
31253
31843
  // src/cli/runtime-profile.ts
31254
31844
  var RUNTIME_PROFILE_ENV_VAR = "LLM_USAGE_PROFILE_RUNTIME";
@@ -31602,6 +32192,7 @@ async function buildUsageEventDataset(options, deps = {}) {
31602
32192
  return parseSelectedAdapters(adaptersToParse, parsingRuntimeConfig.maxParallelFileParsing, {
31603
32193
  eventStore: parseEventStoreRuntimeConfig,
31604
32194
  openedStore: openedEventStore,
32195
+ overrideSourceIds: cliDirectorySourceIds,
31605
32196
  since: configuredOptions.since,
31606
32197
  parseWorkers: {
31607
32198
  workerCount: parsingRuntimeConfig.parseWorkers,
@@ -31614,7 +32205,12 @@ async function buildUsageEventDataset(options, deps = {}) {
31614
32205
  const parseWarnings = eventStoreOpenWarning ? [eventStoreOpenWarning, ...warnings] : warnings;
31615
32206
  throwOnExplicitSourceFailures(sourceFailures, normalizedInputs.explicitSourceIds);
31616
32207
  let parseResultsForFiltering = successfulParseResults;
31617
- const ledger = eventStoreAvailable ? { path: eventStoreRuntimeConfig.path, parsedFiles: [...parsedFiles], historyFiles: [] } : void 0;
32208
+ const ledger = eventStoreAvailable ? {
32209
+ path: eventStoreRuntimeConfig.path,
32210
+ parsedFiles: [...parsedFiles],
32211
+ historyFiles: [],
32212
+ copiedEventCount: 0
32213
+ } : void 0;
31618
32214
  const historyWarnings = [];
31619
32215
  const historyNotes = [];
31620
32216
  const historyStore = openedEventStore;
@@ -31639,7 +32235,14 @@ async function buildUsageEventDataset(options, deps = {}) {
31639
32235
  discoveredFiles: discoveredFiles.filter(
31640
32236
  (file) => !failedFileKeys.has(`${file.source}\0${file.filePath}`)
31641
32237
  ),
31642
- presentFiles: failedFiles,
32238
+ // Files only ever found under a custom directory never departed from
32239
+ // their source's usual location, so a run there leaves them out.
32240
+ presentFiles: [
32241
+ ...failedFiles,
32242
+ ...readOverrideOnlyFiles(historyStore).filter(
32243
+ (file) => !cliDirectorySourceIds.has(file.source)
32244
+ )
32245
+ ],
31643
32246
  repeatingSources: getRepeatingSourceIds(adaptersToParse)
31644
32247
  },
31645
32248
  { unverifiable: "treat-as-departed" }
@@ -31700,6 +32303,13 @@ async function buildUsageEventDataset(options, deps = {}) {
31700
32303
  );
31701
32304
  parseResultsForFiltering = appendMachineEvents(parseResultsForFiltering, machineUsage.events);
31702
32305
  machineWarnings.push(...machineUsage.warnings);
32306
+ const refreshedNames = new Set(refreshOutcomes.map((outcome) => outcome.name));
32307
+ for (const machine of machineUsage.machines) {
32308
+ const failure = refreshedNames.has(machine.name) ? void 0 : formatStoredSyncFailure(machine, nowMs());
32309
+ if (failure) {
32310
+ (failure.stale ? machineWarnings : machineNotes).push(failure.text);
32311
+ }
32312
+ }
31703
32313
  machineNotes.push(
31704
32314
  formatMachinesNote(
31705
32315
  machineUsage.machines,
@@ -31708,6 +32318,21 @@ async function buildUsageEventDataset(options, deps = {}) {
31708
32318
  )
31709
32319
  );
31710
32320
  }
32321
+ const sessionCopyingSources = getSessionCopyingSourceIds(adaptersToParse);
32322
+ parseResultsForFiltering = measureRuntimeProfileStageSync(
32323
+ runtimeProfile,
32324
+ "usage.dataset.count_copies",
32325
+ () => parseResultsForFiltering.map((result) => {
32326
+ if (!sessionCopyingSources.has(result.source)) {
32327
+ return result;
32328
+ }
32329
+ const events = countCopiedSessionEventsOnce(result.events);
32330
+ if (ledger) {
32331
+ ledger.copiedEventCount += result.events.length - events.length;
32332
+ }
32333
+ return { ...result, events };
32334
+ })
32335
+ );
31711
32336
  const filteredEvents = measureRuntimeProfileStageSync(
31712
32337
  runtimeProfile,
31713
32338
  "usage.dataset.filter_events",
@@ -31781,6 +32406,22 @@ async function applyPricingToUsageEventDataset(dataset, deps = {}, pricingLoadMo
31781
32406
  )
31782
32407
  );
31783
32408
  }
32409
+ var MAX_NAMED_UNPRICED_MODELS = 5;
32410
+ function describeUnpricedEvents(events) {
32411
+ const unpricedEvents = events.filter((event) => event.costUsd === void 0);
32412
+ if (unpricedEvents.length === 0) {
32413
+ return void 0;
32414
+ }
32415
+ const models = [...new Set(unpricedEvents.map((event) => event.model ?? "unknown"))].sort();
32416
+ const eventCount = new Intl.NumberFormat("en-US").format(unpricedEvents.length);
32417
+ const eventLabel = unpricedEvents.length === 1 ? "event" : "events";
32418
+ const modelList = limitNamedModels(models, MAX_NAMED_UNPRICED_MODELS).join(", ");
32419
+ return `~ marks costs that leave out ${eventCount} ${eventLabel} with no known price (models: ${modelList})`;
32420
+ }
32421
+ function withUnpricedEventsNote(notes, events) {
32422
+ const note = describeUnpricedEvents(events);
32423
+ return note ? [...notes, note] : [...notes];
32424
+ }
31784
32425
 
31785
32426
  // src/cli/build-usage-data.ts
31786
32427
  var REPORT_PERIOD_NAMES = {
@@ -31793,14 +32434,14 @@ var DEFAULT_REPORT_WINDOWS = {
31793
32434
  weekly: { periods: 8, period: "week" }
31794
32435
  };
31795
32436
  var MAX_LAST_PERIODS = 1e4;
31796
- function parseLastOption(last) {
32437
+ function parseLastOption(last, flag = "--last") {
31797
32438
  if (last === void 0) {
31798
32439
  return void 0;
31799
32440
  }
31800
32441
  const normalized = last.trim();
31801
32442
  const periods = Number.parseInt(normalized, 10);
31802
32443
  if (!/^[1-9]\d*$/u.test(normalized) || periods > MAX_LAST_PERIODS) {
31803
- throw new Error(`--last must be a whole number from 1 to ${String(MAX_LAST_PERIODS)}`);
32444
+ throw new Error(`${flag} must be a whole number from 1 to ${String(MAX_LAST_PERIODS)}`);
31804
32445
  }
31805
32446
  return periods;
31806
32447
  }
@@ -31887,7 +32528,7 @@ async function buildUsageData(granularity, commandOptions, commandDeps = {}) {
31887
32528
  pricingOrigin,
31888
32529
  pricingWarning,
31889
32530
  warnings: dataset.warnings,
31890
- notes: dataset.notes,
32531
+ notes: options.cost === false ? dataset.notes : withUnpricedEventsNote(dataset.notes, pricedEvents),
31891
32532
  activeEnvOverrides: dataset.readEnvVarOverrides(),
31892
32533
  activeConfig: dataset.activeConfig,
31893
32534
  timezone: dataset.normalizedInputs.timezone,
@@ -32154,6 +32795,10 @@ function padLine(content, width) {
32154
32795
  function renderReportHeader(options) {
32155
32796
  const { title, useColor = true } = options;
32156
32797
  const boxWidth = getBoxWidth(title);
32798
+ const terminalWidth = options.terminalWidth ?? resolveTtyColumns(process.stdout);
32799
+ if (terminalWidth !== void 0 && boxWidth > terminalWidth) {
32800
+ return useColor ? pc2.bold(pc2.white(title)) : title;
32801
+ }
32157
32802
  const lines = [];
32158
32803
  const topBorder = drawBoxLine(boxWidth, "\u250C", "\u2500", "\u2510");
32159
32804
  lines.push(useColor ? pc2.gray(topBorder) : topBorder);
@@ -32163,6 +32808,9 @@ function renderReportHeader(options) {
32163
32808
  lines.push(useColor ? pc2.gray(bottomBorder) : bottomBorder);
32164
32809
  return lines.join("\n");
32165
32810
  }
32811
+ function formatNoUsageMessage(filtered) {
32812
+ return filtered ? "No usage data found for the selected filters." : "No usage data found.";
32813
+ }
32166
32814
 
32167
32815
  // src/render/terminal-table.ts
32168
32816
  import pc4 from "picocolors";
@@ -32640,6 +33288,75 @@ function computeColumnWidths(measureRows, options) {
32640
33288
  }
32641
33289
  return widths;
32642
33290
  }
33291
+ function measureBoxedTableWidth(widths) {
33292
+ return widths.reduce((total, width) => total + width + 3, 1);
33293
+ }
33294
+ function measureLinesWidth(cell) {
33295
+ return splitCellLines(cell).reduce((maxWidth, line) => Math.max(maxWidth, visibleWidth(line)), 0);
33296
+ }
33297
+ function joinCellLines(cell) {
33298
+ return splitCellLines(cell).join(" ");
33299
+ }
33300
+ function wrapAtNameBreaks(line, width) {
33301
+ const lines = [];
33302
+ for (const piece of line.split(/(?<=[\s/-])/u)) {
33303
+ const lastLine = lines.at(-1);
33304
+ if (lastLine !== void 0 && visibleWidth((lastLine + piece).trimEnd()) <= width) {
33305
+ lines[lines.length - 1] = lastLine + piece;
33306
+ } else {
33307
+ lines.push(piece);
33308
+ }
33309
+ }
33310
+ return lines.flatMap(
33311
+ (wrappedLine) => splitCellLines(wrapTableColumn([[wrappedLine.trimEnd()]], { columnIndex: 0, width })[0][0])
33312
+ );
33313
+ }
33314
+ function renderStackedRows(options) {
33315
+ const valueColumnIndexes = options.headerCells.map((_, columnIndex) => columnIndex).filter((columnIndex) => columnIndex >= options.titleColumnCount);
33316
+ const labelWidth = valueColumnIndexes.reduce(
33317
+ (maxWidth, columnIndex) => Math.max(maxWidth, visibleWidth(joinCellLines(options.measureHeaderCells[columnIndex]))),
33318
+ 0
33319
+ );
33320
+ const continuationIndent = " ".repeat(2 + labelWidth + 2);
33321
+ const availableValueWidth = Math.max(1, options.terminalWidth - continuationIndent.length);
33322
+ const valueWidth = Math.min(
33323
+ availableValueWidth,
33324
+ options.measureBodyRows.reduce(
33325
+ (maxWidth, row) => valueColumnIndexes.reduce(
33326
+ (rowMax, columnIndex) => Math.max(rowMax, measureLinesWidth(row[columnIndex])),
33327
+ maxWidth
33328
+ ),
33329
+ 0
33330
+ )
33331
+ );
33332
+ const records = options.bodyRows.map((row, rowIndex) => {
33333
+ const title = row.slice(0, options.titleColumnCount).map(joinCellLines).filter((cell) => cell.trim().length > 0).join(" \xB7 ");
33334
+ const valueLines = valueColumnIndexes.flatMap((columnIndex) => {
33335
+ const lines = measureLinesWidth(row[columnIndex]) > availableValueWidth ? splitCellLines(options.measureBodyRows[rowIndex][columnIndex]).flatMap(
33336
+ (line) => wrapAtNameBreaks(line, availableValueWidth)
33337
+ ) : splitCellLines(row[columnIndex]);
33338
+ if (lines.every((line) => line.trim().length === 0)) {
33339
+ return [];
33340
+ }
33341
+ const alignment2 = getColumnAlignment(
33342
+ columnIndex,
33343
+ options.multilineColumnIndex,
33344
+ options.leftAlignedColumnIndexes
33345
+ );
33346
+ const label = alignCellLine(
33347
+ joinCellLines(options.headerCells[columnIndex]),
33348
+ labelWidth,
33349
+ "left"
33350
+ );
33351
+ return lines.map((line, lineIndex) => {
33352
+ const value = alignCellLine(line, valueWidth, alignment2).trimEnd();
33353
+ return lineIndex === 0 ? ` ${label} ${value}` : `${continuationIndent}${value}`;
33354
+ });
33355
+ });
33356
+ return [title, ...valueLines].join("\n");
33357
+ });
33358
+ return records.join("\n\n");
33359
+ }
32643
33360
  function renderUnicodeTable(options) {
32644
33361
  const bodyColumnCount = getMaxRowColumnCount(options.bodyRows, options.headerCells.length);
32645
33362
  const measureColumnCount = getMaxRowColumnCount(
@@ -32671,6 +33388,20 @@ function renderUnicodeTable(options) {
32671
33388
  multilineColumnIndex: options.multilineColumnIndex,
32672
33389
  multilineColumnWidth: options.multilineColumnWidth
32673
33390
  });
33391
+ const normalizedBodyRows = renderableRows.map((row) => row.bodyRow);
33392
+ const normalizedRowMetas = renderableRows.map((row) => row.rowMeta);
33393
+ if (options.terminalWidth !== void 0 && measureBoxedTableWidth(widths) > options.terminalWidth) {
33394
+ return renderStackedRows({
33395
+ headerCells: normalizedHeaderRow,
33396
+ measureHeaderCells: normalizedMeasureHeaderRow,
33397
+ bodyRows: normalizedBodyRows,
33398
+ measureBodyRows: renderableRows.map((row) => row.measureBodyRow),
33399
+ titleColumnCount: options.stackedTitleColumnCount ?? options.multilineColumnIndex + 1,
33400
+ terminalWidth: options.terminalWidth,
33401
+ multilineColumnIndex: options.multilineColumnIndex,
33402
+ leftAlignedColumnIndexes: options.leftAlignedColumnIndexes
33403
+ });
33404
+ }
32674
33405
  const outputLines = [];
32675
33406
  outputLines.push(
32676
33407
  buildBorderLine(widths, {
@@ -32694,8 +33425,6 @@ function renderUnicodeTable(options) {
32694
33425
  right: "\u2524"
32695
33426
  })
32696
33427
  );
32697
- const normalizedBodyRows = renderableRows.map((row) => row.bodyRow);
32698
- const normalizedRowMetas = renderableRows.map((row) => row.rowMeta);
32699
33428
  normalizedBodyRows.forEach((row, rowIndex) => {
32700
33429
  outputLines.push(
32701
33430
  ...toRenderableRowLines(row, {
@@ -32993,7 +33722,8 @@ function renderPreparedTable(rows, prepared, options) {
32993
33722
  rowMetas: toRowMetas(rows),
32994
33723
  layout: options.tableLayout === "per_model_columns" ? "top_aligned" : "compact",
32995
33724
  multilineColumnIndex: prepared.showsModels ? columns.indexOf(modelsColumnIndex2) : columns.indexOf(sourceColumnIndex2),
32996
- multilineColumnWidth: prepared.showsModels ? options.modelsColumnWidth : void 0
33725
+ multilineColumnWidth: prepared.showsModels ? options.modelsColumnWidth : void 0,
33726
+ terminalWidth: options.stackedWidth
32997
33727
  });
32998
33728
  return { output, truncatedModelNames };
32999
33729
  }
@@ -33012,12 +33742,20 @@ function renderTerminalTableWithFit(rows, options = {}) {
33012
33742
  prepared = prepareFitStep(rows, tableLayout, step);
33013
33743
  }
33014
33744
  }
33745
+ const stacked = tableLayout === "compact" && terminalWidth !== void 0 && !fitsTerminal(prepared, terminalWidth);
33746
+ if (stacked) {
33747
+ const listStep = steps.find((step) => step.hiddenColumns.includes("models"));
33748
+ if (listStep) {
33749
+ prepared = prepareFitStep(rows, tableLayout, listStep);
33750
+ }
33751
+ }
33015
33752
  const modelsColumnWidth = resolveModelsColumnWidth(prepared, tableLayout, terminalWidth);
33016
33753
  const { output, truncatedModelNames } = renderPreparedTable(rows, prepared, {
33017
33754
  tableLayout,
33018
33755
  useColor,
33019
33756
  modelsColumnWidth,
33020
- packModels: terminalWidth !== void 0
33757
+ packModels: terminalWidth !== void 0,
33758
+ stackedWidth: stacked ? terminalWidth : void 0
33021
33759
  });
33022
33760
  if (hasExplicitTerminalWidth && terminalWidth !== void 0) {
33023
33761
  const renderedTableWidth = measureTableWidth(output);
@@ -33032,7 +33770,8 @@ function renderTerminalTableWithFit(rows, options = {}) {
33032
33770
  fit: {
33033
33771
  tokenFormat: prepared.step.tokenFormat,
33034
33772
  hiddenColumns: [...prepared.step.hiddenColumns],
33035
- truncatedModelNames
33773
+ truncatedModelNames,
33774
+ stacked
33036
33775
  }
33037
33776
  };
33038
33777
  }
@@ -33147,9 +33886,13 @@ function renderTerminalTable(options) {
33147
33886
  rowMetas: createRowMetas(options.bodyRows.length),
33148
33887
  layout: "compact",
33149
33888
  multilineColumnIndex: 0,
33150
- multilineColumnWidth: options.firstColumnWidth
33889
+ multilineColumnWidth: options.firstColumnWidth,
33890
+ terminalWidth: resolveTtyColumns(process.stdout)
33151
33891
  });
33152
33892
  }
33893
+ function hasNoUsage(compareData) {
33894
+ return compareData.current.totals.events === 0 && compareData.baseline.totals.events === 0;
33895
+ }
33153
33896
  function renderTerminalCompareReport(compareData, options) {
33154
33897
  const useColor = options.useColor ?? shouldUseColorByDefault();
33155
33898
  const lines = [];
@@ -33160,9 +33903,9 @@ function renderTerminalCompareReport(compareData, options) {
33160
33903
  })
33161
33904
  );
33162
33905
  lines.push("");
33163
- if (compareData.current.totals.events === 0 && compareData.baseline.totals.events === 0) {
33164
- lines.push("No usage data found for the selected filters.");
33165
- lines.push("");
33906
+ if (hasNoUsage(compareData)) {
33907
+ lines.push(formatNoUsageMessage(options.filtered ?? false));
33908
+ return lines.join("\n");
33166
33909
  }
33167
33910
  lines.push(
33168
33911
  renderTerminalTable({
@@ -33963,7 +34706,7 @@ async function buildCompareData(options, deps = {}) {
33963
34706
  pricingOrigin,
33964
34707
  pricingWarning,
33965
34708
  warnings: dataset.warnings,
33966
- notes: dataset.notes,
34709
+ notes: withUnpricedEventsNote(dataset.notes, [...currentEvents, ...baselineEvents]),
33967
34710
  activeEnvOverrides: dataset.readEnvVarOverrides(),
33968
34711
  activeConfig: dataset.activeConfig,
33969
34712
  timezone: dataset.normalizedInputs.timezone,
@@ -34622,7 +35365,7 @@ async function prepareCompareReport(options, deps = {}) {
34622
35365
  title: "Compare share card",
34623
35366
  render: (theme) => renderCompareShareSvg(compareData, theme)
34624
35367
  }) : void 0,
34625
- render: (compareData, format) => renderCompareReport(compareData, format)
35368
+ render: (compareData, format) => renderCompareReport(compareData, format, { filtered: hasCliFilters(options) })
34626
35369
  });
34627
35370
  }
34628
35371
  async function runCompareReport(options) {
@@ -34806,19 +35549,21 @@ function formatDecimal(value, options = {}) {
34806
35549
  const formatted = decimalFormatter.format(value);
34807
35550
  return options.approximate ? `~${formatted}` : formatted;
34808
35551
  }
34809
- function toEfficiencyTableCells(rows) {
35552
+ function toEfficiencyTableCells(rows, tokenFormat = "full") {
35553
+ const formatTokens = tokenFormat === "abbreviated" ? formatAbbreviatedTokenCount : formatInteger3;
35554
+ const formatTokenRate = (value) => value !== void 0 && tokenFormat === "abbreviated" ? formatAbbreviatedTokenCount(value) : formatDecimal(value);
34810
35555
  return rows.map((row) => [
34811
35556
  row.rowType === "period_source" ? ` ${row.source}` : row.periodKey,
34812
35557
  formatInteger3(row.rowType === "period_source" ? void 0 : row.commitCount),
34813
35558
  formatInteger3(row.rowType === "period_source" ? void 0 : row.linesAdded),
34814
35559
  formatInteger3(row.rowType === "period_source" ? void 0 : row.linesDeleted),
34815
35560
  formatInteger3(row.rowType === "period_source" ? void 0 : row.linesChanged),
34816
- formatInteger3(row.inputTokens),
34817
- formatInteger3(row.outputTokens),
34818
- formatInteger3(row.reasoningTokens),
34819
- formatInteger3(row.cacheReadTokens),
34820
- formatInteger3(row.cacheWriteTokens),
34821
- formatInteger3(row.totalTokens),
35561
+ formatTokens(row.inputTokens),
35562
+ formatTokens(row.outputTokens),
35563
+ formatTokens(row.reasoningTokens),
35564
+ formatTokens(row.cacheReadTokens),
35565
+ formatTokens(row.cacheWriteTokens),
35566
+ formatTokens(row.totalTokens),
34822
35567
  formatUsd4(row.costUsd, { approximate: row.costIncomplete }),
34823
35568
  formatUsdRate(row.rowType === "period_source" ? void 0 : row.usdPerCommit, {
34824
35569
  approximate: row.costIncomplete
@@ -34826,7 +35571,7 @@ function toEfficiencyTableCells(rows) {
34826
35571
  formatUsdRate(row.rowType === "period_source" ? void 0 : row.usdPer1kLinesChanged, {
34827
35572
  approximate: row.costIncomplete
34828
35573
  }),
34829
- formatDecimal(row.rowType === "period_source" ? void 0 : row.tokensPerCommit),
35574
+ formatTokenRate(row.rowType === "period_source" ? void 0 : row.tokensPerCommit),
34830
35575
  formatDecimal(row.rowType === "period_source" ? void 0 : row.commitsPerUsd, {
34831
35576
  approximate: row.costIncomplete
34832
35577
  })
@@ -34835,15 +35580,45 @@ function toEfficiencyTableCells(rows) {
34835
35580
 
34836
35581
  // src/render/render-efficiency-report.ts
34837
35582
  var periodColumnIndex2 = 0;
34838
- var minimumEfficiencyColumnWidth = 1;
34839
35583
  var commitsColumnIndex = 1;
34840
35584
  var linesAddedColumnIndex = 2;
34841
35585
  var linesDeletedColumnIndex = 3;
34842
35586
  var linesChangedColumnIndex = 4;
35587
+ var inputColumnIndex = 5;
35588
+ var outputColumnIndex = 6;
35589
+ var reasoningColumnIndex = 7;
35590
+ var cacheReadColumnIndex = 8;
35591
+ var cacheWriteColumnIndex = 9;
34843
35592
  var costColumnIndex = 11;
34844
35593
  var usdPerCommitColumnIndex = 12;
34845
35594
  var usdPer1kLinesChangedColumnIndex = 13;
34846
35595
  var commitsPerUsdColumnIndex = 15;
35596
+ var efficiencyFitSteps = [
35597
+ { tokenFormat: "full", hiddenColumnIndexes: [] },
35598
+ { tokenFormat: "abbreviated", hiddenColumnIndexes: [] },
35599
+ {
35600
+ tokenFormat: "abbreviated",
35601
+ hiddenColumnIndexes: [
35602
+ inputColumnIndex,
35603
+ outputColumnIndex,
35604
+ reasoningColumnIndex,
35605
+ cacheWriteColumnIndex
35606
+ ]
35607
+ },
35608
+ {
35609
+ tokenFormat: "abbreviated",
35610
+ hiddenColumnIndexes: [
35611
+ linesAddedColumnIndex,
35612
+ linesDeletedColumnIndex,
35613
+ inputColumnIndex,
35614
+ outputColumnIndex,
35615
+ reasoningColumnIndex,
35616
+ cacheReadColumnIndex,
35617
+ cacheWriteColumnIndex,
35618
+ commitsPerUsdColumnIndex
35619
+ ]
35620
+ }
35621
+ ];
34847
35622
  function getReportTitle(granularity) {
34848
35623
  switch (granularity) {
34849
35624
  case "daily":
@@ -34868,11 +35643,7 @@ function measureRenderedTableWidth(columnWidths) {
34868
35643
  return columnWidths.reduce((sum, width) => sum + width, 0) + columnWidths.length * 3 + 1;
34869
35644
  }
34870
35645
  function computeColumnWidths2(headerCells, bodyRows) {
34871
- const columnCount = Math.max(
34872
- headerCells.length,
34873
- ...bodyRows.map((row) => row.length),
34874
- efficiencyTableHeaders.length
34875
- );
35646
+ const columnCount = Math.max(headerCells.length, ...bodyRows.map((row) => row.length));
34876
35647
  const widths = Array.from({ length: columnCount }, () => 0);
34877
35648
  const measureRow = (row) => {
34878
35649
  for (let columnIndex = 0; columnIndex < columnCount; columnIndex += 1) {
@@ -34887,71 +35658,69 @@ function computeColumnWidths2(headerCells, bodyRows) {
34887
35658
  }
34888
35659
  return widths;
34889
35660
  }
34890
- function resolveWrappedCells(headerCells, bodyRows, widths) {
34891
- let wrappedHeaderCells = [...headerCells];
34892
- let wrappedBodyRows = bodyRows.map((row) => [...row]);
34893
- for (let columnIndex = 0; columnIndex < widths.length; columnIndex += 1) {
34894
- const columnWidth = widths[columnIndex] ?? 0;
34895
- if (columnWidth <= 0) {
34896
- continue;
35661
+ function splitHeaderPieces(header) {
35662
+ return header.split(" ").flatMap((word) => word.split(/(?<=\/)/u));
35663
+ }
35664
+ function wrapHeader(header, width) {
35665
+ const lines = [];
35666
+ for (const piece of splitHeaderPieces(header)) {
35667
+ const lastLine = lines.at(-1);
35668
+ const separator = lastLine === void 0 || lastLine.endsWith("/") ? "" : " ";
35669
+ if (lastLine !== void 0 && visibleWidth(lastLine + separator + piece) <= width) {
35670
+ lines[lines.length - 1] = lastLine + separator + piece;
35671
+ } else {
35672
+ lines.push(piece);
34897
35673
  }
34898
- wrappedHeaderCells = wrapTableColumn([wrappedHeaderCells], {
34899
- columnIndex,
34900
- width: columnWidth
34901
- })[0] ?? [];
34902
- wrappedBodyRows = wrapTableColumn(wrappedBodyRows, {
34903
- columnIndex,
34904
- width: columnWidth
34905
- });
34906
35674
  }
34907
- return {
34908
- wrappedHeaderCells,
34909
- wrappedBodyRows
34910
- };
35675
+ return lines.join("\n");
35676
+ }
35677
+ function computeMinimumColumnWidths(headerCells, bodyRows) {
35678
+ const headerPieceWidths = headerCells.map(
35679
+ (header) => splitHeaderPieces(header).reduce(
35680
+ (maxWidth, piece) => Math.max(maxWidth, visibleWidth(piece)),
35681
+ 0
35682
+ )
35683
+ );
35684
+ return computeColumnWidths2([], bodyRows).map(
35685
+ (bodyWidth, columnIndex) => Math.max(bodyWidth, headerPieceWidths[columnIndex] ?? 0)
35686
+ );
34911
35687
  }
34912
35688
  function fitTableCellsToTerminal(headerCells, bodyRows) {
34913
35689
  const naturalWidths = computeColumnWidths2(headerCells, bodyRows);
34914
35690
  const terminalWidth = resolveTtyColumns(process.stdout);
35691
+ const natural = {
35692
+ headerCells: [...headerCells],
35693
+ bodyRows: bodyRows.map((row) => [...row]),
35694
+ widths: naturalWidths
35695
+ };
34915
35696
  if (terminalWidth === void 0 || measureRenderedTableWidth(naturalWidths) <= terminalWidth) {
34916
- return {
34917
- headerCells: [...headerCells],
34918
- bodyRows: bodyRows.map((row) => [...row]),
34919
- widths: naturalWidths
34920
- };
35697
+ return natural;
35698
+ }
35699
+ const minimumWidths = computeMinimumColumnWidths(headerCells, bodyRows);
35700
+ if (measureRenderedTableWidth(minimumWidths) > terminalWidth) {
35701
+ return { ...natural, stackedWidth: terminalWidth };
34921
35702
  }
34922
35703
  const constrainedWidths = [...naturalWidths];
34923
- let renderedTableWidth = measureRenderedTableWidth(constrainedWidths);
34924
- while (renderedTableWidth > terminalWidth && constrainedWidths.some((width) => width > minimumEfficiencyColumnWidth)) {
34925
- let widestIndex = -1;
34926
- let widestWidth = -1;
34927
- for (let columnIndex = 0; columnIndex < constrainedWidths.length; columnIndex += 1) {
34928
- const columnWidth = constrainedWidths[columnIndex];
34929
- if (columnWidth <= minimumEfficiencyColumnWidth || columnWidth <= widestWidth) {
34930
- continue;
35704
+ let overflowColumns = measureRenderedTableWidth(constrainedWidths) - terminalWidth;
35705
+ while (overflowColumns > 0) {
35706
+ let shrinkIndex = 0;
35707
+ for (let columnIndex = 1; columnIndex < constrainedWidths.length; columnIndex += 1) {
35708
+ if (constrainedWidths[columnIndex] - minimumWidths[columnIndex] > constrainedWidths[shrinkIndex] - minimumWidths[shrinkIndex]) {
35709
+ shrinkIndex = columnIndex;
34931
35710
  }
34932
- widestIndex = columnIndex;
34933
- widestWidth = columnWidth;
34934
35711
  }
34935
- if (widestIndex === -1) {
34936
- break;
34937
- }
34938
- const overflowColumns = renderedTableWidth - terminalWidth;
34939
- const maxReducibleWidth = widestWidth - minimumEfficiencyColumnWidth;
34940
- const reduction = Math.min(overflowColumns, maxReducibleWidth);
34941
- if (reduction <= 0) {
34942
- break;
34943
- }
34944
- constrainedWidths[widestIndex] -= reduction;
34945
- renderedTableWidth -= reduction;
35712
+ const reduction = Math.min(
35713
+ overflowColumns,
35714
+ constrainedWidths[shrinkIndex] - minimumWidths[shrinkIndex]
35715
+ );
35716
+ constrainedWidths[shrinkIndex] -= reduction;
35717
+ overflowColumns -= reduction;
34946
35718
  }
34947
- const { wrappedHeaderCells, wrappedBodyRows } = resolveWrappedCells(
34948
- headerCells,
34949
- bodyRows,
34950
- constrainedWidths
34951
- );
34952
35719
  return {
34953
- headerCells: wrappedHeaderCells,
34954
- bodyRows: wrappedBodyRows,
35720
+ headerCells: headerCells.map(
35721
+ (header, columnIndex) => wrapHeader(header, constrainedWidths[columnIndex])
35722
+ ),
35723
+ bodyRows: natural.bodyRows,
34955
35724
  widths: constrainedWidths
34956
35725
  };
34957
35726
  }
@@ -35021,12 +35790,50 @@ function styleEfficiencyTerminalRows(rows, bodyRows, options) {
35021
35790
  return styledCells;
35022
35791
  });
35023
35792
  }
35793
+ function fitEfficiencyStep(rows, step, options) {
35794
+ const visibleColumnIndexes = efficiencyTableHeaders.map((_, columnIndex) => columnIndex).filter((columnIndex) => !step.hiddenColumnIndexes.includes(columnIndex));
35795
+ const styledRows = styleEfficiencyTerminalRows(
35796
+ rows,
35797
+ toEfficiencyTableCells(rows, step.tokenFormat),
35798
+ options
35799
+ );
35800
+ return fitTableCellsToTerminal(
35801
+ selectColumns(Array.from(efficiencyTableHeaders), visibleColumnIndexes),
35802
+ styledRows.map((row) => selectColumns(row, visibleColumnIndexes))
35803
+ );
35804
+ }
35805
+ function describeEfficiencyFit(step, stacked) {
35806
+ if (stacked) {
35807
+ return "Listed rows instead of a table to fit the terminal. Widen the terminal to see the table.";
35808
+ }
35809
+ const changes = [];
35810
+ if (step.tokenFormat === "abbreviated") {
35811
+ changes.push("abbreviated token counts");
35812
+ }
35813
+ const hiddenHeaders = step.hiddenColumnIndexes.map(
35814
+ (columnIndex) => efficiencyTableHeaders[columnIndex]
35815
+ );
35816
+ if (hiddenHeaders.length > 0) {
35817
+ changes.push(`hid ${hiddenHeaders.slice(0, -1).join(", ")} and ${hiddenHeaders.at(-1) ?? ""}`);
35818
+ }
35819
+ return changes.length > 0 ? `Fitted the table to the terminal: ${changes.join(", ")}. Widen the terminal or use --json for full detail.` : void 0;
35820
+ }
35024
35821
  function renderTerminalEfficiencyTable(rows, options) {
35025
- const headerCells = Array.from(efficiencyTableHeaders);
35026
- const bodyRows = styleEfficiencyTerminalRows(rows, toEfficiencyTableCells(rows), options);
35027
35822
  const rowMetas = rows.map((row) => toTableRowMeta(row));
35028
- const fittedCells = fitTableCellsToTerminal(headerCells, bodyRows);
35029
- return renderUnicodeTable({
35823
+ let fittedStep = efficiencyFitSteps[0];
35824
+ let fittedCells = fitEfficiencyStep(rows, fittedStep, options);
35825
+ for (const step of efficiencyFitSteps.slice(1)) {
35826
+ if (fittedCells.stackedWidth === void 0) {
35827
+ break;
35828
+ }
35829
+ const candidate = fitEfficiencyStep(rows, step, options);
35830
+ if (candidate.stackedWidth === void 0) {
35831
+ fittedStep = step;
35832
+ fittedCells = candidate;
35833
+ }
35834
+ }
35835
+ const note = describeEfficiencyFit(fittedStep, fittedCells.stackedWidth !== void 0);
35836
+ const output = renderUnicodeTable({
35030
35837
  headerCells: fittedCells.headerCells,
35031
35838
  bodyRows: fittedCells.bodyRows,
35032
35839
  measureHeaderCells: fittedCells.headerCells,
@@ -35034,8 +35841,10 @@ function renderTerminalEfficiencyTable(rows, options) {
35034
35841
  rowMetas,
35035
35842
  layout: "compact",
35036
35843
  multilineColumnIndex: periodColumnIndex2,
35037
- multilineColumnWidth: fittedCells.widths[periodColumnIndex2] ?? efficiencyTableHeaders[periodColumnIndex2].length
35844
+ multilineColumnWidth: fittedCells.widths[periodColumnIndex2] ?? efficiencyTableHeaders[periodColumnIndex2].length,
35845
+ terminalWidth: fittedCells.stackedWidth
35038
35846
  });
35847
+ return { output, notes: note ? [note] : [] };
35039
35848
  }
35040
35849
  function renderMarkdownEfficiencyTable(rows) {
35041
35850
  const bodyRows = toEfficiencyTableCells(rows).map(
@@ -35056,19 +35865,22 @@ function renderTerminalEfficiencyReport(efficiencyData, options) {
35056
35865
  useColor
35057
35866
  })
35058
35867
  );
35059
- outputLines.push("");
35060
- outputLines.push(renderTerminalEfficiencyTable(efficiencyData.rows, { useColor }));
35061
- return outputLines.join("\n");
35868
+ const table = renderTerminalEfficiencyTable(efficiencyData.rows, { useColor });
35869
+ outputLines.push("", table.output);
35870
+ return { output: outputLines.join("\n"), notes: table.notes };
35062
35871
  }
35063
- function renderEfficiencyReport(efficiencyData, format, options) {
35872
+ function renderEfficiencyReportWithNotes(efficiencyData, format, options) {
35064
35873
  switch (format) {
35065
35874
  case "json":
35066
- return renderReportJson("efficiency", {
35067
- grouping: efficiencyData.grouping,
35068
- rows: efficiencyData.rows
35069
- });
35875
+ return {
35876
+ output: renderReportJson("efficiency", {
35877
+ grouping: efficiencyData.grouping,
35878
+ rows: efficiencyData.rows
35879
+ }),
35880
+ notes: []
35881
+ };
35070
35882
  case "markdown":
35071
- return renderMarkdownEfficiencyTable(efficiencyData.rows);
35883
+ return { output: renderMarkdownEfficiencyTable(efficiencyData.rows), notes: [] };
35072
35884
  case "terminal":
35073
35885
  return renderTerminalEfficiencyReport(efficiencyData, options);
35074
35886
  }
@@ -35320,12 +36132,22 @@ async function assertRepoDirReadable(repoDir) {
35320
36132
  throw new Error(`Repository path is not a directory: ${repoDir}`);
35321
36133
  }
35322
36134
  }
35323
- async function assertGitRepository(repoDir, runCommand) {
35324
- const gitRepoResult = await runCommand(repoDir, ["rev-parse", "--is-inside-work-tree"]);
35325
- if (gitRepoResult.exitCode === 0) {
35326
- return;
35327
- }
35328
- throw new Error(`Repository is not a git repository: ${repoDir}`);
36135
+ async function isGitRepository(repoDir, runCommand) {
36136
+ const gitRepoResult = await runCommand(repoDir, ["rev-parse", "--is-inside-work-tree"]).catch(
36137
+ (error) => {
36138
+ if (getNodeErrorCode2(error) === "ENOENT") {
36139
+ throw new Error("git was not found on PATH; efficiency needs git installed", {
36140
+ cause: error
36141
+ });
36142
+ }
36143
+ throw error;
36144
+ }
36145
+ );
36146
+ return gitRepoResult.exitCode === 0;
36147
+ }
36148
+ function notGitRepositoryMessage(repoDir, repoDirOption) {
36149
+ const hint = repoDirOption === void 0 ? "<path>" : "<path to a git repository>";
36150
+ return `${repoDir} is not a git repository; pass --repo-dir ${hint}`;
35329
36151
  }
35330
36152
  function isNoCommitHistoryFailure(result) {
35331
36153
  if (result.exitCode !== 128) {
@@ -35598,11 +36420,20 @@ async function collectGitOutcomes(options, deps = {}) {
35598
36420
  const includeMergeCommits = options.includeMergeCommits ?? false;
35599
36421
  const runCommand = deps.runGitCommand ?? runGitCommand;
35600
36422
  if (options.activeUsageDays?.size === 0) {
35601
- return createEmptyOutcomeCollection(repoDir, includeMergeCommits);
36423
+ const emptyCollection = createEmptyOutcomeCollection(repoDir, includeMergeCommits);
36424
+ if (!deps.runGitCommand) {
36425
+ await assertRepoDirReadable(repoDir);
36426
+ if (!await isGitRepository(repoDir, runCommand)) {
36427
+ emptyCollection.warning = notGitRepositoryMessage(repoDir, options.repoDir);
36428
+ }
36429
+ }
36430
+ return emptyCollection;
35602
36431
  }
35603
36432
  if (!deps.runGitCommand) {
35604
36433
  await assertRepoDirReadable(repoDir);
35605
- await assertGitRepository(repoDir, runCommand);
36434
+ if (!await isGitRepository(repoDir, runCommand)) {
36435
+ throw new Error(notGitRepositoryMessage(repoDir, options.repoDir));
36436
+ }
35606
36437
  }
35607
36438
  let authorEmail;
35608
36439
  try {
@@ -35913,8 +36744,8 @@ async function buildEfficiencyData(granularity, options, deps = {}) {
35913
36744
  sourceFailures: dataset.sourceFailures,
35914
36745
  pricingOrigin,
35915
36746
  pricingWarning,
35916
- warnings: dataset.warnings,
35917
- notes: dataset.notes,
36747
+ warnings: gitOutcomes.warning ? [...dataset.warnings, gitOutcomes.warning] : dataset.warnings,
36748
+ notes: withUnpricedEventsNote(dataset.notes, matchedEventsWithSignal),
35918
36749
  activeEnvOverrides: dataset.readEnvVarOverrides(),
35919
36750
  activeConfig: dataset.activeConfig,
35920
36751
  timezone: dataset.normalizedInputs.timezone,
@@ -35968,9 +36799,12 @@ async function prepareEfficiencyReport(granularity, options, deps = {}) {
35968
36799
  title: "Efficiency share card",
35969
36800
  render: (theme) => renderEfficiencyMonthlyShareSvg(efficiencyData, theme)
35970
36801
  }) : void 0,
35971
- render: (efficiencyData, format) => renderEfficiencyReport(efficiencyData, format, {
35972
- granularity
35973
- })
36802
+ render: (efficiencyData, format) => {
36803
+ const { output, notes } = renderEfficiencyReportWithNotes(efficiencyData, format, {
36804
+ granularity
36805
+ });
36806
+ return { output, hintsAfterOutput: notes };
36807
+ }
35974
36808
  });
35975
36809
  }
35976
36810
  function emitEfficiencyReportDiagnostics(diagnostics) {
@@ -36204,7 +37038,8 @@ function renderTerminalOptimizeReport(optimizeData, options) {
36204
37038
  rowMetas: optimizeData.rows.map((row) => toTableRowMeta2(row)),
36205
37039
  layout: "compact",
36206
37040
  multilineColumnIndex: 1,
36207
- multilineColumnWidth: candidateColumnWidth
37041
+ multilineColumnWidth: candidateColumnWidth,
37042
+ terminalWidth: resolveTtyColumns(process.stdout)
36208
37043
  })
36209
37044
  );
36210
37045
  return outputLines.join("\n");
@@ -36382,7 +37217,7 @@ function hasAnyUsageSignal(period) {
36382
37217
  }
36383
37218
  function parseCandidateModelsRaw(candidateModel) {
36384
37219
  if (!candidateModel || Array.isArray(candidateModel) && candidateModel.length === 0) {
36385
- throw new Error("At least one --candidate-model is required");
37220
+ throw new Error("At least one --candidate-model is required, e.g. --candidate-model gpt-5.5");
36386
37221
  }
36387
37222
  const normalizedCandidates = (Array.isArray(candidateModel) ? candidateModel : [candidateModel]).flatMap((candidate) => candidate.split(",")).map((candidate) => candidate.trim().toLowerCase()).filter((candidate) => candidate.length > 0);
36388
37223
  if (normalizedCandidates.length === 0) {
@@ -36431,6 +37266,7 @@ function createSyntheticEvent(period) {
36431
37266
  reasoningTokens: period.reasoningTokens,
36432
37267
  cacheReadTokens: period.cacheReadTokens,
36433
37268
  cacheWriteTokens: period.cacheWriteTokens,
37269
+ cacheWrite1hTokens: period.cacheWrite1hTokens,
36434
37270
  totalTokens: period.totalTokens,
36435
37271
  costMode: "estimated",
36436
37272
  costUsd: void 0
@@ -36533,7 +37369,7 @@ function compareCandidateRank(left, right4) {
36533
37369
  }
36534
37370
  return compareByCodePoint(left.candidateModel, right4.candidateModel);
36535
37371
  }
36536
- function resolveBaselinePeriods(usageRows) {
37372
+ function resolveBaselinePeriods(usageRows, oneHourCacheWritesByPeriod) {
36537
37373
  const periodRows = /* @__PURE__ */ new Map();
36538
37374
  let grandTotalRow;
36539
37375
  for (const row of usageRows) {
@@ -36575,6 +37411,7 @@ function resolveBaselinePeriods(usageRows) {
36575
37411
  reasoningTokens: row.reasoningTokens,
36576
37412
  cacheReadTokens: row.cacheReadTokens,
36577
37413
  cacheWriteTokens: row.cacheWriteTokens,
37414
+ cacheWrite1hTokens: oneHourCacheWritesByPeriod.get(periodKey) ?? 0,
36578
37415
  totalTokens: row.totalTokens,
36579
37416
  baselineCostUsd: row.costUsd,
36580
37417
  baselineCostIncomplete: row.costIncomplete === true
@@ -36589,6 +37426,7 @@ function resolveBaselinePeriods(usageRows) {
36589
37426
  reasoningTokens: allRow.reasoningTokens,
36590
37427
  cacheReadTokens: allRow.cacheReadTokens,
36591
37428
  cacheWriteTokens: allRow.cacheWriteTokens,
37429
+ cacheWrite1hTokens: oneHourCacheWritesByPeriod.get("ALL") ?? 0,
36592
37430
  totalTokens: allRow.totalTokens,
36593
37431
  baselineCostUsd: allRow.costUsd,
36594
37432
  baselineCostIncomplete: allRow.costIncomplete === true
@@ -36601,6 +37439,7 @@ function resolveBaselinePeriods(usageRows) {
36601
37439
  reasoningTokens: 0,
36602
37440
  cacheReadTokens: 0,
36603
37441
  cacheWriteTokens: 0,
37442
+ cacheWrite1hTokens: 0,
36604
37443
  totalTokens: 0,
36605
37444
  baselineCostUsd: 0,
36606
37445
  baselineCostIncomplete: false
@@ -36616,7 +37455,7 @@ function buildWarning(periodKeys) {
36616
37455
  return `Baseline cost exists for zero-token periods (${sortedPeriodKeys.join(", ")}); savings were omitted.`;
36617
37456
  }
36618
37457
  function buildCounterfactualRows(input) {
36619
- const baselinePeriods = resolveBaselinePeriods(input.usageRows);
37458
+ const baselinePeriods = resolveBaselinePeriods(input.usageRows, input.oneHourCacheWritesByPeriod);
36620
37459
  const allPeriod = baselinePeriods.find((period) => period.periodKey === "ALL");
36621
37460
  if (!allPeriod) {
36622
37461
  throw new Error("Missing ALL baseline totals");
@@ -36659,7 +37498,7 @@ function buildCounterfactualRows(input) {
36659
37498
  }
36660
37499
 
36661
37500
  // src/cli/build-optimize-data.ts
36662
- function resolveOptimizeProvider(providers, providerFilter) {
37501
+ function resolveOptimizeProvider(providers, providerFilter, candidateModels) {
36663
37502
  const distinctProviders = collectCanonicalProviderRoots(providers);
36664
37503
  const normalizedProviderFilter = normalizeProviderFilter(providerFilter);
36665
37504
  if (distinctProviders.length > 1) {
@@ -36681,8 +37520,12 @@ function resolveOptimizeProvider(providers, providerFilter) {
36681
37520
  );
36682
37521
  }
36683
37522
  }
37523
+ const candidateProviders = inferCanonicalProviderRootsFromModels(candidateModels);
37524
+ const suggestedProvider = candidateProviders?.length === 1 && distinctProviders.includes(candidateProviders[0]) && distinctProviders.filter(
37525
+ (provider) => matchesCanonicalProviderFilter(provider, candidateProviders[0])
37526
+ ).length === 1 ? ` ${candidateProviders[0]}` : "";
36684
37527
  throw new Error(
36685
- `Optimize requires a single provider; found providers: ${distinctProviders.join(", ")}. Narrow with --provider.`
37528
+ `Optimize requires a single provider; found providers: ${distinctProviders.join(", ")}. Narrow with --provider${suggestedProvider}.`
36686
37529
  );
36687
37530
  }
36688
37531
  if (distinctProviders.length === 1) {
@@ -36704,7 +37547,11 @@ async function buildOptimizeData(granularity, options, deps = {}) {
36704
37547
  const provider = measureRuntimeProfileStageSync(
36705
37548
  deps.runtimeProfile,
36706
37549
  "optimize.resolve_provider",
36707
- () => resolveOptimizeProvider(detectedProviders, dataset.normalizedInputs.providerFilter)
37550
+ () => resolveOptimizeProvider(
37551
+ detectedProviders,
37552
+ dataset.normalizedInputs.providerFilter,
37553
+ candidateModels
37554
+ )
36708
37555
  );
36709
37556
  const { pricedEvents, pricingOrigin, pricingWarning, pricingSource } = await applyPricingToUsageEventDataset(dataset, deps, "force");
36710
37557
  const usageRows = measureRuntimeProfileStageSync(
@@ -36717,11 +37564,25 @@ async function buildOptimizeData(granularity, options, deps = {}) {
36717
37564
  includeModelBreakdown: false
36718
37565
  })
36719
37566
  );
37567
+ const oneHourCacheWritesByPeriod = /* @__PURE__ */ new Map();
37568
+ for (const event of pricedEvents) {
37569
+ if (event.cacheWrite1hTokens === 0) {
37570
+ continue;
37571
+ }
37572
+ const periodKey = getPeriodKey(event.timestamp, granularity, dataset.normalizedInputs.timezone);
37573
+ for (const key of [periodKey, "ALL"]) {
37574
+ oneHourCacheWritesByPeriod.set(
37575
+ key,
37576
+ (oneHourCacheWritesByPeriod.get(key) ?? 0) + event.cacheWrite1hTokens
37577
+ );
37578
+ }
37579
+ }
36720
37580
  const counterfactual = measureRuntimeProfileStageSync(
36721
37581
  deps.runtimeProfile,
36722
37582
  "optimize.counterfactual",
36723
37583
  () => buildCounterfactualRows({
36724
37584
  usageRows,
37585
+ oneHourCacheWritesByPeriod,
36725
37586
  provider,
36726
37587
  candidateModels,
36727
37588
  pricingSource,
@@ -36735,7 +37596,7 @@ async function buildOptimizeData(granularity, options, deps = {}) {
36735
37596
  pricingOrigin,
36736
37597
  pricingWarning,
36737
37598
  warnings: dataset.warnings,
36738
- notes: dataset.notes,
37599
+ notes: withUnpricedEventsNote(dataset.notes, pricedEvents),
36739
37600
  activeEnvOverrides: dataset.readEnvVarOverrides(),
36740
37601
  activeConfig: dataset.activeConfig,
36741
37602
  timezone: dataset.normalizedInputs.timezone,
@@ -36876,12 +37737,7 @@ function formatModels2(models) {
36876
37737
  if (models.length === 0) {
36877
37738
  return "-";
36878
37739
  }
36879
- if (models.length <= MAX_NAMED_MODELS) {
36880
- return models.join("\n");
36881
- }
36882
- return [...models.slice(0, MAX_NAMED_MODELS), `+${models.length - MAX_NAMED_MODELS} more`].join(
36883
- "\n"
36884
- );
37740
+ return limitNamedModels(models, MAX_NAMED_MODELS).join("\n");
36885
37741
  }
36886
37742
  function toSessionTableCells(row, options) {
36887
37743
  return [
@@ -36941,7 +37797,7 @@ function renderTerminalSessionReport(sessionData, options) {
36941
37797
  ""
36942
37798
  ];
36943
37799
  if (bodyRows.length === 0) {
36944
- outputLines.push("No usage data found for the selected filters.");
37800
+ outputLines.push(formatNoUsageMessage(options.filtered ?? false));
36945
37801
  return outputLines.join("\n");
36946
37802
  }
36947
37803
  const modelsColumnIndex3 = headers.length - 1;
@@ -36958,7 +37814,9 @@ function renderTerminalSessionReport(sessionData, options) {
36958
37814
  rowMetas: wrappedRows.map(() => toRowMeta()),
36959
37815
  layout: "top_aligned",
36960
37816
  multilineColumnIndex: modelsColumnIndex3,
36961
- multilineColumnWidth: MODELS_COLUMN_WIDTH
37817
+ multilineColumnWidth: MODELS_COLUMN_WIDTH,
37818
+ terminalWidth: resolveTtyColumns(process.stdout),
37819
+ stackedTitleColumnCount: 1
36962
37820
  })
36963
37821
  );
36964
37822
  return outputLines.join("\n");
@@ -37240,14 +38098,14 @@ async function buildSessionData(options, deps = {}) {
37240
38098
  since: options.since,
37241
38099
  until: options.until
37242
38100
  };
37243
- const diagnostics = buildUsageDiagnostics({
38101
+ const buildDiagnostics = (shownEvents) => buildUsageDiagnostics({
37244
38102
  adaptersToParse: dataset.adaptersToParse,
37245
38103
  successfulParseResults: dataset.successfulParseResults,
37246
38104
  sourceFailures: dataset.sourceFailures,
37247
38105
  pricingOrigin,
37248
38106
  pricingWarning,
37249
38107
  warnings: dataset.warnings,
37250
- notes: dataset.notes,
38108
+ notes: withUnpricedEventsNote(dataset.notes, shownEvents),
37251
38109
  activeEnvOverrides: dataset.readEnvVarOverrides(),
37252
38110
  activeConfig: dataset.activeConfig,
37253
38111
  timezone: dataset.normalizedInputs.timezone,
@@ -37260,11 +38118,14 @@ async function buildSessionData(options, deps = {}) {
37260
38118
  () => aggregateSessionsByRepo(pricedEvents, aggregateOptions)
37261
38119
  );
37262
38120
  const limited2 = limitRows(repoRows, limit, "repos");
38121
+ const shownRepos = new Set(limited2.rows.map((row) => row.repoRoot ?? ""));
37263
38122
  return {
37264
38123
  grouping: "repo",
37265
38124
  rows: limited2.rows,
37266
38125
  limitNote: limited2.limitNote,
37267
- diagnostics
38126
+ diagnostics: buildDiagnostics(
38127
+ pricedEvents.filter((event) => shownRepos.has(event.repoRoot ?? ""))
38128
+ )
37268
38129
  };
37269
38130
  }
37270
38131
  const sessionRows = measureRuntimeProfileStageSync(
@@ -37273,11 +38134,14 @@ async function buildSessionData(options, deps = {}) {
37273
38134
  () => aggregateSessions(pricedEvents, { ...aggregateOptions, ids: idFilters })
37274
38135
  );
37275
38136
  const limited = limitRows(sessionRows, limit, "sessions");
38137
+ const shownSessions = new Set(limited.rows.map((row) => getEventSessionKey(row)));
37276
38138
  return {
37277
38139
  grouping: "session",
37278
38140
  rows: limited.rows,
37279
38141
  limitNote: limited.limitNote,
37280
- diagnostics
38142
+ diagnostics: buildDiagnostics(
38143
+ pricedEvents.filter((event) => shownSessions.has(getEventSessionKey(event)))
38144
+ )
37281
38145
  };
37282
38146
  }
37283
38147
 
@@ -37295,7 +38159,8 @@ async function prepareSessionReport(options, deps = {}) {
37295
38159
  runtimeProfile: deps.runtimeProfile,
37296
38160
  render: (sessionData, format) => renderSessionReport(sessionData, format, {
37297
38161
  timezone: sessionData.diagnostics.timezone,
37298
- truncateSessionIds: !options.id?.length
38162
+ truncateSessionIds: !options.id?.length,
38163
+ filtered: hasCliFilters(options)
37299
38164
  })
37300
38165
  });
37301
38166
  }
@@ -37386,17 +38251,20 @@ function formatCost2(period) {
37386
38251
  }
37387
38252
  return `${period.totals.costIncomplete ? "~" : ""}${usdFormatter6.format(period.totals.costUsd)}`;
37388
38253
  }
38254
+ function formatCostShare(period, costUsd) {
38255
+ const totalCost = period.totals.costUsd ?? 0;
38256
+ if (totalCost <= 0 || costUsd === void 0) {
38257
+ return void 0;
38258
+ }
38259
+ return `${period.totals.costIncomplete ? "~" : ""}${String(Math.round(costUsd / totalCost * 100))}%`;
38260
+ }
37389
38261
  function formatTopSource(period) {
37390
38262
  if (period.sources.length === 0) {
37391
38263
  return "-";
37392
38264
  }
37393
38265
  const topSource = period.sources[0];
37394
- const totalCost = period.totals.costUsd ?? 0;
37395
- if (totalCost <= 0 || topSource.costUsd === void 0) {
37396
- return topSource.source;
37397
- }
37398
- const share = `${String(Math.round(topSource.costUsd / totalCost * 100))}%`;
37399
- return `${topSource.source} (${period.totals.costIncomplete ? "~" : ""}${share})`;
38266
+ const share = formatCostShare(period, topSource.costUsd);
38267
+ return share === void 0 ? topSource.source : `${topSource.source} (${share})`;
37400
38268
  }
37401
38269
  function toTableRow(period) {
37402
38270
  return [
@@ -37409,6 +38277,19 @@ function toTableRow(period) {
37409
38277
  function hasAnyUsage(summaryData) {
37410
38278
  return summaryData.periods.some((period) => period.totals.events > 0);
37411
38279
  }
38280
+ function toNoRecentUsageMessage(summaryData, filtered) {
38281
+ if (filtered) {
38282
+ return "No usage in the last 7 days or this month for the selected filters.";
38283
+ }
38284
+ const latestDay = summaryData.activity.days.filter((day) => day.totalTokens > 0).at(-1);
38285
+ if (latestDay) {
38286
+ return `No usage in the last 7 days or this month. Latest usage: ${latestDay.date}. Try \`llm-usage monthly --all\`.`;
38287
+ }
38288
+ if (summaryData.diagnostics.sessionStats.some((stat10) => stat10.filesFound > 0)) {
38289
+ return "No usage in the past year. Try `llm-usage monthly --all`.";
38290
+ }
38291
+ return "No usage found in the last 7 days or this month. Run `llm-usage doctor` to see which sources were found.";
38292
+ }
37412
38293
  function getTitle(summaryData) {
37413
38294
  const today = summaryData.periods[0]?.until ?? "";
37414
38295
  return `Usage summary for ${today} (${summaryData.timezone})`;
@@ -37461,12 +38342,38 @@ function renderTerminalActivity(activity, options, useColor) {
37461
38342
  ...heatmap.length > 0 ? ["", ...heatmap] : []
37462
38343
  ];
37463
38344
  }
38345
+ function formatTokenShare(tokens, totalTokens) {
38346
+ return `${String(Math.round(tokens / totalTokens * 100))}%`;
38347
+ }
38348
+ function formatMachinesNote2(monthToDate) {
38349
+ if (monthToDate?.machines === void 0 || monthToDate.machines.length < 2) {
38350
+ return void 0;
38351
+ }
38352
+ const byCost = (monthToDate.totals.costUsd ?? 0) > 0;
38353
+ if (!byCost && monthToDate.totals.totalTokens === 0) {
38354
+ return void 0;
38355
+ }
38356
+ const parts = monthToDate.machines.map((machine) => {
38357
+ if (!byCost) {
38358
+ const share2 = formatTokenShare(machine.totalTokens, monthToDate.totals.totalTokens);
38359
+ return `${machine.machine} ${formatCompact(machine.totalTokens)} tokens (${share2})`;
38360
+ }
38361
+ const cost = formatApproxUsd(machine.costUsd, machine.costIncomplete);
38362
+ const share = formatCostShare(monthToDate, machine.costUsd);
38363
+ return share === void 0 ? `${machine.machine} ${cost}` : `${machine.machine} ${cost} (${share})`;
38364
+ });
38365
+ return `This month by machine: ${parts.join(", ")}`;
38366
+ }
37464
38367
  function toMonthNotes(summaryData) {
37465
38368
  const { monthEnd } = summaryData;
37466
38369
  const monthToDate = summaryData.periods.find((period) => period.key === "monthToDate");
37467
38370
  const spentUsd = monthToDate?.totals.costUsd;
37468
38371
  const spent = formatApproxUsd(spentUsd, monthToDate?.totals.costIncomplete);
37469
38372
  const notes = [];
38373
+ const machinesNote = formatMachinesNote2(monthToDate);
38374
+ if (machinesNote !== void 0) {
38375
+ notes.push({ text: machinesNote, warning: false });
38376
+ }
37470
38377
  if (monthEnd.projectedCostUsd !== void 0) {
37471
38378
  notes.push({
37472
38379
  text: `On pace for ${formatApproxUsd(monthEnd.projectedCostUsd, monthEnd.costIncomplete)} this month`,
@@ -37510,12 +38417,16 @@ function renderTerminalSummaryReport(summaryData, options) {
37510
38417
  periodKey: "summary",
37511
38418
  rowKind: "detail"
37512
38419
  }));
37513
- const lines = [renderReportHeader({ title: getTitle(summaryData), useColor }), ""];
38420
+ const lines = [
38421
+ renderReportHeader({
38422
+ title: getTitle(summaryData),
38423
+ useColor,
38424
+ terminalWidth: options.terminalWidth
38425
+ }),
38426
+ ""
38427
+ ];
37514
38428
  if (!hasAnyUsage(summaryData)) {
37515
- lines.push(
37516
- "No usage found in the last 7 days or this month. Run `llm-usage doctor` to see which sources were found."
37517
- );
37518
- lines.push("");
38429
+ lines.push(toNoRecentUsageMessage(summaryData, options.filtered ?? false), "");
37519
38430
  }
37520
38431
  lines.push(
37521
38432
  renderUnicodeTable({
@@ -37527,7 +38438,8 @@ function renderTerminalSummaryReport(summaryData, options) {
37527
38438
  layout: "compact",
37528
38439
  multilineColumnIndex: 0,
37529
38440
  multilineColumnWidth: 13,
37530
- leftAlignedColumnIndexes: [3]
38441
+ leftAlignedColumnIndexes: [3],
38442
+ terminalWidth: options.terminalWidth ?? resolveTtyColumns(process.stdout)
37531
38443
  })
37532
38444
  );
37533
38445
  const monthNotes = toMonthNotes(summaryData);
@@ -37648,6 +38560,80 @@ function renderStats(data, theme) {
37648
38560
  })
37649
38561
  ].join("\n");
37650
38562
  }
38563
+ var machinesLeft = right2 - 660;
38564
+ var machinesTop = 270;
38565
+ var machineSlotWidth = 190;
38566
+ var machineSlots = 3;
38567
+ function toMachineShares(machines, byCost, theme) {
38568
+ const totalCost = machines.reduce((sum, machine) => sum + (machine.costUsd ?? 0), 0);
38569
+ const totalTokens = machines.reduce((sum, machine) => sum + machine.totalTokens, 0);
38570
+ const shareOf = (machine) => byCost ? (machine.costUsd ?? 0) / totalCost : machine.totalTokens / totalTokens;
38571
+ const fills = [theme.heat[3], theme.heat[2], theme.textMuted];
38572
+ const named = machines.length <= machineSlots ? machines : machines.slice(0, machineSlots - 1);
38573
+ const shares = named.map((machine, index) => ({
38574
+ label: machine.machine,
38575
+ share: shareOf(machine),
38576
+ fill: fills[index]
38577
+ }));
38578
+ if (named.length < machines.length) {
38579
+ const rest = machines.slice(named.length);
38580
+ shares.push({
38581
+ label: `${formatInteger2(rest.length)} others`,
38582
+ share: rest.reduce((sum, machine) => sum + shareOf(machine), 0),
38583
+ fill: fills[machineSlots - 1]
38584
+ });
38585
+ }
38586
+ return shares;
38587
+ }
38588
+ function renderMachines(data, theme) {
38589
+ const monthToDate = findPeriod(data, "monthToDate");
38590
+ const machines = monthToDate?.machines ?? [];
38591
+ const byCost = machines.some((machine) => (machine.costUsd ?? 0) > 0);
38592
+ if (machines.length < 2 || !byCost && !machines.some((machine) => machine.totalTokens > 0)) {
38593
+ return "";
38594
+ }
38595
+ const shares = toMachineShares(machines, byCost, theme);
38596
+ const approximate = byCost && monthToDate?.totals.costIncomplete === true ? "~" : "";
38597
+ const barWidth = right2 - machinesLeft;
38598
+ const barTop = machinesTop + 12;
38599
+ const legendY = barTop + 30;
38600
+ let segmentX = machinesLeft;
38601
+ const parts = [
38602
+ svgText(
38603
+ machinesLeft,
38604
+ machinesTop,
38605
+ byCost ? "This month by machine" : "This month by machine (tokens)",
38606
+ {
38607
+ size: 16,
38608
+ fill: theme.textSecondary
38609
+ }
38610
+ ),
38611
+ `<rect x="${machinesLeft}" y="${barTop}" width="${barWidth}" height="8" rx="2" fill="${theme.line}"/>`
38612
+ ];
38613
+ shares.forEach((share, index) => {
38614
+ const width = share.share * barWidth;
38615
+ const slotX = machinesLeft + index * machineSlotWidth;
38616
+ const segmentLeft = segmentX;
38617
+ segmentX += width;
38618
+ parts.push(
38619
+ `<rect x="${segmentLeft.toFixed(2)}" y="${barTop}" width="${width.toFixed(2)}" height="8" rx="2" fill="${share.fill}"/>`,
38620
+ `<circle cx="${slotX + 5}" cy="${legendY - 5}" r="5" fill="${share.fill}"/>`,
38621
+ svgText(slotX + 18, legendY, truncateLabel(share.label, 12), {
38622
+ size: 15,
38623
+ fill: theme.text
38624
+ }),
38625
+ svgText(slotX + 166, legendY, `${approximate}${String(Math.round(share.share * 100))}%`, {
38626
+ size: 15,
38627
+ fill: theme.textSecondary,
38628
+ mono: true,
38629
+ anchor: "end"
38630
+ })
38631
+ );
38632
+ });
38633
+ return `<g data-machines="true">
38634
+ ${parts.join("\n")}
38635
+ </g>`;
38636
+ }
37651
38637
  function renderActivity(data, theme) {
37652
38638
  const { activity } = data;
37653
38639
  const gridBottom2 = gridTop2 + 7 * gridPitch;
@@ -37662,8 +38648,7 @@ function renderActivity(data, theme) {
37662
38648
  ].join("\n");
37663
38649
  }
37664
38650
  function renderSummaryShareSvg(data, theme) {
37665
- const body = data.activity.activeDays === 0 ? renderEmptyState(theme, "No usage in the past year") : `${renderStats(data, theme)}
37666
- ${renderActivity(data, theme)}`;
38651
+ const body = data.activity.activeDays === 0 ? renderEmptyState(theme, "No usage in the past year") : [renderStats(data, theme), renderMachines(data, theme), renderActivity(data, theme)].filter(Boolean).join("\n");
37667
38652
  return renderShareCard({
37668
38653
  theme,
37669
38654
  title: "LLM usage activity",
@@ -37844,15 +38829,31 @@ function isNarrowedByCliFilters(cliOptions) {
37844
38829
  const hasModel = Array.isArray(model) ? model.length > 0 : Boolean(model);
37845
38830
  return hasSource || hasModel || Boolean(cliOptions.provider);
37846
38831
  }
37847
- function compareSourcesByCost(left, right4) {
38832
+ function compareByCost(left, right4) {
37848
38833
  const costDelta = (right4.costUsd ?? 0) - (left.costUsd ?? 0);
37849
38834
  if (costDelta !== 0) {
37850
38835
  return costDelta;
37851
38836
  }
37852
- if (left.totalTokens !== right4.totalTokens) {
37853
- return right4.totalTokens - left.totalTokens;
38837
+ return right4.totalTokens - left.totalTokens;
38838
+ }
38839
+ function compareSourcesByCost(left, right4) {
38840
+ return compareByCost(left, right4) || compareByCodePoint(left.source, right4.source);
38841
+ }
38842
+ function compareMachinesByCost(left, right4) {
38843
+ return compareByCost(left, right4) || compareByCodePoint(left.machine, right4.machine);
38844
+ }
38845
+ function summarizeMachines(events, timezone, sourceOrder) {
38846
+ const eventsByMachine = /* @__PURE__ */ new Map();
38847
+ for (const event of events) {
38848
+ const machine = event.machine ?? LOCAL_MACHINE_NAME;
38849
+ const machineEvents = eventsByMachine.get(machine) ?? [];
38850
+ machineEvents.push(event);
38851
+ eventsByMachine.set(machine, machineEvents);
37854
38852
  }
37855
- return compareByCodePoint(left.source, right4.source);
38853
+ return [...eventsByMachine].map(([machine, machineEvents]) => ({
38854
+ machine,
38855
+ ...summarizeUsageWindow(machineEvents, timezone, sourceOrder).totals
38856
+ })).sort(compareMachinesByCost);
37856
38857
  }
37857
38858
  async function buildSummaryData(options, deps = {}) {
37858
38859
  const userConfigResolution = await resolveUserConfigForOptions(options, deps);
@@ -37875,16 +38876,16 @@ async function buildSummaryData(options, deps = {}) {
37875
38876
  );
37876
38877
  const { pricedEvents, pricingOrigin, pricingWarning, pricingSource } = await applyPricingToUsageEventDataset(dataset, deps, "auto");
37877
38878
  const sourceOrder = dataset.adaptersToParse.map((adapter) => adapter.id);
38879
+ const countsOtherMachines = pricedEvents.some((event) => event.machine !== void 0);
37878
38880
  const periods = measureRuntimeProfileStageSync(
37879
38881
  deps.runtimeProfile,
37880
38882
  "summary.aggregate",
37881
38883
  () => windows.map((window) => {
37882
- const summary = summarizeUsageWindow(
37883
- pricedEvents.filter((event) => isEventWithinWindow(event, window, timezone)),
37884
- timezone,
37885
- sourceOrder
38884
+ const windowEvents = pricedEvents.filter(
38885
+ (event) => isEventWithinWindow(event, window, timezone)
37886
38886
  );
37887
- return {
38887
+ const summary = summarizeUsageWindow(windowEvents, timezone, sourceOrder);
38888
+ const period = {
37888
38889
  key: window.key,
37889
38890
  label: window.label,
37890
38891
  since: window.since,
@@ -37892,6 +38893,10 @@ async function buildSummaryData(options, deps = {}) {
37892
38893
  totals: summary.totals,
37893
38894
  sources: [...summary.sources].map(([source, totals]) => ({ source, ...totals })).sort(compareSourcesByCost)
37894
38895
  };
38896
+ if (countsOtherMachines) {
38897
+ period.machines = summarizeMachines(windowEvents, timezone, sourceOrder);
38898
+ }
38899
+ return period;
37895
38900
  })
37896
38901
  );
37897
38902
  const activity = measureRuntimeProfileStageSync(
@@ -37905,6 +38910,10 @@ async function buildSummaryData(options, deps = {}) {
37905
38910
  pricedEvents.filter((event) => isEventWithinWindow(event, monthToDateWindow, timezone)),
37906
38911
  pricingSource
37907
38912
  ) : void 0;
38913
+ const bestDay = activity.bestDay?.costUsd === void 0 ? void 0 : activity.bestDay.date;
38914
+ const shownCostEvents = pricedEvents.filter(
38915
+ (event) => windows.some((window) => isEventWithinWindow(event, window, timezone)) || getPeriodKey(event.timestamp, "daily", timezone) === bestDay
38916
+ );
37908
38917
  return {
37909
38918
  timezone,
37910
38919
  periods,
@@ -37922,7 +38931,7 @@ async function buildSummaryData(options, deps = {}) {
37922
38931
  pricingOrigin,
37923
38932
  pricingWarning,
37924
38933
  warnings: dataset.warnings,
37925
- notes: dataset.notes,
38934
+ notes: withUnpricedEventsNote(dataset.notes, shownCostEvents),
37926
38935
  activeEnvOverrides: dataset.readEnvVarOverrides(),
37927
38936
  activeConfig: dataset.activeConfig,
37928
38937
  timezone,
@@ -37947,7 +38956,7 @@ async function prepareSummaryReport(options, deps = {}) {
37947
38956
  title: "Activity share card",
37948
38957
  render: (theme) => renderSummaryShareSvg(summaryData, theme)
37949
38958
  }) : void 0,
37950
- render: (summaryData, format) => renderSummaryReport(summaryData, format),
38959
+ render: (summaryData, format) => renderSummaryReport(summaryData, format, { filtered: hasCliFilters(options) }),
37951
38960
  getHintsAfterOutput: (_summaryData, format) => format === "terminal" ? [SUMMARY_NEXT_STEPS_HINT] : []
37952
38961
  });
37953
38962
  }
@@ -38042,9 +39051,6 @@ function formatStatusline(summary, session) {
38042
39051
  return parts.join(SEPARATOR);
38043
39052
  }
38044
39053
  async function buildStatuslineSummary(options, deps) {
38045
- if (options.json) {
38046
- throw new Error("--json is not supported for statusline; use llm-usage summary --json");
38047
- }
38048
39054
  return buildSummaryData({ ...options, pricingOffline: true, sync: false }, deps);
38049
39055
  }
38050
39056
  async function runStatusline(options, deps = {}) {
@@ -38191,7 +39197,7 @@ function renderSummaryOnly(trendsData, options) {
38191
39197
  }
38192
39198
  if (trendsData.totalSeries.summary.observedDayCount === 0) {
38193
39199
  lines.push("No usage data found for the selected date range.");
38194
- lines.push("");
39200
+ return lines.join("\n");
38195
39201
  }
38196
39202
  if (shouldShowNoResolvedCostDataNote(trendsData)) {
38197
39203
  lines.push(
@@ -38350,8 +39356,9 @@ function renderTerminalTrendsReport(trendsData, options) {
38350
39356
  const terminalWidth = resolveTerminalWidth2(options.terminalWidth);
38351
39357
  const accent = trendsData.metric === "cost" ? pc8.green : pc8.cyan;
38352
39358
  const minimumChartWidth = 40;
38353
- if (terminalWidth !== void 0 && terminalWidth < minimumChartWidth) {
38354
- return renderSummaryOnly(trendsData, { useColor, narrowNote: true });
39359
+ const isEmpty = trendsData.totalSeries.summary.observedDayCount === 0;
39360
+ if (isEmpty || terminalWidth !== void 0 && terminalWidth < minimumChartWidth) {
39361
+ return renderSummaryOnly(trendsData, { useColor, narrowNote: !isEmpty });
38355
39362
  }
38356
39363
  const lines = [
38357
39364
  renderReportHeader({
@@ -38360,10 +39367,6 @@ function renderTerminalTrendsReport(trendsData, options) {
38360
39367
  }),
38361
39368
  ""
38362
39369
  ];
38363
- if (trendsData.totalSeries.summary.observedDayCount === 0) {
38364
- lines.push("No usage data found for the selected date range.");
38365
- lines.push("");
38366
- }
38367
39370
  if (shouldShowNoResolvedCostDataNote(trendsData)) {
38368
39371
  lines.push(
38369
39372
  "No resolved cost data for the selected range; use pricing or switch to --metric tokens."
@@ -38714,16 +39717,6 @@ function aggregateTrends(rows, options) {
38714
39717
  }
38715
39718
 
38716
39719
  // src/cli/build-trends-data.ts
38717
- function parseDaysOption(days) {
38718
- if (days === void 0) {
38719
- return void 0;
38720
- }
38721
- const trimmedDays = days.trim();
38722
- if (!/^[1-9]\d*$/u.test(trimmedDays)) {
38723
- throw new Error("--days must be a positive integer");
38724
- }
38725
- return Number.parseInt(trimmedDays, 10);
38726
- }
38727
39720
  function resolveMetric(metric) {
38728
39721
  if (metric === void 0 || metric.trim() === "") {
38729
39722
  return "cost";
@@ -38794,8 +39787,13 @@ function resolveOutputDateRange(options, today, days, observedDates) {
38794
39787
  };
38795
39788
  }
38796
39789
  function resolveTrendsOptions(options, timezone, now) {
38797
- if (options.days !== void 0 && (options.since || options.until)) {
38798
- throw new Error("--days cannot be combined with --since or --until");
39790
+ if (options.last !== void 0 && options.days !== void 0) {
39791
+ throw new Error("--days is an alias of --last; pass only --last");
39792
+ }
39793
+ const daysFlag = options.days === void 0 ? "--last" : "--days";
39794
+ const daysValue = options.last ?? options.days;
39795
+ if (daysValue !== void 0 && (options.since || options.until)) {
39796
+ throw new Error(`${daysFlag} cannot be combined with --since or --until`);
38799
39797
  }
38800
39798
  if (options.since) {
38801
39799
  validateDateInput(options.since, "--since");
@@ -38807,7 +39805,7 @@ function resolveTrendsOptions(options, timezone, now) {
38807
39805
  throw new Error("--since must be less than or equal to --until");
38808
39806
  }
38809
39807
  const metric = resolveMetric(options.metric);
38810
- const days = parseDaysOption(options.days);
39808
+ const days = parseLastOption(daysValue, daysFlag);
38811
39809
  const today = getCurrentLocalDateKey(timezone, now);
38812
39810
  return {
38813
39811
  days,
@@ -38914,6 +39912,10 @@ async function buildTrendsData(options, deps = {}) {
38914
39912
  sourceOrder: dataset.adaptersToParse.map((adapter) => adapter.id)
38915
39913
  })
38916
39914
  );
39915
+ const chartedEvents = resolved.metric === "cost" ? pricingResult.pricedEvents.filter((event) => {
39916
+ const day = getPeriodKey(event.timestamp, "daily", dataset.normalizedInputs.timezone);
39917
+ return day >= outputDateRange.from && day <= outputDateRange.to;
39918
+ }) : [];
38917
39919
  const diagnostics = buildUsageDiagnostics({
38918
39920
  adaptersToParse: dataset.adaptersToParse,
38919
39921
  successfulParseResults: dataset.successfulParseResults,
@@ -38921,7 +39923,7 @@ async function buildTrendsData(options, deps = {}) {
38921
39923
  pricingOrigin: pricingResult.pricingOrigin,
38922
39924
  pricingWarning: pricingResult.pricingWarning,
38923
39925
  warnings: dataset.warnings,
38924
- notes: dataset.notes,
39926
+ notes: withUnpricedEventsNote(dataset.notes, chartedEvents),
38925
39927
  activeEnvOverrides: dataset.readEnvVarOverrides(),
38926
39928
  activeConfig: dataset.activeConfig,
38927
39929
  timezone: dataset.normalizedInputs.timezone,
@@ -39074,7 +40076,8 @@ function describeTableFit(fit, compact, hideCost = false) {
39074
40076
  if (changes.length === 0) {
39075
40077
  return void 0;
39076
40078
  }
39077
- return `Fitted the table to the terminal: ${changes.join(", ")}. Widen the terminal or use --json for full detail.`;
40079
+ const layout = fit.stacked ? "Listed rows instead of a table to fit the terminal" : "Fitted the table to the terminal";
40080
+ return `${layout}: ${changes.join(", ")}. Widen the terminal or use --json for full detail.`;
39078
40081
  }
39079
40082
  function renderTerminalUsageReport(usageData, options) {
39080
40083
  const outputLines = [];
@@ -39083,12 +40086,13 @@ function renderTerminalUsageReport(usageData, options) {
39083
40086
  outputLines.push(
39084
40087
  renderReportHeader({
39085
40088
  title: getReportTitle4(options.granularity),
39086
- useColor
40089
+ useColor,
40090
+ terminalWidth: options.terminalWidth
39087
40091
  })
39088
40092
  );
39089
40093
  outputLines.push("");
39090
- if (usageData.rows.length === 0) {
39091
- outputLines.push("No usage data found for the selected filters.");
40094
+ if (usageData.rows.every((row) => row.rowType === "grand_total")) {
40095
+ outputLines.push(formatNoUsageMessage(options.filtered ?? false));
39092
40096
  return { output: outputLines.join("\n"), notes: [] };
39093
40097
  }
39094
40098
  const { output, fit } = renderTerminalTableWithFit(usageData.rows, {
@@ -39350,7 +40354,8 @@ async function prepareUsageReport(granularity, options, deps = {}) {
39350
40354
  granularity,
39351
40355
  tableLayout,
39352
40356
  compact: options.compact,
39353
- hideCost
40357
+ hideCost,
40358
+ filtered: hasCliFilters(options)
39354
40359
  });
39355
40360
  return { output, hintsAfterOutput: notes };
39356
40361
  },
@@ -40020,9 +41025,6 @@ async function runPruneReport(options, deps = {}) {
40020
41025
  var eventsExportFormats = ["jsonl", "csv"];
40021
41026
  var CSV_HEADER = "source,sessionId,timestamp,repoRoot,provider,model,inputTokens,outputTokens,reasoningTokens,cacheReadTokens,cacheWriteTokens,totalTokens,costUsd,costMode,machine";
40022
41027
  function resolveEventsFormat(options) {
40023
- if (options.json) {
40024
- throw new Error("--json is not supported for events; use --format jsonl");
40025
- }
40026
41028
  const format = options.format ?? "jsonl";
40027
41029
  const resolved = eventsExportFormats.find((candidate) => candidate === format);
40028
41030
  if (!resolved) {
@@ -40208,17 +41210,31 @@ function renderTopTable(headerCells, bodyRows) {
40208
41210
  rowMetas,
40209
41211
  layout: "compact",
40210
41212
  multilineColumnIndex: TOP_ITEM_NAME_COLUMN,
40211
- multilineColumnWidth: nameColumnWidth
41213
+ multilineColumnWidth: nameColumnWidth,
41214
+ terminalWidth: resolveTtyColumns(process.stdout)
40212
41215
  });
40213
41216
  }
41217
+ function toEmptyMessage(recap, filtered) {
41218
+ if (recap.eventCount > 0) {
41219
+ return void 0;
41220
+ }
41221
+ return filtered ? formatNoUsageMessage(true) : `No usage in ${recap.year}.`;
41222
+ }
40214
41223
  function renderWrappedTerminalReport(recap, options) {
40215
41224
  const useColor = options.useColor ?? shouldUseColorByDefault();
40216
41225
  const palette = options.palette ?? defaultTerminalStylePalette;
40217
41226
  const paint = (styler) => (text2) => useColor ? styler(text2) : text2;
40218
- return [
41227
+ const heading = [
40219
41228
  renderReportHeader({ title: `Wrapped ${recap.year}`, useColor }),
40220
41229
  paint(palette.dim)(`${recap.from} to ${recap.to} (${recap.timezone})`),
40221
- "",
41230
+ ""
41231
+ ];
41232
+ const emptyMessage = toEmptyMessage(recap, options.filtered ?? false);
41233
+ if (emptyMessage) {
41234
+ return [...heading, emptyMessage].join("\n");
41235
+ }
41236
+ return [
41237
+ ...heading,
40222
41238
  renderStatLines(recap, paint, palette),
40223
41239
  "",
40224
41240
  "Monthly activity",
@@ -40636,7 +41652,7 @@ async function buildWrappedData(options, deps = {}) {
40636
41652
  pricingOrigin,
40637
41653
  pricingWarning,
40638
41654
  warnings: dataset.warnings,
40639
- notes: dataset.notes,
41655
+ notes: withUnpricedEventsNote(dataset.notes, pricedEvents),
40640
41656
  activeEnvOverrides: dataset.readEnvVarOverrides(),
40641
41657
  activeConfig: dataset.activeConfig,
40642
41658
  timezone: dataset.normalizedInputs.timezone,
@@ -40665,7 +41681,7 @@ async function prepareWrappedReport(options, deps = {}) {
40665
41681
  title: `${wrappedData.recap.year} Wrapped share card`,
40666
41682
  render: (theme) => renderWrappedShareSvg(wrappedData.recap, theme)
40667
41683
  }) : void 0,
40668
- render: (wrappedData, format) => renderWrappedReport(wrappedData.recap, format)
41684
+ render: (wrappedData, format) => renderWrappedReport(wrappedData.recap, format, { filtered: hasCliFilters(options) })
40669
41685
  });
40670
41686
  }
40671
41687
  async function runWrappedReport(options) {
@@ -40678,102 +41694,144 @@ async function runWrappedReport(options) {
40678
41694
  import { Option } from "commander";
40679
41695
  var sharedOptionProfileConfig = {
40680
41696
  usage: {
41697
+ includeJson: true,
41698
+ includeQuiet: true,
40681
41699
  includeDateFilters: true,
40682
41700
  includeMarkdown: true,
40683
41701
  includePerModelColumns: true,
40684
41702
  includePricing: true,
41703
+ includePricingFetch: true,
40685
41704
  includeProviderModelFilters: true,
40686
41705
  includeHistory: true,
41706
+ includeSync: true,
40687
41707
  includeShare: true,
40688
41708
  includeTimezone: true
40689
41709
  },
40690
41710
  summary: {
41711
+ includeJson: true,
41712
+ includeQuiet: true,
40691
41713
  includeDateFilters: false,
40692
41714
  includeMarkdown: true,
40693
41715
  includePerModelColumns: false,
40694
41716
  includePricing: true,
41717
+ includePricingFetch: true,
40695
41718
  includeProviderModelFilters: true,
40696
41719
  includeHistory: true,
41720
+ includeSync: true,
40697
41721
  includeShare: true,
40698
41722
  includeTimezone: true
40699
41723
  },
40700
41724
  specialized: {
41725
+ includeJson: true,
41726
+ includeQuiet: true,
40701
41727
  includeDateFilters: true,
40702
41728
  includeMarkdown: true,
40703
41729
  includePerModelColumns: false,
40704
41730
  includePricing: true,
41731
+ includePricingFetch: true,
40705
41732
  includeProviderModelFilters: true,
40706
41733
  includeHistory: true,
41734
+ includeSync: true,
40707
41735
  includeShare: true,
40708
41736
  includeTimezone: true
40709
41737
  },
40710
41738
  compare: {
41739
+ includeJson: true,
41740
+ includeQuiet: true,
40711
41741
  includeDateFilters: true,
40712
41742
  includeMarkdown: true,
40713
41743
  includePerModelColumns: false,
40714
41744
  includePricing: true,
41745
+ includePricingFetch: true,
40715
41746
  includeProviderModelFilters: true,
40716
41747
  includeHistory: true,
41748
+ includeSync: true,
40717
41749
  includeShare: true,
40718
41750
  includeTimezone: true
40719
41751
  },
40720
41752
  trends: {
41753
+ includeJson: true,
41754
+ includeQuiet: true,
40721
41755
  includeDateFilters: true,
40722
41756
  includeMarkdown: true,
40723
41757
  includePerModelColumns: false,
40724
41758
  includePricing: true,
41759
+ includePricingFetch: true,
40725
41760
  includeProviderModelFilters: true,
40726
41761
  includeHistory: true,
41762
+ includeSync: true,
40727
41763
  includeShare: true,
40728
41764
  includeTimezone: true
40729
41765
  },
40730
41766
  session: {
41767
+ includeJson: true,
41768
+ includeQuiet: true,
40731
41769
  includeDateFilters: true,
40732
41770
  includeMarkdown: true,
40733
41771
  includePerModelColumns: false,
40734
41772
  includePricing: true,
41773
+ includePricingFetch: true,
40735
41774
  includeProviderModelFilters: true,
40736
41775
  includeHistory: true,
41776
+ includeSync: true,
40737
41777
  includeShare: false,
40738
41778
  includeTimezone: true
40739
41779
  },
40740
41780
  wrapped: {
41781
+ includeJson: true,
41782
+ includeQuiet: true,
40741
41783
  includeDateFilters: false,
40742
41784
  includeMarkdown: true,
40743
41785
  includePerModelColumns: false,
40744
41786
  includePricing: true,
41787
+ includePricingFetch: true,
40745
41788
  includeProviderModelFilters: true,
40746
41789
  includeHistory: true,
41790
+ includeSync: true,
40747
41791
  includeShare: true,
40748
41792
  includeTimezone: true
40749
41793
  },
40750
41794
  events: {
41795
+ includeJson: false,
41796
+ jsonAlternative: "use --format jsonl",
41797
+ includeQuiet: true,
40751
41798
  includeDateFilters: true,
40752
41799
  includeMarkdown: false,
40753
41800
  includePerModelColumns: false,
40754
41801
  includePricing: true,
41802
+ includePricingFetch: true,
40755
41803
  includeProviderModelFilters: true,
40756
41804
  includeHistory: true,
41805
+ includeSync: true,
40757
41806
  includeShare: false,
40758
41807
  includeTimezone: true
40759
41808
  },
40760
41809
  statusline: {
41810
+ includeJson: false,
41811
+ jsonAlternative: "use llm-usage summary --json",
41812
+ includeQuiet: false,
40761
41813
  includeDateFilters: false,
40762
41814
  includeMarkdown: false,
40763
41815
  includePerModelColumns: false,
40764
41816
  includePricing: true,
41817
+ includePricingFetch: false,
40765
41818
  includeProviderModelFilters: true,
40766
41819
  includeHistory: true,
41820
+ includeSync: false,
40767
41821
  includeShare: false,
40768
41822
  includeTimezone: true
40769
41823
  },
40770
41824
  doctor: {
41825
+ includeJson: true,
41826
+ includeQuiet: true,
40771
41827
  includeDateFilters: false,
40772
41828
  includeMarkdown: false,
40773
41829
  includePerModelColumns: false,
40774
41830
  includePricing: false,
41831
+ includePricingFetch: false,
40775
41832
  includeProviderModelFilters: false,
40776
41833
  includeHistory: false,
41834
+ includeSync: false,
40777
41835
  includeShare: false,
40778
41836
  includeTimezone: false
40779
41837
  }
@@ -40814,6 +41872,20 @@ function suggestHiddenOptionsOnTypo(command) {
40814
41872
  }
40815
41873
  };
40816
41874
  }
41875
+ function redirectUnsupportedJson(command, alternative) {
41876
+ if (!hasUnknownOptionHook(command)) {
41877
+ return;
41878
+ }
41879
+ const reportUnknownOption = command.unknownOption.bind(command);
41880
+ command.unknownOption = (flag) => {
41881
+ if (flag === "--json") {
41882
+ command.error(`error: --json is not supported for ${command.name()}; ${alternative}`, {
41883
+ code: "commander.unknownOption"
41884
+ });
41885
+ }
41886
+ reportUnknownOption(flag);
41887
+ };
41888
+ }
40817
41889
  function registerSourcePathOptions(command) {
40818
41890
  for (const overrideOption of getSourceOverrideOptions()) {
40819
41891
  const option = new Option(
@@ -40830,7 +41902,7 @@ function registerSourcePathOptions(command) {
40830
41902
  command.help();
40831
41903
  }).addHelpText(
40832
41904
  "after",
40833
- () => hasHiddenOptions(command) ? "\nPer-source path flags (--claude-dir, --codex-dir, --opencode-db, ...) are\nlisted by --help-all." : ""
41905
+ () => hasHiddenOptions(command) ? "\nPer-source path flags (--claude-dir, ...)\nare listed by --help-all." : ""
40834
41906
  );
40835
41907
  suggestHiddenOptionsOnTypo(command);
40836
41908
  }
@@ -40855,7 +41927,19 @@ function registerSharedReportOptions(command, profile) {
40855
41927
  "--source <name>",
40856
41928
  `Filter by source id (repeatable or comma-separated, supported sources ${supportedSourcesSummary})`,
40857
41929
  collectRepeatedOption
40858
- ).option("--json", "Render output as JSON").option("--quiet", "Suppress informational stderr output (warnings still print)").option(
41930
+ );
41931
+ if (profileConfig.includeJson) {
41932
+ configuredCommand.option("--json", "Render output as JSON");
41933
+ } else {
41934
+ redirectUnsupportedJson(configuredCommand, profileConfig.jsonAlternative);
41935
+ }
41936
+ if (profileConfig.includeQuiet) {
41937
+ configuredCommand.option(
41938
+ "--quiet",
41939
+ "Suppress informational stderr output (warnings still print)"
41940
+ );
41941
+ }
41942
+ configuredCommand.option(
40859
41943
  "--verbose",
40860
41944
  "Print detailed diagnostics on stderr (per-source counts, routine skips, config, env)"
40861
41945
  );
@@ -40879,10 +41963,20 @@ function registerSharedReportOptions(command, profile) {
40879
41963
  );
40880
41964
  }
40881
41965
  if (profileConfig.includePricing) {
40882
- configuredCommand.option("--pricing-url <url>", "Override LiteLLM pricing source URL").option(
41966
+ if (profileConfig.includePricingFetch) {
41967
+ configuredCommand.option("--pricing-url <url>", "Override LiteLLM pricing source URL");
41968
+ }
41969
+ configuredCommand.option(
40883
41970
  "--pricing-overrides <path>",
40884
41971
  "Path to a JSON file of per-model pricing overrides (takes precedence over LiteLLM)"
40885
- ).option("--pricing-offline", "Use cached LiteLLM pricing only (no network fetch)").option(
41972
+ );
41973
+ if (profileConfig.includePricingFetch) {
41974
+ configuredCommand.option(
41975
+ "--pricing-offline",
41976
+ "Use cached LiteLLM pricing only (no network fetch)"
41977
+ );
41978
+ }
41979
+ configuredCommand.option(
40886
41980
  "--ignore-pricing-failures",
40887
41981
  "Continue without estimated costs when pricing cannot be loaded"
40888
41982
  );
@@ -40890,12 +41984,18 @@ function registerSharedReportOptions(command, profile) {
40890
41984
  if (profileConfig.includeHistory) {
40891
41985
  configuredCommand.option(
40892
41986
  "--history",
40893
- "include usage from files that no longer exist on disk (the default; fails if the event store is unavailable)"
40894
- ).option("--no-history", "leave out usage from files that no longer exist on disk").option(
41987
+ "Include usage from files that no longer exist on disk (on by default; when passed, fails if the event store is unavailable)"
41988
+ ).option("--no-history", "Leave out usage from files that no longer exist on disk").option(
40895
41989
  "--machine <name>",
40896
41990
  "Count only these machines (repeatable or comma-separated; local is this one; default: all)",
40897
41991
  collectRepeatedOption
40898
- ).option("--no-sync", "use other machines' cached usage without refreshing it over ssh");
41992
+ );
41993
+ if (profileConfig.includeSync) {
41994
+ configuredCommand.option(
41995
+ "--no-sync",
41996
+ "Use other machines' cached usage without refreshing it over ssh"
41997
+ );
41998
+ }
40899
41999
  }
40900
42000
  if (profileConfig.includeMarkdown) {
40901
42001
  configuredCommand.option("--markdown", "Render output as markdown table");
@@ -40937,6 +42037,15 @@ function parseGranularityArgument(value) {
40937
42037
  `Invalid granularity: ${value}. Expected one of: ${GRANULARITY_ARGUMENT_VALUES.join(", ")}`
40938
42038
  );
40939
42039
  }
42040
+ function addGranularityArgument(command) {
42041
+ const reportMissingGranularity = (name) => command.error(
42042
+ `error: missing required argument '${name}' (choose ${GRANULARITY_ARGUMENT_VALUES.join(", ")})`,
42043
+ { code: "commander.missingArgument" }
42044
+ );
42045
+ return Object.assign(command, { missingArgument: reportMissingGranularity }).addArgument(
42046
+ new Argument("<granularity>", "Report period").choices(GRANULARITY_ARGUMENT_VALUES).argParser(parseGranularityArgument)
42047
+ );
42048
+ }
40940
42049
  var MAX_COMMAND_HELP_EXAMPLES = 4;
40941
42050
  function formatHelpExamples(commands) {
40942
42051
  return commands.length === 0 ? "" : ["", "Examples:", ...commands.map((command) => ` $ ${command}`)].join("\n");
@@ -41121,7 +42230,7 @@ var efficiencyReportDefinition = {
41121
42230
  ]
41122
42231
  },
41123
42232
  register(command) {
41124
- command.argument("<granularity>", "Granularity: daily | weekly | monthly", parseGranularityArgument).option("--repo-dir <path>", "Path to repository for Git outcome metrics").option("--include-merge-commits", "Include merge commits in Git outcome metrics").option("--by-source", "Include per-source usage rows under each period").action(
42233
+ addGranularityArgument(command).option("--repo-dir <path>", "Path to repository for Git outcome metrics").option("--include-merge-commits", "Include merge commits in Git outcome metrics").option("--by-source", "Include per-source usage rows under each period").action(
41125
42234
  (granularity, options) => runEfficiencyReport(granularity, options)
41126
42235
  );
41127
42236
  return command;
@@ -41171,7 +42280,7 @@ var optimizeReportDefinition = {
41171
42280
  ]
41172
42281
  },
41173
42282
  register(command) {
41174
- command.argument("<granularity>", "Granularity: daily | weekly | monthly", parseGranularityArgument).option(
42283
+ addGranularityArgument(command).option(
41175
42284
  "--candidate-model <name>",
41176
42285
  "Candidate model for counterfactual pricing (repeatable or comma-separated)",
41177
42286
  collectRepeatedOption
@@ -41195,7 +42304,7 @@ var trendsReportDefinition = {
41195
42304
  includeInCliReference: true
41196
42305
  },
41197
42306
  {
41198
- command: "llm-usage trends --metric tokens --days 7",
42307
+ command: "llm-usage trends --metric tokens --last 7",
41199
42308
  includeInCliReference: true
41200
42309
  },
41201
42310
  {
@@ -41206,9 +42315,9 @@ var trendsReportDefinition = {
41206
42315
  },
41207
42316
  register(command) {
41208
42317
  command.option(
41209
- "--days <n>",
41210
- "Trailing local calendar days to chart; defaults to 30 when no date flags are provided"
41211
- ).option("--metric <name>", "Trend metric: cost | tokens | active-hours", "cost").option(
42318
+ "--last <n>",
42319
+ "Chart the last N local calendar days, counting today; defaults to 30 when no date flags are provided"
42320
+ ).addOption(new Option2("--days <n>", "Alias of --last").hideHelp()).option("--metric <name>", "Trend metric: cost | tokens | active-hours", "cost").option(
41212
42321
  "--by-source",
41213
42322
  "Render one sparkline row per source instead of a single combined chart"
41214
42323
  ).action((options) => runTrendsReport(options));
@@ -41629,7 +42738,7 @@ async function runMachineExport(options, deps = {}) {
41629
42738
  knownFiles
41630
42739
  );
41631
42740
  const end = lines.at(-1);
41632
- const missingEventCount = dataset.filteredEvents.length - (end?.type === "end" ? end.eventCount : 0);
42741
+ const missingEventCount = dataset.filteredEvents.length + dataset.ledger.copiedEventCount - (end?.type === "end" ? end.eventCount : 0);
41633
42742
  if (missingEventCount > 0) {
41634
42743
  logger.warn(
41635
42744
  `machine export left out ${missingEventCount} event(s) that reports count but the event store does not hold`
@@ -42501,6 +43610,11 @@ var events_line_v1_schema_default = {
42501
43610
  description: "Normalized model identifier; omitted when unknown.",
42502
43611
  type: "string"
42503
43612
  },
43613
+ cacheWrite1hTokens: {
43614
+ description: "The part of cacheWriteTokens cached for one hour, which bills at a higher rate (Claude). Absent from events written by versions before 0.11.",
43615
+ type: "integer",
43616
+ minimum: 0
43617
+ },
42504
43618
  costUsd: {
42505
43619
  description: "Cost in USD; omitted when pricing is unresolved.",
42506
43620
  type: "number",
@@ -43548,6 +44662,33 @@ var report_summary_v1_schema_default = {
43548
44662
  required: ["source", "events", "activeDays"],
43549
44663
  unevaluatedProperties: false
43550
44664
  },
44665
+ machineTotals: {
44666
+ type: "object",
44667
+ description: "Usage totals for one machine within a period (non-negative).",
44668
+ allOf: [
44669
+ {
44670
+ $ref: "https://ayagmar.github.io/llm-usage-metrics/report-common.v1.schema.json#/$defs/usageTotals"
44671
+ }
44672
+ ],
44673
+ properties: {
44674
+ machine: {
44675
+ description: "`local` for the machine that ran the report, otherwise the name the machine was added under.",
44676
+ type: "string"
44677
+ },
44678
+ events: {
44679
+ description: "Events in the period.",
44680
+ type: "integer",
44681
+ minimum: 0
44682
+ },
44683
+ activeDays: {
44684
+ description: "Days with at least one event in the period.",
44685
+ type: "integer",
44686
+ minimum: 0
44687
+ }
44688
+ },
44689
+ required: ["machine", "events", "activeDays"],
44690
+ unevaluatedProperties: false
44691
+ },
43551
44692
  period: {
43552
44693
  description: "One summarized period.",
43553
44694
  type: "object",
@@ -43577,6 +44718,13 @@ var report_summary_v1_schema_default = {
43577
44718
  items: {
43578
44719
  $ref: "#/$defs/sourceTotals"
43579
44720
  }
44721
+ },
44722
+ machines: {
44723
+ description: "Machines with usage in the period, by cost then tokens then name. Present only when the report counts other machines' usage in the past year, after its source, provider and model filters (since 0.11).",
44724
+ type: "array",
44725
+ items: {
44726
+ $ref: "#/$defs/machineTotals"
44727
+ }
43580
44728
  }
43581
44729
  },
43582
44730
  required: ["key", "label", "since", "until", "totals", "sources"],
@@ -44276,6 +45424,29 @@ function rejectUnknownCommand(program, args) {
44276
45424
  (Did you mean ${suggestion}?)` : "";
44277
45425
  program.error(`error: unknown command '${unknownCommand}'${hint}`);
44278
45426
  }
45427
+ var SIDE_BY_SIDE_MIN_DESCRIPTION_WIDTH = 40;
45428
+ var STACKED_DESCRIPTION_INDENT = " ";
45429
+ function formatHelpItem(term, termWidth, description, helper) {
45430
+ const helpWidth = this.helpWidth ?? 80;
45431
+ const sideBySideWidth = helpWidth - termWidth - 4;
45432
+ if (!description || sideBySideWidth >= SIDE_BY_SIDE_MIN_DESCRIPTION_WIDTH) {
45433
+ return Help.prototype.formatItem.call(this, term, termWidth, description, helper);
45434
+ }
45435
+ const wrappedDescription = helper.boxWrap(
45436
+ description,
45437
+ helpWidth - STACKED_DESCRIPTION_INDENT.length
45438
+ );
45439
+ return [
45440
+ ` ${term}`,
45441
+ ...wrappedDescription.split("\n").map((line) => `${STACKED_DESCRIPTION_INDENT}${line}`)
45442
+ ].join("\n");
45443
+ }
45444
+ function wrapHelpOnNarrowTerminals(command) {
45445
+ command.configureHelp({ minWidthToWrap: 20, formatItem: formatHelpItem });
45446
+ for (const subcommand of command.commands) {
45447
+ wrapHelpOnNarrowTerminals(subcommand);
45448
+ }
45449
+ }
44279
45450
  function createCli(options = {}) {
44280
45451
  const program = new Command6();
44281
45452
  program.name("llm-usage").description(createRootDescription()).version(options.version ?? "0.0.0").showHelpAfterError();
@@ -44311,6 +45482,7 @@ function createCli(options = {}) {
44311
45482
  setLogLevel("debug");
44312
45483
  }
44313
45484
  });
45485
+ wrapHelpOnNarrowTerminals(program);
44314
45486
  return program;
44315
45487
  }
44316
45488