ccusage 0.6.1 → 0.6.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.
@@ -1,3 +1,3 @@
1
- import "./pricing-fetcher-CfEgfzSr.js";
2
- import { DailyUsage, DailyUsageSchema, DateFilter, LoadOptions, MonthlyUsage, MonthlyUsageSchema, SessionUsage, SessionUsageSchema, UsageData, UsageDataSchema, calculateCostForEntry, formatDate, getDefaultClaudePath, loadDailyUsageData, loadMonthlyUsageData, loadSessionData } from "./data-loader-VdEcqJHc.js";
1
+ import { DailyUsage, DailyUsageSchema, DateFilter, LoadOptions, MonthlyUsage, MonthlyUsageSchema, SessionUsage, SessionUsageSchema, UsageData, UsageDataSchema, calculateCostForEntry, formatDate, getDefaultClaudePath, loadDailyUsageData, loadMonthlyUsageData, loadSessionData } from "./data-loader-B0tJZeHI.js";
2
+ import "./pricing-fetcher-Dq-OLBp4.js";
3
3
  export { DailyUsage, DailyUsageSchema, DateFilter, LoadOptions, MonthlyUsage, MonthlyUsageSchema, SessionUsage, SessionUsageSchema, UsageData, UsageDataSchema, calculateCostForEntry, formatDate, getDefaultClaudePath, loadDailyUsageData, loadMonthlyUsageData, loadSessionData };
@@ -1,6 +1,6 @@
1
- import { DailyUsageSchema, MonthlyUsageSchema, SessionUsageSchema, UsageDataSchema, calculateCostForEntry, formatDate, getDefaultClaudePath, loadDailyUsageData, loadMonthlyUsageData, loadSessionData } from "./data-loader-DP5qBPn6.js";
2
- import "./dist-C0-Tf5eD.js";
3
- import "./logger-DsQC4OvA.js";
4
- import "./pricing-fetcher-BPUgMrB_.js";
1
+ import { DailyUsageSchema, MonthlyUsageSchema, SessionUsageSchema, UsageDataSchema, calculateCostForEntry, formatDate, getDefaultClaudePath, loadDailyUsageData, loadMonthlyUsageData, loadSessionData } from "./data-loader-BfnzLKGl.js";
2
+ import "./dist-BEQ1tJCL.js";
3
+ import "./logger-DixU80sg.js";
4
+ import "./pricing-fetcher-BY3-ryVq.js";
5
5
 
6
6
  export { DailyUsageSchema, MonthlyUsageSchema, SessionUsageSchema, UsageDataSchema, calculateCostForEntry, formatDate, getDefaultClaudePath, loadDailyUsageData, loadMonthlyUsageData, loadSessionData };
@@ -1,44 +1,45 @@
1
- import { UsageDataSchema, glob } from "./data-loader-DP5qBPn6.js";
2
- import { safeParse } from "./dist-C0-Tf5eD.js";
3
- import { logger } from "./logger-DsQC4OvA.js";
4
- import { calculateCostFromTokens, fetchModelPricing, getModelPricing } from "./pricing-fetcher-BPUgMrB_.js";
1
+ import { UsageDataSchema, __toESM, glob, require_usingCtx } from "./data-loader-BfnzLKGl.js";
2
+ import { safeParse } from "./dist-BEQ1tJCL.js";
3
+ import { logger } from "./logger-DixU80sg.js";
4
+ import { PricingFetcher } from "./pricing-fetcher-BY3-ryVq.js";
5
5
  import { readFile } from "node:fs/promises";
6
6
  import { homedir } from "node:os";
7
7
  import path from "node:path";
8
8
 
9
9
  //#region src/debug.ts
10
+ var import_usingCtx = __toESM(require_usingCtx(), 1);
10
11
  const MATCH_THRESHOLD_PERCENT = .1;
11
12
  async function detectMismatches(claudePath) {
12
- const claudeDir = claudePath ?? path.join(homedir(), ".claude", "projects");
13
- const files = await glob(["**/*.jsonl"], {
14
- cwd: claudeDir,
15
- absolute: true
16
- });
17
- const modelPricing = await fetchModelPricing();
18
- const stats = {
19
- totalEntries: 0,
20
- entriesWithBoth: 0,
21
- matches: 0,
22
- mismatches: 0,
23
- discrepancies: [],
24
- modelStats: /* @__PURE__ */ new Map(),
25
- versionStats: /* @__PURE__ */ new Map()
26
- };
27
- for (const file of files) {
28
- const content = await readFile(file, "utf-8");
29
- const lines = content.trim().split("\n").filter((line) => line.length > 0);
30
- for (const line of lines) try {
31
- const parsed = JSON.parse(line);
32
- const result = safeParse(UsageDataSchema, parsed);
33
- if (!result.success) continue;
34
- const data = result.output;
35
- stats.totalEntries++;
36
- if (data.costUSD !== void 0 && data.message.model != null && data.message.model !== "<synthetic>") {
37
- stats.entriesWithBoth++;
38
- const model = data.message.model;
39
- const pricing = getModelPricing(model, modelPricing);
40
- if (pricing != null) {
41
- const calculatedCost = calculateCostFromTokens(data.message.usage, pricing);
13
+ try {
14
+ var _usingCtx = (0, import_usingCtx.default)();
15
+ const claudeDir = claudePath ?? path.join(homedir(), ".claude", "projects");
16
+ const files = await glob(["**/*.jsonl"], {
17
+ cwd: claudeDir,
18
+ absolute: true
19
+ });
20
+ const fetcher = _usingCtx.u(new PricingFetcher());
21
+ const stats = {
22
+ totalEntries: 0,
23
+ entriesWithBoth: 0,
24
+ matches: 0,
25
+ mismatches: 0,
26
+ discrepancies: [],
27
+ modelStats: /* @__PURE__ */ new Map(),
28
+ versionStats: /* @__PURE__ */ new Map()
29
+ };
30
+ for (const file of files) {
31
+ const content = await readFile(file, "utf-8");
32
+ const lines = content.trim().split("\n").filter((line) => line.length > 0);
33
+ for (const line of lines) try {
34
+ const parsed = JSON.parse(line);
35
+ const result = safeParse(UsageDataSchema, parsed);
36
+ if (!result.success) continue;
37
+ const data = result.output;
38
+ stats.totalEntries++;
39
+ if (data.costUSD !== void 0 && data.message.model != null && data.message.model !== "<synthetic>") {
40
+ stats.entriesWithBoth++;
41
+ const model = data.message.model;
42
+ const calculatedCost = await fetcher.calculateCostFromTokens(data.message.usage, model);
42
43
  const difference = Math.abs(data.costUSD - calculatedCost);
43
44
  const percentDiff = data.costUSD > 0 ? difference / data.costUSD * 100 : 0;
44
45
  const modelStat = stats.modelStats.get(model) ?? {
@@ -81,10 +82,14 @@ async function detectMismatches(claudePath) {
81
82
  modelStat.avgPercentDiff = (modelStat.avgPercentDiff * (modelStat.total - 1) + percentDiff) / modelStat.total;
82
83
  stats.modelStats.set(model, modelStat);
83
84
  }
84
- }
85
- } catch {}
85
+ } catch {}
86
+ }
87
+ return stats;
88
+ } catch (_) {
89
+ _usingCtx.e = _;
90
+ } finally {
91
+ _usingCtx.d();
86
92
  }
87
- return stats;
88
93
  }
89
94
  function printMismatchReport(stats, sampleCount = 5) {
90
95
  if (stats.entriesWithBoth === 0) {
package/dist/debug.js CHANGED
@@ -1,7 +1,7 @@
1
- import "./data-loader-DP5qBPn6.js";
2
- import "./dist-C0-Tf5eD.js";
3
- import "./logger-DsQC4OvA.js";
4
- import "./pricing-fetcher-BPUgMrB_.js";
5
- import { detectMismatches, printMismatchReport } from "./debug-C_5Qx11m.js";
1
+ import "./data-loader-BfnzLKGl.js";
2
+ import "./dist-BEQ1tJCL.js";
3
+ import "./logger-DixU80sg.js";
4
+ import "./pricing-fetcher-BY3-ryVq.js";
5
+ import { detectMismatches, printMismatchReport } from "./debug-Bf6GUNZE.js";
6
6
 
7
7
  export { detectMismatches, printMismatchReport };
@@ -73,18 +73,6 @@ function _joinExpects(values2, separator) {
73
73
  if (list.length > 1) return `(${list.join(` ${separator} `)})`;
74
74
  return list[0] ?? "never";
75
75
  }
76
- var ValiError = class extends Error {
77
- /**
78
- * Creates a Valibot error with useful information.
79
- *
80
- * @param issues The error issues.
81
- */
82
- constructor(issues) {
83
- super(issues[0].message);
84
- this.name = "ValiError";
85
- this.issues = issues;
86
- }
87
- };
88
76
  /* @__NO_SIDE_EFFECTS__ */
89
77
  function description(description_) {
90
78
  return {
@@ -360,11 +348,6 @@ function union(options, message2) {
360
348
  }
361
349
  };
362
350
  }
363
- function parse(schema, input, config2) {
364
- const dataset = schema["~run"]({ value: input }, /* @__PURE__ */ getGlobalConfig(config2));
365
- if (dataset.issues) throw new ValiError(dataset.issues);
366
- return dataset.value;
367
- }
368
351
  /* @__NO_SIDE_EFFECTS__ */
369
352
  function pipe(...pipe2) {
370
353
  return {
@@ -397,4 +380,4 @@ function safeParse(schema, input, config2) {
397
380
  }
398
381
 
399
382
  //#endregion
400
- export { array, description, getDefault, literal, number, object, optional, parse, pipe, regex, safeParse, string, union };
383
+ export { array, description, getDefault, literal, number, object, optional, pipe, regex, safeParse, string, union };
@@ -1,4 +1,4 @@
1
- import { getDefault } from "./dist-C0-Tf5eD.js";
1
+ import { getDefault } from "./dist-BEQ1tJCL.js";
2
2
 
3
3
  //#region node_modules/@valibot/to-json-schema/dist/index.js
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { tryImport } from "./index-CISmcbXk-DCA05NUL.js";
1
+ import { tryImport } from "./index-CISmcbXk-x9eVmhGM.js";
2
2
 
3
3
  //#region node_modules/xsschema/dist/effect-WSjEuzC9.js
4
4
  const getToJsonSchemaFn = async () => {
@@ -10,10 +10,10 @@ const tryImport = async (result, name) => {
10
10
  const getToJsonSchemaFn = async (vendor) => {
11
11
  switch (vendor) {
12
12
  case "arktype": return import("./arktype-C-GObzDh-Bx7Fdrqj.js").then(async ({ getToJsonSchemaFn: getToJsonSchemaFn2 }) => getToJsonSchemaFn2());
13
- case "effect": return import("./effect-WSjEuzC9-CJfWUy0j.js").then(async ({ getToJsonSchemaFn: getToJsonSchemaFn2 }) => getToJsonSchemaFn2());
14
- case "sury": return import("./sury-DmrZ3_Oj-CCL_DlTt.js").then(async ({ getToJsonSchemaFn: getToJsonSchemaFn2 }) => getToJsonSchemaFn2());
15
- case "valibot": return import("./valibot-CQk-M5rL-CkjrLVu1.js").then(async ({ getToJsonSchemaFn: getToJsonSchemaFn2 }) => getToJsonSchemaFn2());
16
- case "zod": return import("./zod-Db63SLXj-Dyc_OWjq.js").then(async ({ getToJsonSchemaFn: getToJsonSchemaFn2 }) => getToJsonSchemaFn2());
13
+ case "effect": return import("./effect-WSjEuzC9-ChJ5OQQf.js").then(async ({ getToJsonSchemaFn: getToJsonSchemaFn2 }) => getToJsonSchemaFn2());
14
+ case "sury": return import("./sury-DmrZ3_Oj-l0qqtY-f.js").then(async ({ getToJsonSchemaFn: getToJsonSchemaFn2 }) => getToJsonSchemaFn2());
15
+ case "valibot": return import("./valibot-CQk-M5rL-BNHzwpA0.js").then(async ({ getToJsonSchemaFn: getToJsonSchemaFn2 }) => getToJsonSchemaFn2());
16
+ case "zod": return import("./zod-Db63SLXj-N1oN-yiY.js").then(async ({ getToJsonSchemaFn: getToJsonSchemaFn2 }) => getToJsonSchemaFn2());
17
17
  default: throw new Error(`xsschema: Unsupported schema vendor "${vendor}". see https://xsai.js.org/docs/packages-top/xsschema#unsupported-schema-vendor`);
18
18
  }
19
19
  };
package/dist/index.js CHANGED
@@ -1,13 +1,13 @@
1
1
  #!/usr/bin/env node
2
- import { __commonJS, __require, __toESM, getDefaultClaudePath, loadDailyUsageData, loadMonthlyUsageData, loadSessionData } from "./data-loader-DP5qBPn6.js";
2
+ import { __commonJS, __require, __toESM, formatCurrency, formatNumber, getDefaultClaudePath, loadDailyUsageData, loadMonthlyUsageData, loadSessionData } from "./data-loader-BfnzLKGl.js";
3
3
  import { calculateTotals, createTotalsObject, getTotalTokens } from "./calculate-cost-2IwHSzmi.js";
4
- import { safeParse } from "./dist-C0-Tf5eD.js";
5
- import { description, log, logger, name, version } from "./logger-DsQC4OvA.js";
6
- import "./pricing-fetcher-BPUgMrB_.js";
7
- import { detectMismatches, printMismatchReport } from "./debug-C_5Qx11m.js";
8
- import { CostModes, SortOrders, createMcpServer, dateSchema } from "./mcp-BQdv12mr.js";
4
+ import { safeParse } from "./dist-BEQ1tJCL.js";
5
+ import { description, log, logger, name, version } from "./logger-DixU80sg.js";
6
+ import "./pricing-fetcher-BY3-ryVq.js";
7
+ import { detectMismatches, printMismatchReport } from "./debug-Bf6GUNZE.js";
8
+ import { CostModes, SortOrders, createMcpServer, dateSchema } from "./mcp-nXxiNurt.js";
9
9
  import "./types-DS8M8QF_.js";
10
- import "./index-CISmcbXk-DCA05NUL.js";
10
+ import "./index-CISmcbXk-x9eVmhGM.js";
11
11
  import g$1 from "node:process";
12
12
 
13
13
  //#region node_modules/gunshi/lib/utils-D41C8Abf.js
@@ -2945,15 +2945,6 @@ const sharedCommandConfig = {
2945
2945
  toKebab: true
2946
2946
  };
2947
2947
 
2948
- //#endregion
2949
- //#region src/utils.internal.ts
2950
- function formatNumber(num) {
2951
- return num.toLocaleString("en-US");
2952
- }
2953
- function formatCurrency(amount) {
2954
- return `$${amount.toFixed(2)}`;
2955
- }
2956
-
2957
2948
  //#endregion
2958
2949
  //#region src/commands/daily.ts
2959
2950
  var import_cli_table3$2 = __toESM(require_cli_table3(), 1);
@@ -965,7 +965,7 @@ const consola = createConsola$1();
965
965
  //#endregion
966
966
  //#region package.json
967
967
  var name = "ccusage";
968
- var version = "0.6.1";
968
+ var version = "0.6.2";
969
969
  var description = "Usage analysis tool for Claude Code";
970
970
 
971
971
  //#endregion
package/dist/logger.js CHANGED
@@ -1,3 +1,3 @@
1
- import { log, logger } from "./logger-DsQC4OvA.js";
1
+ import { log, logger } from "./logger-DixU80sg.js";
2
2
 
3
3
  export { log, logger };
@@ -1,8 +1,8 @@
1
- import { __commonJS, __require, __toESM, getDefaultClaudePath, loadDailyUsageData, loadSessionData } from "./data-loader-DP5qBPn6.js";
2
- import { description, literal, object, optional, pipe, regex, string, union } from "./dist-C0-Tf5eD.js";
3
- import { name, version } from "./logger-DsQC4OvA.js";
1
+ import { __commonJS, __require, __toESM, getDefaultClaudePath, loadDailyUsageData, loadSessionData } from "./data-loader-BfnzLKGl.js";
2
+ import { description, literal, object, optional, pipe, regex, string, union } from "./dist-BEQ1tJCL.js";
3
+ import { name, version } from "./logger-DixU80sg.js";
4
4
  import { anyType, arrayType, booleanType, discriminatedUnionType, enumType, literalType, numberType, objectType, optionalType, recordType, stringType, unionType, unknownType } from "./types-DS8M8QF_.js";
5
- import { toJsonSchema } from "./index-CISmcbXk-DCA05NUL.js";
5
+ import { toJsonSchema } from "./index-CISmcbXk-x9eVmhGM.js";
6
6
  import g$1 from "node:process";
7
7
  import { EventEmitter } from "events";
8
8
  import { randomUUID } from "node:crypto";
@@ -2832,8 +2832,8 @@ var require_setprototypeof = __commonJS({ "node_modules/setprototypeof/index.js"
2832
2832
  } });
2833
2833
 
2834
2834
  //#endregion
2835
- //#region node_modules/statuses/codes.json
2836
- var require_codes = __commonJS({ "node_modules/statuses/codes.json"(exports, module) {
2835
+ //#region node_modules/http-errors/node_modules/statuses/codes.json
2836
+ var require_codes = __commonJS({ "node_modules/http-errors/node_modules/statuses/codes.json"(exports, module) {
2837
2837
  module.exports = {
2838
2838
  "100": "Continue",
2839
2839
  "101": "Switching Protocols",
@@ -2902,8 +2902,8 @@ var require_codes = __commonJS({ "node_modules/statuses/codes.json"(exports, mod
2902
2902
  } });
2903
2903
 
2904
2904
  //#endregion
2905
- //#region node_modules/statuses/index.js
2906
- var require_statuses = __commonJS({ "node_modules/statuses/index.js"(exports, module) {
2905
+ //#region node_modules/http-errors/node_modules/statuses/index.js
2906
+ var require_statuses = __commonJS({ "node_modules/http-errors/node_modules/statuses/index.js"(exports, module) {
2907
2907
  /**
2908
2908
  * Module dependencies.
2909
2909
  * @private
@@ -36916,6 +36916,7 @@ var FastMCPSession = class extends FastMCPSessionEventEmitter {
36916
36916
  #clientCapabilities;
36917
36917
  #connectionState = "connecting";
36918
36918
  #loggingLevel = "info";
36919
+ #needsEventLoopFlush = false;
36919
36920
  #pingConfig;
36920
36921
  #pingInterval = null;
36921
36922
  #prompts = [];
@@ -36924,11 +36925,12 @@ var FastMCPSession = class extends FastMCPSessionEventEmitter {
36924
36925
  #roots = [];
36925
36926
  #rootsConfig;
36926
36927
  #server;
36927
- constructor({ auth, instructions, name: name$1, ping, prompts, resources, resourcesTemplates, roots, tools, version: version$1 }) {
36928
+ constructor({ auth, instructions, name: name$1, ping, prompts, resources, resourcesTemplates, roots, tools, transportType, version: version$1 }) {
36928
36929
  super();
36929
36930
  this.#auth = auth;
36930
36931
  this.#pingConfig = ping;
36931
36932
  this.#rootsConfig = roots;
36933
+ this.#needsEventLoopFlush = transportType === "httpStream";
36932
36934
  if (tools.length) this.#capabilities.tools = {};
36933
36935
  if (resources.length || resourcesTemplates.length) this.#capabilities.resources = {};
36934
36936
  if (prompts.length) {
@@ -37271,6 +37273,7 @@ ${e instanceof Error ? e.stack : JSON.stringify(e)}`);
37271
37273
  progressToken
37272
37274
  }
37273
37275
  });
37276
+ if (this.#needsEventLoopFlush) await new Promise((resolve$4) => setImmediate(resolve$4));
37274
37277
  };
37275
37278
  const log$1 = {
37276
37279
  debug: (message, context) => {
@@ -37319,6 +37322,7 @@ ${e instanceof Error ? e.stack : JSON.stringify(e)}`);
37319
37322
  toolName: request$1.params.name
37320
37323
  }
37321
37324
  });
37325
+ if (this.#needsEventLoopFlush) await new Promise((resolve$4) => setImmediate(resolve$4));
37322
37326
  };
37323
37327
  const executeToolPromise = tool.execute(args, {
37324
37328
  log: log$1,
@@ -37464,6 +37468,7 @@ var FastMCP = class extends FastMCPEventEmitter {
37464
37468
  resourcesTemplates: this.#resourcesTemplates,
37465
37469
  roots: this.#options.roots,
37466
37470
  tools: this.#tools,
37471
+ transportType: "stdio",
37467
37472
  version: this.#options.version
37468
37473
  });
37469
37474
  await session.connect(transport);
@@ -37483,6 +37488,7 @@ var FastMCP = class extends FastMCPEventEmitter {
37483
37488
  resourcesTemplates: this.#resourcesTemplates,
37484
37489
  roots: this.#options.roots,
37485
37490
  tools: this.#tools,
37491
+ transportType: "httpStream",
37486
37492
  version: this.#options.version
37487
37493
  });
37488
37494
  },
package/dist/mcp.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import "./pricing-fetcher-CfEgfzSr.js";
2
- import { LoadOptions } from "./data-loader-VdEcqJHc.js";
1
+ import { LoadOptions } from "./data-loader-B0tJZeHI.js";
2
+ import "./pricing-fetcher-Dq-OLBp4.js";
3
3
  import { FastMCP } from "fastmcp";
4
4
 
5
5
  //#region src/mcp.d.ts
package/dist/mcp.js CHANGED
@@ -1,9 +1,9 @@
1
- import "./data-loader-DP5qBPn6.js";
2
- import "./dist-C0-Tf5eD.js";
3
- import "./logger-DsQC4OvA.js";
4
- import "./pricing-fetcher-BPUgMrB_.js";
5
- import { createMcpServer } from "./mcp-BQdv12mr.js";
1
+ import "./data-loader-BfnzLKGl.js";
2
+ import "./dist-BEQ1tJCL.js";
3
+ import "./logger-DixU80sg.js";
4
+ import "./pricing-fetcher-BY3-ryVq.js";
5
+ import { createMcpServer } from "./mcp-nXxiNurt.js";
6
6
  import "./types-DS8M8QF_.js";
7
- import "./index-CISmcbXk-DCA05NUL.js";
7
+ import "./index-CISmcbXk-x9eVmhGM.js";
8
8
 
9
9
  export { createMcpServer };
@@ -0,0 +1,79 @@
1
+ import { number, object, optional, safeParse } from "./dist-BEQ1tJCL.js";
2
+ import { logger } from "./logger-DixU80sg.js";
3
+
4
+ //#region src/pricing-fetcher.ts
5
+ const ModelPricingSchema = object({
6
+ input_cost_per_token: optional(number()),
7
+ output_cost_per_token: optional(number()),
8
+ cache_creation_input_token_cost: optional(number()),
9
+ cache_read_input_token_cost: optional(number())
10
+ });
11
+ const LITELLM_PRICING_URL = "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json";
12
+ var PricingFetcher = class {
13
+ cachedPricing = null;
14
+ constructor() {}
15
+ [Symbol.dispose]() {
16
+ this.clearCache();
17
+ }
18
+ clearCache() {
19
+ this.cachedPricing = null;
20
+ }
21
+ async ensurePricingLoaded() {
22
+ if (this.cachedPricing != null) return this.cachedPricing;
23
+ try {
24
+ logger.warn("Fetching latest model pricing from LiteLLM...");
25
+ const response = await fetch(LITELLM_PRICING_URL);
26
+ if (!response.ok) throw new Error(`Failed to fetch pricing data: ${response.statusText}`);
27
+ const data = await response.json();
28
+ const pricing = /* @__PURE__ */ new Map();
29
+ for (const [modelName, modelData] of Object.entries(data)) if (typeof modelData === "object" && modelData !== null) {
30
+ const parsed = safeParse(ModelPricingSchema, modelData);
31
+ if (parsed.success) pricing.set(modelName, parsed.output);
32
+ }
33
+ this.cachedPricing = pricing;
34
+ logger.info(`Loaded pricing for ${pricing.size} models`);
35
+ return pricing;
36
+ } catch (error) {
37
+ logger.error("Failed to fetch model pricing:", error);
38
+ throw new Error("Could not fetch model pricing data");
39
+ }
40
+ }
41
+ async fetchModelPricing() {
42
+ return this.ensurePricingLoaded();
43
+ }
44
+ async getModelPricing(modelName) {
45
+ const pricing = await this.ensurePricingLoaded();
46
+ const directMatch = pricing.get(modelName);
47
+ if (directMatch != null) return directMatch;
48
+ const variations = [
49
+ modelName,
50
+ `anthropic/${modelName}`,
51
+ `claude-3-5-${modelName}`,
52
+ `claude-3-${modelName}`,
53
+ `claude-${modelName}`
54
+ ];
55
+ for (const variant of variations) {
56
+ const match = pricing.get(variant);
57
+ if (match != null) return match;
58
+ }
59
+ const lowerModel = modelName.toLowerCase();
60
+ for (const [key, value] of pricing) if (key.toLowerCase().includes(lowerModel) || lowerModel.includes(key.toLowerCase())) return value;
61
+ return null;
62
+ }
63
+ async calculateCostFromTokens(tokens, modelName) {
64
+ const pricing = await this.getModelPricing(modelName);
65
+ if (pricing == null) return 0;
66
+ return this.calculateCostFromPricing(tokens, pricing);
67
+ }
68
+ calculateCostFromPricing(tokens, pricing) {
69
+ let cost = 0;
70
+ if (pricing.input_cost_per_token != null) cost += tokens.input_tokens * pricing.input_cost_per_token;
71
+ if (pricing.output_cost_per_token != null) cost += tokens.output_tokens * pricing.output_cost_per_token;
72
+ if (tokens.cache_creation_input_tokens != null && pricing.cache_creation_input_token_cost != null) cost += tokens.cache_creation_input_tokens * pricing.cache_creation_input_token_cost;
73
+ if (tokens.cache_read_input_tokens != null && pricing.cache_read_input_token_cost != null) cost += tokens.cache_read_input_tokens * pricing.cache_read_input_token_cost;
74
+ return cost;
75
+ }
76
+ };
77
+
78
+ //#endregion
79
+ export { PricingFetcher };
@@ -1567,14 +1567,26 @@ declare const ModelPricingSchema: ObjectSchema<{
1567
1567
  readonly cache_read_input_token_cost: OptionalSchema<NumberSchema<undefined>, undefined>;
1568
1568
  }, undefined>;
1569
1569
  type ModelPricing = InferOutput<typeof ModelPricingSchema>;
1570
- declare function clearPricingCache(): void;
1571
- declare function fetchModelPricing(): Promise<Record<string, ModelPricing>>;
1572
- declare function getModelPricing(modelName: string, pricing: Record<string, ModelPricing>): ModelPricing | null;
1573
- declare function calculateCostFromTokens(tokens: {
1574
- input_tokens: number;
1575
- output_tokens: number;
1576
- cache_creation_input_tokens?: number;
1577
- cache_read_input_tokens?: number;
1578
- }, pricing: ModelPricing): number;
1570
+ declare class PricingFetcher implements Disposable {
1571
+ private cachedPricing;
1572
+ constructor();
1573
+ [Symbol.dispose](): void;
1574
+ clearCache(): void;
1575
+ private ensurePricingLoaded;
1576
+ fetchModelPricing(): Promise<Map<string, ModelPricing>>;
1577
+ getModelPricing(modelName: string): Promise<ModelPricing | null>;
1578
+ calculateCostFromTokens(tokens: {
1579
+ input_tokens: number;
1580
+ output_tokens: number;
1581
+ cache_creation_input_tokens?: number;
1582
+ cache_read_input_tokens?: number;
1583
+ }, modelName: string): Promise<number>;
1584
+ calculateCostFromPricing(tokens: {
1585
+ input_tokens: number;
1586
+ output_tokens: number;
1587
+ cache_creation_input_tokens?: number;
1588
+ cache_read_input_tokens?: number;
1589
+ }, pricing: ModelPricing): number;
1590
+ }
1579
1591
  //#endregion
1580
- export { ArraySchema, InferOutput, ModelPricing, NumberSchema, ObjectSchema, OptionalSchema, RegexAction, SchemaWithPipe, StringSchema, calculateCostFromTokens, clearPricingCache, fetchModelPricing, getModelPricing };
1592
+ export { ArraySchema, InferOutput, ModelPricing, NumberSchema, ObjectSchema, OptionalSchema, PricingFetcher, RegexAction, SchemaWithPipe, StringSchema };
@@ -1,2 +1,2 @@
1
- import { ModelPricing, calculateCostFromTokens, clearPricingCache, fetchModelPricing, getModelPricing } from "./pricing-fetcher-CfEgfzSr.js";
2
- export { ModelPricing, calculateCostFromTokens, clearPricingCache, fetchModelPricing, getModelPricing };
1
+ import { ModelPricing, PricingFetcher } from "./pricing-fetcher-Dq-OLBp4.js";
2
+ export { ModelPricing, PricingFetcher };
@@ -1,5 +1,5 @@
1
- import "./dist-C0-Tf5eD.js";
2
- import "./logger-DsQC4OvA.js";
3
- import { calculateCostFromTokens, clearPricingCache, fetchModelPricing, getModelPricing } from "./pricing-fetcher-BPUgMrB_.js";
1
+ import "./dist-BEQ1tJCL.js";
2
+ import "./logger-DixU80sg.js";
3
+ import { PricingFetcher } from "./pricing-fetcher-BY3-ryVq.js";
4
4
 
5
- export { calculateCostFromTokens, clearPricingCache, fetchModelPricing, getModelPricing };
5
+ export { PricingFetcher };
@@ -1,4 +1,4 @@
1
- import { tryImport } from "./index-CISmcbXk-DCA05NUL.js";
1
+ import { tryImport } from "./index-CISmcbXk-x9eVmhGM.js";
2
2
 
3
3
  //#region node_modules/xsschema/dist/sury-DmrZ3_Oj.js
4
4
  const getToJsonSchemaFn = async () => {
@@ -0,0 +1,10 @@
1
+ import { tryImport } from "./index-CISmcbXk-x9eVmhGM.js";
2
+
3
+ //#region node_modules/xsschema/dist/valibot-CQk-M5rL.js
4
+ const getToJsonSchemaFn = async () => {
5
+ const { toJsonSchema } = await tryImport(import("./dist-DAarI-SJ.js"), "@valibot/to-json-schema");
6
+ return (schema) => toJsonSchema(schema);
7
+ };
8
+
9
+ //#endregion
10
+ export { getToJsonSchemaFn };
@@ -1,4 +1,4 @@
1
- import { missingDependenciesUrl } from "./index-CISmcbXk-DCA05NUL.js";
1
+ import { missingDependenciesUrl } from "./index-CISmcbXk-x9eVmhGM.js";
2
2
 
3
3
  //#region node_modules/xsschema/dist/zod-Db63SLXj.js
4
4
  const getToJsonSchemaFn = async () => {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "ccusage",
3
3
  "type": "module",
4
- "version": "0.6.1",
4
+ "version": "0.6.2",
5
5
  "description": "Usage analysis tool for Claude Code",
6
6
  "author": "ryoppippi",
7
7
  "license": "MIT",
@@ -1,60 +0,0 @@
1
- import { number, object, optional, parse } from "./dist-C0-Tf5eD.js";
2
- import { logger } from "./logger-DsQC4OvA.js";
3
-
4
- //#region src/pricing-fetcher.ts
5
- const ModelPricingSchema = object({
6
- input_cost_per_token: optional(number()),
7
- output_cost_per_token: optional(number()),
8
- cache_creation_input_token_cost: optional(number()),
9
- cache_read_input_token_cost: optional(number())
10
- });
11
- const LITELLM_PRICING_URL = "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json";
12
- let cachedPricing = null;
13
- function clearPricingCache() {
14
- cachedPricing = null;
15
- }
16
- async function fetchModelPricing() {
17
- if (cachedPricing != null) return cachedPricing;
18
- try {
19
- logger.warn("Fetching latest model pricing from LiteLLM...");
20
- const response = await fetch(LITELLM_PRICING_URL);
21
- if (!response.ok) throw new Error(`Failed to fetch pricing data: ${response.statusText}`);
22
- const data = await response.json();
23
- const pricing = {};
24
- for (const [modelName, modelData] of Object.entries(data)) if (typeof modelData === "object" && modelData !== null) try {
25
- const parsed = parse(ModelPricingSchema, modelData);
26
- pricing[modelName] = parsed;
27
- } catch {}
28
- cachedPricing = pricing;
29
- logger.info(`Loaded pricing for ${Object.keys(pricing).length} models`);
30
- return pricing;
31
- } catch (error) {
32
- logger.error("Failed to fetch model pricing:", error);
33
- throw new Error("Could not fetch model pricing data");
34
- }
35
- }
36
- function getModelPricing(modelName, pricing) {
37
- if (pricing[modelName] != null) return pricing[modelName];
38
- const variations = [
39
- modelName,
40
- `anthropic/${modelName}`,
41
- `claude-3-5-${modelName}`,
42
- `claude-3-${modelName}`,
43
- `claude-${modelName}`
44
- ];
45
- for (const variant of variations) if (pricing[variant] != null) return pricing[variant];
46
- const lowerModel = modelName.toLowerCase();
47
- for (const [key, value] of Object.entries(pricing)) if (key.toLowerCase().includes(lowerModel) || lowerModel.includes(key.toLowerCase())) return value;
48
- return null;
49
- }
50
- function calculateCostFromTokens(tokens, pricing) {
51
- let cost = 0;
52
- if (pricing.input_cost_per_token != null) cost += tokens.input_tokens * pricing.input_cost_per_token;
53
- if (pricing.output_cost_per_token != null) cost += tokens.output_tokens * pricing.output_cost_per_token;
54
- if (tokens.cache_creation_input_tokens != null && pricing.cache_creation_input_token_cost != null) cost += tokens.cache_creation_input_tokens * pricing.cache_creation_input_token_cost;
55
- if (tokens.cache_read_input_tokens != null && pricing.cache_read_input_token_cost != null) cost += tokens.cache_read_input_tokens * pricing.cache_read_input_token_cost;
56
- return cost;
57
- }
58
-
59
- //#endregion
60
- export { calculateCostFromTokens, clearPricingCache, fetchModelPricing, getModelPricing };
@@ -1,10 +0,0 @@
1
- import { tryImport } from "./index-CISmcbXk-DCA05NUL.js";
2
-
3
- //#region node_modules/xsschema/dist/valibot-CQk-M5rL.js
4
- const getToJsonSchemaFn = async () => {
5
- const { toJsonSchema } = await tryImport(import("./dist-LwbOR2Yw.js"), "@valibot/to-json-schema");
6
- return (schema) => toJsonSchema(schema);
7
- };
8
-
9
- //#endregion
10
- export { getToJsonSchemaFn };