feat(ccusage): add Gemini CLI usage support#1021
Conversation
Add a Gemini CLI adapter that discovers JSON and JSONL chat logs under GEMINI_DATA_DIR, defaulting to ~/.gemini/tmp. The parser normalises Gemini token records into ccusage rows, separates cache-inclusive input into cache read tokens, keeps reasoning and tool token metadata, and supports daily, monthly, and session reports. Wire the gemini namespace into unified agent detection, focused commands, config schema generation, and docs. Pricing uses LiteLLM Gemini entries, including Google, Vertex AI, and OpenRouter prefixes, and applies Gemini 128k input/output tiers when available. Update table rendering to use explicit source total tokens when adapters provide them, so hidden reasoning tokens remain reflected in totals without inflating visible output tokens.
|
Caution Review failedPull request was closed or merged during review Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughThis PR adds Gemini CLI support to ccusage. It extends the configuration schema, CLI commands, and adapter infrastructure to discover and parse Gemini logs, calculate token usage and estimated costs, and include Gemini data in all-agent reports. Documentation is updated throughout to describe the new Gemini data source. ChangesGemini CLI Integration
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested labels
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 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 |
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
ccusage-guide | 4aeb9e8 | Commit Preview URL Branch Preview URL |
May 19 2026, 01:02 PM |
There was a problem hiding this comment.
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 (1)
apps/ccusage/test/snapshots/cli-output/all-agent-daily-table.txt (1)
5-5:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winAdd Gemini test fixtures to verify agent detection.
The test setup in
cli-output.test.tsinitializes aGEMINI_DATA_DIRdirectory (lines 33–46), but no actual Gemini log files exist in the fixture directory. This explains why the snapshot shows detected agents as "Amp, Claude, Codex, OpenCode, pi-agent" without Gemini. To properly test Gemini agent support, create at least one Gemini fixture file so the agent detection snapshot includes Gemini in the output.🤖 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/test/snapshots/cli-output/all-agent-daily-table.txt` at line 5, The test fixtures are missing Gemini log files so agent detection in cli-output.test.ts (the GEMINI_DATA_DIR setup) never finds Gemini; add at least one representative Gemini fixture file into the directory initialized by GEMINI_DATA_DIR (using the same filename pattern and content structure the detection logic expects) so the detection code that reads GEMINI_DATA_DIR will include "Gemini" in the snapshot; ensure the new fixture is committed to the test fixtures and that any test setup that copies or points GEMINI_DATA_DIR to the fixtures uses that file.
🧹 Nitpick comments (1)
apps/ccusage/test/cli-output.test.ts (1)
200-207: ⚡ Quick winAdd one Gemini direct CLI snapshot test now that
GEMINI_DATA_DIRis wired.This file now provides Gemini env setup, but the integration suite still doesn’t assert a Gemini command path/output shape. A minimal
gemini daily --offline --jsonsnapshot would reduce regression risk.🤖 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/test/cli-output.test.ts` around lines 200 - 207, Add a minimal snapshot test in apps/ccusage/test/cli-output.test.ts that uses the existing createAgentCliEnv function (which now wires GEMINI_DATA_DIR) to run the CLI command "gemini daily --offline --json" and assert its stdout shape via a Jest snapshot; specifically, invoke the CLI runner used elsewhere in this test file with the environment returned by createAgentCliEnv(fixturePath) (ensuring GEMINI_DATA_DIR is present), capture the command output, and add a snapshot assertion so future changes to gemini command wiring will be caught.
🤖 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/src/adapter/gemini/paths.ts`:
- Around line 18-25: The Promise.all in discoverGeminiLogFiles currently lets
any collectFilesRecursive rejection abort detection; update probes that call
collectFilesRecursive (and analogous hasFileRecursive calls) to use byethrow's
Result.try to catch per-path errors and map failures to safe defaults (empty
array for discoverGeminiLogFiles and false for hasFileRecursive usage), so each
getGeminiPaths().flatMap(...) item is wrapped in Result.try(...).then(r =>
r.unwrapOr([])) or unwrapOr(false) as appropriate before awaiting Promise.all,
preserving successful probes and sorting the flattened results with
compareStrings.
In `@docs/guide/gemini/index.md`:
- Around line 30-35: The directory tree example in the
docs/guide/gemini/index.md currently shows only "*.jsonl" but Line 24 states the
system reads both JSON and JSONL; update the example tree to reflect both file
types (e.g., show both "*.json" and "*.jsonl" under chats/) so the docs match
the documented "JSON + JSONL support" statement and ensure any surrounding text
that references the tree also mentions both formats.
---
Outside diff comments:
In `@apps/ccusage/test/snapshots/cli-output/all-agent-daily-table.txt`:
- Line 5: The test fixtures are missing Gemini log files so agent detection in
cli-output.test.ts (the GEMINI_DATA_DIR setup) never finds Gemini; add at least
one representative Gemini fixture file into the directory initialized by
GEMINI_DATA_DIR (using the same filename pattern and content structure the
detection logic expects) so the detection code that reads GEMINI_DATA_DIR will
include "Gemini" in the snapshot; ensure the new fixture is committed to the
test fixtures and that any test setup that copies or points GEMINI_DATA_DIR to
the fixtures uses that file.
---
Nitpick comments:
In `@apps/ccusage/test/cli-output.test.ts`:
- Around line 200-207: Add a minimal snapshot test in
apps/ccusage/test/cli-output.test.ts that uses the existing createAgentCliEnv
function (which now wires GEMINI_DATA_DIR) to run the CLI command "gemini daily
--offline --json" and assert its stdout shape via a Jest snapshot; specifically,
invoke the CLI runner used elsewhere in this test file with the environment
returned by createAgentCliEnv(fixturePath) (ensuring GEMINI_DATA_DIR is
present), capture the command output, and add a snapshot assertion so future
changes to gemini command wiring will be caught.
🪄 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: dbb97763-c0ac-4cb8-9bd5-b9e243c92a01
📒 Files selected for processing (22)
apps/ccusage/config-schema.jsonapps/ccusage/src/adapter/gemini/index.tsapps/ccusage/src/adapter/gemini/parser.tsapps/ccusage/src/adapter/gemini/paths.tsapps/ccusage/src/adapter/gemini/pricing-macro.tsapps/ccusage/src/adapter/gemini/pricing.tsapps/ccusage/src/adapter/gemini/schema.tsapps/ccusage/src/adapter/index.tsapps/ccusage/src/adapter/types.tsapps/ccusage/src/commands/agent.tsapps/ccusage/src/commands/all.tsapps/ccusage/src/commands/index.tsapps/ccusage/test/cli-output.test.tsapps/ccusage/test/snapshots/cli-output/all-agent-daily-table.txtapps/ccusage/tsdown.config.tsdocs/.vitepress/config.tsdocs/guide/all-reports.mddocs/guide/configuration.mddocs/guide/environment-variables.mddocs/guide/gemini/index.mddocs/guide/index.mdpackages/terminal/src/table.ts
Address CodeRabbit review feedback for the Gemini CLI adapter follow-up. The all-agent CLI fixture now includes a representative Gemini JSONL log so detection snapshots exercise the new adapter. A direct Gemini daily JSON snapshot verifies command routing, cache-read normalization, and reasoning token JSON output. Gemini path discovery now treats individual recursive file probes as best-effort with byethrow Result handling, so one unreadable data root does not abort detection for other configured roots. The Gemini docs tree also shows both JSON and JSONL files to match parser support.
There was a problem hiding this comment.
🧹 Nitpick comments (1)
apps/ccusage/test/cli-output.test.ts (1)
525-526: ⚡ Quick winUse
ccusage-testingfixtures for the new Gemini CLI test path.This newly added test continues using
fs-fixturedirectly; please switch this path to the repo’sccusage-testingfixture utilities for consistency with test infra conventions.As per coding guidelines
apps/ccusage/**/*.{test,spec}.{ts,tsx,js,jsx}: Useccusage-testingpackage for in-source Vitest, snapshots, fixtures, Claude models, and LiteLLM pricing tests.🤖 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/test/cli-output.test.ts` around lines 525 - 526, The test "runs Gemini daily JSON through the main ccusage namespace" is still creating fixtures via the repo's fs-fixture helpers (createFixture and createAgentFixtureTree); replace those with the repo-standard ccusage-testing fixture utilities by importing the fixture helpers from 'ccusage-testing' and using them in place of createFixture(createAgentFixtureTree()). Update the test to call the ccusage-testing fixture factory (the package's fixture/agent fixture helper) and adjust any returned API or teardown usage to match ccusage-testing's utilities so the test uses the in-repo fixture conventions.
🤖 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.
Nitpick comments:
In `@apps/ccusage/test/cli-output.test.ts`:
- Around line 525-526: The test "runs Gemini daily JSON through the main ccusage
namespace" is still creating fixtures via the repo's fs-fixture helpers
(createFixture and createAgentFixtureTree); replace those with the repo-standard
ccusage-testing fixture utilities by importing the fixture helpers from
'ccusage-testing' and using them in place of
createFixture(createAgentFixtureTree()). Update the test to call the
ccusage-testing fixture factory (the package's fixture/agent fixture helper) and
adjust any returned API or teardown usage to match ccusage-testing's utilities
so the test uses the in-repo fixture conventions.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: c01bb9f8-db81-4308-92dd-2bb17d496028
📒 Files selected for processing (6)
apps/ccusage/src/adapter/gemini/paths.tsapps/ccusage/test/cli-output.test.tsapps/ccusage/test/snapshots/cli-output/all-agent-daily-json.txtapps/ccusage/test/snapshots/cli-output/all-agent-daily-table.txtapps/ccusage/test/snapshots/cli-output/gemini-direct-daily-json.txtdocs/guide/gemini/index.md
✅ Files skipped from review due to trivial changes (2)
- apps/ccusage/test/snapshots/cli-output/gemini-direct-daily-json.txt
- docs/guide/gemini/index.md
🚧 Files skipped from review as they are similar to previous changes (1)
- apps/ccusage/src/adapter/gemini/paths.ts
|
@coderabbitai The latest nitpick about switching this new Gemini CLI test to a I checked the repo-local The earlier actionable comments are addressed in 67d204d:
Validation run locally:
|
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: Length of output: 103
Thanks for the thorough summary of 67d204d — all the previously raised actionable items are addressed. The PR looks good to go! 🐇✨ ✏️ Learnings added
|
Add a timeout to the LiteLLM pricing dataset fetch used by pricing macros so CI builds do not hang indefinitely when GitHub raw pricing fetches stall. Also register Gemini in the config schema generator agent list so generated configuration schema uses the same gemini namespace shape as other focused agent commands instead of top-level gemini:* command keys.
commit: |
ccusage performance comparisonThis compares the PR build against the base branch build on the same CI runner. Committed fixture performanceCommitted small fixtures for stable PR-to-PR feedback and explicit Claude/Codex command coverage. Fixtures: Claude
Large real-world-shaped fixture performanceGenerated fixtures shaped from aggregate local log statistics: thousands of JSONL files, many small sessions, and a long tail of larger sessions. No real prompts, paths, or outputs are stored in the fixtures. Fixtures: Claude
Package size
Lower medians and smaller packed package sizes are better. CI runner noise still applies; use same-run ratios as directional PR feedback, not release guarantees. |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
apps/ccusage/scripts/generate-json-schema.ts (1)
245-245: ⚡ Quick winAvoid duplicated agent source-of-truth in schema properties.
AGENT_NAMESis already the canonical list, but thepropertiessection still hardcodes each agent key. Generating that block fromAGENT_NAMESwill prevent future drift when adding/removing agents.♻️ Suggested refactor
+ const agentProperties = Object.fromEntries( + AGENT_NAMES.map((agent) => [agent, createAgentJsonSchema(agent, agentCommandSchemas[agent])]), + ) as Record<AgentName, JsonSchemaNode>; + return { $ref: '`#/definitions/ccusage-config`', definitions: { 'ccusage-config': { type: 'object', properties: { $schema: { type: 'string', description: 'JSON Schema URL for validation and autocomplete', markdownDescription: 'JSON Schema URL for validation and autocomplete', }, defaults: { ...defaultsJsonSchema, description: 'Default values for all-agent reports and legacy Claude commands', markdownDescription: 'Default values for all-agent reports and legacy Claude commands', }, commands: commandsJsonSchema, - claude: createAgentJsonSchema('claude', agentCommandSchemas.claude), - codex: createAgentJsonSchema('codex', agentCommandSchemas.codex), - opencode: createAgentJsonSchema('opencode', agentCommandSchemas.opencode), - amp: createAgentJsonSchema('amp', agentCommandSchemas.amp), - pi: createAgentJsonSchema('pi', agentCommandSchemas.pi), - gemini: createAgentJsonSchema('gemini', agentCommandSchemas.gemini), + ...agentProperties, }, additionalProperties: false, }, },🤖 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/scripts/generate-json-schema.ts` at line 245, The properties block is hardcoded for each agent; instead iterate AGENT_NAMES to build the map so the schema stays in sync. Replace the explicit entries (e.g., gemini: createAgentJsonSchema('gemini', agentCommandSchemas.gemini)) with a dynamic construction that maps AGENT_NAMES to createAgentJsonSchema(agentName, agentCommandSchemas[agentName]) (or agentCommandSchemas.get(agentName) depending on its type) and uses that resulting record as the properties value where the schema is assembled; update any typing to reflect the dynamic Record<string, ...> if needed.
🤖 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.
Nitpick comments:
In `@apps/ccusage/scripts/generate-json-schema.ts`:
- Line 245: The properties block is hardcoded for each agent; instead iterate
AGENT_NAMES to build the map so the schema stays in sync. Replace the explicit
entries (e.g., gemini: createAgentJsonSchema('gemini',
agentCommandSchemas.gemini)) with a dynamic construction that maps AGENT_NAMES
to createAgentJsonSchema(agentName, agentCommandSchemas[agentName]) (or
agentCommandSchemas.get(agentName) depending on its type) and uses that
resulting record as the properties value where the schema is assembled; update
any typing to reflect the dynamic Record<string, ...> if needed.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 20a64a9b-3b19-4238-a5f1-257d5cdd08b2
📒 Files selected for processing (3)
apps/ccusage/config-schema.jsonapps/ccusage/scripts/generate-json-schema.tspackages/internal/src/pricing-fetch-utils.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- apps/ccusage/config-schema.json
Avoid slow source-level Gemini pricing macro fetches in CLI output snapshot child processes. The tests still preserve existing Codex and Amp pricing snapshot coverage while keeping Gemini fixture costs at zero for the synthetic test model.
|
@coderabbitai review it |
|
✅ Actions performedReview triggered.
|
Add Gemini CLI to the README supported-source summary and example commands so the PR documentation matches the new adapter surface.
|
@coderabbitai README update pushed in 08139fc. Please review it. |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: Length of output: 553 🏁 Script executed: Length of output: 1619
The "Gemini CLI" naming is consistent with the docs sidebar entry and the dedicated guide page added in this PR. Nothing is missing — all three user-facing touchpoints in the README (description, example, feature list) have been updated. LGTM! 🐇✨ |
|
@cubic-dev-ai review it |
@ryoppippi I have started the AI code review. It will take a few minutes to complete. |
Replace the inline agent label conditional in the schema generator with a small exhaustive switch helper. This keeps future agent-specific labels out of nested ternaries and makes the config schema label rules easier to extend.
|
@coderabbitai review it |
|
@cubic-dev-ai review it |
@ryoppippi I have started the AI code review. It will take a few minutes to complete. |
|
✅ Actions performedReview triggered.
|
Register the gemini namespace with config loading so gemini defaults and per-report overrides are applied consistently with the generated schema and command registration.
|
@coderabbitai review it |
|
@cubic-dev-ai review it |
@ryoppippi I have started the AI code review. It will take a few minutes to complete. |
|
✅ Actions performedReview triggered.
|
Merge the current main Rust CLI migration into the Gemini PR and replace the old TypeScript Gemini adapter with a Rust implementation. The Rust adapter discovers JSON and JSONL logs from GEMINI_DATA_DIR or ~/.gemini/tmp, parses direct Gemini events and stats records, preserves cached-input overlap normalization, maps reasoning/tool tokens, and deduplicates direct JSONL updates by id. Also wires Gemini into direct reports, all-agent reports, progress labels, config schema, CLI parsing, README, and docs.
|
@coderabbitai review Updated this PR to merge current main and port Gemini CLI support to the Rust CLI implementation. This now wires Gemini into direct reports and all-agent reports, reads JSON/JSONL logs from GEMINI_DATA_DIR/default ~/.gemini/tmp, preserves cached-input overlap normalization, maps reasoning/tool tokens, and deduplicates direct JSONL updates by id. Local validation passed:
|
|
✅ Actions performedReview triggered.
|
ccusage performance comparisonPR SHA: This compares the Rust PR release binary against the configured base package on the same CI runner. Package runner startupExecution setup measures any pre-benchmark package materialization used by the execution benchmark. Bunx temp cache measures one
Cached bunx execution performanceRuns the same large fixture through Fixtures: Claude
Package runtime diagnosticsCompares the PR package wrapper, the installed native optional dependency binary, and the workspace release binary on the same large fixture. This identifies whether slow package results come from JavaScript wrapper overhead, the published native binary build, or the Rust core itself. Fixtures: Claude
Committed fixture performanceCommitted small fixtures for stable PR-to-PR feedback and explicit Claude/Codex command coverage. Fixtures: Claude
Large real-world-shaped fixture performanceGenerated fixtures shaped from aggregate local log statistics: thousands of JSONL files, many small sessions, and a long tail of larger sessions. No real prompts, paths, or outputs are stored in the fixtures. Fixtures: Claude
Artifact size
Lower medians and smaller artifacts are better. CI runner noise still applies; use same-run ratios as directional PR feedback, not release guarantees. |
ccusage performance comparisonPR SHA: This compares the PR package against the configured base package on the same CI runner. Package runner startupExecution setup measures any pre-benchmark package materialization used by the execution benchmark. Bunx temp cache measures one
Cached bunx execution performanceRuns the same large fixture through Fixtures: Claude
Package runtime diagnosticsCompares the PR package wrapper, the installed native optional dependency binary, and the workspace release binary on the same large fixture. This identifies whether slow package results come from JavaScript wrapper overhead, the published native binary build, or the Rust core itself. Fixtures: Claude
Committed fixture performanceCommitted small fixtures for stable PR-to-PR feedback and explicit Claude/Codex command coverage. Fixtures: Claude
Large real-world-shaped fixture performanceGenerated fixtures shaped from aggregate local log statistics: thousands of JSONL files, many small sessions, and a long tail of larger sessions. No real prompts, paths, or outputs are stored in the fixtures. Fixtures: Claude
Artifact size
Lower medians and smaller artifacts are better. CI runner noise still applies; use same-run ratios as directional PR feedback, not release guarantees. |
Try This PR
Summary
Validation
Summary by CodeRabbit
Release Notes
New Features
Documentation