feat(ccusage): add `all` command to show combined Claude Code and Codex usage by qianhaoq · Pull Request #914 · ccusage/ccusage · GitHub
Skip to content

feat(ccusage): add all command to show combined Claude Code and Codex usage#914

Closed
qianhaoq wants to merge 7 commits into
ccusage:mainfrom
qianhaoq:feat/all-command
Closed

feat(ccusage): add all command to show combined Claude Code and Codex usage#914
qianhaoq wants to merge 7 commits into
ccusage:mainfrom
qianhaoq:feat/all-command

Conversation

@qianhaoq

@qianhaoq qianhaoq commented Mar 29, 2026

Copy link
Copy Markdown

Summary

  • Adds a new ccusage all subcommand that shows daily token usage and cost for both Claude Code and OpenAI Codex in a single invocation, with a combined total cost line at the end
  • Adds exports fields to @ccusage/codex package so its internal modules can be imported by sibling packages in the monorepo
  • Adds @ccusage/codex as a devDependency of ccusage (bundled CLI — kept in devDeps per monorepo convention)

Motivation

Users who use both Claude Code and Codex CLI currently need to run two separate commands (ccusage and npx @ccusage/codex) to see their total AI spend. This PR enables a single ccusage all to show both reports and a combined cost.

Usage

ccusage all
ccusage all --since 20260301
ccusage all --json

Output:

  1. Claude Code daily usage table (existing format)
  2. Codex daily usage table (same format as @ccusage/codex)
  3. Combined Total Cost: $X.XX

Test plan

  • pnpm run typecheck passes (zero errors)
  • pnpm run test passes (252 tests)
  • pnpm run format passes (zero lint errors)
  • Manually ran ccusage all and verified both tables render correctly with combined total

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added "all" command to produce combined Claude Code + Codex daily usage reports (tables and JSON/jq), with ordering, breakdowns, and combined cost totals.
    • Daily report rows now include a stable dateKey for consistent date formatting.
  • Chores

    • Configuration schema extended with a strict commands.all section to validate allowed options.
    • Package exports surface updated and a development helper dependency added.
  • Tests

    • Unit tests for report dateKey, ordering, and combined-cost calculation.

…ex usage

Adds a new `ccusage all` subcommand that displays daily token usage and
cost for both Claude Code and OpenAI Codex in a single invocation, with
a combined total cost line at the end.

- Add `exports` fields to `@ccusage/codex` package.json so its internal
  modules (data-loader, daily-report, pricing, etc.) can be imported by
  sibling packages
- Add `@ccusage/codex` as a devDependency of `ccusage` (bundled CLI)
- Implement `apps/ccusage/src/commands/all.ts` reusing codex data-loader
  and report-builder alongside the existing Claude Code data-loader
- Register `all` in the subcommand map in `commands/index.ts`

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Mar 29, 2026

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/ccusage/src/commands/all.ts`:
- Around line 137-146: The table configuration is incorrectly reading the CLI
flag directly (ctx.values.compact) so config defaults in mergedOptions are
ignored; change both occurrences that set forceCompact (in the tableConfig
objects used when building tables in this command) to use mergedOptions.compact
instead of ctx.values.compact so the merged config (defaults/commands.all) is
respected; search for the tableConfig declarations (and any other places where
forceCompact is assigned) in this file and replace ctx.values.compact with
mergedOptions.compact.
- Around line 66-72: The Codex rows are built without applying the requested
ordering; update the build/emission to respect mergedOptions.order by passing
the order into buildDailyReport (i.e., call buildDailyReport(..., { ..., order:
mergedOptions.order }) when constructing codexRows) and/or apply the same
ordering step used for Claude rows right after codexRows is produced; then
ensure the JSON emission block (the codex JSON path around the current emit at
lines 121-123) and the table rendering block (the codex table path around lines
216-249) use the ordered codexRows (or call the shared order helper used
elsewhere) before emitting.
- Around line 38-41: The code treats --jq as toggling JSON mode (useJson =
Boolean(mergedOptions.json) || mergedOptions.jq != null) but still always dumps
the entire payload before returning; update the output path (the block around
lines 97–128 that currently prints the full payload and returns) to detect
mergedOptions.jq and, when present, run the jq filter against the JSON payload
and print the filtered result (fall back to printing full JSON only when
mergedOptions.jq is absent); keep the existing logger.level adjustment for pure
JSON mode (useJson) but ensure applying mergedOptions.jq controls final printed
output rather than always dumping the raw payload.
- Around line 30-259: The current try/catch around normalizeFilterDate should be
replaced with the repository's Result-based pattern: use Result.try to call
normalizeFilterDate for mergedOptions.since and mergedOptions.until, check
Result.isFailure for each result, call logger.error with the
result.error.message and process.exit(1) on failure, and assign
codexSince/codexUntil from the successful result.value; update the block that
currently references normalizeFilterDate, mergedOptions, logger.error, and
process.exit to use Result.try, Result.isFailure, and result.value instead.
🪄 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: e17ec30a-4f49-4fe4-a74e-6b2c20b3386a

📥 Commits

Reviewing files that changed from the base of the PR and between 61ee04d and 6003086.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (5)
  • apps/ccusage/config-schema.json
  • apps/ccusage/package.json
  • apps/ccusage/src/commands/all.ts
  • apps/ccusage/src/commands/index.ts
  • apps/codex/package.json

Comment thread apps/ccusage/src/commands/all.ts
Comment thread apps/ccusage/src/commands/all.ts Outdated
Comment thread apps/ccusage/src/commands/all.ts
qianhao02 and others added 2 commits March 29, 2026 18:51
…c registry

- Fix --jq flag not working: call processWithJq() instead of raw JSON.stringify
- Fix --order only applying to Claude section: sort codexRows by mergedOptions.order
- Fix compact config file setting silently ignored: use mergedOptions.compact instead of ctx.values.compact
- Regenerate pnpm-lock.yaml using public registry (registry.npmjs.org) to remove internal Meituan registry URLs

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…malization

Use Result.try + Result.isFailure from @praha/byethrow for normalizeFilterDate
calls in the all command, consistent with the repository's error-handling convention.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/ccusage/src/commands/all.ts`:
- Around line 75-81: The Codex rows returned by buildDailyReport (used in
codexRowsRaw) are formatted for display with locale/timezone, so for --json/--jq
output create a separate JSON payload that preserves canonical ISO timestamps:
iterate codexRowsRaw (or better, map directly from codexEvents if original
timestamps are available) and produce codexJsonRows where each item contains a
stable date field (e.g., date_iso or date) set to an ISO 8601 UTC string
(Date.toISOString of the original timestamp) plus the remaining numeric/metric
fields; replace usages that currently emit the display rows (the code around
codexRowsRaw and the similar block at lines 132-134) to emit this new
codexJsonRows for JSON/JQ output while leaving display formatting unchanged for
human output.
- Around line 32-280: Add an in-source Vitest block guarded by if
(import.meta.vitest != null) that unit-tests the allCommand export covering key
branches: JSON output (--json), jq processing (--jq), row ordering
(mergedOptions.order asc/desc) and the combined total line; create a mock ctx
and stub/spy the helper functions used by allCommand (loadDailyUsageData,
loadTokenUsageEvents, buildDailyReport, processWithJq) and logger methods so you
can assert outputs and error paths, and stub CodexPricingSource (pricingSource)
to avoid real disposal side-effects (ensure its Symbol.dispose is a no-op).
Locate tests around the allCommand definition and use the same mergedOptions
inputs (e.g., set mergedOptions.jq, mergedOptions.json, mergedOptions.order) to
drive each branch and assert the expected log/output, and verify combinedCost is
computed from claudeTotals.totalCost and codexTotals.costUSD.
🪄 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: 25fc9f21-31de-49f8-857a-46fdebfb1f65

📥 Commits

Reviewing files that changed from the base of the PR and between ff6dcb5 and 73de73c.

📒 Files selected for processing (1)
  • apps/ccusage/src/commands/all.ts

Comment thread apps/ccusage/src/commands/all.ts
Comment thread apps/ccusage/src/commands/all.ts
qianhao02 and others added 2 commits March 29, 2026 20:28
- Add `dateKey: string` (YYYY-MM-DD) to DailyReportRow type alongside the
  existing locale-formatted `date` display field
- Populate dateKey from summary.date in buildDailyReport
- Use dateKey in `ccusage all --json` Codex output for stable ISO dates
- Add in-source Vitest tests to all.ts covering dateKey format, order
  sorting, and combined cost calculation
- Add dateKey assertion to existing buildDailyReport test

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Pass the full DailyReportRow (including both dateKey and date fields)
directly to the JSON output instead of remapping. This ensures schema
consistency with codex daily --json and exposes the new stable dateKey
alongside the locale-formatted date display field.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@qianhaoq

Copy link
Copy Markdown
Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Mar 29, 2026

Copy link
Copy Markdown
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
apps/ccusage/src/commands/all.ts (1)

41-44: Restore logger level after JSON/JQ execution to avoid global side effects.

Line 43 mutates global logger state, but it is never reset. If this command is invoked multiple times in-process, later commands may inherit quiet logging unexpectedly.

♻️ Proposed refactor
 		// --jq implies --json
 		const useJson = Boolean(mergedOptions.json) || mergedOptions.jq != null;
+		const previousLoggerLevel = logger.level;
 		if (useJson) {
 			logger.level = 0;
 		}
@@
 		} finally {
+			logger.level = previousLoggerLevel;
 			pricingSource[Symbol.dispose]();
 		}

Also applies to: 277-279

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/ccusage/src/commands/all.ts` around lines 41 - 44, The code sets
logger.level = 0 when useJson (computed from mergedOptions.json or
mergedOptions.jq) but never restores it, causing global side effects; update the
all command to save the original logger.level into a local variable before
setting it to 0 and then restore that saved level after the JSON/JQ execution
completes (ensure restoration runs in finally/callback to cover errors). Apply
the same save-and-restore pattern to the second occurrence that currently sets
logger.level (the block around the other JSON/JQ handling) so subsequent
in-process invocations do not inherit the muted logging state.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@apps/ccusage/src/commands/all.ts`:
- Around line 41-44: The code sets logger.level = 0 when useJson (computed from
mergedOptions.json or mergedOptions.jq) but never restores it, causing global
side effects; update the all command to save the original logger.level into a
local variable before setting it to 0 and then restore that saved level after
the JSON/JQ execution completes (ensure restoration runs in finally/callback to
cover errors). Apply the same save-and-restore pattern to the second occurrence
that currently sets logger.level (the block around the other JSON/JQ handling)
so subsequent in-process invocations do not inherit the muted logging state.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 456c1259-0d16-428f-9b19-e1ac6ca522b5

📥 Commits

Reviewing files that changed from the base of the PR and between 419f467 and 300f413.

📒 Files selected for processing (1)
  • apps/ccusage/src/commands/all.ts

- Compute codexTotals from unsorted codexRowsRaw so sort order never
  affects aggregation (ccusage#1)
- Add comments documenting the since/until normalization asymmetry
  between Claude and Codex sides (ccusage#2)
- Remove codexDisplayTotals accumulator; derive table totals row from
  codexTotals via splitUsageTokens (single source of truth) (ccusage#3)
- Remove redundant `?? undefined` in locale cast (ccusage#7)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@qianhaoq

Copy link
Copy Markdown
Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Mar 29, 2026

Copy link
Copy Markdown
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

splitUsageTokens clamps reasoning to output per row, so splitting the
aggregate produces a different result than summing per-row splits when
any row has reasoningOutputTokens > outputTokens. Restore the original
accumulation approach (sum splits row-by-row) so the Total row stays
consistent with the visible per-row values.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@qianhaoq

Copy link
Copy Markdown
Author

Thanks for the review! Regarding the logger.level save-and-restore suggestion: this is an existing pattern used consistently across all commands in this codebase (daily.ts, monthly.ts, session.ts, blocks.ts, weekly.ts, statusline.ts). Since this is a CLI tool where each invocation runs in its own process, the level is never restored in any command. Fixing this in all.ts alone would introduce inconsistency. If this is a concern, it should be addressed as a separate refactor across all commands.

@qianhaoq

Copy link
Copy Markdown
Author

@coderabbitai resume

@coderabbitai

coderabbitai Bot commented Mar 30, 2026

Copy link
Copy Markdown
✅ Actions performed

Reviews resumed.

@qianhaoq

qianhaoq commented Apr 3, 2026

Copy link
Copy Markdown
Author

@ryoppippi All CodeRabbit review comments have been addressed. Ready for review when you have a moment. 🙏

@qianhaoq

Copy link
Copy Markdown
Author

Hi @ryoppippi! Just a gentle ping — all CodeRabbit review comments have been addressed. Would love to get your thoughts when you have a moment. 🙏

@ryoppippi

Copy link
Copy Markdown
Member

@ryoppippi ryoppippi closed this May 17, 2026
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.

2 participants