ccusage 15.4.0 → 15.5.1
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 +6 -0
- package/dist/calculate-cost.d.ts +1 -1
- package/dist/{data-loader-BNrxyvc9.js → data-loader-BAp4u-7e.js} +66 -22
- package/dist/{data-loader-7c4yXbqG.d.ts → data-loader-CgvyDaQD.d.ts} +15 -1
- package/dist/data-loader.d.ts +2 -2
- package/dist/data-loader.js +4 -4
- package/dist/{debug-Brn3ODNf.js → debug-IQBgd8CJ.js} +3 -3
- package/dist/debug.js +4 -4
- package/dist/index.js +297 -78
- package/dist/{logger-mXUMXvyg.js → logger-COLgmk2z.js} +1 -1
- package/dist/logger.js +1 -1
- package/dist/{mcp-CQw7snVU.js → mcp-Ta2UK9sc.js} +23 -3
- package/dist/mcp.d.ts +1 -1
- package/dist/mcp.js +4 -4
- package/dist/{pricing-fetcher-KIIpXo8L.js → pricing-fetcher-eNV76BjF.js} +24 -2
- package/dist/pricing-fetcher.js +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -62,6 +62,11 @@ ccusage blocks --live # Real-time usage dashboard
|
|
|
62
62
|
ccusage daily --since 20250525 --until 20250530
|
|
63
63
|
ccusage daily --json # JSON output
|
|
64
64
|
ccusage daily --breakdown # Per-model cost breakdown
|
|
65
|
+
|
|
66
|
+
# Project analysis
|
|
67
|
+
ccusage daily --instances # Group by project/instance
|
|
68
|
+
ccusage daily --project myproject # Filter to specific project
|
|
69
|
+
ccusage daily --instances --project myproject --json # Combined usage
|
|
65
70
|
```
|
|
66
71
|
|
|
67
72
|
## Features
|
|
@@ -83,6 +88,7 @@ ccusage daily --breakdown # Per-model cost breakdown
|
|
|
83
88
|
- 🔄 **Cache Token Support**: Tracks and displays cache creation and cache read tokens separately
|
|
84
89
|
- 🌐 **Offline Mode**: Use pre-cached pricing data without network connectivity with `--offline` (Claude models only)
|
|
85
90
|
- 🔌 **MCP Integration**: Built-in Model Context Protocol server for integration with other tools
|
|
91
|
+
- 🏗️ **Multi-Instance Support**: Group usage by project with `--instances` flag and filter by specific projects
|
|
86
92
|
- 🚀 **Ultra-Small Bundle**: Unlike other CLI tools, we pay extreme attention to bundle size - incredibly small even without minification!
|
|
87
93
|
|
|
88
94
|
## Documentation
|
package/dist/calculate-cost.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
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-
|
|
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-eNV76BjF.js";
|
|
2
2
|
import { getTotalTokens } from "./_token-utils-WjkbrjKv.js";
|
|
3
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-
|
|
4
|
+
import { logger } from "./logger-COLgmk2z.js";
|
|
5
5
|
import a, { readFile } from "node:fs/promises";
|
|
6
6
|
import path, { posix } from "node:path";
|
|
7
7
|
import process$1 from "node:process";
|
|
@@ -3327,6 +3327,19 @@ function getClaudePaths() {
|
|
|
3327
3327
|
return paths;
|
|
3328
3328
|
}
|
|
3329
3329
|
/**
|
|
3330
|
+
* Extract project name from Claude JSONL file path
|
|
3331
|
+
* @param jsonlPath - Absolute path to JSONL file
|
|
3332
|
+
* @returns Project name extracted from path, or "unknown" if malformed
|
|
3333
|
+
*/
|
|
3334
|
+
function extractProjectFromPath(jsonlPath) {
|
|
3335
|
+
const normalizedPath = jsonlPath.replace(/[/\\]/g, path.sep);
|
|
3336
|
+
const segments = normalizedPath.split(path.sep);
|
|
3337
|
+
const projectsIndex = segments.findIndex((segment) => segment === CLAUDE_PROJECTS_DIR_NAME);
|
|
3338
|
+
if (projectsIndex === -1 || projectsIndex + 1 >= segments.length) return "unknown";
|
|
3339
|
+
const projectName = segments[projectsIndex + 1];
|
|
3340
|
+
return projectName != null && projectName.trim() !== "" ? projectName : "unknown";
|
|
3341
|
+
}
|
|
3342
|
+
/**
|
|
3330
3343
|
* Zod schema for validating Claude usage data from JSONL files
|
|
3331
3344
|
*/
|
|
3332
3345
|
const usageDataSchema = objectType({
|
|
@@ -3369,7 +3382,8 @@ const dailyUsageSchema = objectType({
|
|
|
3369
3382
|
cacheReadTokens: numberType(),
|
|
3370
3383
|
totalCost: numberType(),
|
|
3371
3384
|
modelsUsed: arrayType(modelNameSchema),
|
|
3372
|
-
modelBreakdowns: arrayType(modelBreakdownSchema)
|
|
3385
|
+
modelBreakdowns: arrayType(modelBreakdownSchema),
|
|
3386
|
+
project: stringType().optional()
|
|
3373
3387
|
});
|
|
3374
3388
|
/**
|
|
3375
3389
|
* Zod schema for session-based usage aggregation data
|
|
@@ -3398,7 +3412,8 @@ const monthlyUsageSchema = objectType({
|
|
|
3398
3412
|
cacheReadTokens: numberType(),
|
|
3399
3413
|
totalCost: numberType(),
|
|
3400
3414
|
modelsUsed: arrayType(modelNameSchema),
|
|
3401
|
-
modelBreakdowns: arrayType(modelBreakdownSchema)
|
|
3415
|
+
modelBreakdowns: arrayType(modelBreakdownSchema),
|
|
3416
|
+
project: stringType().optional()
|
|
3402
3417
|
});
|
|
3403
3418
|
/**
|
|
3404
3419
|
* Aggregates token counts and costs by model name
|
|
@@ -3499,6 +3514,16 @@ function filterByDateRange(items, getDate, since, until) {
|
|
|
3499
3514
|
});
|
|
3500
3515
|
}
|
|
3501
3516
|
/**
|
|
3517
|
+
* Filters items by project name
|
|
3518
|
+
*/
|
|
3519
|
+
function filterByProject(items, getProject, projectFilter) {
|
|
3520
|
+
if (projectFilter == null) return items;
|
|
3521
|
+
return items.filter((item) => {
|
|
3522
|
+
const projectName = getProject(item);
|
|
3523
|
+
return projectName === projectFilter;
|
|
3524
|
+
});
|
|
3525
|
+
}
|
|
3526
|
+
/**
|
|
3502
3527
|
* Checks if an entry is a duplicate based on hash
|
|
3503
3528
|
*/
|
|
3504
3529
|
function isDuplicateEntry(uniqueHash, processedHashes) {
|
|
@@ -3684,7 +3709,8 @@ async function loadDailyUsageData(options) {
|
|
|
3684
3709
|
const allFiles = await globUsageFiles(claudePaths);
|
|
3685
3710
|
const fileList = allFiles.map((f$1) => f$1.file);
|
|
3686
3711
|
if (fileList.length === 0) return [];
|
|
3687
|
-
const
|
|
3712
|
+
const projectFilteredFiles = filterByProject(fileList, (filePath) => extractProjectFromPath(filePath), options?.project);
|
|
3713
|
+
const sortedFiles = await sortFilesByTimestamp(projectFilteredFiles);
|
|
3688
3714
|
const mode = options?.mode ?? "auto";
|
|
3689
3715
|
const fetcher = _usingCtx.u(mode === "display" ? null : new PricingFetcher(options?.offline));
|
|
3690
3716
|
const processedHashes = /* @__PURE__ */ new Set();
|
|
@@ -3702,17 +3728,24 @@ async function loadDailyUsageData(options) {
|
|
|
3702
3728
|
markAsProcessed(uniqueHash, processedHashes);
|
|
3703
3729
|
const date = formatDate(data.timestamp);
|
|
3704
3730
|
const cost = fetcher != null ? await calculateCostForEntry(data, mode, fetcher) : data.costUSD ?? 0;
|
|
3731
|
+
const project = extractProjectFromPath(file);
|
|
3705
3732
|
allEntries.push({
|
|
3706
3733
|
data,
|
|
3707
3734
|
date,
|
|
3708
3735
|
cost,
|
|
3709
|
-
model: data.message.model
|
|
3736
|
+
model: data.message.model,
|
|
3737
|
+
project
|
|
3710
3738
|
});
|
|
3711
3739
|
} catch {}
|
|
3712
3740
|
}
|
|
3713
|
-
const
|
|
3714
|
-
const
|
|
3741
|
+
const needsProjectGrouping = options?.groupByProject === true || options?.project != null;
|
|
3742
|
+
const groupingKey = needsProjectGrouping ? (entry) => `${entry.date}\x00${entry.project}` : (entry) => entry.date;
|
|
3743
|
+
const groupedData = groupBy(allEntries, groupingKey);
|
|
3744
|
+
const results = Object.entries(groupedData).map(([groupKey, entries]) => {
|
|
3715
3745
|
if (entries == null) return void 0;
|
|
3746
|
+
const parts = groupKey.split("\0");
|
|
3747
|
+
const date = parts[0] ?? groupKey;
|
|
3748
|
+
const project = parts.length > 1 ? parts[1] : void 0;
|
|
3716
3749
|
const modelAggregates = aggregateByModel(entries, (entry) => entry.model, (entry) => entry.data.message.usage, (entry) => entry.cost);
|
|
3717
3750
|
const modelBreakdowns = createModelBreakdowns(modelAggregates);
|
|
3718
3751
|
const totals = calculateTotals(entries, (entry) => entry.data.message.usage, (entry) => entry.cost);
|
|
@@ -3721,11 +3754,13 @@ async function loadDailyUsageData(options) {
|
|
|
3721
3754
|
date: createDailyDate(date),
|
|
3722
3755
|
...totals,
|
|
3723
3756
|
modelsUsed,
|
|
3724
|
-
modelBreakdowns
|
|
3757
|
+
modelBreakdowns,
|
|
3758
|
+
...project != null && { project }
|
|
3725
3759
|
};
|
|
3726
3760
|
}).filter((item) => item != null);
|
|
3727
|
-
const
|
|
3728
|
-
|
|
3761
|
+
const dateFiltered = filterByDateRange(results, (item) => item.date, options?.since, options?.until);
|
|
3762
|
+
const finalFiltered = filterByProject(dateFiltered, (item) => item.project, options?.project);
|
|
3763
|
+
return sortByDate(finalFiltered, (item) => item.date, options?.order);
|
|
3729
3764
|
} catch (_) {
|
|
3730
3765
|
_usingCtx.e = _;
|
|
3731
3766
|
} finally {
|
|
@@ -3744,8 +3779,9 @@ async function loadSessionData(options) {
|
|
|
3744
3779
|
const claudePaths = toArray(options?.claudePath ?? getClaudePaths());
|
|
3745
3780
|
const filesWithBase = await globUsageFiles(claudePaths);
|
|
3746
3781
|
if (filesWithBase.length === 0) return [];
|
|
3747
|
-
const
|
|
3748
|
-
const
|
|
3782
|
+
const projectFilteredWithBase = filterByProject(filesWithBase, (item) => extractProjectFromPath(item.file), options?.project);
|
|
3783
|
+
const fileToBaseMap = new Map(projectFilteredWithBase.map((f$1) => [f$1.file, f$1.baseDir]));
|
|
3784
|
+
const sortedFilesWithBase = await sortFilesByTimestamp(projectFilteredWithBase.map((f$1) => f$1.file)).then((sortedFiles) => sortedFiles.map((file) => ({
|
|
3749
3785
|
file,
|
|
3750
3786
|
baseDir: fileToBaseMap.get(file) ?? ""
|
|
3751
3787
|
})));
|
|
@@ -3802,8 +3838,9 @@ async function loadSessionData(options) {
|
|
|
3802
3838
|
modelBreakdowns
|
|
3803
3839
|
};
|
|
3804
3840
|
}).filter((item) => item != null);
|
|
3805
|
-
const
|
|
3806
|
-
|
|
3841
|
+
const dateFiltered = filterByDateRange(results, (item) => item.lastActivity, options?.since, options?.until);
|
|
3842
|
+
const sessionFiltered = filterByProject(dateFiltered, (item) => item.projectPath, options?.project);
|
|
3843
|
+
return sortByDate(sessionFiltered, (item) => item.lastActivity, options?.order);
|
|
3807
3844
|
} catch (_) {
|
|
3808
3845
|
_usingCtx3.e = _;
|
|
3809
3846
|
} finally {
|
|
@@ -3818,10 +3855,15 @@ async function loadSessionData(options) {
|
|
|
3818
3855
|
*/
|
|
3819
3856
|
async function loadMonthlyUsageData(options) {
|
|
3820
3857
|
const dailyData = await loadDailyUsageData(options);
|
|
3821
|
-
const
|
|
3858
|
+
const needsProjectGrouping = options?.groupByProject === true || options?.project != null;
|
|
3859
|
+
const groupingKey = needsProjectGrouping ? (data) => `${data.date.substring(0, 7)}\x00${data.project ?? "unknown"}` : (data) => data.date.substring(0, 7);
|
|
3860
|
+
const groupedByMonth = groupBy(dailyData, groupingKey);
|
|
3822
3861
|
const monthlyArray = [];
|
|
3823
|
-
for (const [
|
|
3862
|
+
for (const [groupKey, dailyEntries] of Object.entries(groupedByMonth)) {
|
|
3824
3863
|
if (dailyEntries == null) continue;
|
|
3864
|
+
const parts = groupKey.split("\0");
|
|
3865
|
+
const month = parts[0] ?? groupKey;
|
|
3866
|
+
const project = parts.length > 1 ? parts[1] : void 0;
|
|
3825
3867
|
const allBreakdowns = dailyEntries.flatMap((daily) => daily.modelBreakdowns);
|
|
3826
3868
|
const modelAggregates = aggregateModelBreakdowns(allBreakdowns);
|
|
3827
3869
|
const modelBreakdowns = createModelBreakdowns(modelAggregates);
|
|
@@ -3847,7 +3889,8 @@ async function loadMonthlyUsageData(options) {
|
|
|
3847
3889
|
cacheReadTokens: totalCacheReadTokens,
|
|
3848
3890
|
totalCost,
|
|
3849
3891
|
modelsUsed: uniq(models),
|
|
3850
|
-
modelBreakdowns
|
|
3892
|
+
modelBreakdowns,
|
|
3893
|
+
...project != null && { project }
|
|
3851
3894
|
};
|
|
3852
3895
|
monthlyArray.push(monthlyUsage);
|
|
3853
3896
|
}
|
|
@@ -3873,7 +3916,8 @@ async function loadSessionBlockData(options) {
|
|
|
3873
3916
|
allFiles.push(...files);
|
|
3874
3917
|
}
|
|
3875
3918
|
if (allFiles.length === 0) return [];
|
|
3876
|
-
const
|
|
3919
|
+
const blocksFilteredFiles = filterByProject(allFiles, (filePath) => extractProjectFromPath(filePath), options?.project);
|
|
3920
|
+
const sortedFiles = await sortFilesByTimestamp(blocksFilteredFiles);
|
|
3877
3921
|
const mode = options?.mode ?? "auto";
|
|
3878
3922
|
const fetcher = _usingCtx4.u(mode === "display" ? null : new PricingFetcher(options?.offline));
|
|
3879
3923
|
const processedHashes = /* @__PURE__ */ new Set();
|
|
@@ -3909,17 +3953,17 @@ async function loadSessionBlockData(options) {
|
|
|
3909
3953
|
}
|
|
3910
3954
|
}
|
|
3911
3955
|
const blocks = identifySessionBlocks(allEntries, options?.sessionDurationHours);
|
|
3912
|
-
const
|
|
3956
|
+
const dateFiltered = options?.since != null && options.since !== "" || options?.until != null && options.until !== "" ? blocks.filter((block) => {
|
|
3913
3957
|
const blockDateStr = formatDate(block.startTime.toISOString()).replace(/-/g, "");
|
|
3914
3958
|
if (options.since != null && options.since !== "" && blockDateStr < options.since) return false;
|
|
3915
3959
|
if (options.until != null && options.until !== "" && blockDateStr > options.until) return false;
|
|
3916
3960
|
return true;
|
|
3917
3961
|
}) : blocks;
|
|
3918
|
-
return sortByDate(
|
|
3962
|
+
return sortByDate(dateFiltered, (block) => block.startTime, options?.order);
|
|
3919
3963
|
} catch (_) {
|
|
3920
3964
|
_usingCtx4.e = _;
|
|
3921
3965
|
} finally {
|
|
3922
3966
|
_usingCtx4.d();
|
|
3923
3967
|
}
|
|
3924
3968
|
}
|
|
3925
|
-
export { DEFAULT_SESSION_DURATION_HOURS, calculateBurnRate, calculateCostForEntry, createUniqueHash, dailyUsageSchema, filterRecentBlocks, formatDate, formatDateCompact, getClaudePaths, getEarliestTimestamp, getUsageLimitResetTime, glob, globUsageFiles, identifySessionBlocks, loadDailyUsageData, loadMonthlyUsageData, loadSessionBlockData, loadSessionData, modelBreakdownSchema, monthlyUsageSchema, projectBlockUsage, sessionUsageSchema, sortFilesByTimestamp, uniq, unwrap, usageDataSchema };
|
|
3969
|
+
export { DEFAULT_SESSION_DURATION_HOURS, calculateBurnRate, calculateCostForEntry, createUniqueHash, dailyUsageSchema, extractProjectFromPath, filterRecentBlocks, formatDate, formatDateCompact, getClaudePaths, getEarliestTimestamp, getUsageLimitResetTime, glob, globUsageFiles, identifySessionBlocks, loadDailyUsageData, loadMonthlyUsageData, loadSessionBlockData, loadSessionData, modelBreakdownSchema, monthlyUsageSchema, projectBlockUsage, sessionUsageSchema, sortFilesByTimestamp, uniq, unwrap, usageDataSchema };
|
|
@@ -55,6 +55,12 @@ type SessionBlock = {
|
|
|
55
55
|
* @returns Array of valid Claude data directory paths
|
|
56
56
|
*/
|
|
57
57
|
declare function getClaudePaths(): string[];
|
|
58
|
+
/**
|
|
59
|
+
* Extract project name from Claude JSONL file path
|
|
60
|
+
* @param jsonlPath - Absolute path to JSONL file
|
|
61
|
+
* @returns Project name extracted from path, or "unknown" if malformed
|
|
62
|
+
*/
|
|
63
|
+
declare function extractProjectFromPath(jsonlPath: string): string;
|
|
58
64
|
/**
|
|
59
65
|
* Zod schema for validating Claude usage data from JSONL files
|
|
60
66
|
*/
|
|
@@ -220,6 +226,7 @@ declare const dailyUsageSchema: z.ZodObject<{
|
|
|
220
226
|
cacheReadTokens: number;
|
|
221
227
|
cost: number;
|
|
222
228
|
}>, "many">;
|
|
229
|
+
project: z.ZodOptional<z.ZodString>;
|
|
223
230
|
}, "strip", z.ZodTypeAny, {
|
|
224
231
|
date: string & z.BRAND<"DailyDate">;
|
|
225
232
|
inputTokens: number;
|
|
@@ -236,6 +243,7 @@ declare const dailyUsageSchema: z.ZodObject<{
|
|
|
236
243
|
cacheReadTokens: number;
|
|
237
244
|
cost: number;
|
|
238
245
|
}[];
|
|
246
|
+
project?: string | undefined;
|
|
239
247
|
}, {
|
|
240
248
|
date: string;
|
|
241
249
|
inputTokens: number;
|
|
@@ -252,6 +260,7 @@ declare const dailyUsageSchema: z.ZodObject<{
|
|
|
252
260
|
cacheReadTokens: number;
|
|
253
261
|
cost: number;
|
|
254
262
|
}[];
|
|
263
|
+
project?: string | undefined;
|
|
255
264
|
}>;
|
|
256
265
|
/**
|
|
257
266
|
* Type definition for daily usage aggregation
|
|
@@ -369,6 +378,7 @@ declare const monthlyUsageSchema: z.ZodObject<{
|
|
|
369
378
|
cacheReadTokens: number;
|
|
370
379
|
cost: number;
|
|
371
380
|
}>, "many">;
|
|
381
|
+
project: z.ZodOptional<z.ZodString>;
|
|
372
382
|
}, "strip", z.ZodTypeAny, {
|
|
373
383
|
month: string & z.BRAND<"MonthlyDate">;
|
|
374
384
|
inputTokens: number;
|
|
@@ -385,6 +395,7 @@ declare const monthlyUsageSchema: z.ZodObject<{
|
|
|
385
395
|
cacheReadTokens: number;
|
|
386
396
|
cost: number;
|
|
387
397
|
}[];
|
|
398
|
+
project?: string | undefined;
|
|
388
399
|
}, {
|
|
389
400
|
month: string;
|
|
390
401
|
inputTokens: number;
|
|
@@ -401,6 +412,7 @@ declare const monthlyUsageSchema: z.ZodObject<{
|
|
|
401
412
|
cacheReadTokens: number;
|
|
402
413
|
cost: number;
|
|
403
414
|
}[];
|
|
415
|
+
project?: string | undefined;
|
|
404
416
|
}>;
|
|
405
417
|
/**
|
|
406
418
|
* Type definition for monthly usage aggregation
|
|
@@ -475,6 +487,8 @@ type LoadOptions = {
|
|
|
475
487
|
order?: SortOrder; // Sort order for dates
|
|
476
488
|
offline?: boolean; // Use offline mode for pricing
|
|
477
489
|
sessionDurationHours?: number; // Session block duration in hours
|
|
490
|
+
groupByProject?: boolean; // Group data by project instead of aggregating
|
|
491
|
+
project?: string; // Filter to specific project name
|
|
478
492
|
} & DateFilter;
|
|
479
493
|
/**
|
|
480
494
|
* Loads and aggregates Claude usage data by day
|
|
@@ -505,4 +519,4 @@ declare function loadMonthlyUsageData(options?: LoadOptions): Promise<MonthlyUsa
|
|
|
505
519
|
*/
|
|
506
520
|
declare function loadSessionBlockData(options?: LoadOptions): Promise<SessionBlock[]>;
|
|
507
521
|
//#endregion
|
|
508
|
-
export { DailyUsage, DateFilter, GlobResult, LoadOptions, ModelBreakdown, MonthlyUsage, SessionUsage, UsageData, calculateCostForEntry, createUniqueHash, dailyUsageSchema, formatDate, formatDateCompact, getClaudePaths, getEarliestTimestamp, getUsageLimitResetTime, globUsageFiles, loadDailyUsageData, loadMonthlyUsageData, loadSessionBlockData, loadSessionData, modelBreakdownSchema, monthlyUsageSchema, sessionUsageSchema, sortFilesByTimestamp, usageDataSchema };
|
|
522
|
+
export { DailyUsage, DateFilter, GlobResult, LoadOptions, ModelBreakdown, MonthlyUsage, SessionUsage, UsageData, calculateCostForEntry, createUniqueHash, dailyUsageSchema, extractProjectFromPath, formatDate, formatDateCompact, getClaudePaths, getEarliestTimestamp, getUsageLimitResetTime, globUsageFiles, loadDailyUsageData, loadMonthlyUsageData, loadSessionBlockData, loadSessionData, modelBreakdownSchema, monthlyUsageSchema, sessionUsageSchema, sortFilesByTimestamp, usageDataSchema };
|
package/dist/data-loader.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { DailyUsage, DateFilter, GlobResult, LoadOptions, ModelBreakdown, MonthlyUsage, SessionUsage, UsageData, calculateCostForEntry, createUniqueHash, dailyUsageSchema, formatDate, formatDateCompact, getClaudePaths, getEarliestTimestamp, getUsageLimitResetTime, globUsageFiles, loadDailyUsageData, loadMonthlyUsageData, loadSessionBlockData, loadSessionData, modelBreakdownSchema, monthlyUsageSchema, sessionUsageSchema, sortFilesByTimestamp, usageDataSchema } from "./data-loader-
|
|
1
|
+
import { DailyUsage, DateFilter, GlobResult, LoadOptions, ModelBreakdown, MonthlyUsage, SessionUsage, UsageData, calculateCostForEntry, createUniqueHash, dailyUsageSchema, extractProjectFromPath, formatDate, formatDateCompact, getClaudePaths, getEarliestTimestamp, getUsageLimitResetTime, globUsageFiles, loadDailyUsageData, loadMonthlyUsageData, loadSessionBlockData, loadSessionData, modelBreakdownSchema, monthlyUsageSchema, sessionUsageSchema, sortFilesByTimestamp, usageDataSchema } from "./data-loader-CgvyDaQD.js";
|
|
2
2
|
import "./pricing-fetcher-B3SvKOod.js";
|
|
3
|
-
export { DailyUsage, DateFilter, GlobResult, LoadOptions, ModelBreakdown, MonthlyUsage, SessionUsage, UsageData, calculateCostForEntry, createUniqueHash, dailyUsageSchema, formatDate, formatDateCompact, getClaudePaths, getEarliestTimestamp, getUsageLimitResetTime, globUsageFiles, loadDailyUsageData, loadMonthlyUsageData, loadSessionBlockData, loadSessionData, modelBreakdownSchema, monthlyUsageSchema, sessionUsageSchema, sortFilesByTimestamp, usageDataSchema };
|
|
3
|
+
export { DailyUsage, DateFilter, GlobResult, LoadOptions, ModelBreakdown, MonthlyUsage, SessionUsage, UsageData, calculateCostForEntry, createUniqueHash, dailyUsageSchema, extractProjectFromPath, formatDate, formatDateCompact, getClaudePaths, getEarliestTimestamp, getUsageLimitResetTime, globUsageFiles, loadDailyUsageData, loadMonthlyUsageData, loadSessionBlockData, loadSessionData, modelBreakdownSchema, monthlyUsageSchema, sessionUsageSchema, sortFilesByTimestamp, usageDataSchema };
|
package/dist/data-loader.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import "./pricing-fetcher-
|
|
1
|
+
import "./pricing-fetcher-eNV76BjF.js";
|
|
2
2
|
import "./_token-utils-WjkbrjKv.js";
|
|
3
3
|
import "./_types-BHFM59hI.js";
|
|
4
|
-
import { calculateCostForEntry, createUniqueHash, dailyUsageSchema, formatDate, formatDateCompact, getClaudePaths, getEarliestTimestamp, getUsageLimitResetTime, globUsageFiles, loadDailyUsageData, loadMonthlyUsageData, loadSessionBlockData, loadSessionData, modelBreakdownSchema, monthlyUsageSchema, sessionUsageSchema, sortFilesByTimestamp, usageDataSchema } from "./data-loader-
|
|
5
|
-
import "./logger-
|
|
6
|
-
export { calculateCostForEntry, createUniqueHash, dailyUsageSchema, formatDate, formatDateCompact, getClaudePaths, getEarliestTimestamp, getUsageLimitResetTime, globUsageFiles, loadDailyUsageData, loadMonthlyUsageData, loadSessionBlockData, loadSessionData, modelBreakdownSchema, monthlyUsageSchema, sessionUsageSchema, sortFilesByTimestamp, usageDataSchema };
|
|
4
|
+
import { calculateCostForEntry, createUniqueHash, dailyUsageSchema, extractProjectFromPath, formatDate, formatDateCompact, getClaudePaths, getEarliestTimestamp, getUsageLimitResetTime, globUsageFiles, loadDailyUsageData, loadMonthlyUsageData, loadSessionBlockData, loadSessionData, modelBreakdownSchema, monthlyUsageSchema, sessionUsageSchema, sortFilesByTimestamp, usageDataSchema } from "./data-loader-BAp4u-7e.js";
|
|
5
|
+
import "./logger-COLgmk2z.js";
|
|
6
|
+
export { calculateCostForEntry, createUniqueHash, dailyUsageSchema, extractProjectFromPath, formatDate, formatDateCompact, getClaudePaths, getEarliestTimestamp, getUsageLimitResetTime, globUsageFiles, 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, isFailure, require_usingCtx, try_ } from "./pricing-fetcher-
|
|
2
|
-
import { getClaudePaths, glob, unwrap, usageDataSchema } from "./data-loader-
|
|
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-eNV76BjF.js";
|
|
2
|
+
import { getClaudePaths, glob, unwrap, usageDataSchema } from "./data-loader-BAp4u-7e.js";
|
|
3
|
+
import { logger } from "./logger-COLgmk2z.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);
|
package/dist/debug.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import "./pricing-fetcher-
|
|
1
|
+
import "./pricing-fetcher-eNV76BjF.js";
|
|
2
2
|
import "./_token-utils-WjkbrjKv.js";
|
|
3
3
|
import "./_types-BHFM59hI.js";
|
|
4
|
-
import "./data-loader-
|
|
5
|
-
import "./logger-
|
|
6
|
-
import { detectMismatches, printMismatchReport } from "./debug-
|
|
4
|
+
import "./data-loader-BAp4u-7e.js";
|
|
5
|
+
import "./logger-COLgmk2z.js";
|
|
6
|
+
import { detectMismatches, printMismatchReport } from "./debug-IQBgd8CJ.js";
|
|
7
7
|
export { detectMismatches, printMismatchReport };
|
package/dist/index.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { BLOCKS_COMPACT_WIDTH_THRESHOLD, BLOCKS_DEFAULT_TERMINAL_WIDTH, BLOCKS_WARNING_THRESHOLD, BURN_RATE_THRESHOLDS, DEFAULT_RECENT_DAYS, DEFAULT_REFRESH_INTERVAL_SECONDS, MAX_REFRESH_INTERVAL_SECONDS, MCP_DEFAULT_PORT, MIN_REFRESH_INTERVAL_SECONDS, MIN_RENDER_INTERVAL_MS, PricingFetcher, __commonJSMin, __require, __toESM, isFailure, require_usingCtx, try_ } from "./pricing-fetcher-
|
|
2
|
+
import { BLOCKS_COMPACT_WIDTH_THRESHOLD, BLOCKS_DEFAULT_TERMINAL_WIDTH, BLOCKS_WARNING_THRESHOLD, BURN_RATE_THRESHOLDS, DEFAULT_RECENT_DAYS, DEFAULT_REFRESH_INTERVAL_SECONDS, MAX_REFRESH_INTERVAL_SECONDS, MCP_DEFAULT_PORT, MIN_REFRESH_INTERVAL_SECONDS, MIN_RENDER_INTERVAL_MS, PROJECT_ALIASES_ENV, PricingFetcher, __commonJSMin, __require, __toESM, isFailure, require_usingCtx, try_ } from "./pricing-fetcher-eNV76BjF.js";
|
|
3
3
|
import { getTotalTokens } from "./_token-utils-WjkbrjKv.js";
|
|
4
4
|
import { CostModes, SortOrders, filterDateSchema } from "./_types-BHFM59hI.js";
|
|
5
5
|
import { calculateTotals, createTotalsObject } from "./calculate-cost-BDqO4yWA.js";
|
|
6
|
-
import { DEFAULT_SESSION_DURATION_HOURS, calculateBurnRate, calculateCostForEntry, createUniqueHash, filterRecentBlocks, formatDateCompact, getClaudePaths, getEarliestTimestamp, getUsageLimitResetTime, globUsageFiles, identifySessionBlocks, loadDailyUsageData, loadMonthlyUsageData, loadSessionBlockData, loadSessionData, projectBlockUsage, sortFilesByTimestamp, uniq, usageDataSchema } from "./data-loader-
|
|
7
|
-
import { description, log, logger, name, version } from "./logger-
|
|
8
|
-
import { detectMismatches, printMismatchReport } from "./debug-
|
|
9
|
-
import { createMcpHttpApp, createMcpServer, startMcpServerStdio } from "./mcp-
|
|
6
|
+
import { DEFAULT_SESSION_DURATION_HOURS, calculateBurnRate, calculateCostForEntry, createUniqueHash, filterRecentBlocks, formatDateCompact, getClaudePaths, getEarliestTimestamp, getUsageLimitResetTime, globUsageFiles, identifySessionBlocks, loadDailyUsageData, loadMonthlyUsageData, loadSessionBlockData, loadSessionData, projectBlockUsage, sortFilesByTimestamp, uniq, usageDataSchema } from "./data-loader-BAp4u-7e.js";
|
|
7
|
+
import { description, log, logger, name, version } from "./logger-COLgmk2z.js";
|
|
8
|
+
import { detectMismatches, printMismatchReport } from "./debug-IQBgd8CJ.js";
|
|
9
|
+
import { createMcpHttpApp, createMcpServer, startMcpServerStdio } from "./mcp-Ta2UK9sc.js";
|
|
10
10
|
import { readFile } from "node:fs/promises";
|
|
11
11
|
import process$1 from "node:process";
|
|
12
12
|
import { createServer } from "node:http";
|
|
@@ -3729,13 +3729,6 @@ function formatTokensShort(num) {
|
|
|
3729
3729
|
return num.toString();
|
|
3730
3730
|
}
|
|
3731
3731
|
/**
|
|
3732
|
-
* Column layout constants for detail rows
|
|
3733
|
-
*/
|
|
3734
|
-
const DETAIL_COLUMN_WIDTHS = {
|
|
3735
|
-
col1: 46,
|
|
3736
|
-
col2: 37
|
|
3737
|
-
};
|
|
3738
|
-
/**
|
|
3739
3732
|
* Renders the live display for an active session block
|
|
3740
3733
|
*/
|
|
3741
3734
|
function renderLiveDisplay(terminal, block, config) {
|
|
@@ -3744,6 +3737,9 @@ function renderLiveDisplay(terminal, block, config) {
|
|
|
3744
3737
|
const totalTokens = getTotalTokens(block.tokenCounts);
|
|
3745
3738
|
const elapsed = (now.getTime() - block.startTime.getTime()) / (1e3 * 60);
|
|
3746
3739
|
const remaining = (block.endTime.getTime() - now.getTime()) / (1e3 * 60);
|
|
3740
|
+
const formatTokenDisplay = (tokens, useShort) => {
|
|
3741
|
+
return useShort ? formatTokensShort(tokens) : formatNumber(tokens);
|
|
3742
|
+
};
|
|
3747
3743
|
if (width < 60) {
|
|
3748
3744
|
renderCompactLiveDisplay(terminal, block, config, totalTokens, elapsed, remaining);
|
|
3749
3745
|
return;
|
|
@@ -3751,12 +3747,19 @@ function renderLiveDisplay(terminal, block, config) {
|
|
|
3751
3747
|
const boxWidth = Math.min(120, width - 2);
|
|
3752
3748
|
const boxMargin = Math.floor((width - boxWidth) / 2);
|
|
3753
3749
|
const marginStr = " ".repeat(boxMargin);
|
|
3754
|
-
const labelWidth = 14;
|
|
3755
|
-
const percentWidth = 7;
|
|
3756
|
-
const shortLabelWidth = 20;
|
|
3757
|
-
const barWidth = boxWidth - labelWidth - percentWidth - shortLabelWidth - 4;
|
|
3758
3750
|
const sessionDuration = elapsed + remaining;
|
|
3759
3751
|
const sessionPercent = elapsed / sessionDuration * 100;
|
|
3752
|
+
const sessionRightText = `${sessionPercent.toFixed(1).padStart(6)}%`;
|
|
3753
|
+
const tokenPercent = config.tokenLimit != null && config.tokenLimit > 0 ? totalTokens / config.tokenLimit * 100 : 0;
|
|
3754
|
+
const usageRightText = config.tokenLimit != null && config.tokenLimit > 0 ? `${tokenPercent.toFixed(1).padStart(6)}% (${formatTokensShort(totalTokens)}/${formatTokensShort(config.tokenLimit)})` : `(${formatTokensShort(totalTokens)} tokens)`;
|
|
3755
|
+
const projection = projectBlockUsage(block);
|
|
3756
|
+
const projectedPercent = projection != null && config.tokenLimit != null && config.tokenLimit > 0 ? projection.totalTokens / config.tokenLimit * 100 : 0;
|
|
3757
|
+
const projectionRightText = projection != null ? config.tokenLimit != null && config.tokenLimit > 0 ? `${projectedPercent.toFixed(1).padStart(6)}% (${formatTokensShort(projection.totalTokens)}/${formatTokensShort(config.tokenLimit)})` : `(${formatTokensShort(projection.totalTokens)} tokens)` : "";
|
|
3758
|
+
const maxRightTextWidth = Math.max(stringWidth(sessionRightText), stringWidth(usageRightText), projection != null ? stringWidth(projectionRightText) : 0);
|
|
3759
|
+
const labelWidth = 14;
|
|
3760
|
+
const spacing = 4;
|
|
3761
|
+
const boxPadding = 4;
|
|
3762
|
+
const barWidth = boxWidth - labelWidth - maxRightTextWidth - spacing - boxPadding;
|
|
3760
3763
|
const sessionProgressBar = createProgressBar(elapsed, sessionDuration, barWidth, {
|
|
3761
3764
|
showPercentage: false,
|
|
3762
3765
|
fillChar: import_picocolors$5.default.cyan("█"),
|
|
@@ -3776,23 +3779,24 @@ function renderLiveDisplay(terminal, block, config) {
|
|
|
3776
3779
|
second: "2-digit",
|
|
3777
3780
|
hour12: true
|
|
3778
3781
|
});
|
|
3782
|
+
const detailsIndent = 3;
|
|
3783
|
+
const detailsSpacing = 2;
|
|
3784
|
+
const detailsAvailableWidth = boxWidth - 3 - detailsIndent;
|
|
3779
3785
|
terminal.write(`${marginStr}┌${"─".repeat(boxWidth - 2)}┐\n`);
|
|
3780
3786
|
terminal.write(`${marginStr}│${import_picocolors$5.default.bold(centerText("CLAUDE CODE - LIVE TOKEN USAGE MONITOR", boxWidth - 2))}│\n`);
|
|
3781
3787
|
terminal.write(`${marginStr}├${"─".repeat(boxWidth - 2)}┤\n`);
|
|
3782
3788
|
terminal.write(`${marginStr}│${" ".repeat(boxWidth - 2)}│\n`);
|
|
3783
3789
|
const sessionLabel = import_picocolors$5.default.bold("⏱️ SESSION");
|
|
3784
3790
|
const sessionLabelWidth = stringWidth(sessionLabel);
|
|
3785
|
-
const sessionBarStr = `${sessionLabel}${"".padEnd(Math.max(0, labelWidth - sessionLabelWidth))} ${sessionProgressBar} ${
|
|
3791
|
+
const sessionBarStr = `${sessionLabel}${"".padEnd(Math.max(0, labelWidth - sessionLabelWidth))} ${sessionProgressBar} ${sessionRightText}`;
|
|
3786
3792
|
const sessionBarPadded = sessionBarStr + " ".repeat(Math.max(0, boxWidth - 3 - stringWidth(sessionBarStr)));
|
|
3787
3793
|
terminal.write(`${marginStr}│ ${sessionBarPadded}│\n`);
|
|
3788
|
-
const
|
|
3789
|
-
const
|
|
3790
|
-
const
|
|
3791
|
-
|
|
3792
|
-
const
|
|
3793
|
-
|
|
3794
|
-
const pad2 = " ".repeat(Math.max(0, DETAIL_COLUMN_WIDTHS.col2 - col2Visible));
|
|
3795
|
-
const sessionDetails = ` ${col1}${pad1}${pad2}${col3}`;
|
|
3794
|
+
const sessionCol1 = `${import_picocolors$5.default.gray("Started:")} ${startTime}`;
|
|
3795
|
+
const sessionCol2 = `${import_picocolors$5.default.gray("Elapsed:")} ${prettyMilliseconds(elapsed * 60 * 1e3, { compact: true })}`;
|
|
3796
|
+
const sessionCol3 = `${import_picocolors$5.default.gray("Remaining:")} ${prettyMilliseconds(remaining * 60 * 1e3, { compact: true })} (${endTime})`;
|
|
3797
|
+
let sessionDetails = `${" ".repeat(detailsIndent)}${sessionCol1}${" ".repeat(detailsSpacing)}${sessionCol2}${" ".repeat(detailsSpacing)}${sessionCol3}`;
|
|
3798
|
+
const sessionDetailsWidth = stringWidth(sessionCol1) + stringWidth(sessionCol2) + stringWidth(sessionCol3) + detailsSpacing * 2;
|
|
3799
|
+
if (sessionDetailsWidth > detailsAvailableWidth) sessionDetails = `${" ".repeat(detailsIndent)}${sessionCol1}${" ".repeat(detailsSpacing)}${sessionCol3}`;
|
|
3796
3800
|
const sessionDetailsPadded = sessionDetails + " ".repeat(Math.max(0, boxWidth - 3 - stringWidth(sessionDetails)));
|
|
3797
3801
|
let usageLimitResetTimePadded = null;
|
|
3798
3802
|
if (block.usageLimitResetTime !== void 0 && now < block.usageLimitResetTime) {
|
|
@@ -3809,7 +3813,6 @@ function renderLiveDisplay(terminal, block, config) {
|
|
|
3809
3813
|
terminal.write(`${marginStr}│${" ".repeat(boxWidth - 2)}│\n`);
|
|
3810
3814
|
terminal.write(`${marginStr}├${"─".repeat(boxWidth - 2)}┤\n`);
|
|
3811
3815
|
terminal.write(`${marginStr}│${" ".repeat(boxWidth - 2)}│\n`);
|
|
3812
|
-
const tokenPercent = config.tokenLimit != null && config.tokenLimit > 0 ? totalTokens / config.tokenLimit * 100 : 0;
|
|
3813
3816
|
let barColor = import_picocolors$5.default.green;
|
|
3814
3817
|
if (tokenPercent > 100) barColor = import_picocolors$5.default.red;
|
|
3815
3818
|
else if (tokenPercent > 80) barColor = import_picocolors$5.default.yellow;
|
|
@@ -3822,35 +3825,51 @@ function renderLiveDisplay(terminal, block, config) {
|
|
|
3822
3825
|
}) : `[${import_picocolors$5.default.green("█".repeat(Math.floor(barWidth * .1)))}${import_picocolors$5.default.gray("░".repeat(barWidth - Math.floor(barWidth * .1)))}]`;
|
|
3823
3826
|
const burnRate = calculateBurnRate(block);
|
|
3824
3827
|
const rateIndicator = getRateIndicator(burnRate);
|
|
3825
|
-
const
|
|
3828
|
+
const buildRateDisplay = (useShort) => {
|
|
3829
|
+
if (burnRate == null) return `${import_picocolors$5.default.bold("Burn Rate:")} N/A`;
|
|
3830
|
+
const rateValue = Math.round(burnRate.tokensPerMinute);
|
|
3831
|
+
const formattedRate = useShort ? formatTokensShort(rateValue) : formatNumber(rateValue);
|
|
3832
|
+
return `${import_picocolors$5.default.bold("Burn Rate:")} ${formattedRate} token/min ${rateIndicator}`;
|
|
3833
|
+
};
|
|
3826
3834
|
const usageLabel = import_picocolors$5.default.bold("🔥 USAGE");
|
|
3827
3835
|
const usageLabelWidth = stringWidth(usageLabel);
|
|
3828
|
-
const
|
|
3829
|
-
|
|
3830
|
-
|
|
3831
|
-
|
|
3832
|
-
|
|
3833
|
-
|
|
3834
|
-
|
|
3835
|
-
|
|
3836
|
-
|
|
3837
|
-
|
|
3838
|
-
|
|
3836
|
+
const usageBarStr = `${usageLabel}${"".padEnd(Math.max(0, labelWidth - usageLabelWidth))} ${usageBar} ${usageRightText}`;
|
|
3837
|
+
let rateDisplay = buildRateDisplay(false);
|
|
3838
|
+
let usageCol1 = `${import_picocolors$5.default.gray("Tokens:")} ${formatTokenDisplay(totalTokens, false)} (${rateDisplay})`;
|
|
3839
|
+
let usageCol2 = config.tokenLimit != null && config.tokenLimit > 0 ? `${import_picocolors$5.default.gray("Limit:")} ${formatTokenDisplay(config.tokenLimit, false)} tokens` : "";
|
|
3840
|
+
const usageCol3 = `${import_picocolors$5.default.gray("Cost:")} ${formatCurrency(block.costUSD)}`;
|
|
3841
|
+
let totalWidth = stringWidth(usageCol1);
|
|
3842
|
+
if (usageCol2.length > 0) totalWidth += detailsSpacing + stringWidth(usageCol2);
|
|
3843
|
+
totalWidth += detailsSpacing + stringWidth(usageCol3);
|
|
3844
|
+
let useTwoLineLayout = false;
|
|
3845
|
+
if (totalWidth > detailsAvailableWidth) {
|
|
3846
|
+
useTwoLineLayout = true;
|
|
3847
|
+
rateDisplay = buildRateDisplay(true);
|
|
3848
|
+
usageCol1 = `${import_picocolors$5.default.gray("Tokens:")} ${formatTokenDisplay(totalTokens, true)} (${rateDisplay})`;
|
|
3849
|
+
if (usageCol2.length > 0) usageCol2 = `${import_picocolors$5.default.gray("Limit:")} ${formatTokenDisplay(config.tokenLimit, true)} tokens`;
|
|
3850
|
+
}
|
|
3839
3851
|
const usageBarPadded = usageBarStr + " ".repeat(Math.max(0, boxWidth - 3 - stringWidth(usageBarStr)));
|
|
3840
3852
|
terminal.write(`${marginStr}│ ${usageBarPadded}│\n`);
|
|
3841
|
-
|
|
3842
|
-
|
|
3843
|
-
|
|
3844
|
-
|
|
3845
|
-
|
|
3846
|
-
|
|
3847
|
-
|
|
3853
|
+
if (useTwoLineLayout) {
|
|
3854
|
+
const usageDetailsLine1 = `${" ".repeat(detailsIndent)}${usageCol1}`;
|
|
3855
|
+
const usageDetailsLine1Padded = usageDetailsLine1 + " ".repeat(Math.max(0, boxWidth - 3 - stringWidth(usageDetailsLine1)));
|
|
3856
|
+
terminal.write(`${marginStr}│ ${usageDetailsLine1Padded}│\n`);
|
|
3857
|
+
let usageDetailsLine2;
|
|
3858
|
+
if (usageCol2.length > 0) usageDetailsLine2 = `${" ".repeat(detailsIndent)}${usageCol2}${" ".repeat(detailsSpacing)}${usageCol3}`;
|
|
3859
|
+
else usageDetailsLine2 = `${" ".repeat(detailsIndent)}${usageCol3}`;
|
|
3860
|
+
const usageDetailsLine2Padded = usageDetailsLine2 + " ".repeat(Math.max(0, boxWidth - 3 - stringWidth(usageDetailsLine2)));
|
|
3861
|
+
terminal.write(`${marginStr}│ ${usageDetailsLine2Padded}│\n`);
|
|
3862
|
+
} else {
|
|
3863
|
+
let usageDetails;
|
|
3864
|
+
if (usageCol2.length > 0) usageDetails = `${" ".repeat(detailsIndent)}${usageCol1}${" ".repeat(detailsSpacing)}${usageCol2}${" ".repeat(detailsSpacing)}${usageCol3}`;
|
|
3865
|
+
else usageDetails = `${" ".repeat(detailsIndent)}${usageCol1}${" ".repeat(detailsSpacing)}${usageCol3}`;
|
|
3866
|
+
const usageDetailsPadded = usageDetails + " ".repeat(Math.max(0, boxWidth - 3 - stringWidth(usageDetails)));
|
|
3867
|
+
terminal.write(`${marginStr}│ ${usageDetailsPadded}│\n`);
|
|
3868
|
+
}
|
|
3848
3869
|
terminal.write(`${marginStr}│${" ".repeat(boxWidth - 2)}│\n`);
|
|
3849
3870
|
terminal.write(`${marginStr}├${"─".repeat(boxWidth - 2)}┤\n`);
|
|
3850
3871
|
terminal.write(`${marginStr}│${" ".repeat(boxWidth - 2)}│\n`);
|
|
3851
|
-
const projection = projectBlockUsage(block);
|
|
3852
3872
|
if (projection != null) {
|
|
3853
|
-
const projectedPercent = config.tokenLimit != null && config.tokenLimit > 0 ? projection.totalTokens / config.tokenLimit * 100 : 0;
|
|
3854
3873
|
let projBarColor = import_picocolors$5.default.green;
|
|
3855
3874
|
if (projectedPercent > 100) projBarColor = import_picocolors$5.default.red;
|
|
3856
3875
|
else if (projectedPercent > 80) projBarColor = import_picocolors$5.default.yellow;
|
|
@@ -3864,32 +3883,27 @@ function renderLiveDisplay(terminal, block, config) {
|
|
|
3864
3883
|
const limitStatus = config.tokenLimit != null && config.tokenLimit > 0 ? projectedPercent > 100 ? import_picocolors$5.default.red("❌ WILL EXCEED LIMIT") : projectedPercent > 80 ? import_picocolors$5.default.yellow("⚠️ APPROACHING LIMIT") : import_picocolors$5.default.green("✓ WITHIN LIMIT") : import_picocolors$5.default.green("✓ ON TRACK");
|
|
3865
3884
|
const projLabel = import_picocolors$5.default.bold("📈 PROJECTION");
|
|
3866
3885
|
const projLabelWidth = stringWidth(projLabel);
|
|
3867
|
-
|
|
3868
|
-
|
|
3869
|
-
|
|
3870
|
-
|
|
3871
|
-
|
|
3872
|
-
|
|
3873
|
-
|
|
3874
|
-
|
|
3875
|
-
|
|
3876
|
-
|
|
3877
|
-
|
|
3878
|
-
|
|
3879
|
-
|
|
3880
|
-
|
|
3886
|
+
const projBarStr = `${projLabel}${"".padEnd(Math.max(0, labelWidth - projLabelWidth))} ${projectionBar} ${projectionRightText}`;
|
|
3887
|
+
const projBarPadded = projBarStr + " ".repeat(Math.max(0, boxWidth - 3 - stringWidth(projBarStr)));
|
|
3888
|
+
terminal.write(`${marginStr}│ ${projBarPadded}│\n`);
|
|
3889
|
+
const projCol1 = `${import_picocolors$5.default.gray("Status:")} ${limitStatus}`;
|
|
3890
|
+
let projCol2 = `${import_picocolors$5.default.gray("Tokens:")} ${formatTokenDisplay(projection.totalTokens, false)}`;
|
|
3891
|
+
const projCol3 = `${import_picocolors$5.default.gray("Cost:")} ${formatCurrency(projection.totalCost)}`;
|
|
3892
|
+
const projTotalWidth = stringWidth(projCol1) + stringWidth(projCol2) + stringWidth(projCol3) + detailsSpacing * 2;
|
|
3893
|
+
let projUseTwoLineLayout = false;
|
|
3894
|
+
if (projTotalWidth > detailsAvailableWidth) {
|
|
3895
|
+
projUseTwoLineLayout = true;
|
|
3896
|
+
projCol2 = `${import_picocolors$5.default.gray("Tokens:")} ${formatTokenDisplay(projection.totalTokens, true)}`;
|
|
3897
|
+
}
|
|
3898
|
+
if (projUseTwoLineLayout) {
|
|
3899
|
+
const projDetailsLine1 = `${" ".repeat(detailsIndent)}${projCol1}`;
|
|
3900
|
+
const projDetailsLine1Padded = projDetailsLine1 + " ".repeat(Math.max(0, boxWidth - 3 - stringWidth(projDetailsLine1)));
|
|
3901
|
+
terminal.write(`${marginStr}│ ${projDetailsLine1Padded}│\n`);
|
|
3902
|
+
const projDetailsLine2 = `${" ".repeat(detailsIndent)}${projCol2}${" ".repeat(detailsSpacing)}${projCol3}`;
|
|
3903
|
+
const projDetailsLine2Padded = projDetailsLine2 + " ".repeat(Math.max(0, boxWidth - 3 - stringWidth(projDetailsLine2)));
|
|
3904
|
+
terminal.write(`${marginStr}│ ${projDetailsLine2Padded}│\n`);
|
|
3881
3905
|
} else {
|
|
3882
|
-
const
|
|
3883
|
-
const projBarPadded = projBarStr + " ".repeat(Math.max(0, boxWidth - 3 - stringWidth(projBarStr)));
|
|
3884
|
-
terminal.write(`${marginStr}│ ${projBarPadded}│\n`);
|
|
3885
|
-
const col1$1 = `${import_picocolors$5.default.gray("Status:")} ${limitStatus}`;
|
|
3886
|
-
const col2$1 = `${import_picocolors$5.default.gray("Tokens:")} ${formatNumber(projection.totalTokens)}`;
|
|
3887
|
-
const col3$1 = `${import_picocolors$5.default.gray("Cost:")} ${formatCurrency(projection.totalCost)}`;
|
|
3888
|
-
const col1Visible$1 = stringWidth(col1$1);
|
|
3889
|
-
const col2Visible$1 = stringWidth(col2$1);
|
|
3890
|
-
const pad1$1 = " ".repeat(Math.max(0, DETAIL_COLUMN_WIDTHS.col1 - col1Visible$1));
|
|
3891
|
-
const pad2$1 = " ".repeat(Math.max(0, DETAIL_COLUMN_WIDTHS.col2 - col2Visible$1));
|
|
3892
|
-
const projDetails = ` ${col1$1}${pad1$1}${col2$1}${pad2$1}${col3$1}`;
|
|
3906
|
+
const projDetails = `${" ".repeat(detailsIndent)}${projCol1}${" ".repeat(detailsSpacing)}${projCol2}${" ".repeat(detailsSpacing)}${projCol3}`;
|
|
3893
3907
|
const projDetailsPadded = projDetails + " ".repeat(Math.max(0, boxWidth - 3 - stringWidth(projDetails)));
|
|
3894
3908
|
terminal.write(`${marginStr}│ ${projDetailsPadded}│\n`);
|
|
3895
3909
|
}
|
|
@@ -3970,7 +3984,15 @@ async function startLiveMonitoring(config) {
|
|
|
3970
3984
|
}
|
|
3971
3985
|
renderActiveBlock(terminal, activeBlock, config);
|
|
3972
3986
|
lastRenderTime = Date.now();
|
|
3973
|
-
|
|
3987
|
+
let resizeEventHandler;
|
|
3988
|
+
try {
|
|
3989
|
+
await Promise.race([delayWithAbort(config.refreshInterval, abortController.signal), new Promise((resolve) => {
|
|
3990
|
+
resizeEventHandler = resolve;
|
|
3991
|
+
process$1.stdout.once("resize", resolve);
|
|
3992
|
+
})]);
|
|
3993
|
+
} finally {
|
|
3994
|
+
if (resizeEventHandler != null) process$1.stdout.removeListener("resize", resizeEventHandler);
|
|
3995
|
+
}
|
|
3974
3996
|
}
|
|
3975
3997
|
},
|
|
3976
3998
|
catch: (error) => error
|
|
@@ -4329,11 +4351,162 @@ const blocksCommand = define({
|
|
|
4329
4351
|
}
|
|
4330
4352
|
}
|
|
4331
4353
|
});
|
|
4354
|
+
/**
|
|
4355
|
+
* Group daily usage data by project for JSON output
|
|
4356
|
+
*/
|
|
4357
|
+
function groupByProject(dailyData) {
|
|
4358
|
+
const projects = {};
|
|
4359
|
+
for (const data of dailyData) {
|
|
4360
|
+
const projectName = data.project ?? "unknown";
|
|
4361
|
+
if (projects[projectName] == null) projects[projectName] = [];
|
|
4362
|
+
projects[projectName].push({
|
|
4363
|
+
date: data.date,
|
|
4364
|
+
inputTokens: data.inputTokens,
|
|
4365
|
+
outputTokens: data.outputTokens,
|
|
4366
|
+
cacheCreationTokens: data.cacheCreationTokens,
|
|
4367
|
+
cacheReadTokens: data.cacheReadTokens,
|
|
4368
|
+
totalTokens: getTotalTokens(data),
|
|
4369
|
+
totalCost: data.totalCost,
|
|
4370
|
+
modelsUsed: data.modelsUsed,
|
|
4371
|
+
modelBreakdowns: data.modelBreakdowns
|
|
4372
|
+
});
|
|
4373
|
+
}
|
|
4374
|
+
return projects;
|
|
4375
|
+
}
|
|
4376
|
+
/**
|
|
4377
|
+
* Group daily usage data by project for table display
|
|
4378
|
+
*/
|
|
4379
|
+
function groupDataByProject(dailyData) {
|
|
4380
|
+
const projects = {};
|
|
4381
|
+
for (const data of dailyData) {
|
|
4382
|
+
const projectName = data.project ?? "unknown";
|
|
4383
|
+
if (projects[projectName] == null) projects[projectName] = [];
|
|
4384
|
+
projects[projectName].push(data);
|
|
4385
|
+
}
|
|
4386
|
+
return projects;
|
|
4387
|
+
}
|
|
4388
|
+
/**
|
|
4389
|
+
* Cache for parsed aliases to avoid repeated parsing
|
|
4390
|
+
*/
|
|
4391
|
+
let aliasCache = null;
|
|
4392
|
+
/**
|
|
4393
|
+
* Parse project aliases from environment variable
|
|
4394
|
+
* @returns Map of raw project names to their aliases
|
|
4395
|
+
*/
|
|
4396
|
+
function getProjectAliases() {
|
|
4397
|
+
if (aliasCache !== null) return aliasCache;
|
|
4398
|
+
aliasCache = /* @__PURE__ */ new Map();
|
|
4399
|
+
const aliasEnv = (process$1.env[PROJECT_ALIASES_ENV] ?? "").trim();
|
|
4400
|
+
if (aliasEnv === "") return aliasCache;
|
|
4401
|
+
const pairs = aliasEnv.split(",").map((pair) => pair.trim()).filter((pair) => pair !== "");
|
|
4402
|
+
for (const pair of pairs) {
|
|
4403
|
+
const parts = pair.split("=").map((s) => s.trim());
|
|
4404
|
+
const rawName = parts[0];
|
|
4405
|
+
const alias = parts[1];
|
|
4406
|
+
if (rawName != null && alias != null && rawName !== "" && alias !== "") aliasCache.set(rawName, alias);
|
|
4407
|
+
}
|
|
4408
|
+
return aliasCache;
|
|
4409
|
+
}
|
|
4410
|
+
/**
|
|
4411
|
+
* Extract meaningful project name from directory-style project paths
|
|
4412
|
+
* Uses improved heuristics to handle complex project structures
|
|
4413
|
+
*
|
|
4414
|
+
* @param projectName - Raw project name from directory path
|
|
4415
|
+
* @returns Cleaned and formatted project name
|
|
4416
|
+
*
|
|
4417
|
+
* @example
|
|
4418
|
+
* ```typescript
|
|
4419
|
+
* // Basic cleanup
|
|
4420
|
+
* parseProjectName('-Users-phaedrus-Development-ccusage')
|
|
4421
|
+
* // → 'ccusage'
|
|
4422
|
+
*
|
|
4423
|
+
* // Complex project with feature branch
|
|
4424
|
+
* parseProjectName('-Users-phaedrus-Development-adminifi-edugakko-api--feature-ticket-002-configure-dependabot')
|
|
4425
|
+
* // → 'configure-dependabot'
|
|
4426
|
+
*
|
|
4427
|
+
* // Handle unknown projects
|
|
4428
|
+
* parseProjectName('unknown')
|
|
4429
|
+
* // → 'Unknown Project'
|
|
4430
|
+
* ```
|
|
4431
|
+
*/
|
|
4432
|
+
function parseProjectName(projectName) {
|
|
4433
|
+
if (projectName === "unknown" || projectName === "") return "Unknown Project";
|
|
4434
|
+
let cleaned = projectName;
|
|
4435
|
+
if (cleaned.match(/^[A-Z]:\\Users\\|^\\Users\\/) != null) {
|
|
4436
|
+
const segments = cleaned.split("\\");
|
|
4437
|
+
const userIndex = segments.findIndex((seg) => seg === "Users");
|
|
4438
|
+
if (userIndex !== -1 && userIndex + 3 < segments.length) cleaned = segments.slice(userIndex + 3).join("-");
|
|
4439
|
+
}
|
|
4440
|
+
if (cleaned.startsWith("-Users-") || cleaned.startsWith("/Users/")) {
|
|
4441
|
+
const separator = cleaned.startsWith("-Users-") ? "-" : "/";
|
|
4442
|
+
const segments = cleaned.split(separator).filter((s) => s.length > 0);
|
|
4443
|
+
const userIndex = segments.findIndex((seg) => seg === "Users");
|
|
4444
|
+
if (userIndex !== -1 && userIndex + 3 < segments.length) cleaned = segments.slice(userIndex + 3).join("-");
|
|
4445
|
+
}
|
|
4446
|
+
if (cleaned === projectName) cleaned = projectName.replace(/^[/\\-]+|[/\\-]+$/g, "");
|
|
4447
|
+
if (cleaned.match(/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}/i) != null) {
|
|
4448
|
+
const parts = cleaned.split("-");
|
|
4449
|
+
if (parts.length >= 5) cleaned = parts.slice(-2).join("-");
|
|
4450
|
+
}
|
|
4451
|
+
if (cleaned.includes("--")) {
|
|
4452
|
+
const parts = cleaned.split("--");
|
|
4453
|
+
if (parts.length >= 2 && parts[0] != null) cleaned = parts[0];
|
|
4454
|
+
}
|
|
4455
|
+
if (cleaned.includes("-") && cleaned.length > 20) {
|
|
4456
|
+
const segments = cleaned.split("-");
|
|
4457
|
+
const meaningfulSegments = segments.filter((seg) => seg.length > 2 && seg.match(/^(?:dev|development|feat|feature|fix|bug|test|staging|prod|production|main|master|branch)$/i) == null);
|
|
4458
|
+
if (meaningfulSegments.length >= 2) {
|
|
4459
|
+
const lastSegments = meaningfulSegments.slice(-2);
|
|
4460
|
+
if (lastSegments.join("-").length >= 6) cleaned = lastSegments.join("-");
|
|
4461
|
+
else if (meaningfulSegments.length >= 3) cleaned = meaningfulSegments.slice(-3).join("-");
|
|
4462
|
+
}
|
|
4463
|
+
}
|
|
4464
|
+
cleaned = cleaned.replace(/^[/\\-]+|[/\\-]+$/g, "");
|
|
4465
|
+
return cleaned !== "" ? cleaned : projectName !== "" ? projectName : "Unknown Project";
|
|
4466
|
+
}
|
|
4467
|
+
/**
|
|
4468
|
+
* Format project name for display with custom alias support
|
|
4469
|
+
*
|
|
4470
|
+
* @param projectName - Raw project name from directory path
|
|
4471
|
+
* @returns User-friendly project name with alias support
|
|
4472
|
+
*
|
|
4473
|
+
* @example
|
|
4474
|
+
* ```typescript
|
|
4475
|
+
* // Without aliases
|
|
4476
|
+
* formatProjectName('-Users-phaedrus-Development-ccusage')
|
|
4477
|
+
* // → 'ccusage'
|
|
4478
|
+
*
|
|
4479
|
+
* // With alias (when CCUSAGE_PROJECT_ALIASES="ccusage=Usage Tracker")
|
|
4480
|
+
* formatProjectName('-Users-phaedrus-Development-ccusage')
|
|
4481
|
+
* // → 'Usage Tracker'
|
|
4482
|
+
* ```
|
|
4483
|
+
*/
|
|
4484
|
+
function formatProjectName(projectName) {
|
|
4485
|
+
const aliases = getProjectAliases();
|
|
4486
|
+
if (aliases.has(projectName)) return aliases.get(projectName);
|
|
4487
|
+
const parsed = parseProjectName(projectName);
|
|
4488
|
+
if (aliases.has(parsed)) return aliases.get(parsed);
|
|
4489
|
+
return parsed;
|
|
4490
|
+
}
|
|
4332
4491
|
var import_picocolors$2 = __toESM(require_picocolors(), 1);
|
|
4333
4492
|
const dailyCommand = define({
|
|
4334
4493
|
name: "daily",
|
|
4335
4494
|
description: "Show usage report grouped by date",
|
|
4336
4495
|
...sharedCommandConfig,
|
|
4496
|
+
args: {
|
|
4497
|
+
...sharedCommandConfig.args,
|
|
4498
|
+
instances: {
|
|
4499
|
+
type: "boolean",
|
|
4500
|
+
short: "i",
|
|
4501
|
+
description: "Show usage breakdown by project/instance",
|
|
4502
|
+
default: false
|
|
4503
|
+
},
|
|
4504
|
+
project: {
|
|
4505
|
+
type: "string",
|
|
4506
|
+
short: "p",
|
|
4507
|
+
description: "Filter to specific project name"
|
|
4508
|
+
}
|
|
4509
|
+
},
|
|
4337
4510
|
async run(ctx) {
|
|
4338
4511
|
if (ctx.values.json) logger.level = 0;
|
|
4339
4512
|
const dailyData = await loadDailyUsageData({
|
|
@@ -4341,7 +4514,9 @@ const dailyCommand = define({
|
|
|
4341
4514
|
until: ctx.values.until,
|
|
4342
4515
|
mode: ctx.values.mode,
|
|
4343
4516
|
order: ctx.values.order,
|
|
4344
|
-
offline: ctx.values.offline
|
|
4517
|
+
offline: ctx.values.offline,
|
|
4518
|
+
groupByProject: ctx.values.instances,
|
|
4519
|
+
project: ctx.values.project
|
|
4345
4520
|
});
|
|
4346
4521
|
if (dailyData.length === 0) {
|
|
4347
4522
|
if (ctx.values.json) log(JSON.stringify([]));
|
|
@@ -4354,7 +4529,10 @@ const dailyCommand = define({
|
|
|
4354
4529
|
printMismatchReport(mismatchStats, ctx.values.debugSamples);
|
|
4355
4530
|
}
|
|
4356
4531
|
if (ctx.values.json) {
|
|
4357
|
-
const jsonOutput = {
|
|
4532
|
+
const jsonOutput = ctx.values.instances && dailyData.some((d) => d.project != null) ? {
|
|
4533
|
+
projects: groupByProject(dailyData),
|
|
4534
|
+
totals: createTotalsObject(totals)
|
|
4535
|
+
} : {
|
|
4358
4536
|
daily: dailyData.map((data) => ({
|
|
4359
4537
|
date: data.date,
|
|
4360
4538
|
inputTokens: data.inputTokens,
|
|
@@ -4364,7 +4542,8 @@ const dailyCommand = define({
|
|
|
4364
4542
|
totalTokens: getTotalTokens(data),
|
|
4365
4543
|
totalCost: data.totalCost,
|
|
4366
4544
|
modelsUsed: data.modelsUsed,
|
|
4367
|
-
modelBreakdowns: data.modelBreakdowns
|
|
4545
|
+
modelBreakdowns: data.modelBreakdowns,
|
|
4546
|
+
...data.project != null && { project: data.project }
|
|
4368
4547
|
})),
|
|
4369
4548
|
totals: createTotalsObject(totals)
|
|
4370
4549
|
};
|
|
@@ -4410,7 +4589,46 @@ const dailyCommand = define({
|
|
|
4410
4589
|
],
|
|
4411
4590
|
compactThreshold: 100
|
|
4412
4591
|
});
|
|
4413
|
-
|
|
4592
|
+
if (ctx.values.instances && dailyData.some((d) => d.project != null)) {
|
|
4593
|
+
const projectGroups = groupDataByProject(dailyData);
|
|
4594
|
+
let isFirstProject = true;
|
|
4595
|
+
for (const [projectName, projectData] of Object.entries(projectGroups)) {
|
|
4596
|
+
if (!isFirstProject) table.push([
|
|
4597
|
+
"",
|
|
4598
|
+
"",
|
|
4599
|
+
"",
|
|
4600
|
+
"",
|
|
4601
|
+
"",
|
|
4602
|
+
"",
|
|
4603
|
+
"",
|
|
4604
|
+
""
|
|
4605
|
+
]);
|
|
4606
|
+
table.push([
|
|
4607
|
+
import_picocolors$2.default.cyan(`Project: ${formatProjectName(projectName)}`),
|
|
4608
|
+
"",
|
|
4609
|
+
"",
|
|
4610
|
+
"",
|
|
4611
|
+
"",
|
|
4612
|
+
"",
|
|
4613
|
+
"",
|
|
4614
|
+
""
|
|
4615
|
+
]);
|
|
4616
|
+
for (const data of projectData) {
|
|
4617
|
+
table.push([
|
|
4618
|
+
data.date,
|
|
4619
|
+
formatModelsDisplayMultiline(data.modelsUsed),
|
|
4620
|
+
formatNumber(data.inputTokens),
|
|
4621
|
+
formatNumber(data.outputTokens),
|
|
4622
|
+
formatNumber(data.cacheCreationTokens),
|
|
4623
|
+
formatNumber(data.cacheReadTokens),
|
|
4624
|
+
formatNumber(getTotalTokens(data)),
|
|
4625
|
+
formatCurrency(data.totalCost)
|
|
4626
|
+
]);
|
|
4627
|
+
if (ctx.values.breakdown) pushBreakdownRows(table, data.modelBreakdowns);
|
|
4628
|
+
}
|
|
4629
|
+
isFirstProject = false;
|
|
4630
|
+
}
|
|
4631
|
+
} else for (const data of dailyData) {
|
|
4414
4632
|
table.push([
|
|
4415
4633
|
data.date,
|
|
4416
4634
|
formatModelsDisplayMultiline(data.modelsUsed),
|
|
@@ -5072,7 +5290,8 @@ const sessionCommand = define({
|
|
|
5072
5290
|
totalCost: data.totalCost,
|
|
5073
5291
|
lastActivity: data.lastActivity,
|
|
5074
5292
|
modelsUsed: data.modelsUsed,
|
|
5075
|
-
modelBreakdowns: data.modelBreakdowns
|
|
5293
|
+
modelBreakdowns: data.modelBreakdowns,
|
|
5294
|
+
projectPath: data.projectPath
|
|
5076
5295
|
})),
|
|
5077
5296
|
totals: createTotalsObject(totals)
|
|
5078
5297
|
};
|
|
@@ -951,7 +951,7 @@ function _getDefaultLogLevel() {
|
|
|
951
951
|
}
|
|
952
952
|
const consola = createConsola$1();
|
|
953
953
|
var name = "ccusage";
|
|
954
|
-
var version = "15.
|
|
954
|
+
var version = "15.5.1";
|
|
955
955
|
var description = "Usage analysis tool for Claude Code";
|
|
956
956
|
/**
|
|
957
957
|
* Application logger instance with package name tag
|
package/dist/logger.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { log, logger } from "./logger-
|
|
1
|
+
import { log, logger } from "./logger-COLgmk2z.js";
|
|
2
2
|
export { log, logger };
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { __commonJSMin, __toESM, require_usingCtx } from "./pricing-fetcher-
|
|
1
|
+
import { __commonJSMin, __toESM, require_usingCtx } from "./pricing-fetcher-eNV76BjF.js";
|
|
2
2
|
import { getTotalTokens } from "./_token-utils-WjkbrjKv.js";
|
|
3
3
|
import { ZodFirstPartyTypeKind, ZodOptional, ZodType, arrayType, booleanType, discriminatedUnionType, enumType, filterDateSchema, literalType, numberType, objectType, optionalType, recordType, stringType, unionType, unknownType } from "./_types-BHFM59hI.js";
|
|
4
4
|
import { calculateTotals, createTotalsObject } from "./calculate-cost-BDqO4yWA.js";
|
|
5
|
-
import { getClaudePaths, loadDailyUsageData, loadMonthlyUsageData, loadSessionBlockData, loadSessionData } from "./data-loader-
|
|
6
|
-
import { name, version } from "./logger-
|
|
5
|
+
import { getClaudePaths, loadDailyUsageData, loadMonthlyUsageData, loadSessionBlockData, loadSessionData } from "./data-loader-BAp4u-7e.js";
|
|
6
|
+
import { name, version } from "./logger-COLgmk2z.js";
|
|
7
7
|
import process from "node:process";
|
|
8
8
|
const LATEST_PROTOCOL_VERSION = "2025-06-18";
|
|
9
9
|
const SUPPORTED_PROTOCOL_VERSIONS = [
|
|
@@ -1605,6 +1605,7 @@ var Protocol = class {
|
|
|
1605
1605
|
this._responseHandlers = /* @__PURE__ */ new Map();
|
|
1606
1606
|
this._progressHandlers = /* @__PURE__ */ new Map();
|
|
1607
1607
|
this._timeoutInfo = /* @__PURE__ */ new Map();
|
|
1608
|
+
this._pendingDebouncedNotifications = /* @__PURE__ */ new Set();
|
|
1608
1609
|
this.setNotificationHandler(CancelledNotificationSchema, (notification) => {
|
|
1609
1610
|
const controller = this._requestHandlerAbortControllers.get(notification.params.requestId);
|
|
1610
1611
|
controller === null || controller === void 0 || controller.abort(notification.params.reason);
|
|
@@ -1679,6 +1680,7 @@ var Protocol = class {
|
|
|
1679
1680
|
const responseHandlers = this._responseHandlers;
|
|
1680
1681
|
this._responseHandlers = /* @__PURE__ */ new Map();
|
|
1681
1682
|
this._progressHandlers.clear();
|
|
1683
|
+
this._pendingDebouncedNotifications.clear();
|
|
1682
1684
|
this._transport = void 0;
|
|
1683
1685
|
(_a = this.onclose) === null || _a === void 0 || _a.call(this);
|
|
1684
1686
|
const error = new McpError(ErrorCode.ConnectionClosed, "Connection closed");
|
|
@@ -1872,8 +1874,26 @@ var Protocol = class {
|
|
|
1872
1874
|
* Emits a notification, which is a one-way message that does not expect a response.
|
|
1873
1875
|
*/
|
|
1874
1876
|
async notification(notification, options) {
|
|
1877
|
+
var _a, _b;
|
|
1875
1878
|
if (!this._transport) throw new Error("Not connected");
|
|
1876
1879
|
this.assertNotificationCapability(notification.method);
|
|
1880
|
+
const debouncedMethods = (_b = (_a = this._options) === null || _a === void 0 ? void 0 : _a.debouncedNotificationMethods) !== null && _b !== void 0 ? _b : [];
|
|
1881
|
+
const canDebounce = debouncedMethods.includes(notification.method) && !notification.params && !(options === null || options === void 0 ? void 0 : options.relatedRequestId);
|
|
1882
|
+
if (canDebounce) {
|
|
1883
|
+
if (this._pendingDebouncedNotifications.has(notification.method)) return;
|
|
1884
|
+
this._pendingDebouncedNotifications.add(notification.method);
|
|
1885
|
+
Promise.resolve().then(() => {
|
|
1886
|
+
var _a$1;
|
|
1887
|
+
this._pendingDebouncedNotifications.delete(notification.method);
|
|
1888
|
+
if (!this._transport) return;
|
|
1889
|
+
const jsonrpcNotification$1 = {
|
|
1890
|
+
...notification,
|
|
1891
|
+
jsonrpc: "2.0"
|
|
1892
|
+
};
|
|
1893
|
+
(_a$1 = this._transport) === null || _a$1 === void 0 || _a$1.send(jsonrpcNotification$1, options).catch((error) => this._onerror(error));
|
|
1894
|
+
});
|
|
1895
|
+
return;
|
|
1896
|
+
}
|
|
1877
1897
|
const jsonrpcNotification = {
|
|
1878
1898
|
...notification,
|
|
1879
1899
|
jsonrpc: "2.0"
|
package/dist/mcp.d.ts
CHANGED
package/dist/mcp.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import "./pricing-fetcher-
|
|
1
|
+
import "./pricing-fetcher-eNV76BjF.js";
|
|
2
2
|
import "./_token-utils-WjkbrjKv.js";
|
|
3
3
|
import "./_types-BHFM59hI.js";
|
|
4
4
|
import "./calculate-cost-BDqO4yWA.js";
|
|
5
|
-
import "./data-loader-
|
|
6
|
-
import "./logger-
|
|
7
|
-
import { createMcpHttpApp, createMcpServer, startMcpServerStdio } from "./mcp-
|
|
5
|
+
import "./data-loader-BAp4u-7e.js";
|
|
6
|
+
import "./logger-COLgmk2z.js";
|
|
7
|
+
import { createMcpHttpApp, createMcpServer, startMcpServerStdio } from "./mcp-Ta2UK9sc.js";
|
|
8
8
|
export { createMcpHttpApp, createMcpServer, startMcpServerStdio };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { modelPricingSchema } from "./_types-BHFM59hI.js";
|
|
2
|
-
import { logger } from "./logger-
|
|
2
|
+
import { logger } from "./logger-COLgmk2z.js";
|
|
3
3
|
import { createRequire } from "node:module";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import F, { homedir } from "node:os";
|
|
@@ -192,6 +192,28 @@ const DEFAULT_CLAUDE_CONFIG_PATH = `${XDG_CONFIG_DIR}/claude`;
|
|
|
192
192
|
*/
|
|
193
193
|
const CLAUDE_CONFIG_DIR_ENV = "CLAUDE_CONFIG_DIR";
|
|
194
194
|
/**
|
|
195
|
+
* Environment variable for custom project name aliases
|
|
196
|
+
*
|
|
197
|
+
* Allows users to configure readable display names for cryptic or long project directory names.
|
|
198
|
+
* This is particularly useful for:
|
|
199
|
+
* - UUID-based project directories generated by Claude Code
|
|
200
|
+
* - Long path-based project names that are hard to read in tables
|
|
201
|
+
* - Custom branding of project names for organizational consistency
|
|
202
|
+
*
|
|
203
|
+
* Format: "raw-name=alias,another-name=other-alias"
|
|
204
|
+
* Example: "a2cd99ed-a586-4fe4-8f59-b0026409ec09=My Project,long-project-name=Short"
|
|
205
|
+
*
|
|
206
|
+
* Environment variable approach is used because:
|
|
207
|
+
* - No config file needed - simple and lightweight configuration
|
|
208
|
+
* - Works in any shell/environment without file management
|
|
209
|
+
* - Easy to set temporarily for specific invocations
|
|
210
|
+
* - Follows Unix conventions for tool configuration
|
|
211
|
+
* - Doesn't require file system permissions or config directory setup
|
|
212
|
+
*
|
|
213
|
+
* Used to override display names for project directories in all output formats.
|
|
214
|
+
*/
|
|
215
|
+
const PROJECT_ALIASES_ENV = "CCUSAGE_PROJECT_ALIASES";
|
|
216
|
+
/**
|
|
195
217
|
* Claude projects directory name within the data directory
|
|
196
218
|
* Contains subdirectories for each project with usage data
|
|
197
219
|
*/
|
|
@@ -538,4 +560,4 @@ var PricingFetcher = class {
|
|
|
538
560
|
return cost;
|
|
539
561
|
}
|
|
540
562
|
};
|
|
541
|
-
export { BLOCKS_COMPACT_WIDTH_THRESHOLD, BLOCKS_DEFAULT_TERMINAL_WIDTH, BLOCKS_WARNING_THRESHOLD, BURN_RATE_THRESHOLDS, CLAUDE_CONFIG_DIR_ENV, CLAUDE_PROJECTS_DIR_NAME, DEBUG_MATCH_THRESHOLD_PERCENT, DEFAULT_CLAUDE_CODE_PATH, DEFAULT_CLAUDE_CONFIG_PATH, DEFAULT_RECENT_DAYS, DEFAULT_REFRESH_INTERVAL_SECONDS, MAX_REFRESH_INTERVAL_SECONDS, MCP_DEFAULT_PORT, MIN_REFRESH_INTERVAL_SECONDS, MIN_RENDER_INTERVAL_MS, PricingFetcher, USAGE_DATA_GLOB_PATTERN, USER_HOME_DIR, __commonJSMin, __require, __toESM, isFailure, isPromise, require_usingCtx, try_ };
|
|
563
|
+
export { BLOCKS_COMPACT_WIDTH_THRESHOLD, BLOCKS_DEFAULT_TERMINAL_WIDTH, BLOCKS_WARNING_THRESHOLD, BURN_RATE_THRESHOLDS, CLAUDE_CONFIG_DIR_ENV, CLAUDE_PROJECTS_DIR_NAME, DEBUG_MATCH_THRESHOLD_PERCENT, DEFAULT_CLAUDE_CODE_PATH, DEFAULT_CLAUDE_CONFIG_PATH, DEFAULT_RECENT_DAYS, DEFAULT_REFRESH_INTERVAL_SECONDS, MAX_REFRESH_INTERVAL_SECONDS, MCP_DEFAULT_PORT, MIN_REFRESH_INTERVAL_SECONDS, MIN_RENDER_INTERVAL_MS, PROJECT_ALIASES_ENV, PricingFetcher, USAGE_DATA_GLOB_PATTERN, USER_HOME_DIR, __commonJSMin, __require, __toESM, isFailure, isPromise, require_usingCtx, try_ };
|
package/dist/pricing-fetcher.js
CHANGED