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
5 changes: 5 additions & 0 deletions apps/ccusage/src/_shared-args.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,11 @@ export const sharedArgs = {
description: 'Force compact mode for narrow displays (better for screenshots)',
default: false,
},
noCost: {
type: 'boolean',
description: 'Hide cost column from output (useful for Pro subscribers)',
default: false,
},
} as const satisfies Args;

/**
Expand Down
49 changes: 38 additions & 11 deletions apps/ccusage/src/commands/blocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,7 @@ export const blocksCommand = define({
}
const burnRate = calculateBurnRate(block);
const projection = projectBlockUsage(block);
const hideCost = Boolean(ctx.values.noCost);

logger.box('Current Session Block Status');

Expand All @@ -340,18 +341,33 @@ export const blocksCommand = define({
log(pc.bold('Current Usage:'));
log(` Input Tokens: ${formatNumber(block.tokenCounts.inputTokens)}`);
log(` Output Tokens: ${formatNumber(block.tokenCounts.outputTokens)}`);
log(` Total Cost: ${formatCurrency(block.costUSD)}\n`);
if (!hideCost) {
log(` Total Cost: ${formatCurrency(block.costUSD)}\n`);
}
else {
log('');
}

if (burnRate != null) {
log(pc.bold('Burn Rate:'));
log(` Tokens/minute: ${formatNumber(burnRate.tokensPerMinute)}`);
log(` Cost/hour: ${formatCurrency(burnRate.costPerHour)}\n`);
if (!hideCost) {
log(` Cost/hour: ${formatCurrency(burnRate.costPerHour)}\n`);
}
else {
log('');
}
}

if (projection != null) {
log(pc.bold('Projected Usage (if current rate continues):'));
log(` Total Tokens: ${formatNumber(projection.totalTokens)}`);
log(` Total Cost: ${formatCurrency(projection.totalCost)}\n`);
if (!hideCost) {
log(` Total Cost: ${formatCurrency(projection.totalCost)}\n`);
}
else {
log('');
}

if (ctx.values.tokenLimit != null) {
// Parse token limit
Expand Down Expand Up @@ -381,6 +397,7 @@ export const blocksCommand = define({

// Calculate token limit if "max" is specified
const actualTokenLimit = parseTokenLimit(ctx.values.tokenLimit, maxTokensFromAll);
const hideCost = Boolean(ctx.values.noCost);

const tableHeaders = ['Block Start', 'Duration/Status', 'Models', 'Tokens'];
const tableAligns: ('left' | 'right' | 'center')[] = ['left', 'left', 'left', 'right'];
Expand All @@ -391,8 +408,10 @@ export const blocksCommand = define({
tableAligns.push('right');
}

tableHeaders.push('Cost');
tableAligns.push('right');
if (!hideCost) {
tableHeaders.push('Cost');
tableAligns.push('right');
}

const table = new ResponsiveTable({
head: tableHeaders,
Expand Down Expand Up @@ -420,7 +439,9 @@ export const blocksCommand = define({
if (actualTokenLimit != null && actualTokenLimit > 0) {
gapRow.push(pc.gray('-'));
}
gapRow.push(pc.gray('-'));
if (!hideCost) {
gapRow.push(pc.gray('-'));
}
table.push(gapRow);
}
else {
Expand All @@ -442,7 +463,9 @@ export const blocksCommand = define({
row.push(percentage > 100 ? pc.red(percentText) : percentText);
}

row.push(formatCurrency(block.costUSD));
if (!hideCost) {
row.push(formatCurrency(block.costUSD));
}
table.push(row);

// Add REMAINING and PROJECTED rows for active blocks
Expand All @@ -461,14 +484,16 @@ export const blocksCommand = define({
? `${remainingPercent.toFixed(1)}%`
: pc.red('0.0%');

const remainingRow = [
const remainingRow: (string | { content: string; hAlign: 'right' })[] = [
{ content: pc.gray(`(assuming ${formatNumber(actualTokenLimit)} token limit)`), hAlign: 'right' as const },
pc.blue('REMAINING'),
'',
remainingText,
remainingPercentText,
'', // No cost for remaining - it's about token limit, not cost
];
if (!hideCost) {
remainingRow.push(''); // No cost for remaining - it's about token limit, not cost
}
table.push(remainingRow);
}

Expand All @@ -480,7 +505,7 @@ export const blocksCommand = define({
? pc.red(projectedTokens)
: projectedTokens;

const projectedRow = [
const projectedRow: (string | { content: string; hAlign: 'right' })[] = [
{ content: pc.gray('(assuming current burn rate)'), hAlign: 'right' as const },
pc.yellow('PROJECTED'),
'',
Expand All @@ -494,7 +519,9 @@ export const blocksCommand = define({
projectedRow.push(percentText);
}

projectedRow.push(formatCurrency(projection.totalCost));
if (!hideCost) {
projectedRow.push(formatCurrency(projection.totalCost));
}
table.push(projectedRow);
}
}
Expand Down
28 changes: 14 additions & 14 deletions apps/ccusage/src/commands/daily.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,14 +133,20 @@ export const dailyCommand = define({
// Print header
logger.box('Claude Code Token Usage Report - Daily');

const hideCost = Boolean(mergedOptions.noCost);

// Create table with compact mode support
const tableConfig: UsageReportConfig = {
firstColumnName: 'Date',
dateFormatter: (dateStr: string) => formatDateCompact(dateStr, mergedOptions.timezone, mergedOptions.locale ?? undefined),
forceCompact: ctx.values.compact,
hideCost,
};
const table = createUsageReportTable(tableConfig);

// Calculate column count based on hideCost
const columnCount = hideCost ? 7 : 8;

// 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,19 +157,13 @@ export const dailyCommand = define({
// Add project section header
if (!isFirstProject) {
// Add empty row for visual separation between projects
table.push(['', '', '', '', '', '', '', '']);
table.push(Array.from({ length: columnCount }, () => ''));
}

// Add project header row
table.push([
pc.cyan(`Project: ${formatProjectName(projectName, projectAliases)}`),
'',
'',
'',
'',
'',
'',
'',
...Array.from({ length: columnCount - 1 }, () => ''),
]);

// Add data rows for this project
Expand All @@ -175,12 +175,12 @@ export const dailyCommand = define({
cacheReadTokens: data.cacheReadTokens,
totalCost: data.totalCost,
modelsUsed: data.modelsUsed,
});
}, { hideCost });
table.push(row);

// Add model breakdown rows if flag is set
if (mergedOptions.breakdown) {
pushBreakdownRows(table, data.modelBreakdowns);
pushBreakdownRows(table, data.modelBreakdowns, 1, 0, hideCost);
}
}

Expand All @@ -198,18 +198,18 @@ export const dailyCommand = define({
cacheReadTokens: data.cacheReadTokens,
totalCost: data.totalCost,
modelsUsed: data.modelsUsed,
});
}, { hideCost });
table.push(row);

// Add model breakdown rows if flag is set
if (mergedOptions.breakdown) {
pushBreakdownRows(table, data.modelBreakdowns);
pushBreakdownRows(table, data.modelBreakdowns, 1, 0, hideCost);
}
}
}

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

// Add totals
const totalsRow = formatTotalsRow({
Expand All @@ -218,7 +218,7 @@ export const dailyCommand = define({
cacheCreationTokens: totals.cacheCreationTokens,
cacheReadTokens: totals.cacheReadTokens,
totalCost: totals.totalCost,
});
}, { hideCost });
table.push(totalsRow);

log(table.toString());
Expand Down
14 changes: 10 additions & 4 deletions apps/ccusage/src/commands/monthly.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,14 +98,20 @@ export const monthlyCommand = define({
// Print header
logger.box('Claude Code Token Usage Report - Monthly');

const hideCost = Boolean(mergedOptions.noCost);

// Create table with compact mode support
const tableConfig: UsageReportConfig = {
firstColumnName: 'Month',
dateFormatter: (dateStr: string) => formatDateCompact(dateStr, mergedOptions.timezone, mergedOptions.locale ?? DEFAULT_LOCALE),
forceCompact: ctx.values.compact,
hideCost,
};
const table = createUsageReportTable(tableConfig);

// Calculate column count based on hideCost
const columnCount = hideCost ? 7 : 8;

// Add monthly data
for (const data of monthlyData) {
// Main row
Expand All @@ -116,17 +122,17 @@ export const monthlyCommand = define({
cacheReadTokens: data.cacheReadTokens,
totalCost: data.totalCost,
modelsUsed: data.modelsUsed,
});
}, { hideCost });
table.push(row);

// Add model breakdown rows if flag is set
if (mergedOptions.breakdown) {
pushBreakdownRows(table, data.modelBreakdowns);
pushBreakdownRows(table, data.modelBreakdowns, 1, 0, hideCost);
}
}

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

// Add totals
const totalsRow = formatTotalsRow({
Expand All @@ -135,7 +141,7 @@ export const monthlyCommand = define({
cacheCreationTokens: totals.cacheCreationTokens,
cacheReadTokens: totals.cacheReadTokens,
totalCost: totals.totalCost,
});
}, { hideCost });
table.push(totalsRow);

log(table.toString());
Expand Down
14 changes: 10 additions & 4 deletions apps/ccusage/src/commands/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,15 +124,21 @@ export const sessionCommand = define({
// Print header
logger.box('Claude Code Token Usage Report - By Session');

const hideCost = Boolean(ctx.values.noCost);

// Create table with compact mode support
const tableConfig: UsageReportConfig = {
firstColumnName: 'Session',
includeLastActivity: true,
dateFormatter: (dateStr: string) => formatDateCompact(dateStr, ctx.values.timezone, ctx.values.locale),
forceCompact: ctx.values.compact,
hideCost,
};
const table = createUsageReportTable(tableConfig);

// Calculate column count based on hideCost (session has Last Activity column)
const columnCount = hideCost ? 8 : 9;

// Add session data
let maxSessionLength = 0;
for (const data of sessionData) {
Expand All @@ -148,18 +154,18 @@ export const sessionCommand = define({
cacheReadTokens: data.cacheReadTokens,
totalCost: data.totalCost,
modelsUsed: data.modelsUsed,
}, data.lastActivity);
}, { lastActivity: data.lastActivity, hideCost });
table.push(row);

// Add model breakdown rows if flag is set
if (ctx.values.breakdown) {
// Session has 1 extra column before data and 1 trailing column
pushBreakdownRows(table, data.modelBreakdowns, 1, 1);
pushBreakdownRows(table, data.modelBreakdowns, 1, 1, hideCost);
}
}

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

// Add totals
const totalsRow = formatTotalsRow({
Expand All @@ -168,7 +174,7 @@ export const sessionCommand = define({
cacheCreationTokens: totals.cacheCreationTokens,
cacheReadTokens: totals.cacheReadTokens,
totalCost: totals.totalCost,
}, true); // Include Last Activity column
}, { includeLastActivity: true, hideCost });
table.push(totalsRow);

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