ccusage 0.4.1 → 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/{calculate-cost-DMC4FhU4.js → calculate-cost-BnufbprY.js} +1 -1
- package/dist/calculate-cost.d.ts +5 -2
- package/dist/calculate-cost.js +1 -1
- package/dist/{data-loader-BBdPk24U.js → data-loader-B8mdiY5r.js} +122 -1608
- package/dist/data-loader-DtCt7sNl.d.ts +56 -0
- package/dist/data-loader.d.ts +4 -1
- package/dist/data-loader.js +4 -1
- package/dist/debug-Oce2b5bO.js +142 -0
- package/dist/debug.d.ts +39 -0
- package/dist/debug.js +7 -0
- package/dist/dist-D6rk8Ra5.js +462 -0
- package/dist/{data-loader-D1LHcGfa.d.ts → index-Bazt8Nfd.d.ts} +323 -76
- package/dist/index.js +33 -265
- package/dist/logger-nCODI08N.js +977 -0
- package/dist/logger.d.ts +10 -0
- package/dist/logger.js +3 -0
- package/dist/pricing-fetcher-BqlslEH3.d.ts +21 -0
- package/dist/pricing-fetcher-bvi4lbXl.js +60 -0
- package/dist/pricing-fetcher.d.ts +3 -0
- package/dist/pricing-fetcher.js +5 -0
- package/dist/shared-args-DWaGio0e.js +61 -0
- package/dist/shared-args.d.ts +94 -0
- package/dist/shared-args.js +8 -0
- package/dist/types-BfZ5dOy7.d.ts +79 -0
- package/dist/types-DjlBTM5P.js +41 -0
- package/dist/types.d.ts +3 -0
- package/dist/types.js +4 -0
- package/dist/utils-BeihwpHn.js +10 -0
- package/dist/utils.d.ts +5 -0
- package/dist/utils.js +3 -0
- package/package.json +7 -1
- /package/dist/{prompt-_w55ddDU.js → prompt-BwcIpzWm.js} +0 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { ArraySchema, InferOutput, NumberSchema, ObjectSchema, OptionalSchema, StringSchema } from "./index-Bazt8Nfd.js";
|
|
2
|
+
import { ModelPricing } from "./pricing-fetcher-BqlslEH3.js";
|
|
3
|
+
import { CostMode } from "./types-BfZ5dOy7.js";
|
|
4
|
+
|
|
5
|
+
//#region src/data-loader.d.ts
|
|
6
|
+
declare const getDefaultClaudePath: () => string;
|
|
7
|
+
declare const UsageDataSchema: ObjectSchema<{
|
|
8
|
+
readonly timestamp: StringSchema<undefined>;
|
|
9
|
+
readonly version: OptionalSchema<StringSchema<undefined>, undefined>;
|
|
10
|
+
readonly message: ObjectSchema<{
|
|
11
|
+
readonly usage: ObjectSchema<{
|
|
12
|
+
readonly input_tokens: NumberSchema<undefined>;
|
|
13
|
+
readonly output_tokens: NumberSchema<undefined>;
|
|
14
|
+
readonly cache_creation_input_tokens: OptionalSchema<NumberSchema<undefined>, undefined>;
|
|
15
|
+
readonly cache_read_input_tokens: OptionalSchema<NumberSchema<undefined>, undefined>;
|
|
16
|
+
}, undefined>;
|
|
17
|
+
readonly model: OptionalSchema<StringSchema<undefined>, undefined>;
|
|
18
|
+
}, undefined>;
|
|
19
|
+
readonly costUSD: OptionalSchema<NumberSchema<undefined>, undefined>;
|
|
20
|
+
}, undefined>;
|
|
21
|
+
type UsageData = InferOutput<typeof UsageDataSchema>;
|
|
22
|
+
declare const DailyUsageSchema: ObjectSchema<{
|
|
23
|
+
readonly date: StringSchema<undefined>;
|
|
24
|
+
readonly inputTokens: NumberSchema<undefined>;
|
|
25
|
+
readonly outputTokens: NumberSchema<undefined>;
|
|
26
|
+
readonly cacheCreationTokens: NumberSchema<undefined>;
|
|
27
|
+
readonly cacheReadTokens: NumberSchema<undefined>;
|
|
28
|
+
readonly totalCost: NumberSchema<undefined>;
|
|
29
|
+
}, undefined>;
|
|
30
|
+
type DailyUsage = InferOutput<typeof DailyUsageSchema>;
|
|
31
|
+
declare const SessionUsageSchema: ObjectSchema<{
|
|
32
|
+
readonly sessionId: StringSchema<undefined>;
|
|
33
|
+
readonly projectPath: StringSchema<undefined>;
|
|
34
|
+
readonly inputTokens: NumberSchema<undefined>;
|
|
35
|
+
readonly outputTokens: NumberSchema<undefined>;
|
|
36
|
+
readonly cacheCreationTokens: NumberSchema<undefined>;
|
|
37
|
+
readonly cacheReadTokens: NumberSchema<undefined>;
|
|
38
|
+
readonly totalCost: NumberSchema<undefined>;
|
|
39
|
+
readonly lastActivity: StringSchema<undefined>;
|
|
40
|
+
readonly versions: ArraySchema<StringSchema<undefined>, undefined>;
|
|
41
|
+
}, undefined>;
|
|
42
|
+
type SessionUsage = InferOutput<typeof SessionUsageSchema>;
|
|
43
|
+
declare const formatDate: (dateStr: string) => string;
|
|
44
|
+
declare const calculateCostForEntry: (data: UsageData, mode: CostMode, modelPricing: Record<string, ModelPricing>) => number;
|
|
45
|
+
interface DateFilter {
|
|
46
|
+
since?: string;
|
|
47
|
+
until?: string;
|
|
48
|
+
}
|
|
49
|
+
interface LoadOptions extends DateFilter {
|
|
50
|
+
claudePath?: string;
|
|
51
|
+
mode?: CostMode;
|
|
52
|
+
}
|
|
53
|
+
declare function loadUsageData(options?: LoadOptions): Promise<DailyUsage[]>;
|
|
54
|
+
declare function loadSessionData(options?: LoadOptions): Promise<SessionUsage[]>;
|
|
55
|
+
//#endregion
|
|
56
|
+
export { DailyUsage, DailyUsageSchema as DailyUsageSchema$1, DateFilter, LoadOptions, SessionUsage, SessionUsageSchema as SessionUsageSchema$1, UsageData, UsageDataSchema as UsageDataSchema$1, calculateCostForEntry as calculateCostForEntry$1, formatDate as formatDate$1, getDefaultClaudePath as getDefaultClaudePath$1, loadSessionData as loadSessionData$1, loadUsageData as loadUsageData$1 };
|
package/dist/data-loader.d.ts
CHANGED
|
@@ -1,2 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
import "./index-Bazt8Nfd.js";
|
|
2
|
+
import "./pricing-fetcher-BqlslEH3.js";
|
|
3
|
+
import "./types-BfZ5dOy7.js";
|
|
4
|
+
import { DailyUsage, DailyUsageSchema$1 as DailyUsageSchema, DateFilter, LoadOptions, SessionUsage, SessionUsageSchema$1 as SessionUsageSchema, UsageData, UsageDataSchema$1 as UsageDataSchema, calculateCostForEntry$1 as calculateCostForEntry, formatDate$1 as formatDate, getDefaultClaudePath$1 as getDefaultClaudePath, loadSessionData$1 as loadSessionData, loadUsageData$1 as loadUsageData } from "./data-loader-DtCt7sNl.js";
|
|
2
5
|
export { DailyUsage, DailyUsageSchema, DateFilter, LoadOptions, SessionUsage, SessionUsageSchema, UsageData, UsageDataSchema, calculateCostForEntry, formatDate, getDefaultClaudePath, loadSessionData, loadUsageData };
|
package/dist/data-loader.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
-
import { DailyUsageSchema, SessionUsageSchema, UsageDataSchema, calculateCostForEntry, formatDate, getDefaultClaudePath, loadSessionData, loadUsageData } from "./data-loader-
|
|
1
|
+
import { DailyUsageSchema, SessionUsageSchema, UsageDataSchema, calculateCostForEntry, formatDate, getDefaultClaudePath, loadSessionData, loadUsageData } from "./data-loader-B8mdiY5r.js";
|
|
2
|
+
import "./dist-D6rk8Ra5.js";
|
|
3
|
+
import "./logger-nCODI08N.js";
|
|
4
|
+
import "./pricing-fetcher-bvi4lbXl.js";
|
|
2
5
|
|
|
3
6
|
export { DailyUsageSchema, SessionUsageSchema, UsageDataSchema, calculateCostForEntry, formatDate, getDefaultClaudePath, loadSessionData, loadUsageData };
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { UsageDataSchema, glob } from "./data-loader-B8mdiY5r.js";
|
|
2
|
+
import { safeParse } from "./dist-D6rk8Ra5.js";
|
|
3
|
+
import { logger } from "./logger-nCODI08N.js";
|
|
4
|
+
import { calculateCostFromTokens, fetchModelPricing, getModelPricing } from "./pricing-fetcher-bvi4lbXl.js";
|
|
5
|
+
import { readFile } from "node:fs/promises";
|
|
6
|
+
import { homedir } from "node:os";
|
|
7
|
+
import path from "node:path";
|
|
8
|
+
|
|
9
|
+
//#region src/debug.ts
|
|
10
|
+
const MATCH_THRESHOLD_PERCENT = .1;
|
|
11
|
+
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: new Map(),
|
|
25
|
+
versionStats: 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 && data.message.model !== "<synthetic>") {
|
|
37
|
+
stats.entriesWithBoth++;
|
|
38
|
+
const model = data.message.model;
|
|
39
|
+
const pricing = getModelPricing(model, modelPricing);
|
|
40
|
+
if (pricing) {
|
|
41
|
+
const calculatedCost = calculateCostFromTokens(data.message.usage, pricing);
|
|
42
|
+
const difference = Math.abs(data.costUSD - calculatedCost);
|
|
43
|
+
const percentDiff = data.costUSD > 0 ? difference / data.costUSD * 100 : 0;
|
|
44
|
+
const modelStat = stats.modelStats.get(model) || {
|
|
45
|
+
total: 0,
|
|
46
|
+
matches: 0,
|
|
47
|
+
mismatches: 0,
|
|
48
|
+
avgPercentDiff: 0
|
|
49
|
+
};
|
|
50
|
+
modelStat.total++;
|
|
51
|
+
if (data.version) {
|
|
52
|
+
const versionStat = stats.versionStats.get(data.version) || {
|
|
53
|
+
total: 0,
|
|
54
|
+
matches: 0,
|
|
55
|
+
mismatches: 0,
|
|
56
|
+
avgPercentDiff: 0
|
|
57
|
+
};
|
|
58
|
+
versionStat.total++;
|
|
59
|
+
if (percentDiff < MATCH_THRESHOLD_PERCENT) versionStat.matches++;
|
|
60
|
+
else versionStat.mismatches++;
|
|
61
|
+
versionStat.avgPercentDiff = (versionStat.avgPercentDiff * (versionStat.total - 1) + percentDiff) / versionStat.total;
|
|
62
|
+
stats.versionStats.set(data.version, versionStat);
|
|
63
|
+
}
|
|
64
|
+
if (percentDiff < .1) {
|
|
65
|
+
stats.matches++;
|
|
66
|
+
modelStat.matches++;
|
|
67
|
+
} else {
|
|
68
|
+
stats.mismatches++;
|
|
69
|
+
modelStat.mismatches++;
|
|
70
|
+
stats.discrepancies.push({
|
|
71
|
+
file: path.basename(file),
|
|
72
|
+
timestamp: data.timestamp,
|
|
73
|
+
model,
|
|
74
|
+
originalCost: data.costUSD,
|
|
75
|
+
calculatedCost,
|
|
76
|
+
difference,
|
|
77
|
+
percentDiff,
|
|
78
|
+
usage: data.message.usage
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
modelStat.avgPercentDiff = (modelStat.avgPercentDiff * (modelStat.total - 1) + percentDiff) / modelStat.total;
|
|
82
|
+
stats.modelStats.set(model, modelStat);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
} catch (e) {}
|
|
86
|
+
}
|
|
87
|
+
return stats;
|
|
88
|
+
}
|
|
89
|
+
function printMismatchReport(stats, sampleCount = 5) {
|
|
90
|
+
if (stats.entriesWithBoth === 0) {
|
|
91
|
+
logger.info("No pricing data found to analyze.");
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
const matchRate = stats.matches / stats.entriesWithBoth * 100;
|
|
95
|
+
logger.info("\n=== Pricing Mismatch Debug Report ===");
|
|
96
|
+
logger.info(`Total entries processed: ${stats.totalEntries.toLocaleString()}`);
|
|
97
|
+
logger.info(`Entries with both costUSD and model: ${stats.entriesWithBoth.toLocaleString()}`);
|
|
98
|
+
logger.info(`Matches (within 0.1%): ${stats.matches.toLocaleString()}`);
|
|
99
|
+
logger.info(`Mismatches: ${stats.mismatches.toLocaleString()}`);
|
|
100
|
+
logger.info(`Match rate: ${matchRate.toFixed(2)}%`);
|
|
101
|
+
if (stats.mismatches > 0 && stats.modelStats.size > 0) {
|
|
102
|
+
logger.info("\n=== Model Statistics ===");
|
|
103
|
+
const sortedModels = Array.from(stats.modelStats.entries()).sort((a, b) => b[1].mismatches - a[1].mismatches);
|
|
104
|
+
for (const [model, modelStat] of sortedModels) if (modelStat.mismatches > 0) {
|
|
105
|
+
const modelMatchRate = modelStat.matches / modelStat.total * 100;
|
|
106
|
+
logger.info(`${model}:`);
|
|
107
|
+
logger.info(` Total entries: ${modelStat.total.toLocaleString()}`);
|
|
108
|
+
logger.info(` Matches: ${modelStat.matches.toLocaleString()} (${modelMatchRate.toFixed(1)}%)`);
|
|
109
|
+
logger.info(` Mismatches: ${modelStat.mismatches.toLocaleString()}`);
|
|
110
|
+
logger.info(` Avg % difference: ${modelStat.avgPercentDiff.toFixed(1)}%`);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
if (stats.mismatches > 0 && stats.versionStats.size > 0) {
|
|
114
|
+
logger.info("\n=== Version Statistics ===");
|
|
115
|
+
const sortedVersions = Array.from(stats.versionStats.entries()).filter(([_, versionStat]) => versionStat.mismatches > 0).sort((a, b) => b[1].mismatches - a[1].mismatches);
|
|
116
|
+
for (const [version, versionStat] of sortedVersions) {
|
|
117
|
+
const versionMatchRate = versionStat.matches / versionStat.total * 100;
|
|
118
|
+
logger.info(`${version}:`);
|
|
119
|
+
logger.info(` Total entries: ${versionStat.total.toLocaleString()}`);
|
|
120
|
+
logger.info(` Matches: ${versionStat.matches.toLocaleString()} (${versionMatchRate.toFixed(1)}%)`);
|
|
121
|
+
logger.info(` Mismatches: ${versionStat.mismatches.toLocaleString()}`);
|
|
122
|
+
logger.info(` Avg % difference: ${versionStat.avgPercentDiff.toFixed(1)}%`);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
if (stats.discrepancies.length > 0 && sampleCount > 0) {
|
|
126
|
+
logger.info(`\n=== Sample Discrepancies (first ${sampleCount}) ===`);
|
|
127
|
+
const samples = stats.discrepancies.slice(0, sampleCount);
|
|
128
|
+
for (const disc of samples) {
|
|
129
|
+
logger.info(`File: ${disc.file}`);
|
|
130
|
+
logger.info(`Timestamp: ${disc.timestamp}`);
|
|
131
|
+
logger.info(`Model: ${disc.model}`);
|
|
132
|
+
logger.info(`Original cost: $${disc.originalCost.toFixed(6)}`);
|
|
133
|
+
logger.info(`Calculated cost: $${disc.calculatedCost.toFixed(6)}`);
|
|
134
|
+
logger.info(`Difference: $${disc.difference.toFixed(6)} (${disc.percentDiff.toFixed(2)}%)`);
|
|
135
|
+
logger.info(`Tokens: ${JSON.stringify(disc.usage)}`);
|
|
136
|
+
logger.info("---");
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
//#endregion
|
|
142
|
+
export { detectMismatches, printMismatchReport };
|
package/dist/debug.d.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
//#region src/debug.d.ts
|
|
2
|
+
interface Discrepancy {
|
|
3
|
+
file: string;
|
|
4
|
+
timestamp: string;
|
|
5
|
+
model: string;
|
|
6
|
+
originalCost: number;
|
|
7
|
+
calculatedCost: number;
|
|
8
|
+
difference: number;
|
|
9
|
+
percentDiff: number;
|
|
10
|
+
usage: {
|
|
11
|
+
input_tokens: number;
|
|
12
|
+
output_tokens: number;
|
|
13
|
+
cache_creation_input_tokens?: number;
|
|
14
|
+
cache_read_input_tokens?: number;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
interface MismatchStats {
|
|
18
|
+
totalEntries: number;
|
|
19
|
+
entriesWithBoth: number;
|
|
20
|
+
matches: number;
|
|
21
|
+
mismatches: number;
|
|
22
|
+
discrepancies: Discrepancy[];
|
|
23
|
+
modelStats: Map<string, {
|
|
24
|
+
total: number;
|
|
25
|
+
matches: number;
|
|
26
|
+
mismatches: number;
|
|
27
|
+
avgPercentDiff: number;
|
|
28
|
+
}>;
|
|
29
|
+
versionStats: Map<string, {
|
|
30
|
+
total: number;
|
|
31
|
+
matches: number;
|
|
32
|
+
mismatches: number;
|
|
33
|
+
avgPercentDiff: number;
|
|
34
|
+
}>;
|
|
35
|
+
}
|
|
36
|
+
declare function detectMismatches(claudePath?: string): Promise<MismatchStats>;
|
|
37
|
+
declare function printMismatchReport(stats: MismatchStats, sampleCount?: number): void;
|
|
38
|
+
//#endregion
|
|
39
|
+
export { detectMismatches, printMismatchReport };
|
package/dist/debug.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import "./data-loader-B8mdiY5r.js";
|
|
2
|
+
import "./dist-D6rk8Ra5.js";
|
|
3
|
+
import "./logger-nCODI08N.js";
|
|
4
|
+
import "./pricing-fetcher-bvi4lbXl.js";
|
|
5
|
+
import { detectMismatches, printMismatchReport } from "./debug-Oce2b5bO.js";
|
|
6
|
+
|
|
7
|
+
export { detectMismatches, printMismatchReport };
|