ccusage 15.1.0 → 15.3.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.
- package/README.md +36 -2
- package/dist/_token-utils-WjkbrjKv.js +12 -0
- package/dist/{_types-Cr2YEzKm.js → _types-BHFM59hI.js} +4 -9
- package/dist/{calculate-cost-CoS7we68.js → calculate-cost-BDqO4yWA.js} +4 -15
- package/dist/calculate-cost.d.ts +41 -11
- package/dist/calculate-cost.js +3 -2
- package/dist/{data-loader-BeaFK_sH.js → data-loader-R9pMvoQp.js} +67 -34
- package/dist/{data-loader-DZczD-9E.d.ts → data-loader-a9CiVyT5.d.ts} +32 -8
- package/dist/data-loader.d.ts +3 -3
- package/dist/data-loader.js +6 -5
- package/dist/{debug-BmJuGBXC.js → debug-Cyr1LS0T.js} +22 -11
- package/dist/debug.js +6 -5
- package/dist/index.js +443 -335
- package/dist/{logger-Cke8hliP.js → logger-DeTONwj8.js} +3 -3
- package/dist/logger.d.ts +4 -1
- package/dist/logger.js +1 -1
- package/dist/{mcp-DKqp_F9c.js → mcp-Kff7A2dF.js} +235 -43
- package/dist/mcp.d.ts +2 -2
- package/dist/mcp.js +7 -5
- package/dist/{pricing-fetcher-BZe7AafW.d.ts → pricing-fetcher-B3SvKOod.d.ts} +10 -3
- package/dist/{pricing-fetcher-Dm8hcn_h.js → pricing-fetcher-DaK2jizg.js} +180 -45
- package/dist/pricing-fetcher.d.ts +1 -1
- package/dist/pricing-fetcher.js +3 -3
- package/dist/{prompt-j5YimnLx.js → prompt-DsUFNEY7.js} +2 -2
- package/package.json +5 -2
package/README.md
CHANGED
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
<a href="https://npmjs.com/package/ccusage"><img src="https://img.shields.io/npm/v/ccusage?color=yellow" alt="npm version" /></a>
|
|
8
8
|
<a href="https://tanstack.com/stats/npm?packageGroups=%5B%7B%22packages%22:%5B%7B%22name%22:%22ccusage%22%7D%5D%7D%5D&range=30-days&transform=none&binType=daily&showDataMode=all&height=400"><img src="https://img.shields.io/npm/dy/ccusage" alt="NPM Downloads" /></a>
|
|
9
9
|
<a href="https://packagephobia.com/result?p=ccusage"><img src="https://packagephobia.com/badge?p=ccusage" alt="install size" /></a>
|
|
10
|
+
<a href="https://deepwiki.com/ryoppippi/ccusage"><img src="https://img.shields.io/badge/DeepWiki-ryoppippi%2Fccusage-blue.svg?logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACwAAAAyCAYAAAAnWDnqAAAAAXNSR0IArs4c6QAAA05JREFUaEPtmUtyEzEQhtWTQyQLHNak2AB7ZnyXZMEjXMGeK/AIi+QuHrMnbChYY7MIh8g01fJoopFb0uhhEqqcbWTp06/uv1saEDv4O3n3dV60RfP947Mm9/SQc0ICFQgzfc4CYZoTPAswgSJCCUJUnAAoRHOAUOcATwbmVLWdGoH//PB8mnKqScAhsD0kYP3j/Yt5LPQe2KvcXmGvRHcDnpxfL2zOYJ1mFwrryWTz0advv1Ut4CJgf5uhDuDj5eUcAUoahrdY/56ebRWeraTjMt/00Sh3UDtjgHtQNHwcRGOC98BJEAEymycmYcWwOprTgcB6VZ5JK5TAJ+fXGLBm3FDAmn6oPPjR4rKCAoJCal2eAiQp2x0vxTPB3ALO2CRkwmDy5WohzBDwSEFKRwPbknEggCPB/imwrycgxX2NzoMCHhPkDwqYMr9tRcP5qNrMZHkVnOjRMWwLCcr8ohBVb1OMjxLwGCvjTikrsBOiA6fNyCrm8V1rP93iVPpwaE+gO0SsWmPiXB+jikdf6SizrT5qKasx5j8ABbHpFTx+vFXp9EnYQmLx02h1QTTrl6eDqxLnGjporxl3NL3agEvXdT0WmEost648sQOYAeJS9Q7bfUVoMGnjo4AZdUMQku50McDcMWcBPvr0SzbTAFDfvJqwLzgxwATnCgnp4wDl6Aa+Ax283gghmj+vj7feE2KBBRMW3FzOpLOADl0Isb5587h/U4gGvkt5v60Z1VLG8BhYjbzRwyQZemwAd6cCR5/XFWLYZRIMpX39AR0tjaGGiGzLVyhse5C9RKC6ai42ppWPKiBagOvaYk8lO7DajerabOZP46Lby5wKjw1HCRx7p9sVMOWGzb/vA1hwiWc6jm3MvQDTogQkiqIhJV0nBQBTU+3okKCFDy9WwferkHjtxib7t3xIUQtHxnIwtx4mpg26/HfwVNVDb4oI9RHmx5WGelRVlrtiw43zboCLaxv46AZeB3IlTkwouebTr1y2NjSpHz68WNFjHvupy3q8TFn3Hos2IAk4Ju5dCo8B3wP7VPr/FGaKiG+T+v+TQqIrOqMTL1VdWV1DdmcbO8KXBz6esmYWYKPwDL5b5FA1a0hwapHiom0r/cKaoqr+27/XcrS5UwSMbQAAAABJRU5ErkJggg==" alt="DeepWiki"></a>
|
|
11
|
+
<!-- DeepWiki badge generated by https://deepwiki.ryoppippi.com/ -->
|
|
10
12
|
<a href="https://github.com/hesreallyhim/awesome-claude-code"><img src="https://awesome.re/mentioned-badge.svg" alt="Mentioned in Awesome Claude Code" /></a>
|
|
11
13
|
</p>
|
|
12
14
|
|
|
@@ -18,8 +20,29 @@
|
|
|
18
20
|
|
|
19
21
|
## Installation
|
|
20
22
|
|
|
23
|
+
### Quick Start (Recommended)
|
|
24
|
+
|
|
25
|
+
Thanks to ccusage's incredibly small bundle size ([](https://packagephobia.com/result?p=ccusage)), you can run it directly without installation:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
# Using bunx (recommended for speed)
|
|
29
|
+
bunx ccusage
|
|
30
|
+
|
|
31
|
+
# Using npx
|
|
32
|
+
npx ccusage@latest
|
|
33
|
+
|
|
34
|
+
# Using deno (with security flags)
|
|
35
|
+
deno run -E -R=$HOME/.claude/projects/ -S=homedir -N='raw.githubusercontent.com:443' npm:ccusage@latest
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
> 💡 **Tip**: We recommend using `bunx` instead of `npx` for a massive speed improvement!
|
|
39
|
+
|
|
40
|
+
### Local Installation (Optional)
|
|
41
|
+
|
|
42
|
+
Since ccusage has such a small bundle size, installation is entirely optional:
|
|
43
|
+
|
|
21
44
|
```bash
|
|
22
|
-
npm
|
|
45
|
+
npm install -g ccusage
|
|
23
46
|
```
|
|
24
47
|
|
|
25
48
|
## Usage
|
|
@@ -60,13 +83,24 @@ ccusage daily --breakdown # Per-model cost breakdown
|
|
|
60
83
|
- 🔄 **Cache Token Support**: Tracks and displays cache creation and cache read tokens separately
|
|
61
84
|
- 🌐 **Offline Mode**: Use pre-cached pricing data without network connectivity with `--offline` (Claude models only)
|
|
62
85
|
- 🔌 **MCP Integration**: Built-in Model Context Protocol server for integration with other tools
|
|
86
|
+
- 🚀 **Ultra-Small Bundle**: Unlike other CLI tools, we pay extreme attention to bundle size - incredibly small even without minification!
|
|
63
87
|
|
|
64
88
|
## Documentation
|
|
65
89
|
|
|
66
|
-
Full documentation is available at **[ccusage.
|
|
90
|
+
Full documentation is available at **[ccusage.com](https://ccusage.com/)**
|
|
67
91
|
|
|
68
92
|
## Sponsors
|
|
69
93
|
|
|
94
|
+
### Featured Sponsor
|
|
95
|
+
|
|
96
|
+
Check out these [47 Claude Code ProTips from Greg Baugues.](https://www.youtube.com/watch?v=TiNpzxoBPz0&lc=UgyVgQyOhfJJlheVMcB4AaABAg)
|
|
97
|
+
|
|
98
|
+
<p align="center">
|
|
99
|
+
<a href="https://www.youtube.com/watch?v=TiNpzxoBPz0&lc=UgyVgQyOhfJJlheVMcB4AaABAg">
|
|
100
|
+
<img src="https://cdn.jsdelivr.net/gh/ryoppippi/ccusage@main/docs/public/claude_code_protips_thumbnail_v1.png" alt="47 Claude Code ProTips from Greg Baugues" width="600">
|
|
101
|
+
</a>
|
|
102
|
+
</p>
|
|
103
|
+
|
|
70
104
|
<p align="center">
|
|
71
105
|
<a href="https://github.com/sponsors/ryoppippi">
|
|
72
106
|
<img src="https://cdn.jsdelivr.net/gh/ryoppippi/sponsors@main/sponsors.svg">
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Calculates the total number of tokens across all token types
|
|
3
|
+
* Supports both raw usage data format and aggregated data format
|
|
4
|
+
* @param tokenCounts - Object containing counts for each token type
|
|
5
|
+
* @returns Total number of tokens
|
|
6
|
+
*/
|
|
7
|
+
function getTotalTokens(tokenCounts) {
|
|
8
|
+
const cacheCreation = "cacheCreationInputTokens" in tokenCounts ? tokenCounts.cacheCreationInputTokens : tokenCounts.cacheCreationTokens;
|
|
9
|
+
const cacheRead = "cacheReadInputTokens" in tokenCounts ? tokenCounts.cacheReadInputTokens : tokenCounts.cacheReadTokens;
|
|
10
|
+
return tokenCounts.inputTokens + tokenCounts.outputTokens + cacheCreation + cacheRead;
|
|
11
|
+
}
|
|
12
|
+
export { getTotalTokens };
|
|
@@ -725,7 +725,7 @@ const ipv6CidrRegex = /^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1
|
|
|
725
725
|
const base64Regex = /^([0-9a-zA-Z+/]{4})*(([0-9a-zA-Z+/]{2}==)|([0-9a-zA-Z+/]{3}=))?$/;
|
|
726
726
|
const base64urlRegex = /^([0-9a-zA-Z-_]{4})*(([0-9a-zA-Z-_]{2}(==)?)|([0-9a-zA-Z-_]{3}(=)?))?$/;
|
|
727
727
|
const dateRegexSource = `((\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-((0[13578]|1[02])-(0[1-9]|[12]\\d|3[01])|(0[469]|11)-(0[1-9]|[12]\\d|30)|(02)-(0[1-9]|1\\d|2[0-8])))`;
|
|
728
|
-
const dateRegex = new RegExp(`^${dateRegexSource}$`);
|
|
728
|
+
const dateRegex = /* @__PURE__ */ new RegExp(`^${dateRegexSource}$`);
|
|
729
729
|
function timeRegexSource(args) {
|
|
730
730
|
let secondsRegexSource = `[0-5]\\d`;
|
|
731
731
|
if (args.precision) secondsRegexSource = `${secondsRegexSource}\\.\\d{${args.precision}}`;
|
|
@@ -734,7 +734,7 @@ function timeRegexSource(args) {
|
|
|
734
734
|
return `([01]\\d|2[0-3]):[0-5]\\d(:${secondsRegexSource})${secondsQuantifier}`;
|
|
735
735
|
}
|
|
736
736
|
function timeRegex(args) {
|
|
737
|
-
return new RegExp(`^${timeRegexSource(args)}$`);
|
|
737
|
+
return /* @__PURE__ */ new RegExp(`^${timeRegexSource(args)}$`);
|
|
738
738
|
}
|
|
739
739
|
function datetimeRegex(args) {
|
|
740
740
|
let regex = `${dateRegexSource}T${timeRegexSource(args)}`;
|
|
@@ -742,7 +742,7 @@ function datetimeRegex(args) {
|
|
|
742
742
|
opts.push(args.local ? `Z?` : `Z`);
|
|
743
743
|
if (args.offset) opts.push(`([+-]\\d{2}:?\\d{2})`);
|
|
744
744
|
regex = `${regex}(${opts.join("|")})`;
|
|
745
|
-
return new RegExp(`^${regex}$`);
|
|
745
|
+
return /* @__PURE__ */ new RegExp(`^${regex}$`);
|
|
746
746
|
}
|
|
747
747
|
function isValidIP(ip, version) {
|
|
748
748
|
if ((version === "v4" || !version) && ipv4Regex.test(ip)) return true;
|
|
@@ -3581,11 +3581,6 @@ const createDailyDate = (value) => dailyDateSchema.parse(value);
|
|
|
3581
3581
|
const createMonthlyDate = (value) => monthlyDateSchema.parse(value);
|
|
3582
3582
|
const createProjectPath = (value) => projectPathSchema.parse(value);
|
|
3583
3583
|
/**
|
|
3584
|
-
* Legacy schema for backward compatibility
|
|
3585
|
-
* @deprecated Use filterDateSchema instead for better type safety
|
|
3586
|
-
*/
|
|
3587
|
-
const dateSchema = stringType().regex(/^\d{8}$/, "Date must be in YYYYMMDD format");
|
|
3588
|
-
/**
|
|
3589
3584
|
* Available cost calculation modes
|
|
3590
3585
|
* - auto: Use pre-calculated costs when available, otherwise calculate from tokens
|
|
3591
3586
|
* - calculate: Always calculate costs from token counts using model pricing
|
|
@@ -3609,4 +3604,4 @@ const modelPricingSchema = objectType({
|
|
|
3609
3604
|
cache_creation_input_token_cost: numberType().optional(),
|
|
3610
3605
|
cache_read_input_token_cost: numberType().optional()
|
|
3611
3606
|
});
|
|
3612
|
-
export { CostModes, SortOrders, ZodFirstPartyTypeKind, ZodOptional, ZodType, activityDateSchema, arrayType, booleanType, createDailyDate, createMonthlyDate, createProjectPath, createSessionId, dailyDateSchema,
|
|
3607
|
+
export { CostModes, SortOrders, ZodFirstPartyTypeKind, ZodOptional, ZodType, activityDateSchema, arrayType, booleanType, createDailyDate, createMonthlyDate, createProjectPath, createSessionId, dailyDateSchema, discriminatedUnionType, enumType, filterDateSchema, isoTimestampSchema, literalType, messageIdSchema, modelNameSchema, modelPricingSchema, monthlyDateSchema, numberType, objectType, optionalType, projectPathSchema, recordType, requestIdSchema, sessionIdSchema, stringType, unionType, unknownType, versionSchema };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { getTotalTokens } from "./_token-utils-WjkbrjKv.js";
|
|
1
2
|
/**
|
|
2
3
|
* Calculates total token usage and cost across multiple usage data entries
|
|
3
4
|
* @param data - Array of daily, monthly, or session usage data
|
|
@@ -19,26 +20,14 @@ function calculateTotals(data) {
|
|
|
19
20
|
});
|
|
20
21
|
}
|
|
21
22
|
/**
|
|
22
|
-
* Calculates the sum of all token types (input, output, cache creation, cache read)
|
|
23
|
-
* @param tokens - Token data containing different token counts
|
|
24
|
-
* @returns Total number of tokens across all types
|
|
25
|
-
*/
|
|
26
|
-
function getTotalTokens(tokens) {
|
|
27
|
-
return tokens.inputTokens + tokens.outputTokens + tokens.cacheCreationTokens + tokens.cacheReadTokens;
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
23
|
* Creates a complete totals object by adding total token count to existing totals
|
|
31
24
|
* @param totals - Token totals with cost information
|
|
32
25
|
* @returns Complete totals object including total token sum
|
|
33
26
|
*/
|
|
34
27
|
function createTotalsObject(totals) {
|
|
35
28
|
return {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
cacheCreationTokens: totals.cacheCreationTokens,
|
|
39
|
-
cacheReadTokens: totals.cacheReadTokens,
|
|
40
|
-
totalTokens: getTotalTokens(totals),
|
|
41
|
-
totalCost: totals.totalCost
|
|
29
|
+
...totals,
|
|
30
|
+
totalTokens: getTotalTokens(totals)
|
|
42
31
|
};
|
|
43
32
|
}
|
|
44
|
-
export { calculateTotals, createTotalsObject
|
|
33
|
+
export { calculateTotals, createTotalsObject };
|
package/dist/calculate-cost.d.ts
CHANGED
|
@@ -1,17 +1,51 @@
|
|
|
1
|
-
import { DailyUsage, MonthlyUsage, SessionUsage } from "./data-loader-
|
|
2
|
-
import "./pricing-fetcher-
|
|
1
|
+
import { DailyUsage, MonthlyUsage, SessionUsage } from "./data-loader-a9CiVyT5.js";
|
|
2
|
+
import "./pricing-fetcher-B3SvKOod.js";
|
|
3
3
|
|
|
4
|
-
//#region src/
|
|
4
|
+
//#region src/_token-utils.d.ts
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
* Token
|
|
7
|
+
* @fileoverview Token calculation utilities
|
|
8
|
+
*
|
|
9
|
+
* This module provides shared utilities for calculating token totals
|
|
10
|
+
* across different token types. Used throughout the application to
|
|
11
|
+
* ensure consistent token counting logic.
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Token counts structure for raw usage data (uses InputTokens suffix)
|
|
15
|
+
*/
|
|
16
|
+
type TokenCounts = {
|
|
17
|
+
inputTokens: number;
|
|
18
|
+
outputTokens: number;
|
|
19
|
+
cacheCreationInputTokens: number;
|
|
20
|
+
cacheReadInputTokens: number;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Token counts structure for aggregated data (uses shorter names)
|
|
8
24
|
*/
|
|
9
|
-
type
|
|
25
|
+
type AggregatedTokenCounts = {
|
|
10
26
|
inputTokens: number;
|
|
11
27
|
outputTokens: number;
|
|
12
28
|
cacheCreationTokens: number;
|
|
13
29
|
cacheReadTokens: number;
|
|
14
30
|
};
|
|
31
|
+
/**
|
|
32
|
+
* Union type that supports both token count formats
|
|
33
|
+
*/
|
|
34
|
+
type AnyTokenCounts = TokenCounts | AggregatedTokenCounts;
|
|
35
|
+
/**
|
|
36
|
+
* Calculates the total number of tokens across all token types
|
|
37
|
+
* Supports both raw usage data format and aggregated data format
|
|
38
|
+
* @param tokenCounts - Object containing counts for each token type
|
|
39
|
+
* @returns Total number of tokens
|
|
40
|
+
*/
|
|
41
|
+
declare function getTotalTokens(tokenCounts: AnyTokenCounts): number;
|
|
42
|
+
//#endregion
|
|
43
|
+
//#region src/calculate-cost.d.ts
|
|
44
|
+
/**
|
|
45
|
+
* Alias for AggregatedTokenCounts from shared utilities
|
|
46
|
+
* @deprecated Use AggregatedTokenCounts from _token-utils.ts instead
|
|
47
|
+
*/
|
|
48
|
+
type TokenData = AggregatedTokenCounts;
|
|
15
49
|
/**
|
|
16
50
|
* Token totals including cost information
|
|
17
51
|
*/
|
|
@@ -30,12 +64,8 @@ type TotalsObject = TokenTotals & {
|
|
|
30
64
|
* @returns Aggregated token totals and cost
|
|
31
65
|
*/
|
|
32
66
|
declare function calculateTotals(data: Array<DailyUsage | MonthlyUsage | SessionUsage>): TokenTotals;
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
* @param tokens - Token data containing different token counts
|
|
36
|
-
* @returns Total number of tokens across all types
|
|
37
|
-
*/
|
|
38
|
-
declare function getTotalTokens(tokens: TokenData): number;
|
|
67
|
+
// Re-export getTotalTokens from shared utilities for backward compatibility
|
|
68
|
+
|
|
39
69
|
/**
|
|
40
70
|
* Creates a complete totals object by adding total token count to existing totals
|
|
41
71
|
* @param totals - Token totals with cost information
|
package/dist/calculate-cost.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
import "./
|
|
2
|
-
import
|
|
1
|
+
import { getTotalTokens } from "./_token-utils-WjkbrjKv.js";
|
|
2
|
+
import "./_types-BHFM59hI.js";
|
|
3
|
+
import { calculateTotals, createTotalsObject } from "./calculate-cost-BDqO4yWA.js";
|
|
3
4
|
export { calculateTotals, createTotalsObject, getTotalTokens };
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import { CLAUDE_CONFIG_DIR_ENV, CLAUDE_PROJECTS_DIR_NAME, DEFAULT_CLAUDE_CODE_PATH, DEFAULT_CLAUDE_CONFIG_PATH, DEFAULT_RECENT_DAYS, PricingFetcher, USAGE_DATA_GLOB_PATTERN, USER_HOME_DIR, __commonJSMin, __require, __toESM, require_usingCtx } from "./pricing-fetcher-
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { CLAUDE_CONFIG_DIR_ENV, CLAUDE_PROJECTS_DIR_NAME, DEFAULT_CLAUDE_CODE_PATH, DEFAULT_CLAUDE_CONFIG_PATH, DEFAULT_RECENT_DAYS, PricingFetcher, USAGE_DATA_GLOB_PATTERN, USER_HOME_DIR, __commonJSMin, __require, __toESM, isFailure, isPromise, require_usingCtx } from "./pricing-fetcher-DaK2jizg.js";
|
|
2
|
+
import { getTotalTokens } from "./_token-utils-WjkbrjKv.js";
|
|
3
|
+
import { activityDateSchema, arrayType, booleanType, createDailyDate, createMonthlyDate, createProjectPath, createSessionId, dailyDateSchema, isoTimestampSchema, messageIdSchema, modelNameSchema, monthlyDateSchema, numberType, objectType, projectPathSchema, requestIdSchema, sessionIdSchema, stringType, versionSchema } from "./_types-BHFM59hI.js";
|
|
4
|
+
import { logger } from "./logger-DeTONwj8.js";
|
|
4
5
|
import a, { readFile } from "node:fs/promises";
|
|
5
|
-
import F, { homedir } from "node:os";
|
|
6
6
|
import path, { posix } from "node:path";
|
|
7
7
|
import process$1 from "node:process";
|
|
8
8
|
import b from "node:fs";
|
|
9
|
+
import F from "node:os";
|
|
9
10
|
function toArray(array) {
|
|
10
11
|
array = array ?? [];
|
|
11
12
|
return Array.isArray(array) ? array : [array];
|
|
@@ -240,6 +241,35 @@ function isObject$1(x) {
|
|
|
240
241
|
*/ function unreachable(...args) {
|
|
241
242
|
throw new UnreachableError(args);
|
|
242
243
|
}
|
|
244
|
+
const isResult = (result) => "object" == typeof result && null !== result && "type" in result && ("Success" === result.type && "value" in result || "Failure" === result.type && "error" in result);
|
|
245
|
+
const unwrap = (...args) => {
|
|
246
|
+
const firstArgument = args[0];
|
|
247
|
+
if (isResult(firstArgument) || isPromise(firstArgument)) {
|
|
248
|
+
const result = firstArgument;
|
|
249
|
+
const hasDefault$1 = 2 === args.length;
|
|
250
|
+
const defaultValue$1 = hasDefault$1 ? args[1] : void 0;
|
|
251
|
+
const apply = (r) => {
|
|
252
|
+
if (isFailure(r)) {
|
|
253
|
+
if (hasDefault$1) return defaultValue$1;
|
|
254
|
+
throw new Error(String(r.error));
|
|
255
|
+
}
|
|
256
|
+
return r.value;
|
|
257
|
+
};
|
|
258
|
+
return isPromise(result) ? result.then(apply) : apply(result);
|
|
259
|
+
}
|
|
260
|
+
const hasDefault = 1 === args.length;
|
|
261
|
+
const defaultValue = hasDefault ? args[0] : void 0;
|
|
262
|
+
return (result) => {
|
|
263
|
+
const apply = (r) => {
|
|
264
|
+
if (isFailure(r)) {
|
|
265
|
+
if (hasDefault) return defaultValue;
|
|
266
|
+
throw new Error(String(r.error));
|
|
267
|
+
}
|
|
268
|
+
return r.value;
|
|
269
|
+
};
|
|
270
|
+
return isPromise(result) ? result.then(apply) : apply(result);
|
|
271
|
+
};
|
|
272
|
+
};
|
|
243
273
|
function groupBy(arr, getKeyFromItem) {
|
|
244
274
|
const result = {};
|
|
245
275
|
for (let i = 0; i < arr.length; i++) {
|
|
@@ -3139,12 +3169,14 @@ function createBlock(startTime, entries, now, sessionDurationMs) {
|
|
|
3139
3169
|
};
|
|
3140
3170
|
let costUSD = 0;
|
|
3141
3171
|
const models = [];
|
|
3172
|
+
let usageLimitResetTime;
|
|
3142
3173
|
for (const entry of entries) {
|
|
3143
3174
|
tokenCounts.inputTokens += entry.usage.inputTokens;
|
|
3144
3175
|
tokenCounts.outputTokens += entry.usage.outputTokens;
|
|
3145
3176
|
tokenCounts.cacheCreationInputTokens += entry.usage.cacheCreationInputTokens;
|
|
3146
3177
|
tokenCounts.cacheReadInputTokens += entry.usage.cacheReadInputTokens;
|
|
3147
3178
|
costUSD += entry.costUSD ?? 0;
|
|
3179
|
+
usageLimitResetTime = entry.usageLimitResetTime ?? usageLimitResetTime;
|
|
3148
3180
|
models.push(entry.model);
|
|
3149
3181
|
}
|
|
3150
3182
|
return {
|
|
@@ -3156,7 +3188,8 @@ function createBlock(startTime, entries, now, sessionDurationMs) {
|
|
|
3156
3188
|
entries,
|
|
3157
3189
|
tokenCounts,
|
|
3158
3190
|
costUSD,
|
|
3159
|
-
models: uniq(models)
|
|
3191
|
+
models: uniq(models),
|
|
3192
|
+
usageLimitResetTime
|
|
3160
3193
|
};
|
|
3161
3194
|
}
|
|
3162
3195
|
/**
|
|
@@ -3202,7 +3235,7 @@ function calculateBurnRate(block) {
|
|
|
3202
3235
|
const lastEntry = lastEntryData.timestamp;
|
|
3203
3236
|
const durationMinutes = (lastEntry.getTime() - firstEntry.getTime()) / (1e3 * 60);
|
|
3204
3237
|
if (durationMinutes <= 0) return null;
|
|
3205
|
-
const totalTokens = block.tokenCounts
|
|
3238
|
+
const totalTokens = getTotalTokens(block.tokenCounts);
|
|
3206
3239
|
const tokensPerMinute = totalTokens / durationMinutes;
|
|
3207
3240
|
const costPerHour = block.costUSD / durationMinutes * 60;
|
|
3208
3241
|
return {
|
|
@@ -3222,7 +3255,7 @@ function projectBlockUsage(block) {
|
|
|
3222
3255
|
const now = /* @__PURE__ */ new Date();
|
|
3223
3256
|
const remainingTime = block.endTime.getTime() - now.getTime();
|
|
3224
3257
|
const remainingMinutes = Math.max(0, remainingTime / (1e3 * 60));
|
|
3225
|
-
const currentTokens = block.tokenCounts
|
|
3258
|
+
const currentTokens = getTotalTokens(block.tokenCounts);
|
|
3226
3259
|
const projectedAdditionalTokens = burnRate.tokensPerMinute * remainingMinutes;
|
|
3227
3260
|
const totalTokens = currentTokens + projectedAdditionalTokens;
|
|
3228
3261
|
const projectedAdditionalCost = burnRate.costPerHour / 60 * remainingMinutes;
|
|
@@ -3241,7 +3274,7 @@ function projectBlockUsage(block) {
|
|
|
3241
3274
|
*/
|
|
3242
3275
|
function filterRecentBlocks(blocks, days = DEFAULT_RECENT_DAYS) {
|
|
3243
3276
|
const now = /* @__PURE__ */ new Date();
|
|
3244
|
-
const cutoffTime = new Date(now.getTime() - days * 24 * 60 * 60 * 1e3);
|
|
3277
|
+
const cutoffTime = /* @__PURE__ */ new Date(now.getTime() - days * 24 * 60 * 60 * 1e3);
|
|
3245
3278
|
return blocks.filter((block) => {
|
|
3246
3279
|
return block.startTime >= cutoffTime || block.isActive;
|
|
3247
3280
|
});
|
|
@@ -3291,26 +3324,6 @@ function getClaudePaths() {
|
|
|
3291
3324
|
return paths;
|
|
3292
3325
|
}
|
|
3293
3326
|
/**
|
|
3294
|
-
* Default path for Claude data directory
|
|
3295
|
-
* Uses environment variable CLAUDE_CONFIG_DIR if set, otherwise defaults to ~/.claude
|
|
3296
|
-
* @deprecated Use getClaudePaths() instead for multiple path support
|
|
3297
|
-
*/
|
|
3298
|
-
function getDefaultClaudePath() {
|
|
3299
|
-
const envPath = (process$1.env[CLAUDE_CONFIG_DIR_ENV] ?? "").trim();
|
|
3300
|
-
if (envPath !== "") {
|
|
3301
|
-
const firstPath = envPath.split(",")[0]?.trim();
|
|
3302
|
-
if (firstPath != null && firstPath !== "") {
|
|
3303
|
-
if (!isDirectorySync(firstPath)) throw new Error(`CLAUDE_CONFIG_DIR path is not a valid directory: ${firstPath}`);
|
|
3304
|
-
return firstPath;
|
|
3305
|
-
}
|
|
3306
|
-
}
|
|
3307
|
-
const newDefaultPath = DEFAULT_CLAUDE_CONFIG_PATH;
|
|
3308
|
-
if (isDirectorySync(newDefaultPath)) return newDefaultPath;
|
|
3309
|
-
const oldDefaultPath = path.join(USER_HOME_DIR, DEFAULT_CLAUDE_CODE_PATH);
|
|
3310
|
-
if (isDirectorySync(oldDefaultPath)) return oldDefaultPath;
|
|
3311
|
-
return oldDefaultPath;
|
|
3312
|
-
}
|
|
3313
|
-
/**
|
|
3314
3327
|
* Zod schema for validating Claude usage data from JSONL files
|
|
3315
3328
|
*/
|
|
3316
3329
|
const usageDataSchema = objectType({
|
|
@@ -3324,10 +3337,12 @@ const usageDataSchema = objectType({
|
|
|
3324
3337
|
cache_read_input_tokens: numberType().optional()
|
|
3325
3338
|
}),
|
|
3326
3339
|
model: modelNameSchema.optional(),
|
|
3327
|
-
id: messageIdSchema.optional()
|
|
3340
|
+
id: messageIdSchema.optional(),
|
|
3341
|
+
content: arrayType(objectType({ text: stringType().optional() })).optional()
|
|
3328
3342
|
}),
|
|
3329
3343
|
costUSD: numberType().optional(),
|
|
3330
|
-
requestId: requestIdSchema.optional()
|
|
3344
|
+
requestId: requestIdSchema.optional(),
|
|
3345
|
+
isApiErrorMessage: booleanType().optional()
|
|
3331
3346
|
});
|
|
3332
3347
|
/**
|
|
3333
3348
|
* Zod schema for model-specific usage breakdown data
|
|
@@ -3602,17 +3617,33 @@ async function sortFilesByTimestamp(files) {
|
|
|
3602
3617
|
async function calculateCostForEntry(data, mode, fetcher) {
|
|
3603
3618
|
if (mode === "display") return data.costUSD ?? 0;
|
|
3604
3619
|
if (mode === "calculate") {
|
|
3605
|
-
if (data.message.model != null) return fetcher.calculateCostFromTokens(data.message.usage, data.message.model);
|
|
3620
|
+
if (data.message.model != null) return unwrap(fetcher.calculateCostFromTokens(data.message.usage, data.message.model), 0);
|
|
3606
3621
|
return 0;
|
|
3607
3622
|
}
|
|
3608
3623
|
if (mode === "auto") {
|
|
3609
3624
|
if (data.costUSD != null) return data.costUSD;
|
|
3610
|
-
if (data.message.model != null) return fetcher.calculateCostFromTokens(data.message.usage, data.message.model);
|
|
3625
|
+
if (data.message.model != null) return unwrap(fetcher.calculateCostFromTokens(data.message.usage, data.message.model), 0);
|
|
3611
3626
|
return 0;
|
|
3612
3627
|
}
|
|
3613
3628
|
unreachable(mode);
|
|
3614
3629
|
}
|
|
3615
3630
|
/**
|
|
3631
|
+
* Get Claude Code usage limit expiration date
|
|
3632
|
+
* @param data - Usage data entry
|
|
3633
|
+
* @returns Usage limit expiration date
|
|
3634
|
+
*/
|
|
3635
|
+
function getUsageLimitResetTime(data) {
|
|
3636
|
+
let resetTime = null;
|
|
3637
|
+
if (data.isApiErrorMessage === true) {
|
|
3638
|
+
const timestampMatch = data.message?.content?.find((c) => c.text != null && c.text.includes("Claude AI usage limit reached"))?.text?.match(/\|(\d+)/) ?? null;
|
|
3639
|
+
if (timestampMatch?.[1] != null) {
|
|
3640
|
+
const resetTimestamp = Number.parseInt(timestampMatch[1]);
|
|
3641
|
+
resetTime = resetTimestamp > 0 ? /* @__PURE__ */ new Date(resetTimestamp * 1e3) : null;
|
|
3642
|
+
}
|
|
3643
|
+
}
|
|
3644
|
+
return resetTime;
|
|
3645
|
+
}
|
|
3646
|
+
/**
|
|
3616
3647
|
* Loads and aggregates Claude usage data by day
|
|
3617
3648
|
* Processes all JSONL files in the Claude projects directory and groups usage by date
|
|
3618
3649
|
* @param options - Optional configuration for loading and filtering data
|
|
@@ -3849,6 +3880,7 @@ async function loadSessionBlockData(options) {
|
|
|
3849
3880
|
if (isDuplicateEntry(uniqueHash, processedHashes)) continue;
|
|
3850
3881
|
markAsProcessed(uniqueHash, processedHashes);
|
|
3851
3882
|
const cost = fetcher != null ? await calculateCostForEntry(data, mode, fetcher) : data.costUSD ?? 0;
|
|
3883
|
+
const usageLimitResetTime = getUsageLimitResetTime(data);
|
|
3852
3884
|
allEntries.push({
|
|
3853
3885
|
timestamp: new Date(data.timestamp),
|
|
3854
3886
|
usage: {
|
|
@@ -3859,7 +3891,8 @@ async function loadSessionBlockData(options) {
|
|
|
3859
3891
|
},
|
|
3860
3892
|
costUSD: cost,
|
|
3861
3893
|
model: data.message.model ?? "unknown",
|
|
3862
|
-
version: data.version
|
|
3894
|
+
version: data.version,
|
|
3895
|
+
usageLimitResetTime: usageLimitResetTime ?? void 0
|
|
3863
3896
|
});
|
|
3864
3897
|
} catch (error) {
|
|
3865
3898
|
logger.debug(`Skipping invalid JSON line in 5-hour blocks: ${error instanceof Error ? error.message : String(error)}`);
|
|
@@ -3879,4 +3912,4 @@ async function loadSessionBlockData(options) {
|
|
|
3879
3912
|
_usingCtx4.d();
|
|
3880
3913
|
}
|
|
3881
3914
|
}
|
|
3882
|
-
export { DEFAULT_SESSION_DURATION_HOURS, calculateBurnRate, calculateCostForEntry, createUniqueHash, dailyUsageSchema, filterRecentBlocks, formatDate, formatDateCompact, getClaudePaths,
|
|
3915
|
+
export { DEFAULT_SESSION_DURATION_HOURS, calculateBurnRate, calculateCostForEntry, createUniqueHash, dailyUsageSchema, filterRecentBlocks, formatDate, formatDateCompact, getClaudePaths, getEarliestTimestamp, getUsageLimitResetTime, glob, identifySessionBlocks, loadDailyUsageData, loadMonthlyUsageData, loadSessionBlockData, loadSessionData, modelBreakdownSchema, monthlyUsageSchema, projectBlockUsage, sessionUsageSchema, sortFilesByTimestamp, uniq, unwrap, usageDataSchema };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CostMode, PricingFetcher, SortOrder } from "./pricing-fetcher-
|
|
1
|
+
import { CostMode, PricingFetcher, SortOrder } from "./pricing-fetcher-B3SvKOod.js";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
|
|
4
4
|
//#region src/_session-blocks.d.ts
|
|
@@ -17,6 +17,7 @@ type LoadedUsageEntry = {
|
|
|
17
17
|
costUSD: number | null;
|
|
18
18
|
model: string;
|
|
19
19
|
version?: string;
|
|
20
|
+
usageLimitResetTime?: Date; // Claude API usage limit reset time
|
|
20
21
|
};
|
|
21
22
|
/**
|
|
22
23
|
* Aggregated token counts for different token types
|
|
@@ -41,6 +42,7 @@ type SessionBlock = {
|
|
|
41
42
|
tokenCounts: TokenCounts;
|
|
42
43
|
costUSD: number;
|
|
43
44
|
models: string[];
|
|
45
|
+
usageLimitResetTime?: Date; // Claude API usage limit reset time
|
|
44
46
|
};
|
|
45
47
|
/**
|
|
46
48
|
* Represents usage burn rate calculations
|
|
@@ -53,12 +55,6 @@ type SessionBlock = {
|
|
|
53
55
|
* @returns Array of valid Claude data directory paths
|
|
54
56
|
*/
|
|
55
57
|
declare function getClaudePaths(): string[];
|
|
56
|
-
/**
|
|
57
|
-
* Default path for Claude data directory
|
|
58
|
-
* Uses environment variable CLAUDE_CONFIG_DIR if set, otherwise defaults to ~/.claude
|
|
59
|
-
* @deprecated Use getClaudePaths() instead for multiple path support
|
|
60
|
-
*/
|
|
61
|
-
declare function getDefaultClaudePath(): string;
|
|
62
58
|
/**
|
|
63
59
|
* Zod schema for validating Claude usage data from JSONL files
|
|
64
60
|
*/
|
|
@@ -84,6 +80,13 @@ declare const usageDataSchema: z.ZodObject<{
|
|
|
84
80
|
}>;
|
|
85
81
|
model: z.ZodOptional<z.ZodBranded<z.ZodString, "ModelName">>;
|
|
86
82
|
id: z.ZodOptional<z.ZodBranded<z.ZodString, "MessageId">>;
|
|
83
|
+
content: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
84
|
+
text: z.ZodOptional<z.ZodString>;
|
|
85
|
+
}, "strip", z.ZodTypeAny, {
|
|
86
|
+
text?: string | undefined;
|
|
87
|
+
}, {
|
|
88
|
+
text?: string | undefined;
|
|
89
|
+
}>, "many">>;
|
|
87
90
|
}, "strip", z.ZodTypeAny, {
|
|
88
91
|
usage: {
|
|
89
92
|
input_tokens: number;
|
|
@@ -93,6 +96,9 @@ declare const usageDataSchema: z.ZodObject<{
|
|
|
93
96
|
};
|
|
94
97
|
model?: (string & z.BRAND<"ModelName">) | undefined;
|
|
95
98
|
id?: (string & z.BRAND<"MessageId">) | undefined;
|
|
99
|
+
content?: {
|
|
100
|
+
text?: string | undefined;
|
|
101
|
+
}[] | undefined;
|
|
96
102
|
}, {
|
|
97
103
|
usage: {
|
|
98
104
|
input_tokens: number;
|
|
@@ -102,9 +108,13 @@ declare const usageDataSchema: z.ZodObject<{
|
|
|
102
108
|
};
|
|
103
109
|
model?: string | undefined;
|
|
104
110
|
id?: string | undefined;
|
|
111
|
+
content?: {
|
|
112
|
+
text?: string | undefined;
|
|
113
|
+
}[] | undefined;
|
|
105
114
|
}>;
|
|
106
115
|
costUSD: z.ZodOptional<z.ZodNumber>;
|
|
107
116
|
requestId: z.ZodOptional<z.ZodBranded<z.ZodString, "RequestId">>;
|
|
117
|
+
isApiErrorMessage: z.ZodOptional<z.ZodBoolean>;
|
|
108
118
|
}, "strip", z.ZodTypeAny, {
|
|
109
119
|
timestamp: string & z.BRAND<"ISOTimestamp">;
|
|
110
120
|
version?: (string & z.BRAND<"Version">) | undefined;
|
|
@@ -117,9 +127,13 @@ declare const usageDataSchema: z.ZodObject<{
|
|
|
117
127
|
};
|
|
118
128
|
model?: (string & z.BRAND<"ModelName">) | undefined;
|
|
119
129
|
id?: (string & z.BRAND<"MessageId">) | undefined;
|
|
130
|
+
content?: {
|
|
131
|
+
text?: string | undefined;
|
|
132
|
+
}[] | undefined;
|
|
120
133
|
};
|
|
121
134
|
costUSD?: number | undefined;
|
|
122
135
|
requestId?: (string & z.BRAND<"RequestId">) | undefined;
|
|
136
|
+
isApiErrorMessage?: boolean | undefined;
|
|
123
137
|
}, {
|
|
124
138
|
timestamp: string;
|
|
125
139
|
version?: string | undefined;
|
|
@@ -132,9 +146,13 @@ declare const usageDataSchema: z.ZodObject<{
|
|
|
132
146
|
};
|
|
133
147
|
model?: string | undefined;
|
|
134
148
|
id?: string | undefined;
|
|
149
|
+
content?: {
|
|
150
|
+
text?: string | undefined;
|
|
151
|
+
}[] | undefined;
|
|
135
152
|
};
|
|
136
153
|
costUSD?: number | undefined;
|
|
137
154
|
requestId?: string | undefined;
|
|
155
|
+
isApiErrorMessage?: boolean | undefined;
|
|
138
156
|
}>;
|
|
139
157
|
/**
|
|
140
158
|
* Type definition for Claude usage data entries from JSONL files
|
|
@@ -422,6 +440,12 @@ declare function sortFilesByTimestamp(files: string[]): Promise<string[]>;
|
|
|
422
440
|
* @returns Calculated cost in USD
|
|
423
441
|
*/
|
|
424
442
|
declare function calculateCostForEntry(data: UsageData, mode: CostMode, fetcher: PricingFetcher): Promise<number>;
|
|
443
|
+
/**
|
|
444
|
+
* Get Claude Code usage limit expiration date
|
|
445
|
+
* @param data - Usage data entry
|
|
446
|
+
* @returns Usage limit expiration date
|
|
447
|
+
*/
|
|
448
|
+
declare function getUsageLimitResetTime(data: UsageData): Date | null;
|
|
425
449
|
/**
|
|
426
450
|
* Date range filter for limiting usage data by date
|
|
427
451
|
*/
|
|
@@ -468,4 +492,4 @@ declare function loadMonthlyUsageData(options?: LoadOptions): Promise<MonthlyUsa
|
|
|
468
492
|
*/
|
|
469
493
|
declare function loadSessionBlockData(options?: LoadOptions): Promise<SessionBlock[]>;
|
|
470
494
|
//#endregion
|
|
471
|
-
export { DailyUsage, DateFilter, LoadOptions, ModelBreakdown, MonthlyUsage, SessionUsage, UsageData, calculateCostForEntry, createUniqueHash, dailyUsageSchema, formatDate, formatDateCompact, getClaudePaths,
|
|
495
|
+
export { DailyUsage, DateFilter, LoadOptions, ModelBreakdown, MonthlyUsage, SessionUsage, UsageData, calculateCostForEntry, createUniqueHash, dailyUsageSchema, formatDate, formatDateCompact, getClaudePaths, getEarliestTimestamp, getUsageLimitResetTime, loadDailyUsageData, loadMonthlyUsageData, loadSessionBlockData, loadSessionData, modelBreakdownSchema, monthlyUsageSchema, sessionUsageSchema, sortFilesByTimestamp, usageDataSchema };
|
package/dist/data-loader.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { DailyUsage, DateFilter, LoadOptions, ModelBreakdown, MonthlyUsage, SessionUsage, UsageData, calculateCostForEntry, createUniqueHash, dailyUsageSchema, formatDate, formatDateCompact, getClaudePaths,
|
|
2
|
-
import "./pricing-fetcher-
|
|
3
|
-
export { DailyUsage, DateFilter, LoadOptions, ModelBreakdown, MonthlyUsage, SessionUsage, UsageData, calculateCostForEntry, createUniqueHash, dailyUsageSchema, formatDate, formatDateCompact, getClaudePaths,
|
|
1
|
+
import { DailyUsage, DateFilter, LoadOptions, ModelBreakdown, MonthlyUsage, SessionUsage, UsageData, calculateCostForEntry, createUniqueHash, dailyUsageSchema, formatDate, formatDateCompact, getClaudePaths, getEarliestTimestamp, getUsageLimitResetTime, loadDailyUsageData, loadMonthlyUsageData, loadSessionBlockData, loadSessionData, modelBreakdownSchema, monthlyUsageSchema, sessionUsageSchema, sortFilesByTimestamp, usageDataSchema } from "./data-loader-a9CiVyT5.js";
|
|
2
|
+
import "./pricing-fetcher-B3SvKOod.js";
|
|
3
|
+
export { DailyUsage, DateFilter, LoadOptions, ModelBreakdown, MonthlyUsage, SessionUsage, UsageData, calculateCostForEntry, createUniqueHash, dailyUsageSchema, formatDate, formatDateCompact, getClaudePaths, getEarliestTimestamp, getUsageLimitResetTime, loadDailyUsageData, loadMonthlyUsageData, loadSessionBlockData, loadSessionData, modelBreakdownSchema, monthlyUsageSchema, sessionUsageSchema, sortFilesByTimestamp, usageDataSchema };
|
package/dist/data-loader.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import "./pricing-fetcher-
|
|
2
|
-
import "./
|
|
3
|
-
import
|
|
4
|
-
import "./
|
|
5
|
-
|
|
1
|
+
import "./pricing-fetcher-DaK2jizg.js";
|
|
2
|
+
import "./_token-utils-WjkbrjKv.js";
|
|
3
|
+
import "./_types-BHFM59hI.js";
|
|
4
|
+
import { calculateCostForEntry, createUniqueHash, dailyUsageSchema, formatDate, formatDateCompact, getClaudePaths, getEarliestTimestamp, getUsageLimitResetTime, loadDailyUsageData, loadMonthlyUsageData, loadSessionBlockData, loadSessionData, modelBreakdownSchema, monthlyUsageSchema, sessionUsageSchema, sortFilesByTimestamp, usageDataSchema } from "./data-loader-R9pMvoQp.js";
|
|
5
|
+
import "./logger-DeTONwj8.js";
|
|
6
|
+
export { calculateCostForEntry, createUniqueHash, dailyUsageSchema, formatDate, formatDateCompact, getClaudePaths, getEarliestTimestamp, getUsageLimitResetTime, loadDailyUsageData, loadMonthlyUsageData, loadSessionBlockData, loadSessionData, modelBreakdownSchema, monthlyUsageSchema, sessionUsageSchema, sortFilesByTimestamp, usageDataSchema };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { CLAUDE_PROJECTS_DIR_NAME, DEBUG_MATCH_THRESHOLD_PERCENT, PricingFetcher, USAGE_DATA_GLOB_PATTERN, __toESM, require_usingCtx } from "./pricing-fetcher-
|
|
2
|
-
import {
|
|
3
|
-
import { logger } from "./logger-
|
|
1
|
+
import { CLAUDE_PROJECTS_DIR_NAME, DEBUG_MATCH_THRESHOLD_PERCENT, PricingFetcher, USAGE_DATA_GLOB_PATTERN, __toESM, isFailure, require_usingCtx, try_ } from "./pricing-fetcher-DaK2jizg.js";
|
|
2
|
+
import { getClaudePaths, glob, unwrap, usageDataSchema } from "./data-loader-R9pMvoQp.js";
|
|
3
|
+
import { logger } from "./logger-DeTONwj8.js";
|
|
4
4
|
import { readFile } from "node:fs/promises";
|
|
5
5
|
import path from "node:path";
|
|
6
6
|
var import_usingCtx = __toESM(require_usingCtx(), 1);
|
|
@@ -13,7 +13,13 @@ var import_usingCtx = __toESM(require_usingCtx(), 1);
|
|
|
13
13
|
async function detectMismatches(claudePath) {
|
|
14
14
|
try {
|
|
15
15
|
var _usingCtx = (0, import_usingCtx.default)();
|
|
16
|
-
|
|
16
|
+
let claudeDir;
|
|
17
|
+
if (claudePath != null && claudePath !== "") claudeDir = claudePath;
|
|
18
|
+
else {
|
|
19
|
+
const paths = getClaudePaths();
|
|
20
|
+
if (paths.length === 0) throw new Error("No valid Claude data directory found");
|
|
21
|
+
claudeDir = path.join(paths[0], CLAUDE_PROJECTS_DIR_NAME);
|
|
22
|
+
}
|
|
17
23
|
const files = await glob([USAGE_DATA_GLOB_PATTERN], {
|
|
18
24
|
cwd: claudeDir,
|
|
19
25
|
absolute: true
|
|
@@ -31,16 +37,21 @@ async function detectMismatches(claudePath) {
|
|
|
31
37
|
for (const file of files) {
|
|
32
38
|
const content = await readFile(file, "utf-8");
|
|
33
39
|
const lines = content.trim().split("\n").filter((line) => line.length > 0);
|
|
34
|
-
for (const line of lines)
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
40
|
+
for (const line of lines) {
|
|
41
|
+
const parseParser = try_({
|
|
42
|
+
try: () => JSON.parse(line),
|
|
43
|
+
catch: () => /* @__PURE__ */ new Error("Invalid JSON")
|
|
44
|
+
});
|
|
45
|
+
const parseResult = parseParser();
|
|
46
|
+
if (isFailure(parseResult)) continue;
|
|
47
|
+
const schemaResult = usageDataSchema.safeParse(parseResult.value);
|
|
48
|
+
if (!schemaResult.success) continue;
|
|
49
|
+
const data = schemaResult.data;
|
|
39
50
|
stats.totalEntries++;
|
|
40
51
|
if (data.costUSD !== void 0 && data.message.model != null && data.message.model !== "<synthetic>") {
|
|
41
52
|
stats.entriesWithBoth++;
|
|
42
53
|
const model = data.message.model;
|
|
43
|
-
const calculatedCost = await fetcher.calculateCostFromTokens(data.message.usage, model);
|
|
54
|
+
const calculatedCost = await unwrap(fetcher.calculateCostFromTokens(data.message.usage, model));
|
|
44
55
|
const difference = Math.abs(data.costUSD - calculatedCost);
|
|
45
56
|
const percentDiff = data.costUSD > 0 ? difference / data.costUSD * 100 : 0;
|
|
46
57
|
const modelStat = stats.modelStats.get(model) ?? {
|
|
@@ -83,7 +94,7 @@ async function detectMismatches(claudePath) {
|
|
|
83
94
|
modelStat.avgPercentDiff = (modelStat.avgPercentDiff * (modelStat.total - 1) + percentDiff) / modelStat.total;
|
|
84
95
|
stats.modelStats.set(model, modelStat);
|
|
85
96
|
}
|
|
86
|
-
}
|
|
97
|
+
}
|
|
87
98
|
}
|
|
88
99
|
return stats;
|
|
89
100
|
} catch (_) {
|