ccusage 0.4.0 → 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,9 +1,13 @@
1
1
  #!/usr/bin/env node
2
- import { UsageDataSchema, __commonJS, __require, __toESM, boolean, calculateCostFromTokens, description, fetchModelPricing, getDefaultClaudePath, getModelPricing, glob, loadSessionData, loadUsageData, log, logger, name, number, object, optional, pipe, record, regex, safeParse, string, union, version } from "./data-loader-DlG6jpnf.js";
3
- import { calculateTotals, createTotalsObject, getTotalTokens } from "./calculate-cost-DMC4FhU4.js";
4
- import { readFile } from "node:fs/promises";
5
- import { homedir } from "node:os";
6
- import path from "node:path";
2
+ import { __commonJS, __require, __toESM, loadSessionData, loadUsageData } from "./data-loader-B8mdiY5r.js";
3
+ import { formatCurrency, formatNumber } from "./utils-BeihwpHn.js";
4
+ import "./dist-D6rk8Ra5.js";
5
+ import { description, log, logger, name, version } from "./logger-nCODI08N.js";
6
+ import "./pricing-fetcher-bvi4lbXl.js";
7
+ import "./types-DjlBTM5P.js";
8
+ import { calculateTotals, createTotalsObject, getTotalTokens } from "./calculate-cost-BnufbprY.js";
9
+ import { detectMismatches, printMismatchReport } from "./debug-Oce2b5bO.js";
10
+ import { sharedCommandConfig } from "./shared-args-DWaGio0e.js";
7
11
  import process$1 from "node:process";
8
12
 
9
13
  //#region node_modules/gunshi/lib/utils-B_QNzw5q.js
@@ -1133,7 +1137,7 @@ async function executeCommand(cmd, ctx, name$1) {
1133
1137
 
1134
1138
  //#endregion
1135
1139
  //#region node_modules/cli-table3/src/debug.js
1136
- var require_debug = __commonJS({ "node_modules/cli-table3/src/debug.js"(exports, module) {
1140
+ var require_debug$1 = __commonJS({ "node_modules/cli-table3/src/debug.js"(exports, module) {
1137
1141
  let messages = [];
1138
1142
  let level = 0;
1139
1143
  const debug$3 = (msg, min) => {
@@ -1168,7 +1172,7 @@ var require_ansi_regex = __commonJS({ "node_modules/ansi-regex/index.js"(exports
1168
1172
  //#region node_modules/strip-ansi/index.js
1169
1173
  var require_strip_ansi = __commonJS({ "node_modules/strip-ansi/index.js"(exports, module) {
1170
1174
  const ansiRegex = require_ansi_regex();
1171
- module.exports = (string$1) => typeof string$1 === "string" ? string$1.replace(ansiRegex(), "") : string$1;
1175
+ module.exports = (string) => typeof string === "string" ? string.replace(ansiRegex(), "") : string;
1172
1176
  } });
1173
1177
 
1174
1178
  //#endregion
@@ -1197,14 +1201,14 @@ var require_string_width = __commonJS({ "node_modules/string-width/index.js"(exp
1197
1201
  const stripAnsi = require_strip_ansi();
1198
1202
  const isFullwidthCodePoint = require_is_fullwidth_code_point();
1199
1203
  const emojiRegex = require_emoji_regex();
1200
- const stringWidth$1 = (string$1) => {
1201
- if (typeof string$1 !== "string" || string$1.length === 0) return 0;
1202
- string$1 = stripAnsi(string$1);
1203
- if (string$1.length === 0) return 0;
1204
- string$1 = string$1.replace(emojiRegex(), " ");
1204
+ const stringWidth$1 = (string) => {
1205
+ if (typeof string !== "string" || string.length === 0) return 0;
1206
+ string = stripAnsi(string);
1207
+ if (string.length === 0) return 0;
1208
+ string = string.replace(emojiRegex(), " ");
1205
1209
  let width = 0;
1206
- for (let i = 0; i < string$1.length; i++) {
1207
- const code = string$1.codePointAt(i);
1210
+ for (let i = 0; i < string.length; i++) {
1211
+ const code = string.codePointAt(i);
1208
1212
  if (code <= 31 || code >= 127 && code <= 159) continue;
1209
1213
  if (code >= 768 && code <= 879) continue;
1210
1214
  if (code > 65535) i++;
@@ -1218,7 +1222,7 @@ var require_string_width = __commonJS({ "node_modules/string-width/index.js"(exp
1218
1222
 
1219
1223
  //#endregion
1220
1224
  //#region node_modules/cli-table3/src/utils.js
1221
- var require_utils = __commonJS({ "node_modules/cli-table3/src/utils.js"(exports, module) {
1225
+ var require_utils$1 = __commonJS({ "node_modules/cli-table3/src/utils.js"(exports, module) {
1222
1226
  const stringWidth = require_string_width();
1223
1227
  function codeRegex(capture) {
1224
1228
  return capture ? /\u001b\[((?:\d*;){0,5}\d*)m/g : /\u001b\[(?:\d*;){0,5}\d*m/g;
@@ -2181,8 +2185,8 @@ var require_safe = __commonJS({ "node_modules/@colors/colors/safe.js"(exports, m
2181
2185
  //#endregion
2182
2186
  //#region node_modules/cli-table3/src/cell.js
2183
2187
  var require_cell = __commonJS({ "node_modules/cli-table3/src/cell.js"(exports, module) {
2184
- const { info, debug: debug$2 } = require_debug();
2185
- const utils$1 = require_utils();
2188
+ const { info, debug: debug$2 } = require_debug$1();
2189
+ const utils$1 = require_utils$1();
2186
2190
  var Cell$1 = class Cell$1 {
2187
2191
  /**
2188
2192
  * A representation of a cell within the table.
@@ -2509,7 +2513,7 @@ var require_cell = __commonJS({ "node_modules/cli-table3/src/cell.js"(exports, m
2509
2513
  //#endregion
2510
2514
  //#region node_modules/cli-table3/src/layout-manager.js
2511
2515
  var require_layout_manager = __commonJS({ "node_modules/cli-table3/src/layout-manager.js"(exports, module) {
2512
- const { warn, debug: debug$1 } = require_debug();
2516
+ const { warn, debug: debug$1 } = require_debug$1();
2513
2517
  const Cell = require_cell();
2514
2518
  const { ColSpanCell, RowSpanCell } = Cell;
2515
2519
  (function() {
@@ -2719,8 +2723,8 @@ var require_layout_manager = __commonJS({ "node_modules/cli-table3/src/layout-ma
2719
2723
  //#endregion
2720
2724
  //#region node_modules/cli-table3/src/table.js
2721
2725
  var require_table = __commonJS({ "node_modules/cli-table3/src/table.js"(exports, module) {
2722
- const debug = require_debug();
2723
- const utils = require_utils();
2726
+ const debug = require_debug$1();
2727
+ const utils = require_utils$1();
2724
2728
  const tableLayout = require_layout_manager();
2725
2729
  var Table$2 = class extends Array {
2726
2730
  constructor(opts) {
@@ -2809,17 +2813,17 @@ var require_picocolors = __commonJS({ "node_modules/picocolors/picocolors.js"(ex
2809
2813
  let p = process || {}, argv = p.argv || [], env = p.env || {};
2810
2814
  let isColorSupported = !(!!env.NO_COLOR || argv.includes("--no-color")) && (!!env.FORCE_COLOR || argv.includes("--color") || p.platform === "win32" || (p.stdout || {}).isTTY && env.TERM !== "dumb" || !!env.CI);
2811
2815
  let formatter = (open, close, replace = open) => (input) => {
2812
- let string$1 = "" + input, index = string$1.indexOf(close, open.length);
2813
- return ~index ? open + replaceClose(string$1, close, replace, index) + close : open + string$1 + close;
2816
+ let string = "" + input, index = string.indexOf(close, open.length);
2817
+ return ~index ? open + replaceClose(string, close, replace, index) + close : open + string + close;
2814
2818
  };
2815
- let replaceClose = (string$1, close, replace, index) => {
2819
+ let replaceClose = (string, close, replace, index) => {
2816
2820
  let result = "", cursor = 0;
2817
2821
  do {
2818
- result += string$1.substring(cursor, index) + replace;
2822
+ result += string.substring(cursor, index) + replace;
2819
2823
  cursor = index + close.length;
2820
- index = string$1.indexOf(close, cursor);
2824
+ index = string.indexOf(close, cursor);
2821
2825
  } while (~index);
2822
- return result + string$1.substring(cursor);
2826
+ return result + string.substring(cursor);
2823
2827
  };
2824
2828
  let createColors = (enabled = isColorSupported) => {
2825
2829
  let f = enabled ? formatter : () => String;
@@ -2873,243 +2877,7 @@ var require_picocolors = __commonJS({ "node_modules/picocolors/picocolors.js"(ex
2873
2877
  } });
2874
2878
 
2875
2879
  //#endregion
2876
- //#region debug.ts
2877
- const MATCH_THRESHOLD_PERCENT = .1;
2878
- async function detectMismatches(claudePath) {
2879
- const claudeDir = claudePath || path.join(homedir(), ".claude", "projects");
2880
- const files = await glob(["**/*.jsonl"], {
2881
- cwd: claudeDir,
2882
- absolute: true
2883
- });
2884
- const modelPricing = await fetchModelPricing();
2885
- const stats = {
2886
- totalEntries: 0,
2887
- entriesWithBoth: 0,
2888
- matches: 0,
2889
- mismatches: 0,
2890
- discrepancies: [],
2891
- modelStats: new Map(),
2892
- versionStats: new Map()
2893
- };
2894
- for (const file of files) {
2895
- const content = await readFile(file, "utf-8");
2896
- const lines = content.trim().split("\n").filter((line) => line.length > 0);
2897
- for (const line of lines) try {
2898
- const parsed = JSON.parse(line);
2899
- const result = safeParse(UsageDataSchema, parsed);
2900
- if (!result.success) continue;
2901
- const data = result.output;
2902
- stats.totalEntries++;
2903
- if (data.costUSD !== void 0 && data.message.model && data.message.model !== "<synthetic>") {
2904
- stats.entriesWithBoth++;
2905
- const model = data.message.model;
2906
- const pricing = getModelPricing(model, modelPricing);
2907
- if (pricing) {
2908
- const calculatedCost = calculateCostFromTokens(data.message.usage, pricing);
2909
- const difference = Math.abs(data.costUSD - calculatedCost);
2910
- const percentDiff = data.costUSD > 0 ? difference / data.costUSD * 100 : 0;
2911
- const modelStat = stats.modelStats.get(model) || {
2912
- total: 0,
2913
- matches: 0,
2914
- mismatches: 0,
2915
- avgPercentDiff: 0
2916
- };
2917
- modelStat.total++;
2918
- if (data.version) {
2919
- const versionStat = stats.versionStats.get(data.version) || {
2920
- total: 0,
2921
- matches: 0,
2922
- mismatches: 0,
2923
- avgPercentDiff: 0
2924
- };
2925
- versionStat.total++;
2926
- if (percentDiff < MATCH_THRESHOLD_PERCENT) versionStat.matches++;
2927
- else versionStat.mismatches++;
2928
- versionStat.avgPercentDiff = (versionStat.avgPercentDiff * (versionStat.total - 1) + percentDiff) / versionStat.total;
2929
- stats.versionStats.set(data.version, versionStat);
2930
- }
2931
- if (percentDiff < .1) {
2932
- stats.matches++;
2933
- modelStat.matches++;
2934
- } else {
2935
- stats.mismatches++;
2936
- modelStat.mismatches++;
2937
- stats.discrepancies.push({
2938
- file: path.basename(file),
2939
- timestamp: data.timestamp,
2940
- model,
2941
- originalCost: data.costUSD,
2942
- calculatedCost,
2943
- difference,
2944
- percentDiff,
2945
- usage: data.message.usage
2946
- });
2947
- }
2948
- modelStat.avgPercentDiff = (modelStat.avgPercentDiff * (modelStat.total - 1) + percentDiff) / modelStat.total;
2949
- stats.modelStats.set(model, modelStat);
2950
- }
2951
- }
2952
- } catch (e) {}
2953
- }
2954
- return stats;
2955
- }
2956
- function printMismatchReport(stats, sampleCount = 5) {
2957
- if (stats.entriesWithBoth === 0) {
2958
- logger.info("No pricing data found to analyze.");
2959
- return;
2960
- }
2961
- const matchRate = stats.matches / stats.entriesWithBoth * 100;
2962
- logger.info("\n=== Pricing Mismatch Debug Report ===");
2963
- logger.info(`Total entries processed: ${stats.totalEntries.toLocaleString()}`);
2964
- logger.info(`Entries with both costUSD and model: ${stats.entriesWithBoth.toLocaleString()}`);
2965
- logger.info(`Matches (within 0.1%): ${stats.matches.toLocaleString()}`);
2966
- logger.info(`Mismatches: ${stats.mismatches.toLocaleString()}`);
2967
- logger.info(`Match rate: ${matchRate.toFixed(2)}%`);
2968
- if (stats.mismatches > 0 && stats.modelStats.size > 0) {
2969
- logger.info("\n=== Model Statistics ===");
2970
- const sortedModels = Array.from(stats.modelStats.entries()).sort((a, b) => b[1].mismatches - a[1].mismatches);
2971
- for (const [model, modelStat] of sortedModels) if (modelStat.mismatches > 0) {
2972
- const modelMatchRate = modelStat.matches / modelStat.total * 100;
2973
- logger.info(`${model}:`);
2974
- logger.info(` Total entries: ${modelStat.total.toLocaleString()}`);
2975
- logger.info(` Matches: ${modelStat.matches.toLocaleString()} (${modelMatchRate.toFixed(1)}%)`);
2976
- logger.info(` Mismatches: ${modelStat.mismatches.toLocaleString()}`);
2977
- logger.info(` Avg % difference: ${modelStat.avgPercentDiff.toFixed(1)}%`);
2978
- }
2979
- }
2980
- if (stats.mismatches > 0 && stats.versionStats.size > 0) {
2981
- logger.info("\n=== Version Statistics ===");
2982
- const sortedVersions = Array.from(stats.versionStats.entries()).filter(([_, versionStat]) => versionStat.mismatches > 0).sort((a, b) => b[1].mismatches - a[1].mismatches);
2983
- for (const [version$2, versionStat] of sortedVersions) {
2984
- const versionMatchRate = versionStat.matches / versionStat.total * 100;
2985
- logger.info(`${version$2}:`);
2986
- logger.info(` Total entries: ${versionStat.total.toLocaleString()}`);
2987
- logger.info(` Matches: ${versionStat.matches.toLocaleString()} (${versionMatchRate.toFixed(1)}%)`);
2988
- logger.info(` Mismatches: ${versionStat.mismatches.toLocaleString()}`);
2989
- logger.info(` Avg % difference: ${versionStat.avgPercentDiff.toFixed(1)}%`);
2990
- }
2991
- }
2992
- if (stats.discrepancies.length > 0 && sampleCount > 0) {
2993
- logger.info(`\n=== Sample Discrepancies (first ${sampleCount}) ===`);
2994
- const samples = stats.discrepancies.slice(0, sampleCount);
2995
- for (const disc of samples) {
2996
- logger.info(`File: ${disc.file}`);
2997
- logger.info(`Timestamp: ${disc.timestamp}`);
2998
- logger.info(`Model: ${disc.model}`);
2999
- logger.info(`Original cost: $${disc.originalCost.toFixed(6)}`);
3000
- logger.info(`Calculated cost: $${disc.calculatedCost.toFixed(6)}`);
3001
- logger.info(`Difference: $${disc.difference.toFixed(6)} (${disc.percentDiff.toFixed(2)}%)`);
3002
- logger.info(`Tokens: ${JSON.stringify(disc.usage)}`);
3003
- logger.info("---");
3004
- }
3005
- }
3006
- }
3007
-
3008
- //#endregion
3009
- //#region types.ts
3010
- const ModelSpecSchema = object({
3011
- max_tokens: optional(union([number(), string()])),
3012
- max_input_tokens: optional(union([number(), string()])),
3013
- max_output_tokens: optional(union([number(), string()])),
3014
- input_cost_per_token: optional(number()),
3015
- output_cost_per_token: optional(number()),
3016
- output_cost_per_reasoning_token: optional(number()),
3017
- cache_creation_input_token_cost: optional(number()),
3018
- cache_read_input_token_cost: optional(number()),
3019
- litellm_provider: optional(string()),
3020
- mode: optional(string()),
3021
- supports_function_calling: optional(boolean()),
3022
- supports_parallel_function_calling: optional(boolean()),
3023
- supports_vision: optional(boolean()),
3024
- supports_audio_input: optional(boolean()),
3025
- supports_audio_output: optional(boolean()),
3026
- supports_prompt_caching: optional(boolean()),
3027
- supports_response_schema: optional(boolean()),
3028
- supports_system_messages: optional(boolean()),
3029
- supports_reasoning: optional(boolean()),
3030
- supports_web_search: optional(boolean()),
3031
- search_context_cost_per_query: optional(object({
3032
- search_context_size_low: number(),
3033
- search_context_size_medium: number(),
3034
- search_context_size_high: number()
3035
- })),
3036
- deprecation_date: optional(string())
3037
- });
3038
- const LiteLLMModelPricesSchema = record(string(), ModelSpecSchema);
3039
- const dateSchema = pipe(string(), regex(/^\d{8}$/, "Date must be in YYYYMMDD format"));
3040
- const CostModes = [
3041
- "auto",
3042
- "calculate",
3043
- "display"
3044
- ];
3045
-
3046
- //#endregion
3047
- //#region shared-args.ts
3048
- const parseDateArg = (value) => {
3049
- const result = safeParse(dateSchema, value);
3050
- if (!result.success) throw new TypeError(result.issues[0].message);
3051
- return result.output;
3052
- };
3053
- const sharedArgs = {
3054
- since: {
3055
- type: "custom",
3056
- short: "s",
3057
- description: "Filter from date (YYYYMMDD format)",
3058
- parse: parseDateArg
3059
- },
3060
- until: {
3061
- type: "custom",
3062
- short: "u",
3063
- description: "Filter until date (YYYYMMDD format)",
3064
- parse: parseDateArg
3065
- },
3066
- path: {
3067
- type: "string",
3068
- short: "p",
3069
- description: "Custom path to Claude data directory",
3070
- default: getDefaultClaudePath()
3071
- },
3072
- json: {
3073
- type: "boolean",
3074
- short: "j",
3075
- description: "Output in JSON format",
3076
- default: false
3077
- },
3078
- mode: {
3079
- type: "enum",
3080
- short: "m",
3081
- description: "Cost calculation mode: auto (use costUSD if exists, otherwise calculate), calculate (always calculate), display (always use costUSD)",
3082
- default: "auto",
3083
- choices: CostModes
3084
- },
3085
- debug: {
3086
- type: "boolean",
3087
- short: "d",
3088
- description: "Show pricing mismatch information for debugging",
3089
- default: false
3090
- },
3091
- debugSamples: {
3092
- type: "number",
3093
- description: "Number of sample discrepancies to show in debug output (default: 5)",
3094
- default: 5
3095
- }
3096
- };
3097
- const sharedCommandConfig = {
3098
- args: sharedArgs,
3099
- toKebab: true
3100
- };
3101
-
3102
- //#endregion
3103
- //#region utils.ts
3104
- const formatNumber = (num) => {
3105
- return num.toLocaleString("en-US");
3106
- };
3107
- const formatCurrency = (amount) => {
3108
- return `$${amount.toFixed(2)}`;
3109
- };
3110
-
3111
- //#endregion
3112
- //#region commands/daily.ts
2880
+ //#region src/commands/daily.ts
3113
2881
  var import_cli_table3$1 = __toESM(require_cli_table3(), 1);
3114
2882
  var import_picocolors$1 = __toESM(require_picocolors(), 1);
3115
2883
  const dailyCommand = define({
@@ -3117,6 +2885,7 @@ const dailyCommand = define({
3117
2885
  description: "Show usage report grouped by date",
3118
2886
  ...sharedCommandConfig,
3119
2887
  async run(ctx) {
2888
+ if (ctx.values.json) logger.level = 0;
3120
2889
  const options = {
3121
2890
  since: ctx.values.since,
3122
2891
  until: ctx.values.until,
@@ -3198,13 +2967,13 @@ const dailyCommand = define({
3198
2967
  import_picocolors$1.default.yellow(formatNumber(getTotalTokens(totals))),
3199
2968
  import_picocolors$1.default.yellow(formatCurrency(totals.totalCost))
3200
2969
  ]);
3201
- console.log(table.toString());
2970
+ log(table.toString());
3202
2971
  }
3203
2972
  }
3204
2973
  });
3205
2974
 
3206
2975
  //#endregion
3207
- //#region commands/session.ts
2976
+ //#region src/commands/session.ts
3208
2977
  var import_cli_table3 = __toESM(require_cli_table3(), 1);
3209
2978
  var import_picocolors = __toESM(require_picocolors(), 1);
3210
2979
  const sessionCommand = define({
@@ -3212,6 +2981,7 @@ const sessionCommand = define({
3212
2981
  description: "Show usage report grouped by conversation session",
3213
2982
  ...sharedCommandConfig,
3214
2983
  async run(ctx) {
2984
+ if (ctx.values.json) logger.level = 0;
3215
2985
  const options = {
3216
2986
  since: ctx.values.since,
3217
2987
  until: ctx.values.until,
@@ -3313,13 +3083,13 @@ const sessionCommand = define({
3313
3083
  import_picocolors.default.yellow(formatCurrency(totals.totalCost)),
3314
3084
  ""
3315
3085
  ]);
3316
- console.log(table.toString());
3086
+ log(table.toString());
3317
3087
  }
3318
3088
  }
3319
3089
  });
3320
3090
 
3321
3091
  //#endregion
3322
- //#region index.ts
3092
+ //#region src/commands/index.ts
3323
3093
  const subCommands = new Map();
3324
3094
  subCommands.set("daily", dailyCommand);
3325
3095
  subCommands.set("session", sessionCommand);