Skip to content

fix(terminal): correct compact and unicode widths - #1129

Merged
ryoppippi merged 2 commits into
mainfrom
codex/fix-terminal-width-behavior
May 23, 2026
Merged

ryoppippi merged 2 commits into
mainfrom
codex/fix-terminal-width-behavior

Conversation

@ryoppippi

@ryoppippi ryoppippi commented May 23, 2026 •

Copy link
Copy Markdown
Member

Addresses the terminal behavior findings from CodeRabbit on #1127 in a separate stacked PR so the module split can remain mechanical.

This fixes compact date rendering in narrow terminal tables and replaces the ad-hoc non-ASCII width calculation with unicode-width.

@coderabbitai please review this follow-up PR. It intentionally contains the behavior changes that were kept out of #1127.

Testing:

  • direnv exec . cargo test --manifest-path rust/Cargo.toml -p ccusage-terminal
  • direnv exec . cargo clippy --manifest-path rust/Cargo.toml --workspace --all-targets -- -D warnings
  • direnv exec . git push -u origin codex/fix-terminal-width-behavior (pre-push: cargo test, typos, oxfmt, gitleaks, clippy)

Summary by cubic

Fixes compact date rendering in narrow terminal tables and switches to standard Unicode width calculation. Tables now align correctly with CJK, combining marks, and ambiguous-width characters.

  • Bug Fixes

    • Compact dates: keep 12 columns only when the table already fits; otherwise use 10 for narrow layouts; snapshot updated.
    • Use unicode-width for display width: CJK=2, combining marks/controls=0, ambiguous-width treated as narrow; tests added.
  • Dependencies

    • Add unicode-width 0.2.2.

Written for commit 26f3a6f. Summary will update on new commits. Review in cubic

Summary by CodeRabbit

  • Bug Fixes
    • Fixed character display width calculation so CJK characters and combining marks render correctly in terminal output, preventing misaligned text.
    • Improved table column width fitting so tables adjust more reliably to terminal size, reducing truncation and layout shifts.

Review Change Stack

@coderabbitai

coderabbitai Bot commented May 23, 2026 •

Copy link
Copy Markdown

Caution

Review failed

Pull request was closed or merged during review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c8b81789-cb5a-4d2c-9cb1-1dd3757e8d55

📥 Commits

Reviewing files that changed from the base of the PR and between 588ee58 and 26f3a6f.

⛔ Files ignored due to path filters (2)
  • rust/Cargo.lock is excluded by !**/*.lock
  • rust/crates/ccusage-terminal/src/snapshots/ccusage_terminal__table__tests__snapshots_narrow_table_with_wrapping_truncation_and_compact_dates.snap is excluded by !**/*.snap
📒 Files selected for processing (3)
  • rust/crates/ccusage-terminal/Cargo.toml
  • rust/crates/ccusage-terminal/src/table.rs
  • rust/crates/ccusage-terminal/src/width.rs
✅ Files skipped from review due to trivial changes (1)
  • rust/crates/ccusage-terminal/Cargo.toml

📝 Walkthrough

Walkthrough

Adds the unicode-width crate, updates character display-width calculation to use UnicodeWidthChar::width (with 0 fallback) and tests, and refines column-fitting to compute an overflow-aware first-column minimum passed into fit_widths_to_terminal.

Changes

Unicode Character Width and Table Fitting

Layer / File(s) Summary
Unicode dependency and width implementation
rust/crates/ccusage-terminal/Cargo.toml, rust/crates/ccusage-terminal/src/width.rs
Adds unicode-width = "0.2.2". Replaces the ASCII/non-ASCII heuristic with UnicodeWidthChar::width(ch) (default 0) in char_display_width and adds unit tests for visible_width and char_display_width.
Column first-min and fitting refinement
rust/crates/ccusage-terminal/src/table.rs
column_widths computes an overflow-aware first_column_min (10 when compact_dates AND total_required > terminal_width; otherwise 12 with compaction or 10 without) and passes it into fit_widths_to_terminal, removing the post-fit first-column overflow adjustment.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • ryoppippi/ccusage#722: Related adjustments to table column minimum width rules during terminal fitting across repositories.
  • ryoppippi/ccusage#1127: Recent changes touching ccusage-terminal's width and table fitting logic; closely related to the width/refit updates here.

Poem

🐰
I measured every little glyph and mark,
from bell to CJK bold and stark.
Tables stretch and columns mind,
with unicode rules now finely aligned.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 22.22% 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 accurately summarizes the main changes: fixes to compact date width logic and replacement of ad-hoc ASCII width calculation with unicode-width crate for proper CJK and combining mark handling.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/fix-terminal-width-behavior

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.

@ryoppippi

Copy link
Copy Markdown
Member Author

@coderabbitai please review this stacked follow-up. It contains the compact-date and Unicode-width behavior fixes requested on #1127.

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented May 23, 2026 •

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
ccusage-guide 26f3a6f Commit Preview URL

Branch Preview URL
May 23 2026, 01:56 PM

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

No issues found across 5 files

Re-trigger cubic

@coderabbitai

coderabbitai Bot commented May 23, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Get PR details and diff
gh pr view 1129 --repo ryoppippi/ccusage
echo "---DIFF---"
gh pr diff 1129 --repo ryoppippi/ccusage

Length of output: 7100


@ryoppippi Thanks for this follow-up PR! Here's the review.


Review of #1129

rust/crates/ccusage-terminal/src/table.rs — compact date width logic

The refactored first_column_min computation is correct and simpler than the original (eliminates the post-fit_widths_to_terminal .max(10) mutation). One nit: the first and last arms of the expression both return 10, so the whole thing can be collapsed to a single condition:

let first_column_min = if self.compact_dates && total_required <= self.terminal_width {
    12
} else {
    10
};

This makes the intent clearer: "use 12 only when compact_dates is on and the table fits; fall back to 10 otherwise." The snapshot diff confirms the narrower column renders correctly.


rust/crates/ccusage-terminal/src/width.rs — char_display_width via unicode-width

Replacing the blanket else → 2 with a proper Unicode lookup is a solid improvement. A few points:

width_cjk vs width

width_cjk treats ambiguous-width characters as wide (2) in an East Asian context, while width treats them as narrow (1). Ambiguous characters include things like ±, °, and many Greek/Latin extended letters. For most Western terminal users whose terminals are not in CJK mode, width_cjk will over-count these characters by 1 column each, potentially misaligning columns. Using UnicodeWidthChar::width(ch).unwrap_or(1) (falling back to 1 for control chars rather than 0) would be more correct for the general case, while still correctly identifying CJK ideographs as wide.

unwrap_or(0) for control characters

width_cjk returns None for control characters (e.g. \t, \x00). Returning 0 for them is reasonable since visible_width presumably strips/skips ANSI sequences already, but it's worth a test or a comment.

Tests

The new test is a good starting point. Consider adding coverage for the ambiguous-width and None cases:

#[test]
fn char_display_width_cases() {
    // ASCII
    assert_eq!(char_display_width('a'), 1);
    // CJK ideograph
    assert_eq!(char_display_width('表'), 2);
    // Combining mark (width 0 — does not advance cursor)
    assert_eq!(char_display_width('\u{0301}'), 0);
    // Control character → unwrap_or(0)
    assert_eq!(char_display_width('\x07'), 0);
}

Dependency

unicode-width 0.2.2 is the current latest release — good choice. The semver spec "0.2.2" in Cargo.toml allows compatible patch bumps, which is fine.


Summary

Area Status
Compact date width logic ✅ Correct — optional simplification nit
unicode-width integration ✅ Significant improvement over old blanket else → 2
width_cjk vs width choice ⚠️ May over-count ambiguous chars on non-CJK terminals
Tests ✅ Core cases covered; missing char_display_width edge cases
Dependency version ✅ Latest, no known vulnerabilities

The main actionable item is the width_cjk / width question — worth a deliberate choice with a comment explaining why, either way.

@ryoppippi

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented May 23, 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.

@ryoppippi

Copy link
Copy Markdown
Member Author

@coderabbitai pushed 0e8eacc to address the standard Unicode width review note: it now uses UnicodeWidthChar::width, keeps controls at zero width, covers ambiguous-width characters in tests, and simplifies the compact-date width condition. Please review again.

@coderabbitai

coderabbitai Bot commented May 23, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Get the latest diff for commit 0e8eacc
gh pr diff 1129 --repo ryoppippi/ccusage
echo "---COMMIT---"
gh api repos/ryoppippi/ccusage/commits/0e8eacc

Length of output: 13251


@ryoppippi Everything looks great — all three items from the previous review have been addressed cleanly in commit 0e8eacc:

Change Status
width_cjk → width (standard, non-CJK-biased) ✅
unwrap_or(0) for control characters ✅
Tests: ASCII, CJK, combining mark, control, ambiguous (±→1) ✅
Compact-date condition collapsed to single if/else ✅

The char_display_width implementation is now a clean one-liner, and the test suite explicitly pins the ambiguous-width case to 1, which makes the design intent self-documenting. The snapshot update also correctly reflects the narrower compact date wrapping. No further changes needed.

[approve]

Base automatically changed from codex/split-terminal-crate to main May 23, 2026 13:55
ryoppippi added 2 commits May 23, 2026 14:55
Fix the terminal table width logic called out during review in a follow-up commit stacked on the terminal split.

The compact date mode now lowers the first-column minimum only when the table is actually too wide, which lets date compaction render in narrow layouts. Width calculation now uses unicode-width so combining marks and CJK glyphs do not distort table and title layout.

This is separate from the mechanical module split so the first PR can stay behavior-preserving.
Use unicode-width standard width calculation for terminal table output so ambiguous-width characters are measured like non-CJK terminal columns while CJK and combining marks still render with their expected widths.

Simplify the compact-date minimum width condition to keep the behavior explicit: preserve a 12-column date only when compact dates are enabled and the table already fits, otherwise allow the 10-column compact form. Add direct width cases for ASCII, CJK, combining marks, controls, and ambiguous characters.
@ryoppippi
ryoppippi force-pushed the codex/fix-terminal-width-behavior branch from 0e8eacc to 26f3a6f Compare May 23, 2026 13:56
@ryoppippi

Copy link
Copy Markdown
Member Author

@coderabbitai rebased this follow-up onto main after #1127 was merged, preserving only the compact-date and Unicode-width fixes in this PR. Please review the updated diff again.

@ryoppippi

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented May 23, 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 commented May 23, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
gh pr diff 1129 --repo ryoppippi/ccusage
echo "---PR VIEW---"
gh pr view 1129 --repo ryoppippi/ccusage
echo "---COMMITS---"
gh api repos/ryoppippi/ccusage/pulls/1129/commits | jq '[.[] | {sha: .sha, message: .commit.message}]'

Length of output: 9414


@ryoppippi The rebase onto main looks clean — all the fixes from commit 26f3a6f are preserved intact with no regressions introduced:

Area Status
unicode-width 0.2.2 dependency & lockfile ✅
UnicodeWidthChar::width (standard, non-CJK-biased) ✅
unwrap_or(0) for control chars ✅
Tests: ASCII, CJK, combining mark, control, ambiguous (±→1) ✅
Compact-date single if/else condition ✅
Snapshot updated (narrower 10-col date, 2026/05-18 wrap) ✅

The only diff artifact from the rebase is the assertion_line bump from 494 → 495 in the snapshot, which is harmless. Everything else is identical to what was approved previously. Good to go!

[approve]

@ryoppippi
ryoppippi merged commit dffcfd3 into main May 23, 2026
26 of 27 checks passed
@ryoppippi
ryoppippi deleted the codex/fix-terminal-width-behavior branch May 23, 2026 14:00
@github-actions

Copy link
Copy Markdown
Contributor

ccusage performance comparison

PR SHA: 588ee58ccbdf
Base SHA: d8c775e2cec8

This compares the PR package against the configured base package on the same CI runner.

Package runner startup

Execution setup measures any pre-benchmark package materialization used by the execution benchmark. Bunx temp cache measures one bunx -p <url> ccusage --version run with an empty Bun install cache. Warm reuses that cache and reports the median of repeated runs.

Package SHA Execution setup Bunx temp cache Bunx warm median Warm samples
Base pkg.pr.new d8c775e2cec8 412.0ms 408.0ms 33.4ms 3
PR pkg.pr.new 588ee58ccbdf 450.0ms 413.8ms 34.6ms 3

Cached bunx execution performance

Runs the same large fixture through bunx -p <pkg.pr.new URL> ccusage after the Bun install cache has already been populated by the startup measurement. This separates cached package-runner execution from first-fetch package materialization.

Fixtures: Claude /home/runner/work/_temp/ccusage-large-fixture (1.01 GiB, 2,597 files), Codex /home/runner/work/_temp/ccusage-large-codex-fixture (1.01 GiB, 2,597 files)
Base package: d8c775e2cec8; PR package: 588ee58ccbdf. Both run through bunx -p <pkg.pr.new URL> ccusage using the warmed Bun install cache from package runner startup, measured by hyperfine with 0 warmups and 1 runs.

Command Input Base median PR median PR vs base Base throughput PR throughput
bunx -p <pkg> ccusage claude --offline --json 1.01 GiB 489.0ms 486.3ms 1.01x 2.06 GiB/s 2.07 GiB/s
bunx -p <pkg> ccusage codex --offline --json 1.01 GiB 362.2ms 350.8ms 1.03x 2.78 GiB/s 2.87 GiB/s

Package runtime diagnostics

Compares 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 /home/runner/work/_temp/ccusage-large-fixture (1.01 GiB, 2,597 files), Codex /home/runner/work/_temp/ccusage-large-codex-fixture (1.01 GiB, 2,597 files)
All rows run --offline --json, measured by hyperfine with 0 warmups and 1 runs. This isolates wrapper overhead from the installed native optional dependency and the workspace release binary built on the runner.

Command Runtime Input Median Throughput Samples
claude --offline --json Package wrapper 1.01 GiB 483.8ms 2.08 GiB/s 1
claude --offline --json Installed native binary 1.01 GiB 475.9ms 2.12 GiB/s 1
codex --offline --json Package wrapper 1.01 GiB 355.0ms 2.84 GiB/s 1
codex --offline --json Installed native binary 1.01 GiB 356.8ms 2.82 GiB/s 1

Committed fixture performance

Committed small fixtures for stable PR-to-PR feedback and explicit Claude/Codex command coverage.

Fixtures: Claude apps/ccusage/test/fixtures/claude (0.00 MiB, 2 files), Codex apps/ccusage/test/fixtures/codex (0.00 MiB, 1 files)
Base runs the published ccusage package from pkg.pr.new, installed before measurement; PR runs the published ccusage package from pkg.pr.new, installed before measurement. Both run --offline --json, measured by hyperfine with 2 warmups and 7 runs.

Command Input Base median PR median PR vs base Base throughput PR throughput
claude daily --offline --json 0.00 MiB 30.9ms 31.1ms 1.00x 0.05 MiB/s 0.05 MiB/s
claude session --offline --json 0.00 MiB 30.1ms 30.2ms 1.00x 0.05 MiB/s 0.05 MiB/s
codex daily --offline --json 0.00 MiB 30.8ms 31.1ms 0.99x 0.03 MiB/s 0.03 MiB/s
codex session --offline --json 0.00 MiB 30.1ms 30.2ms 1.00x 0.03 MiB/s 0.03 MiB/s

Large real-world-shaped fixture performance

Generated 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 /home/runner/work/_temp/ccusage-large-fixture (1.01 GiB, 2,597 files), Codex /home/runner/work/_temp/ccusage-large-codex-fixture (1.01 GiB, 2,597 files)
Base runs the published ccusage package from pkg.pr.new, installed before measurement; PR runs the published ccusage package from pkg.pr.new, installed before measurement. Both run --offline --json, measured by hyperfine with 0 warmups and 1 runs.

Command Input Base median PR median PR vs base Base throughput PR throughput
claude --offline --json 1.01 GiB 483.9ms 478.7ms 1.01x 2.08 GiB/s 2.10 GiB/s
codex --offline --json 1.01 GiB 352.7ms 348.7ms 1.01x 2.85 GiB/s 2.89 GiB/s

Artifact size

Artifact Base PR Delta Ratio
packed ccusage-*.tgz 14.25 KiB 14.25 KiB -0.00 KiB 1.00x
installed native package binary 3289.49 KiB 3353.49 KiB +64.00 KiB 0.98x

Lower medians and smaller artifacts are better. CI runner noise still applies; use same-run ratios as directional PR feedback, not release guarantees.

@github-actions

Copy link
Copy Markdown
Contributor

ccusage performance comparison

PR SHA: 588ee58ccbdf
Base SHA: d8c775e2cec8

This compares the Rust PR release binary against the configured base package on the same CI runner.

Package runner startup

Execution setup measures any pre-benchmark package materialization used by the execution benchmark. Bunx temp cache measures one bunx -p <url> ccusage --version run with an empty Bun install cache. Warm reuses that cache and reports the median of repeated runs.

Package SHA Execution setup Bunx temp cache Bunx warm median Warm samples
Base pkg.pr.new d8c775e2cec8 596.0ms 466.2ms 33.8ms 3
PR pkg.pr.new 588ee58ccbdf 521.7ms 610.4ms 35.1ms 3

Cached bunx execution performance

Runs the same large fixture through bunx -p <pkg.pr.new URL> ccusage after the Bun install cache has already been populated by the startup measurement. This separates cached package-runner execution from first-fetch package materialization.

Fixtures: Claude /home/runner/work/_temp/ccusage-large-fixture (1.01 GiB, 2,597 files), Codex /home/runner/work/_temp/ccusage-large-codex-fixture (1.01 GiB, 2,597 files)
Base package: d8c775e2cec8; PR package: 588ee58ccbdf. Both run through bunx -p <pkg.pr.new URL> ccusage using the warmed Bun install cache from package runner startup, measured by hyperfine with 0 warmups and 1 runs.

Command Input Base median PR median PR vs base Base throughput PR throughput
bunx -p <pkg> ccusage claude --offline --json 1.01 GiB 497.0ms 507.4ms 0.98x 2.03 GiB/s 1.98 GiB/s
bunx -p <pkg> ccusage codex --offline --json 1.01 GiB 355.1ms 358.3ms 0.99x 2.84 GiB/s 2.81 GiB/s

Package runtime diagnostics

Compares 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 /home/runner/work/_temp/ccusage-large-fixture (1.01 GiB, 2,597 files), Codex /home/runner/work/_temp/ccusage-large-codex-fixture (1.01 GiB, 2,597 files)
All rows run --offline --json, measured by hyperfine with 0 warmups and 1 runs. This isolates wrapper overhead from the installed native optional dependency and the workspace release binary built on the runner.

Command Runtime Input Median Throughput Samples
claude --offline --json Package wrapper 1.01 GiB 487.4ms 2.07 GiB/s 1
claude --offline --json Installed native binary 1.01 GiB 464.3ms 2.17 GiB/s 1
codex --offline --json Package wrapper 1.01 GiB 353.8ms 2.85 GiB/s 1
codex --offline --json Installed native binary 1.01 GiB 368.9ms 2.73 GiB/s 1

Committed fixture performance

Committed small fixtures for stable PR-to-PR feedback and explicit Claude/Codex command coverage.

Fixtures: Claude apps/ccusage/test/fixtures/claude (0.00 MiB, 2 files), Codex apps/ccusage/test/fixtures/codex (0.00 MiB, 1 files)
Base runs the published ccusage package from pkg.pr.new, installed before measurement; PR runs rust/target/release/ccusage directly. Both run --offline --json, measured by hyperfine with 2 warmups and 7 runs.

Command Input Base median PR median PR vs base Base throughput PR throughput
claude daily --offline --json 0.00 MiB 31.2ms 4.5ms 6.92x 0.05 MiB/s 0.34 MiB/s
claude session --offline --json 0.00 MiB 31.2ms 4.5ms 6.89x 0.05 MiB/s 0.34 MiB/s
codex daily --offline --json 0.00 MiB 30.9ms 4.2ms 7.36x 0.03 MiB/s 0.20 MiB/s
codex session --offline --json 0.00 MiB 30.5ms 4.2ms 7.28x 0.03 MiB/s 0.20 MiB/s

Large real-world-shaped fixture performance

Generated 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 /home/runner/work/_temp/ccusage-large-fixture (1.01 GiB, 2,597 files), Codex /home/runner/work/_temp/ccusage-large-codex-fixture (1.01 GiB, 2,597 files)
Base runs the published ccusage package from pkg.pr.new, installed before measurement; PR runs rust/target/release/ccusage directly. Both run --offline --json, measured by hyperfine with 0 warmups and 1 runs.

Command Input Base median PR median PR vs base Base throughput PR throughput
claude --offline --json 1.01 GiB 856.8ms 461.5ms 1.86x 1.17 GiB/s 2.18 GiB/s
codex --offline --json 1.01 GiB 359.6ms 323.1ms 1.11x 2.80 GiB/s 3.12 GiB/s

Artifact size

Artifact Base PR Delta Ratio
packed ccusage-*.tgz 14.25 KiB 14.25 KiB -0.00 KiB 1.00x
installed native package binary 3289.49 KiB 3353.49 KiB +64.00 KiB 0.98x

Lower medians and smaller artifacts are better. CI runner noise still applies; use same-run ratios as directional PR feedback, not release guarantees.

@github-actions

Copy link
Copy Markdown
Contributor

ccusage performance comparison

PR SHA: 0e8eacc41336
Base SHA: d8c775e2cec8

This compares the Rust PR release binary against the configured base package on the same CI runner.

Package runner startup

Execution setup measures any pre-benchmark package materialization used by the execution benchmark. Bunx temp cache measures one bunx -p <url> ccusage --version run with an empty Bun install cache. Warm reuses that cache and reports the median of repeated runs.

Package SHA Execution setup Bunx temp cache Bunx warm median Warm samples
Base pkg.pr.new d8c775e2cec8 409.4ms 549.4ms 34.7ms 3
PR pkg.pr.new 0e8eacc41336 578.4ms 505.3ms 34.4ms 3

Cached bunx execution performance

Runs the same large fixture through bunx -p <pkg.pr.new URL> ccusage after the Bun install cache has already been populated by the startup measurement. This separates cached package-runner execution from first-fetch package materialization.

Fixtures: Claude /home/runner/work/_temp/ccusage-large-fixture (1.01 GiB, 2,597 files), Codex /home/runner/work/_temp/ccusage-large-codex-fixture (1.01 GiB, 2,597 files)
Base package: d8c775e2cec8; PR package: 0e8eacc41336. Both run through bunx -p <pkg.pr.new URL> ccusage using the warmed Bun install cache from package runner startup, measured by hyperfine with 0 warmups and 1 runs.

Command Input Base median PR median PR vs base Base throughput PR throughput
bunx -p <pkg> ccusage claude --offline --json 1.01 GiB 506.3ms 506.2ms 1.00x 1.99 GiB/s 1.99 GiB/s
bunx -p <pkg> ccusage codex --offline --json 1.01 GiB 367.5ms 367.7ms 1.00x 2.74 GiB/s 2.74 GiB/s

Package runtime diagnostics

Compares 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 /home/runner/work/_temp/ccusage-large-fixture (1.01 GiB, 2,597 files), Codex /home/runner/work/_temp/ccusage-large-codex-fixture (1.01 GiB, 2,597 files)
All rows run --offline --json, measured by hyperfine with 0 warmups and 1 runs. This isolates wrapper overhead from the installed native optional dependency and the workspace release binary built on the runner.

Command Runtime Input Median Throughput Samples
claude --offline --json Package wrapper 1.01 GiB 497.7ms 2.02 GiB/s 1
claude --offline --json Installed native binary 1.01 GiB 471.7ms 2.13 GiB/s 1
codex --offline --json Package wrapper 1.01 GiB 357.5ms 2.82 GiB/s 1
codex --offline --json Installed native binary 1.01 GiB 326.5ms 3.08 GiB/s 1

Committed fixture performance

Committed small fixtures for stable PR-to-PR feedback and explicit Claude/Codex command coverage.

Fixtures: Claude apps/ccusage/test/fixtures/claude (0.00 MiB, 2 files), Codex apps/ccusage/test/fixtures/codex (0.00 MiB, 1 files)
Base runs the published ccusage package from pkg.pr.new, installed before measurement; PR runs rust/target/release/ccusage directly. Both run --offline --json, measured by hyperfine with 2 warmups and 7 runs.

Command Input Base median PR median PR vs base Base throughput PR throughput
claude daily --offline --json 0.00 MiB 31.7ms 4.9ms 6.42x 0.05 MiB/s 0.31 MiB/s
claude session --offline --json 0.00 MiB 32.3ms 4.6ms 6.97x 0.05 MiB/s 0.33 MiB/s
codex daily --offline --json 0.00 MiB 31.8ms 4.4ms 7.25x 0.03 MiB/s 0.20 MiB/s
codex session --offline --json 0.00 MiB 31.8ms 4.3ms 7.38x 0.03 MiB/s 0.20 MiB/s

Large real-world-shaped fixture performance

Generated 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 /home/runner/work/_temp/ccusage-large-fixture (1.01 GiB, 2,597 files), Codex /home/runner/work/_temp/ccusage-large-codex-fixture (1.01 GiB, 2,597 files)
Base runs the published ccusage package from pkg.pr.new, installed before measurement; PR runs rust/target/release/ccusage directly. Both run --offline --json, measured by hyperfine with 0 warmups and 1 runs.

Command Input Base median PR median PR vs base Base throughput PR throughput
claude --offline --json 1.01 GiB 490.7ms 471.6ms 1.04x 2.05 GiB/s 2.13 GiB/s
codex --offline --json 1.01 GiB 364.9ms 331.2ms 1.10x 2.76 GiB/s 3.04 GiB/s

Artifact size

Artifact Base PR Delta Ratio
packed ccusage-*.tgz 14.25 KiB 14.25 KiB -0.00 KiB 1.00x
installed native package binary 3289.49 KiB 3353.49 KiB +64.00 KiB 0.98x

Lower medians and smaller artifacts are better. CI runner noise still applies; use same-run ratios as directional PR feedback, not release guarantees.

@github-actions

Copy link
Copy Markdown
Contributor

ccusage performance comparison

PR SHA: 0e8eacc41336
Base SHA: d8c775e2cec8

This compares the PR package against the configured base package on the same CI runner.

Package runner startup

Execution setup measures any pre-benchmark package materialization used by the execution benchmark. Bunx temp cache measures one bunx -p <url> ccusage --version run with an empty Bun install cache. Warm reuses that cache and reports the median of repeated runs.

Package SHA Execution setup Bunx temp cache Bunx warm median Warm samples
Base pkg.pr.new d8c775e2cec8 659.1ms 526.1ms 35.7ms 3
PR pkg.pr.new 0e8eacc41336 414.2ms 475.4ms 36.1ms 3

Cached bunx execution performance

Runs the same large fixture through bunx -p <pkg.pr.new URL> ccusage after the Bun install cache has already been populated by the startup measurement. This separates cached package-runner execution from first-fetch package materialization.

Fixtures: Claude /home/runner/work/_temp/ccusage-large-fixture (1.01 GiB, 2,597 files), Codex /home/runner/work/_temp/ccusage-large-codex-fixture (1.01 GiB, 2,597 files)
Base package: d8c775e2cec8; PR package: 0e8eacc41336. Both run through bunx -p <pkg.pr.new URL> ccusage using the warmed Bun install cache from package runner startup, measured by hyperfine with 0 warmups and 1 runs.

Command Input Base median PR median PR vs base Base throughput PR throughput
bunx -p <pkg> ccusage claude --offline --json 1.01 GiB 514.5ms 506.8ms 1.02x 1.96 GiB/s 1.99 GiB/s
bunx -p <pkg> ccusage codex --offline --json 1.01 GiB 367.2ms 367.8ms 1.00x 2.74 GiB/s 2.74 GiB/s

Package runtime diagnostics

Compares 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 /home/runner/work/_temp/ccusage-large-fixture (1.01 GiB, 2,597 files), Codex /home/runner/work/_temp/ccusage-large-codex-fixture (1.01 GiB, 2,597 files)
All rows run --offline --json, measured by hyperfine with 0 warmups and 1 runs. This isolates wrapper overhead from the installed native optional dependency and the workspace release binary built on the runner.

Command Runtime Input Median Throughput Samples
claude --offline --json Package wrapper 1.01 GiB 500.7ms 2.01 GiB/s 1
claude --offline --json Installed native binary 1.01 GiB 469.2ms 2.15 GiB/s 1
codex --offline --json Package wrapper 1.01 GiB 361.9ms 2.78 GiB/s 1
codex --offline --json Installed native binary 1.01 GiB 334.5ms 3.01 GiB/s 1

Committed fixture performance

Committed small fixtures for stable PR-to-PR feedback and explicit Claude/Codex command coverage.

Fixtures: Claude apps/ccusage/test/fixtures/claude (0.00 MiB, 2 files), Codex apps/ccusage/test/fixtures/codex (0.00 MiB, 1 files)
Base runs the published ccusage package from pkg.pr.new, installed before measurement; PR runs the published ccusage package from pkg.pr.new, installed before measurement. Both run --offline --json, measured by hyperfine with 2 warmups and 7 runs.

Command Input Base median PR median PR vs base Base throughput PR throughput
claude daily --offline --json 0.00 MiB 32.5ms 32.8ms 0.99x 0.05 MiB/s 0.05 MiB/s
claude session --offline --json 0.00 MiB 32.7ms 33.2ms 0.99x 0.05 MiB/s 0.05 MiB/s
codex daily --offline --json 0.00 MiB 32.4ms 32.3ms 1.00x 0.03 MiB/s 0.03 MiB/s
codex session --offline --json 0.00 MiB 32.8ms 33.0ms 0.99x 0.03 MiB/s 0.03 MiB/s

Large real-world-shaped fixture performance

Generated 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 /home/runner/work/_temp/ccusage-large-fixture (1.01 GiB, 2,597 files), Codex /home/runner/work/_temp/ccusage-large-codex-fixture (1.01 GiB, 2,597 files)
Base runs the published ccusage package from pkg.pr.new, installed before measurement; PR runs the published ccusage package from pkg.pr.new, installed before measurement. Both run --offline --json, measured by hyperfine with 0 warmups and 1 runs.

Command Input Base median PR median PR vs base Base throughput PR throughput
claude --offline --json 1.01 GiB 508.1ms 509.5ms 1.00x 1.98 GiB/s 1.98 GiB/s
codex --offline --json 1.01 GiB 367.1ms 363.3ms 1.01x 2.74 GiB/s 2.77 GiB/s

Artifact size

Artifact Base PR Delta Ratio
packed ccusage-*.tgz 14.25 KiB 14.25 KiB -0.00 KiB 1.00x
installed native package binary 3289.49 KiB 3353.49 KiB +64.00 KiB 0.98x

Lower medians and smaller artifacts are better. CI runner noise still applies; use same-run ratios as directional PR feedback, not release guarantees.

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