feat(ccusage): add all command to show combined Claude Code and Codex usage#914
feat(ccusage): add all command to show combined Claude Code and Codex usage#914qianhaoq wants to merge 7 commits intoryoppippi:mainfrom
all command to show combined Claude Code and Codex usage#914Conversation
…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>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughAdds a new Changes
Sequence Diagram(s)sequenceDiagram
participant CLI as CLI Handler
participant Claude as Claude Loader
participant Codex as Codex Loader
participant Pricing as Codex Pricing Source
participant Output as Formatter
CLI->>Claude: request daily usage (since/until)
activate Claude
Claude-->>CLI: claude daily rows
deactivate Claude
CLI->>Codex: request sessions & daily data
activate Codex
Codex-->>CLI: codex daily rows / session warnings
deactivate Codex
CLI->>Pricing: init CodexPricingSource (maybe offline)
activate Pricing
Pricing-->>CLI: pricing source ready
deactivate Pricing
CLI->>CLI: aggregate rows, compute totals (tokens, cost)
CLI->>Output: render JSON (optional jq) or human tables
activate Output
Output-->>CLI: formatted output
deactivate Output
CLI->>Pricing: dispose pricing resources (finally)
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
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
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (5)
apps/ccusage/config-schema.jsonapps/ccusage/package.jsonapps/ccusage/src/commands/all.tsapps/ccusage/src/commands/index.tsapps/codex/package.json
…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>
There was a problem hiding this comment.
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
📒 Files selected for processing (1)
apps/ccusage/src/commands/all.ts
- 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>
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
🧹 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
📒 Files selected for processing (1)
apps/ccusage/src/commands/all.ts
- Compute codexTotals from unsorted codexRowsRaw so sort order never affects aggregation (ryoppippi#1) - Add comments documenting the since/until normalization asymmetry between Claude and Codex sides (ryoppippi#2) - Remove codexDisplayTotals accumulator; derive table totals row from codexTotals via splitUsageTokens (single source of truth) (ryoppippi#3) - Remove redundant `?? undefined` in locale cast (ryoppippi#7) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
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>
|
Thanks for the review! Regarding the |
|
@coderabbitai resume |
✅ Actions performedReviews resumed. |
Summary
ccusage allsubcommand 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 endexportsfields to@ccusage/codexpackage so its internal modules can be imported by sibling packages in the monorepo@ccusage/codexas adevDependencyofccusage(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 (
ccusageandnpx @ccusage/codex) to see their total AI spend. This PR enables a singleccusage allto show both reports and a combined cost.Usage
Output:
@ccusage/codex)Combined Total Cost: $X.XXTest plan
pnpm run typecheckpasses (zero errors)pnpm run testpasses (252 tests)pnpm run formatpasses (zero lint errors)ccusage alland verified both tables render correctly with combined total🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Chores
Tests