Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions apps/ccusage/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ npx ccusage blocks --live # Real-time usage dashboard
npx ccusage daily --since 20250525 --until 20250530
npx ccusage daily --json # JSON output
npx ccusage daily --breakdown # Per-model cost breakdown
npx ccusage daily --prompts # Show prompt count column
npx ccusage daily --timezone UTC # Use UTC timezone
npx ccusage daily --locale ja-JP # Use Japanese locale for date/time formatting

Expand All @@ -113,6 +114,10 @@ npx ccusage daily --instances # Group by project/instance
npx ccusage daily --project myproject # Filter to specific project
npx ccusage daily --instances --project myproject --json # Combined usage

# Prompt analysis
npx ccusage daily --prompts # Show how many prompts you sent each day
npx ccusage daily --prompts --json # Include prompt counts in JSON output

# Compact mode for screenshots/sharing
npx ccusage --compact # Force compact table mode
npx ccusage monthly --compact # Compact monthly report
Expand All @@ -126,6 +131,7 @@ npx ccusage monthly --compact # Compact monthly report
- ⏰ **5-Hour Blocks Report**: Track usage within Claude's billing windows with active block monitoring
- 📈 **Live Monitoring**: Real-time dashboard showing active session progress, token burn rate, and cost projections with `blocks --live`
- 🚀 **Statusline Integration**: Compact usage display for Claude Code status bar hooks (Beta)
- 🔢 **Prompt Count**: Show number of prompts/messages sent per day with `--prompts` flag
- 🤖 **Model Tracking**: See which Claude models you're using (Opus, Sonnet, etc.)
- 📊 **Model Breakdown**: View per-model cost breakdown with `--breakdown` flag
- 📅 **Date Filtering**: Filter reports by date range using `--since` and `--until`
Expand All @@ -145,6 +151,64 @@ npx ccusage monthly --compact # Compact monthly report
- ⚙️ **Configuration Files**: Set defaults with JSON configuration files, complete with IDE autocomplete and validation
- 🚀 **Ultra-Small Bundle**: Unlike other CLI tools, we pay extreme attention to bundle size - incredibly small even without minification!

## Prompt Count Examples

### Standard Daily Report (Default)

```
┌──────────┬─────────────────┬──────────┬──────────┬──────────┐
│ Date │ Models │ Input │ Output │ Cost │
├──────────┼─────────────────┼──────────┼──────────┼──────────┤
│ 2025-01-15│ claude-sonnet-4 │ 694,203 │ 36,324 │ $2.09 │
│ 2025-01-16│ claude-sonnet-4 │ 4,852,324 │ 63,844 │ $5.92 │
├──────────┼─────────────────┼──────────┼──────────┼──────────┤
│ Total │ │ 5,546,527 │ 100,168 │ $8.01 │
└──────────┴─────────────────┴──────────┴──────────┴──────────┘
```

### Daily Report with Prompt Counts (`--prompts`)

```
┌──────────┬─────────────────┬──────────┬──────────┬──────────┐
│ Date │ Models │ Prompts │ Input │ Output │ Cost │
├──────────┼─────────────────┼──────────┼──────────┼──────────┤
│ 2025-01-15│ claude-sonnet-4 │ 273 │ 694,203 │ 36,324 │ $2.09 │
│ 2025-01-16│ claude-sonnet-4 │ 448 │ 4,852,324 │ 63,844 │ $5.92 │
├──────────┼─────────────────┼──────────┼──────────┼──────────┤
│ Total │ │ 721 │ 5,546,527 │ 100,168 │ $8.01 │
└──────────┴─────────────────┴──────────┴──────────┴──────────┘
```

The prompt count shows exactly how many individual messages/prompts you sent to Claude each day, helping you understand your usage patterns beyond just token counts and costs.

### Monthly Report with Prompt Counts (`--prompts`)

```
┌──────────┬──────────────────────┬──────────┬──────────┬──────────┐
│ Month │ Models │ Prompts │ Input │ Output │ Cost │
├──────────┼──────────────────────┼──────────┼──────────┼──────────┤
│ 2025-01 │ claude-sonnet-4 │ 1,247 │ 5,546,527 │ 100,168 │ $8.01 │
│ 2024-12 │ claude-sonnet-4 │ 892 │ 3,214,789 │ 89,234 │ $4.67 │
├──────────┼──────────────────────┼──────────┼──────────┼──────────┤
│ Total │ │ 2,139 │ 8,761,316 │ 189,402 │ $12.68 │
└──────────┴──────────────────────┴──────────┴──────────┴──────────┘
```

### Weekly Report with Prompt Counts (`--prompts`)

```
┌──────────┬─────────────────┬──────────┬──────────┬──────────┐
│ Week │ Models │ Prompts │ Input │ Output │ Cost │
├──────────┼─────────────────┼──────────┼──────────┼──────────┤
│ 2025-01-13│ claude-sonnet-4 │ 721 │ 5,546,527 │ 100,168 │ $8.01 │
│ 2025-01-06│ claude-sonnet-4 │ 518 │ 2,891,234 │ 78,912 │ $3.45 │
├──────────┼─────────────────┼──────────┼──────────┼──────────┤
│ Total │ │ 1,239 │ 8,437,761 │ 179,080 │ $11.46 │
└──────────┴─────────────────┴──────────┴──────────┴──────────┘
```

The `--prompts` flag works with all time-based reports (daily, weekly, monthly) to show how many prompts you sent during each time period.

## Documentation

Full documentation is available at **[ccusage.com](https://ccusage.com/)**
Expand Down
5 changes: 5 additions & 0 deletions apps/ccusage/src/_daily-grouping.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ if (import.meta.vitest != null) {
totalCost: 0.01,
modelsUsed: [createModelName('claude-sonnet-4-20250514')],
modelBreakdowns: [],
promptCount: 5,
},
{
date: createDailyDate('2024-01-01'),
Expand All @@ -81,6 +82,7 @@ if (import.meta.vitest != null) {
totalCost: 0.02,
modelsUsed: [createModelName('claude-opus-4-20250514')],
modelBreakdowns: [],
promptCount: 8,
},
];

Expand All @@ -105,6 +107,7 @@ if (import.meta.vitest != null) {
totalCost: 0.01,
modelsUsed: [createModelName('claude-sonnet-4-20250514')],
modelBreakdowns: [],
promptCount: 3,
},
];

Expand All @@ -128,6 +131,7 @@ if (import.meta.vitest != null) {
totalCost: 0.01,
modelsUsed: [createModelName('claude-sonnet-4-20250514')],
modelBreakdowns: [],
promptCount: 5,
},
{
date: createDailyDate('2024-01-02'),
Expand All @@ -139,6 +143,7 @@ if (import.meta.vitest != null) {
totalCost: 0.008,
modelsUsed: [createModelName('claude-sonnet-4-20250514')],
modelBreakdowns: [],
promptCount: 4,
},
];

Expand Down
2 changes: 2 additions & 0 deletions apps/ccusage/src/calculate-cost.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ if (import.meta.vitest != null) {
totalCost: 0.01,
modelsUsed: [createModelName('claude-sonnet-4-20250514')],
modelBreakdowns: [],
promptCount: 3,
},
{
date: createDailyDate('2024-01-02'),
Expand All @@ -104,6 +105,7 @@ if (import.meta.vitest != null) {
totalCost: 0.02,
modelsUsed: [createModelName('claude-opus-4-20250514')],
modelBreakdowns: [],
promptCount: 5,
},
];

Expand Down
42 changes: 29 additions & 13 deletions apps/ccusage/src/commands/daily.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ export const dailyCommand = define({
description: 'Comma-separated project aliases (e.g., \'ccusage=Usage Tracker,myproject=My Project\')',
hidden: true,
},
prompts: {
type: 'boolean',
description: 'Show prompt count column',
default: false,
},
},
async run(ctx) {
// Load configuration and merge with CLI arguments
Expand Down Expand Up @@ -87,6 +92,9 @@ export const dailyCommand = define({
// Calculate totals
const totals = calculateTotals(dailyData);

// Calculate total prompt count
const totalPromptCount = dailyData.reduce((sum, day) => sum + (day.promptCount || 0), 0);

// Show debug information if requested
if (mergedOptions.debug && !useJson) {
const mismatchStats = await detectMismatches(undefined);
Expand All @@ -111,6 +119,7 @@ export const dailyCommand = define({
totalCost: data.totalCost,
modelsUsed: data.modelsUsed,
modelBreakdowns: data.modelBreakdowns,
...(mergedOptions.prompts && { promptCount: data.promptCount }),
...(data.project != null && { project: data.project }),
})),
totals: createTotalsObject(totals),
Expand Down Expand Up @@ -138,9 +147,13 @@ export const dailyCommand = define({
firstColumnName: 'Date',
dateFormatter: (dateStr: string) => formatDateCompact(dateStr, mergedOptions.timezone, mergedOptions.locale ?? undefined),
forceCompact: ctx.values.compact,
includePrompts: Boolean(mergedOptions.prompts),
};
const table = createUsageReportTable(tableConfig);

// Calculate column count based on configuration
const columnCount = 8 + (mergedOptions.prompts ? 1 : 0); // Base columns + optional Prompts column

// Add daily data - group by project if instances flag is used
if (Boolean(mergedOptions.instances) && dailyData.some(d => d.project != null)) {
// Group data by project for visual separation
Expand All @@ -151,20 +164,20 @@ export const dailyCommand = define({
// Add project section header
if (!isFirstProject) {
// Add empty row for visual separation between projects
table.push(['', '', '', '', '', '', '', '']);
const projectSeparatorRow: (string | number)[] = Array.from({ length: columnCount }, () => '');
table.push(projectSeparatorRow);
}

// Add project header row
table.push([
const projectHeaderRow: (string | number)[] = [
pc.cyan(`Project: ${formatProjectName(projectName, projectAliases)}`),
'',
'',
'',
'',
'',
'',
'',
]);
];
// Fill remaining columns with empty strings
while (projectHeaderRow.length < columnCount) {
projectHeaderRow.push('');
}
table.push(projectHeaderRow);

// Add data rows for this project
for (const data of projectData) {
Expand All @@ -175,7 +188,8 @@ export const dailyCommand = define({
cacheReadTokens: data.cacheReadTokens,
totalCost: data.totalCost,
modelsUsed: data.modelsUsed,
});
promptCount: data.promptCount,
}, Boolean(mergedOptions.prompts));
table.push(row);

// Add model breakdown rows if flag is set
Expand All @@ -198,7 +212,8 @@ export const dailyCommand = define({
cacheReadTokens: data.cacheReadTokens,
totalCost: data.totalCost,
modelsUsed: data.modelsUsed,
});
promptCount: data.promptCount,
}, Boolean(mergedOptions.prompts));
table.push(row);

// Add model breakdown rows if flag is set
Expand All @@ -209,7 +224,7 @@ export const dailyCommand = define({
}

// Add empty row for visual separation before totals
addEmptySeparatorRow(table, 8);
addEmptySeparatorRow(table, columnCount);

// Add totals
const totalsRow = formatTotalsRow({
Expand All @@ -218,7 +233,8 @@ export const dailyCommand = define({
cacheCreationTokens: totals.cacheCreationTokens,
cacheReadTokens: totals.cacheReadTokens,
totalCost: totals.totalCost,
});
promptCount: totalPromptCount,
}, Boolean(mergedOptions.prompts));
table.push(totalsRow);

log(table.toString());
Expand Down
22 changes: 18 additions & 4 deletions apps/ccusage/src/commands/monthly.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,14 @@ import { log, logger } from '../logger.ts';
export const monthlyCommand = define({
name: 'monthly',
description: 'Show usage report grouped by month',
...sharedCommandConfig,
args: {
...sharedCommandConfig.args,
prompts: {
type: 'boolean',
description: 'Include prompt count column',
default: false,
},
},
async run(ctx) {
// Load configuration and merge with CLI arguments
const config = loadConfig(ctx.values.config, ctx.values.debug);
Expand Down Expand Up @@ -77,8 +84,12 @@ export const monthlyCommand = define({
totalCost: data.totalCost,
modelsUsed: data.modelsUsed,
modelBreakdowns: data.modelBreakdowns,
promptCount: data.promptCount,
})),
totals: createTotalsObject(totals),
totals: {
...createTotalsObject(totals),
promptCount: monthlyData.reduce((sum, data) => sum + (data.promptCount || 0), 0),
},
};

// Process with jq if specified
Expand All @@ -103,6 +114,7 @@ export const monthlyCommand = define({
firstColumnName: 'Month',
dateFormatter: (dateStr: string) => formatDateCompact(dateStr, mergedOptions.timezone, mergedOptions.locale ?? DEFAULT_LOCALE),
forceCompact: ctx.values.compact,
includePrompts: ctx.values.prompts,
};
const table = createUsageReportTable(tableConfig);

Expand All @@ -116,7 +128,8 @@ export const monthlyCommand = define({
cacheReadTokens: data.cacheReadTokens,
totalCost: data.totalCost,
modelsUsed: data.modelsUsed,
});
promptCount: data.promptCount,
}, true); // Enable prompts column
table.push(row);

// Add model breakdown rows if flag is set
Expand All @@ -135,7 +148,8 @@ export const monthlyCommand = define({
cacheCreationTokens: totals.cacheCreationTokens,
cacheReadTokens: totals.cacheReadTokens,
totalCost: totals.totalCost,
});
promptCount: monthlyData.reduce((sum, data) => sum + (data.promptCount || 0), 0),
}, true); // Enable prompts in totals row
table.push(totalsRow);

log(table.toString());
Expand Down
4 changes: 2 additions & 2 deletions apps/ccusage/src/commands/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ export const sessionCommand = define({
cacheReadTokens: data.cacheReadTokens,
totalCost: data.totalCost,
modelsUsed: data.modelsUsed,
}, data.lastActivity);
}, false, data.lastActivity);
table.push(row);

// Add model breakdown rows if flag is set
Expand All @@ -168,7 +168,7 @@ export const sessionCommand = define({
cacheCreationTokens: totals.cacheCreationTokens,
cacheReadTokens: totals.cacheReadTokens,
totalCost: totals.totalCost,
}, true); // Include Last Activity column
}, false, true); // Include Last Activity column
table.push(totalsRow);

log(table.toString());
Expand Down
18 changes: 15 additions & 3 deletions apps/ccusage/src/commands/weekly.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ export const weeklyCommand = define({
default: 'sunday' as const,
choices: WEEK_DAYS,
},
prompts: {
type: 'boolean',
description: 'Include prompt count column',
default: false,
},
},
toKebab: true,
async run(ctx) {
Expand Down Expand Up @@ -87,8 +92,12 @@ export const weeklyCommand = define({
totalCost: data.totalCost,
modelsUsed: data.modelsUsed,
modelBreakdowns: data.modelBreakdowns,
promptCount: data.promptCount,
})),
totals: createTotalsObject(totals),
totals: {
...createTotalsObject(totals),
promptCount: weeklyData.reduce((sum, data) => sum + (data.promptCount || 0), 0),
},
};

// Process with jq if specified
Expand All @@ -113,6 +122,7 @@ export const weeklyCommand = define({
firstColumnName: 'Week',
dateFormatter: (dateStr: string) => formatDateCompact(dateStr, mergedOptions.timezone, mergedOptions.locale ?? undefined),
forceCompact: ctx.values.compact,
includePrompts: ctx.values.prompts,
};
const table = createUsageReportTable(tableConfig);

Expand All @@ -126,7 +136,8 @@ export const weeklyCommand = define({
cacheReadTokens: data.cacheReadTokens,
totalCost: data.totalCost,
modelsUsed: data.modelsUsed,
});
promptCount: data.promptCount,
}, true); // Enable prompts column
table.push(row);

// Add model breakdown rows if flag is set
Expand All @@ -145,7 +156,8 @@ export const weeklyCommand = define({
cacheCreationTokens: totals.cacheCreationTokens,
cacheReadTokens: totals.cacheReadTokens,
totalCost: totals.totalCost,
});
promptCount: weeklyData.reduce((sum, data) => sum + (data.promptCount || 0), 0),
}, true); // Enable prompts in totals row
table.push(totalsRow);

log(table.toString());
Expand Down
Loading