Skip to content

feat(ccusage): add --prompts flag to claude daily/weekly/monthly reports (rebase of #710 onto v19)#992

Open
akiratee wants to merge 2 commits into
ryoppippi:mainfrom
akiratee:revive-prompts-flag
Open

feat(ccusage): add --prompts flag to claude daily/weekly/monthly reports (rebase of #710 onto v19)#992
akiratee wants to merge 2 commits into
ryoppippi:mainfrom
akiratee:revive-prompts-flag

Conversation

@akiratee
Copy link
Copy Markdown

@akiratee akiratee commented May 12, 2026

Summary

Reimplements @antonioribeiro's #710 (--prompts flag for daily/weekly/monthly reports) on top of the v19 adapter architecture. The original PR sat against pre-v19 code that has since been substantially reshaped (#1004 adapter unification, #1007 file-prefix rename, #1000 all-agent reports). A literal rebase wasn't viable, so this is a fresh implementation that preserves #710's scope and behavior while fitting the new layout.

Scope is intentionally limited to the Claude adapter to match #710. Generalizing promptCount to the shared adapter layer (so Codex/Amp/OpenCode/Pi inherit the column) is a separate change - happy to do that if you'd prefer it bundled.

What's in here

Adapter (apps/ccusage/src/adapter/claude/data-loader.ts)

  • Track promptCount on the shared UsageSummaryAccumulator and surface it from finalizeUsageSummary.
  • Add promptCount: number to DailyUsage, WeeklyUsage, MonthlyUsage, and BucketUsage.
  • Bucket aggregation (used by weekly/monthly) sums each daily's promptCount so the numbers stay consistent across reports.

Terminal (packages/terminal/src/table.ts)

  • New includePrompts?: boolean on UsageReportConfig.
  • New optional promptCount?: number on UsageData.
  • When set, the Prompts column slots between Models (or Agent) and Input in both base and compact layouts.
  • formatUsageDataRow and formatTotalsRow derive whether to render a Prompts cell from data.promptCount != null - no signature breakage for existing callers.

Commands (apps/ccusage/src/commands/{daily,weekly,monthly}.ts)

  • New prompts boolean CLI arg (defaults to false).
  • Thread includePrompts through table config, row/total formatters, separator column count, and pushBreakdownRows offset (2 instead of 1 when --prompts is on) so --breakdown rows stay aligned.
  • JSON output gates promptCount on rows, totals, and emptyOutput totals behind --prompts so the payload shape is stable when the flag is off.

Project grouping (apps/ccusage/src/daily-grouping.ts, json-output-types.ts)

  • groupByProject takes a new includePrompts argument and propagates promptCount into DailyProjectOutput (which gained an optional promptCount field). Keeps daily --instances --prompts --json consistent with the flat output.

Misc

  • README: added a feature-list bullet describing the flag and its semantics.
  • config-schema.json regenerated.

Note on semantics

promptCount counts usage-bearing entries (one per assistant API call). A single user message that triggers N tool iterations counts as N+ entries, not 1. The companion PR #679 (blocks command) filters to user-role messages instead, so the two PRs count different things under the same flag. Worth deciding whether to unify the definition before merging both.

Test plan

  • pnpm test - 498/498 pass (3 pre-existing skipped)
  • pnpm lint - clean
  • pnpm --filter ccusage typecheck - clean
  • pnpm --filter ccusage build - clean
  • Manually verified ccusage claude daily / claude weekly / claude monthly against real Claude Code data: Total-row input-token / cost figures match between flag states (proves no column shift).
  • Manually verified ccusage claude weekly --breakdown --prompts: breakdown rows have an empty Prompts cell so model token columns stay aligned with the data row above.
  • Verified --json gating: promptCount absent on rows and totals without --prompts, present with it.
  • Verified ccusage claude daily --instances --prompts --json propagates promptCount through groupByProject and totals.
  • Confirmed default ccusage daily (all-agent unified report) is unaffected.

Closes #710. Companion PR #679 is independent.

Summary by CodeRabbit

  • New Features
    • Added a --prompts option for daily, weekly, and monthly reports to show a Prompts column (counts of usage-bearing API requests, including tool-call iterations). Feature is disabled by default.
  • Documentation
    • README updated with a Prompt Count feature note explaining the Prompts column and semantics.
  • Tests
    • Updated tests/fixtures to cover prompt-count behavior in aggregation and output.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 12, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 6444433a-3848-4158-8b7a-30fc2ff309f3

📥 Commits

Reviewing files that changed from the base of the PR and between 6f55a7e and db52777.

📒 Files selected for processing (2)
  • apps/ccusage/src/daily-grouping.ts
  • packages/terminal/src/table.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/ccusage/src/daily-grouping.ts
  • packages/terminal/src/table.ts

📝 Walkthrough

Walkthrough

This PR adds a --prompts flag to daily, weekly, and monthly usage reports. The feature tracks prompt counts from raw usage entries, aggregates them across time periods, and displays them in both JSON and terminal table output via a new optional Prompts column positioned before the Input column.

Changes

Prompt Count Feature Implementation

Layer / File(s) Summary
Data model and aggregation
apps/ccusage/src/adapter/claude/data-loader.ts
DailyUsage, MonthlyUsage, WeeklyUsage, and BucketUsage types now include promptCount field. UsageSummaryAccumulator totals track promptCount and increment it once per usage entry. loadBucketUsageData aggregates prompt counts when building monthly/weekly buckets from daily results. Monthly and weekly aggregation tests updated to expect promptCount in output.
Terminal table rendering
packages/terminal/src/table.ts
UsageReportConfig gains optional includePrompts flag and UsageData gains optional promptCount field. createUsageReportTable conditionally injects Prompts column into headers before Input when enabled. formatUsageDataRow and formatTotalsRow conditionally splice prompt-count cells at computed indices based on agent/totals presence.
Daily command wiring
apps/ccusage/src/commands/daily.ts
Added --prompts boolean CLI argument. Computes includePrompts and totalPromptCount by summing daily records. JSON output conditionally includes per-day promptCount and promptCount in totals. Terminal table config sets includePrompts and adjusts columnCount for separator sizing. Both grouped and non-grouped rendering branches pass promptCount to row formatters and use includePrompts ? 2 : 1 for breakdown row insertion offset.
Monthly command wiring
apps/ccusage/src/commands/monthly.ts
Added --prompts boolean CLI argument. Derives includePrompts and totalPromptCount from monthly data. JSON output conditionally adds per-month promptCount and aggregated promptCount in totals (including empty data path). Terminal table enables optional prompt column, adjusts columnCount for separators, passes per-month promptCount to row formatters, and uses includePrompts ? 2 : 1 for breakdown offset.
Weekly command wiring
apps/ccusage/src/commands/weekly.ts
Added --prompts boolean CLI argument. Derives includePrompts and totalPromptCount from weekly data. JSON output conditionally includes per-week promptCount and aggregated promptCount in totals (including empty data path). Terminal table enables optional prompt column, adjusts columnCount, passes per-week promptCount to formatters, and uses includePrompts ? 2 : 1 for breakdown offset.
Configuration, grouping, types, tests, and documentation
apps/ccusage/config-schema.json, apps/ccusage/src/daily-grouping.ts, apps/ccusage/src/json-output-types.ts, apps/ccusage/src/calculate-cost.ts, apps/ccusage/README.md
Config schema adds prompts: boolean (default false) to all daily/weekly/monthly command blocks. groupByProject signature updated to accept optional includePrompts parameter; conditionally includes promptCount in project JSON output. DailyProjectOutput type adds optional promptCount field. Test fixtures in calculate-cost.ts and daily-grouping.ts updated to include promptCount in DailyUsage objects. README documents --prompts flag and what prompt counts represent.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • ryoppippi/ccusage#52: Touches breakdown-row column-offset and table rendering that this PR also adjusts for the Prompts column.
  • ryoppippi/ccusage#1000: Related table column injection and conditional cell formatting in packages/terminal/src/table.ts which this PR extends for Prompts.

Suggested reviewers

  • ryoppippi

Poem

🐰 Hopping through usage with joy,
Counts of prompts now join the fray,
Daily, weekly, monthly cheer—
Columns bloom and numbers play,
Tables wag their whiskers bright.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 54.55% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main change: adding a --prompts flag to claude daily/weekly/monthly reports, with context that it's a rebase of #710 onto v19.
Linked Issues check ✅ Passed The PR successfully implements all coding objectives from issue #710: --prompts flag added to daily/weekly/monthly commands, promptCount tracked in data schemas, Prompts column renders conditionally, JSON output gates promptCount behind flag, and grouping utilities propagate promptCount.
Out of Scope Changes check ✅ Passed All changes are scoped to the declared feature: promptCount tracking in adapter/data-loader, config-schema updates, CLI flags across three commands, terminal table rendering, supporting utilities, and documentation. No unrelated changes detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

apps/ccusage/src/daily-grouping.ts

[baseline-browser-mapping] The data in this module is over two months old. To ensure accurate Baseline data, please update: npm i baseline-browser-mapping@latest -D
tsconfig.json is not found. we cannot use type-aware rules.

Oops! Something went wrong! :(

ESLint: 9.35.0

Error [ERR_MODULE_NOT_FOUND]: Cannot find package 'eslint-plugin-format' imported from /node_modules/.pnpm/@antfu+eslint-config@4.19.0_@vue+compiler-sfc@3.5.30_eslint@9.35.0_typescript@5.9.2_vit_670a2c5c75d4275eabd7bc195a173ee6/node_modules/@antfu/eslint-config/dist/index.js
at Object.getPackageJSONURL (node:internal/modules/package_json_reader:301:9)
at packageResolve (node:internal/modules/esm/resolve:764:81)
at moduleResolve (node:internal/modules/esm/resolve:855:18)
at defaultResolve (node:internal/modules/esm/resolve:988:11)
at #cachedDefaultResolve (node:internal/modules/esm/loader:697:20)
at #resolveAndMaybeBlockOnLoaderThread (node:internal/modules/esm/loader:714:38)
at ModuleLoader.resolveSync (node:internal/modules/esm/loader:746:52)
at #resolve (node:internal/modules/esm/loader:679:17)
at ModuleLoader.getOrCreateModuleJob (node:internal/modules/esm/loader:599:35)
at node:internal/modules/esm/loader:628:32

packages/terminal/src/table.ts

[baseline-browser-mapping] The data in this module is over two months old. To ensure accurate Baseline data, please update: npm i baseline-browser-mapping@latest -D
tsconfig.json is not found. we cannot use type-aware rules.

Oops! Something went wrong! :(

ESLint: 9.35.0

Error [ERR_MODULE_NOT_FOUND]: Cannot find package 'eslint-plugin-format' imported from /node_modules/.pnpm/@antfu+eslint-config@4.19.0_@vue+compiler-sfc@3.5.30_eslint@9.35.0_typescript@5.9.2_vit_670a2c5c75d4275eabd7bc195a173ee6/node_modules/@antfu/eslint-config/dist/index.js
at Object.getPackageJSONURL (node:internal/modules/package_json_reader:301:9)
at packageResolve (node:internal/modules/esm/resolve:764:81)
at moduleResolve (node:internal/modules/esm/resolve:855:18)
at defaultResolve (node:internal/modules/esm/resolve:988:11)
at #cachedDefaultResolve (node:internal/modules/esm/loader:697:20)
at #resolveAndMaybeBlockOnLoaderThread (node:internal/modules/esm/loader:714:38)
at ModuleLoader.resolveSync (node:internal/modules/esm/loader:746:52)
at #resolve (node:internal/modules/esm/loader:679:17)
at ModuleLoader.getOrCreateModuleJob (node:internal/modules/esm/loader:599:35)
at node:internal/modules/esm/loader:628:32


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (4)
apps/ccusage/src/commands/weekly.ts (2)

56-66: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Gate and stabilize promptCount in weekly JSON output.

Line 96/Line 100 always emit promptCount, but Line 56-66 omits it in empty output. This makes the JSON shape inconsistent and breaks consumers relying on stable fields.

💡 Suggested fix
@@
-		const weeklyData = await loadWeeklyUsageData(mergedOptions);
+		const weeklyData = await loadWeeklyUsageData(mergedOptions);
+		const includePrompts = Boolean(mergedOptions.prompts);
@@
-				const emptyOutput = {
+				const emptyOutput = {
 					weekly: [],
 					totals: {
 						inputTokens: 0,
 						outputTokens: 0,
 						cacheCreationTokens: 0,
 						cacheReadTokens: 0,
 						totalTokens: 0,
 						totalCost: 0,
+						...(includePrompts && { promptCount: 0 }),
 					},
 				};
@@
-					modelBreakdowns: data.modelBreakdowns,
-					promptCount: data.promptCount,
+					modelBreakdowns: data.modelBreakdowns,
+					...(includePrompts && { promptCount: data.promptCount }),
 				})),
-				totals: {
-					...createTotalsObject(totals),
-					promptCount: weeklyData.reduce((sum, data) => sum + (data.promptCount || 0), 0),
-				},
+				totals: {
+					...createTotalsObject(totals),
+					...(includePrompts && {
+						promptCount: weeklyData.reduce((sum, data) => sum + (data.promptCount ?? 0), 0),
+					}),
+				},
 			};

Also applies to: 86-101

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/ccusage/src/commands/weekly.ts` around lines 56 - 66, The empty JSON
shape named emptyOutput is missing the promptCount field which makes the weekly
output inconsistent; update the totals object in emptyOutput (and any other
default/empty result objects around the same area) to include promptCount: 0 so
the weekly output always emits promptCount, ensuring the JSON shape matches the
non-empty path that currently sets promptCount.

149-151: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Fix breakdown-column shift when --prompts is enabled.

On Line 150, pushBreakdownRows still uses the default pre-metric offset, so with prompts enabled the breakdown metrics render one column too far left.

💡 Suggested fix
-				if (mergedOptions.breakdown) {
-					pushBreakdownRows(table, data.modelBreakdowns);
-				}
+				if (mergedOptions.breakdown) {
+					pushBreakdownRows(table, data.modelBreakdowns, includePrompts ? 2 : 1);
+				}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/ccusage/src/commands/weekly.ts` around lines 149 - 151, The breakdown
rows are being rendered with the default pre-metric offset, causing a one-column
left shift when prompts are enabled; update the call at the
mergedOptions.breakdown branch to pass the current pre-metric offset used for
the rest of the table (the same offset variable used when rendering
metrics/prompts — e.g., preMetricOffset or columnStart) into pushBreakdownRows,
or modify pushBreakdownRows to accept and apply that offset; ensure the function
signature for pushBreakdownRows is updated accordingly and all other call sites
are adjusted to use the correct offset so breakdown columns align when --prompts
is enabled.
apps/ccusage/src/commands/daily.ts (1)

109-132: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Include promptCount in daily JSON totals when --prompts is enabled.

totalPromptCount is computed, and row-level promptCount is conditionally emitted, but JSON totals never includes promptCount.

Proposed fix
 		if (useJson) {
+			const jsonTotals = {
+				...createTotalsObject(totals),
+				...(mergedOptions.prompts === true && { promptCount: totalPromptCount }),
+			};
+
 			// Output JSON format - group by project if instances flag is used
 			const jsonOutput =
 				Boolean(mergedOptions.instances) && dailyData.some((d) => d.project != null)
 					? {
 							projects: groupByProject(dailyData),
-							totals: createTotalsObject(totals),
+							totals: jsonTotals,
 						}
 					: {
 							daily: dailyData.map((data) => ({
 								date: data.date,
@@
 								...(mergedOptions.prompts === true && { promptCount: data.promptCount }),
 								...(data.project != null && { project: data.project }),
 							})),
-							totals: createTotalsObject(totals),
+							totals: jsonTotals,
 						};
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/ccusage/src/commands/daily.ts` around lines 109 - 132, The JSON totals
object doesn't include promptCount when --prompts is enabled; update the code
that builds the JSON output (the branch using createTotalsObject(totals)) to
include promptCount conditionally when mergedOptions.prompts === true by pulling
the value from the existing totals/totalPromptCount; either modify
createTotalsObject to return { ..., promptCount: totals.totalPromptCount } when
prompts are enabled or, where createTotalsObject(totals) is used, spread its
result and add ...(mergedOptions.prompts === true && { promptCount:
totals.totalPromptCount }) so the JSON totals include promptCount.
apps/ccusage/src/commands/monthly.ts (1)

47-56: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Gate monthly JSON promptCount behind --prompts.

promptCount is emitted unconditionally in monthly JSON rows/totals, so --prompts currently has no effect in JSON mode and changes payload shape even when the flag is off.

Proposed fix
 				const emptyOutput = {
 					monthly: [],
 					totals: {
 						inputTokens: 0,
 						outputTokens: 0,
 						cacheCreationTokens: 0,
 						cacheReadTokens: 0,
 						totalTokens: 0,
 						totalCost: 0,
+						...(mergedOptions.prompts === true && { promptCount: 0 }),
 					},
 				};
@@
 				monthly: monthlyData.map((data) => ({
 					month: data.month,
 					inputTokens: data.inputTokens,
 					outputTokens: data.outputTokens,
 					cacheCreationTokens: data.cacheCreationTokens,
 					cacheReadTokens: data.cacheReadTokens,
 					totalTokens: getTotalTokens(data),
 					totalCost: data.totalCost,
 					modelsUsed: data.modelsUsed,
 					modelBreakdowns: data.modelBreakdowns,
-					promptCount: data.promptCount,
+					...(mergedOptions.prompts === true && { promptCount: data.promptCount }),
 				})),
 				totals: {
 					...createTotalsObject(totals),
-					promptCount: monthlyData.reduce((sum, data) => sum + (data.promptCount || 0), 0),
+					...(mergedOptions.prompts === true && {
+						promptCount: monthlyData.reduce((sum, data) => sum + (data.promptCount || 0), 0),
+					}),
 				},

Also applies to: 77-92

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/ccusage/src/commands/monthly.ts` around lines 47 - 56, The monthly JSON
currently always emits the promptCount field (in the emptyOutput.totals and each
monthly row), so the --prompts flag has no effect and changes the payload shape;
update the JSON construction logic (references: emptyOutput, monthly array
entries, totals, promptCount) to only add the promptCount property when the
--prompts flag is true (the same condition used for non-JSON output), and apply
the same gating in the other JSON construction site mentioned (the block around
lines 77-92) so both per-month rows and the totals object omit promptCount
unless the prompts flag is enabled.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/ccusage/README.md`:
- Line 163: The sentence "The prompt count shows exactly how many individual
messages/prompts you sent to Claude each day" overstates semantics; change the
copy to clarify that the metric counts usage-bearing API/chat turns or logged
entries (i.e., prompts that generated usage) rather than literal user-typed
messages. Update the README line containing that exact sentence to something
like: "The prompt count reflects the number of usage-bearing chat turns/entries
recorded per day, not necessarily every individual keystroke or draft message."
Make the same wording change at the other occurrence (the line around the other
referenced sentence) so both descriptions consistently refer to usage-bearing
turns/entries.
- Around line 139-190: The fenced code blocks in README.md lack language
identifiers and trigger markdownlint MD040; update each triple-backtick block
shown (the four sample tables) to include a language tag such as text by
replacing ``` with ```text for those blocks (the Daily, Monthly, Weekly and the
first table) so all code fences include a language identifier.

---

Outside diff comments:
In `@apps/ccusage/src/commands/daily.ts`:
- Around line 109-132: The JSON totals object doesn't include promptCount when
--prompts is enabled; update the code that builds the JSON output (the branch
using createTotalsObject(totals)) to include promptCount conditionally when
mergedOptions.prompts === true by pulling the value from the existing
totals/totalPromptCount; either modify createTotalsObject to return { ...,
promptCount: totals.totalPromptCount } when prompts are enabled or, where
createTotalsObject(totals) is used, spread its result and add
...(mergedOptions.prompts === true && { promptCount: totals.totalPromptCount })
so the JSON totals include promptCount.

In `@apps/ccusage/src/commands/monthly.ts`:
- Around line 47-56: The monthly JSON currently always emits the promptCount
field (in the emptyOutput.totals and each monthly row), so the --prompts flag
has no effect and changes the payload shape; update the JSON construction logic
(references: emptyOutput, monthly array entries, totals, promptCount) to only
add the promptCount property when the --prompts flag is true (the same condition
used for non-JSON output), and apply the same gating in the other JSON
construction site mentioned (the block around lines 77-92) so both per-month
rows and the totals object omit promptCount unless the prompts flag is enabled.

In `@apps/ccusage/src/commands/weekly.ts`:
- Around line 56-66: The empty JSON shape named emptyOutput is missing the
promptCount field which makes the weekly output inconsistent; update the totals
object in emptyOutput (and any other default/empty result objects around the
same area) to include promptCount: 0 so the weekly output always emits
promptCount, ensuring the JSON shape matches the non-empty path that currently
sets promptCount.
- Around line 149-151: The breakdown rows are being rendered with the default
pre-metric offset, causing a one-column left shift when prompts are enabled;
update the call at the mergedOptions.breakdown branch to pass the current
pre-metric offset used for the rest of the table (the same offset variable used
when rendering metrics/prompts — e.g., preMetricOffset or columnStart) into
pushBreakdownRows, or modify pushBreakdownRows to accept and apply that offset;
ensure the function signature for pushBreakdownRows is updated accordingly and
all other call sites are adjusted to use the correct offset so breakdown columns
align when --prompts is enabled.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 187f3d38-9962-4e82-b605-47bcbfc1d5be

📥 Commits

Reviewing files that changed from the base of the PR and between d7e6993 and c821694.

📒 Files selected for processing (11)
  • apps/ccusage/README.md
  • apps/ccusage/config-schema.json
  • apps/ccusage/src/_daily-grouping.ts
  • apps/ccusage/src/_json-output-types.ts
  • apps/ccusage/src/calculate-cost.ts
  • apps/ccusage/src/commands/daily.ts
  • apps/ccusage/src/commands/monthly.ts
  • apps/ccusage/src/commands/session.ts
  • apps/ccusage/src/commands/weekly.ts
  • apps/ccusage/src/data-loader.ts
  • packages/terminal/src/table.ts

Comment thread apps/ccusage/README.md Outdated
Comment thread apps/ccusage/README.md Outdated
akiratee added a commit to akiratee/ccusage that referenced this pull request May 14, 2026
- daily.ts: include promptCount in JSON totals when --prompts is set
  (both flat and --instances project-grouped outputs).
- weekly/monthly.ts: gate JSON promptCount behind --prompts so the
  flag actually has an effect in JSON mode and the payload shape is
  stable when off. Also gate the emptyOutput totals.
- daily/weekly/monthly.ts: pass includePrompts-aware pre-metric
  offset to pushBreakdownRows so breakdown rows align under the
  correct columns when --breakdown is combined with --prompts.
- README: add language tags to fenced code blocks (markdownlint
  MD040); clarify that the prompt count reflects usage-bearing
  entries (one per API request, including tool-call iterations),
  not literal user-typed messages.
@akiratee
Copy link
Copy Markdown
Author

Heads up - main moved substantially since I opened this (v19 major cut, the adapter unification in #1004, file-prefix rename in #1007, the all-agent reports in #1000). The rebase isn't mechanical anymore - the data loader now lives in `adapter/claude/data-loader.ts` and command shapes changed enough that I'm going to re-implement on top of v19 rather than force-fit the old diff.

Keeping scope the same as #710 - `--prompts` for daily/weekly/monthly on the Claude adapter. Happy to generalize `promptCount` to the shared adapter layer so Codex/Amp/OpenCode/Pi get it for free, but that feels like a separate PR unless you'd prefer it bundled. Let me know.

Will push an updated branch shortly.

Reimplements antonioribeiro's ryoppippi#710 on top of v19's adapter architecture.
Adds an optional `--prompts` flag to the Claude-scoped daily, weekly, and
monthly reports that displays a Prompts column with the number of
usage-bearing entries (one per API request, including each tool-call
iteration within a single user message) recorded per bucket.

Scope is limited to the Claude adapter to match ryoppippi#710. Generalizing
promptCount to the shared adapter layer (so Codex/Amp/OpenCode/Pi inherit
the column) is a separate change.

Changes:

- adapter/claude/data-loader: track `promptCount` on the shared
  `UsageSummaryAccumulator`, surface it from `finalizeUsageSummary`, and
  expose it on `DailyUsage`/`WeeklyUsage`/`MonthlyUsage`/`BucketUsage`.
  Bucket aggregation sums each daily's `promptCount` so weekly/monthly
  numbers stay consistent with daily.
- packages/terminal/table: add `includePrompts` to `UsageReportConfig`
  and an optional `promptCount` on `UsageData`. When set, `Prompts`
  slots between Models (or Agent) and Input in both base and compact
  layouts. `formatUsageDataRow` and `formatTotalsRow` derive whether to
  render a Prompts cell from `data.promptCount != null`.
- commands/daily, commands/weekly, commands/monthly: add `prompts` CLI
  arg, thread `includePrompts` through table config, row/total
  formatters, and `pushBreakdownRows` offset (2 instead of 1 when
  prompts is on) so breakdown rows stay aligned with `--breakdown`.
  JSON output gates `promptCount` on rows, totals, and `emptyOutput`
  totals behind `--prompts` so payload shape is stable when the flag is
  off.
- `groupByProject` (daily --instances JSON) takes a new `includePrompts`
  argument and propagates `promptCount`; `DailyProjectOutput` gained
  optional `promptCount`.
- README: mention the flag in the feature list.
- config-schema.json regenerated.

Co-Authored-By: Antonio Ribeiro <acr@antoniocarlosribeiro.com>
@akiratee akiratee force-pushed the revive-prompts-flag branch from ab4ff08 to 6f55a7e Compare May 17, 2026 16:33
@akiratee akiratee changed the title feat(ccusage): revive --prompts flag for daily/weekly/monthly reports (rebase of #710) feat(ccusage): add --prompts flag to claude daily/weekly/monthly reports (rebase of #710 onto v19) May 17, 2026
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/terminal/src/table.ts (1)

846-855: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Keep the Prompts column in compact all-agent tables too.

When includeAgent and includePrompts are both true, the compact header starts as Date | Agent | Total Tokens | Cost and never gets a Prompts column because this logic only inserts before Input. On narrow terminals, --prompts silently disappears for that layout.

Also applies to: 863-877

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/terminal/src/table.ts` around lines 846 - 855, The compact table
configuration omits the Prompts column when both config.includeAgent and
config.includePrompts are true; update the logic that builds compactHeaders,
compactAligns, and compactMinColumnWidths (the variables compactHeaders,
compactAligns, compactMinColumnWidths) so that if config.includePrompts is true
you insert a "Prompts" column (with matching alignment 'left' and an appropriate
min width) into the compact arrays even in the includeAgent branch; apply the
same change to the second compact-building block referenced around the other
occurrence (lines constructing those same variables for the alternate case) so
compact all-agent tables retain the Prompts column on narrow terminals.
🧹 Nitpick comments (1)
apps/ccusage/src/daily-grouping.ts (1)

63-123: ⚡ Quick win

Add test coverage for the includePrompts parameter.

The tests currently do not verify that promptCount is conditionally included/excluded based on the includePrompts flag. Consider adding test cases that assert:

  • When includePrompts is false (or omitted), the output records should not contain promptCount.
  • When includePrompts is true, the output records should contain promptCount with the expected value.
✅ Proposed test additions
 	describe('groupByProject', () => {
 		it('groups daily data by project for JSON output', () => {
 			const mockData = [
 				{
 					date: createDailyDate('2024-01-01'),
 					project: 'project-a',
 					inputTokens: 1000,
 					outputTokens: 500,
 					cacheCreationTokens: 100,
 					cacheReadTokens: 200,
 					totalCost: 0.01,
 					modelsUsed: [createModelName('claude-sonnet-4-20250514')],
 					modelBreakdowns: [],
 					promptCount: 0,
 				},
 				{
 					date: createDailyDate('2024-01-01'),
 					project: 'project-b',
 					inputTokens: 2000,
 					outputTokens: 1000,
 					cacheCreationTokens: 200,
 					cacheReadTokens: 300,
 					totalCost: 0.02,
 					modelsUsed: [createModelName('claude-opus-4-20250514')],
 					modelBreakdowns: [],
 					promptCount: 0,
 				},
 			];
 
 			const result = groupByProject(mockData);
 
 			expect(Object.keys(result)).toHaveLength(2);
 			expect(result['project-a']).toHaveLength(1);
 			expect(result['project-b']).toHaveLength(1);
 			expect(result['project-a']![0]!.totalTokens).toBe(1800);
 			expect(result['project-b']![0]!.totalTokens).toBe(3500);
 		});
+
+		it('excludes promptCount when includePrompts is false', () => {
+			const mockData = [
+				{
+					date: createDailyDate('2024-01-01'),
+					project: 'project-a',
+					inputTokens: 1000,
+					outputTokens: 500,
+					cacheCreationTokens: 0,
+					cacheReadTokens: 0,
+					totalCost: 0.01,
+					modelsUsed: [createModelName('claude-sonnet-4-20250514')],
+					modelBreakdowns: [],
+					promptCount: 5,
+				},
+			];
+
+			const result = groupByProject(mockData, false);
+
+			expect(result['project-a']![0]!).not.toHaveProperty('promptCount');
+		});
+
+		it('includes promptCount when includePrompts is true', () => {
+			const mockData = [
+				{
+					date: createDailyDate('2024-01-01'),
+					project: 'project-a',
+					inputTokens: 1000,
+					outputTokens: 500,
+					cacheCreationTokens: 0,
+					cacheReadTokens: 0,
+					totalCost: 0.01,
+					modelsUsed: [createModelName('claude-sonnet-4-20250514')],
+					modelBreakdowns: [],
+					promptCount: 5,
+				},
+			];
+
+			const result = groupByProject(mockData, true);
+
+			expect(result['project-a']![0]!.promptCount).toBe(5);
+		});
 
 		it('handles unknown project names', () => {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/ccusage/src/daily-grouping.ts` around lines 63 - 123, Add tests for the
includePrompts flag in the groupByProject unit suite: create two new cases (or
extend existing ones) that call groupByProject(mockData, includePrompts) where
includePrompts is omitted/false and where it is true; for the false/omitted case
assert that the returned project records do NOT have a promptCount property, and
for the true case assert that each record contains promptCount with the expected
value (e.g., sum of promptCount from inputs). Reference the groupByProject
function and its includePrompts parameter when adding these assertions.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/terminal/src/table.ts`:
- Around line 937-941: The insertion of the Prompts cell should be driven by the
table layout config (e.g., includePrompts) rather than the presence of
data.promptCount: replace the condition that checks data.promptCount with a
check of the layout flag (includePrompts) and always splice a cell at the
computed insertAt index; when promptCount is missing insert an empty string or
placeholder (instead of skipping the splice) so subsequent cells (like Input)
don't shift. Apply the same change for the second occurrence that mirrors lines
979-983, keeping the insert index logic using data.agent and formatting with
formatNumber when promptCount exists.

---

Outside diff comments:
In `@packages/terminal/src/table.ts`:
- Around line 846-855: The compact table configuration omits the Prompts column
when both config.includeAgent and config.includePrompts are true; update the
logic that builds compactHeaders, compactAligns, and compactMinColumnWidths (the
variables compactHeaders, compactAligns, compactMinColumnWidths) so that if
config.includePrompts is true you insert a "Prompts" column (with matching
alignment 'left' and an appropriate min width) into the compact arrays even in
the includeAgent branch; apply the same change to the second compact-building
block referenced around the other occurrence (lines constructing those same
variables for the alternate case) so compact all-agent tables retain the Prompts
column on narrow terminals.

---

Nitpick comments:
In `@apps/ccusage/src/daily-grouping.ts`:
- Around line 63-123: Add tests for the includePrompts flag in the
groupByProject unit suite: create two new cases (or extend existing ones) that
call groupByProject(mockData, includePrompts) where includePrompts is
omitted/false and where it is true; for the false/omitted case assert that the
returned project records do NOT have a promptCount property, and for the true
case assert that each record contains promptCount with the expected value (e.g.,
sum of promptCount from inputs). Reference the groupByProject function and its
includePrompts parameter when adding these assertions.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f206e3a1-72cc-4baf-847e-41b0f4fbb9fb

📥 Commits

Reviewing files that changed from the base of the PR and between ab4ff08 and 6f55a7e.

📒 Files selected for processing (10)
  • apps/ccusage/README.md
  • apps/ccusage/config-schema.json
  • apps/ccusage/src/adapter/claude/data-loader.ts
  • apps/ccusage/src/calculate-cost.ts
  • apps/ccusage/src/commands/daily.ts
  • apps/ccusage/src/commands/monthly.ts
  • apps/ccusage/src/commands/weekly.ts
  • apps/ccusage/src/daily-grouping.ts
  • apps/ccusage/src/json-output-types.ts
  • packages/terminal/src/table.ts
✅ Files skipped from review due to trivial changes (2)
  • apps/ccusage/README.md
  • apps/ccusage/src/calculate-cost.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • apps/ccusage/src/commands/weekly.ts
  • apps/ccusage/src/commands/monthly.ts
  • apps/ccusage/src/commands/daily.ts

Comment on lines +937 to +941
if (data.promptCount != null) {
// Prompts column sits just before Input; index = (agent ? 3 : 2)
const insertAt = data.agent != null ? 3 : 2;
row.splice(insertAt, 0, formatNumber(data.promptCount));
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Drive Prompts-cell insertion from layout config, not from promptCount presence.

If the table is created with includePrompts: true but a row omits promptCount, these helpers emit one fewer cell than the header and shift Input under Prompts. Because UsageData.promptCount is optional, that mismatch is currently reachable from the public API.

Suggested fix
 export function formatUsageDataRow(
 	firstColumnValue: string,
 	data: UsageData,
+	includePrompts = false,
 	lastActivity?: string,
 ): (string | number)[] {
@@
-	if (data.promptCount != null) {
-		// Prompts column sits just before Input; index = (agent ? 3 : 2)
-		const insertAt = data.agent != null ? 3 : 2;
-		row.splice(insertAt, 0, formatNumber(data.promptCount));
+	if (includePrompts) {
+		const insertAt = data.agent != null ? 3 : 2;
+		row.splice(insertAt, 0, data.promptCount != null ? formatNumber(data.promptCount) : '');
 	}
@@
 export function formatTotalsRow(
 	totals: UsageData,
 	includeLastActivity = false,
 	includeAgent = false,
+	includePrompts = false,
 ): (string | number)[] {
@@
-	if (totals.promptCount != null) {
-		// Prompts column sits just before Input
-		const insertAt = includeAgent ? 3 : 2;
-		row.splice(insertAt, 0, pc.yellow(formatNumber(totals.promptCount)));
+	if (includePrompts) {
+		const insertAt = includeAgent ? 3 : 2;
+		row.splice(
+			insertAt,
+			0,
+			totals.promptCount != null ? pc.yellow(formatNumber(totals.promptCount)) : '',
+		);
 	}

Also applies to: 979-983

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/terminal/src/table.ts` around lines 937 - 941, The insertion of the
Prompts cell should be driven by the table layout config (e.g., includePrompts)
rather than the presence of data.promptCount: replace the condition that checks
data.promptCount with a check of the layout flag (includePrompts) and always
splice a cell at the computed insertAt index; when promptCount is missing insert
an empty string or placeholder (instead of skipping the splice) so subsequent
cells (like Input) don't shift. Apply the same change for the second occurrence
that mirrors lines 979-983, keeping the insert index logic using data.agent and
formatting with formatNumber when promptCount exists.

…-review)

- terminal/table: when both includeAgent and includePrompts are set,
  the compact layout has no Input column so the previous insert-before-
  Input logic silently dropped the Prompts column on narrow terminals.
  Fall back to inserting before Total Tokens in that case so the
  Prompts column survives in compact all-agent layouts. Not reachable
  from any current user path (this PR keeps --prompts on the Claude-
  only commands which don't set includeAgent) but unblocks the planned
  all-adapter follow-up.
- daily-grouping: add tests covering the includePrompts toggle so the
  conditional propagation is regression-protected.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant