Skip to content

fix(terminal): preserve numeric columns in narrow tables - #1671

Merged
ryoppippi merged 7 commits into
mainfrom
codex/fix/issue-946-clean
Aug 31, 2026
Merged

ryoppippi merged 7 commits into
mainfrom
codex/fix/issue-946-clean

Conversation

@ryoppippi

@ryoppippi ryoppippi commented Aug 31, 2026 •

Copy link
Copy Markdown
Member

Summary\n\n- Preserve numeric content when responsive terminal tables fit at the boundary.\n- Let wrap-capable text columns yield optional width before numeric cells are truncated.\n- Keep ANSI and wide-character handling intact.\n\n## Validation\n\n- Focused terminal and Codex report tests pass.\n- Verified the nine-column Codex layout at COLUMNS=120 in cmux.\n\nFixes #946


Summary by cubic

Fixes #946 so terminal tables preserve numeric column content and ANSI formatting when they shrink to fit. Previously width fitting could truncate large numeric values even though wrap-capable text columns had space to give; now text columns yield first and measured numeric widths are reserved before any truncation.

  • The Models column is capped at a fixed width so it stops consuming responsive space.
  • List markers stay attached to truncated model names, and active color sequences are replayed and reset so style doesn't leak into borders.
  • Fallback widths for non-numeric columns come from cell content so markers stay visible when Models isn't the second column.

Written for commit 1d0d237. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • Bug Fixes
    • Improved terminal table layout across different window widths.
    • Preserved numeric column readability while fitting tables to available space.
    • Limited model names to prevent excessively wide columns.
    • Improved handling of colored text and terminal formatting across wrapped lines.
    • Kept list markers attached to their following text when wrapping.
    • Refined compact date display in constrained layouts.

ryoppippi and others added 4 commits August 31, 2026 02:00
Keep wide model lists from consuming responsive table space while preserving numeric widths derived from every rendered row, including totals.

Co-authored-by: cristos <[email protected]>
Prioritize text-column reduction and redistribute fitted capacity to measured numeric columns so large totals remain visible whenever the table can accommodate them.

Co-authored-by: cristos <[email protected]>
Reserve measured numeric cell widths before distributing optional table padding, and reset ANSI-styled cell fragments before padding and borders.

Co-authored-by: cristos <[email protected]>
When measured numeric content plus the Date and Models fallback minima needs one more column than the terminal provides, the fallback scaler can truncate numeric cells even though the table can fit. Allow wrap-capable text columns to give back space down to the established text floor before falling back, so numeric cells remain intact at the boundary.
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Aug 31, 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 1d0d237 Commit Preview URL

Branch Preview URL
Aug 31 2026, 04:27 AM

@coderabbitai

coderabbitai Bot commented Aug 31, 2026 •

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: dc15a0ff-119e-4427-a53b-28dfddb9e78f

📥 Commits

Reviewing files that changed from the base of the PR and between e73c9b9 and 1d0d237.

⛔ Files ignored due to path filters (2)
  • rust/crates/ccusage-terminal/src/snapshots/ccusage_terminal__table__tests__preserves_ansi_continuation_after_truncation_in_a_narrow_table.snap is excluded by !**/*.snap
  • 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 (2)
  • rust/crates/ccusage-terminal/src/table.rs
  • rust/crates/ccusage-terminal/src/width.rs

Included review availability: Your plan provides up to 10 included reviews per hour; 4 remain after this review.


📝 Walkthrough

Walkthrough

The terminal table now caps model content, preserves numeric widths during fitting, updates compact-date behavior, distributes spare width, and maintains ANSI-safe wrapping and padding. Tests cover constrained layouts, model truncation, list markers, ANSI continuation, and reset handling.

Changes

Terminal layout behavior

Layer / File(s) Summary
Model and numeric width inputs
rust/crates/ccusage-terminal/src/table.rs
column_widths caps the Models column, measures numeric and text content widths, and passes fitting metadata to fit_widths_to_terminal.
Terminal width fitting
rust/crates/ccusage-terminal/src/table.rs
fit_widths_to_terminal preserves numeric content, shrinks non-right-aligned columns, distributes spare width, and applies the updated compact-date threshold. Tests cover constrained layouts and model-column placement.
ANSI-safe cell rendering
rust/crates/ccusage-terminal/src/table.rs, rust/crates/ccusage-terminal/src/width.rs
ansi_continuation preserves active SGR codes across wrapped fragments. ensure_ansi_reset adds missing reset sequences. pad_cell applies resets before measuring and rendering cells. Tests cover list markers, multiline ANSI content, truncation, and cell boundaries.

Estimated code review effort: 4 (Complex) | ~45 minutes

Merge Risk: ⚪ Minimal · up to 1d0d2

This PR improves narrow terminal table layout by preserving numeric values while allowing text columns to yield space, without changing external interfaces or deployment behavior. No actionable merge-blocking risk remains beyond normal checks and review.

Sequence Diagram(s)

sequenceDiagram
  participant TableRenderer
  participant column_widths
  participant fit_widths_to_terminal
  participant wrap_cell_line
  participant pad_cell
  participant Terminal

  TableRenderer->>column_widths: calculate model, numeric, and text widths
  column_widths->>fit_widths_to_terminal: pass content minimums and layout metadata
  fit_widths_to_terminal->>fit_widths_to_terminal: fit columns to terminal width
  fit_widths_to_terminal-->>TableRenderer: return fitted column widths
  TableRenderer->>wrap_cell_line: wrap over-wide cell content
  wrap_cell_line->>wrap_cell_line: preserve list markers and ANSI continuation
  TableRenderer->>pad_cell: format each cell
  pad_cell->>Terminal: render reset-safe padded cells
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 52.94% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 34 functions across 2 files. 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 identifies the primary change: preserving numeric columns in narrow terminal tables.
Linked Issues check ✅ Passed The changes address issue #946 by capping the Models column, preserving numeric content widths during responsive fitting, reducing the impact of long model names, and retaining compact-mode behavior.
Out of Scope Changes check ✅ Passed The ANSI handling, list-marker wrapping, date compaction, and regression tests support reliable terminal table rendering and the linked issue objectives. No unrelated code changes are evident.
  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 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/issue-946-clean

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.

@pullfrog pullfrog 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.

Important

This PR has two narrow-layout/rendering regressions that should be addressed before merging.

Reviewed changes

  • Responsive width fitting — Reviewed the new model-column cap, numeric-width reservation, fallback minima, compact-date handling, and spare-width redistribution in ccusage-terminal.
  • ANSI cell padding — Reviewed the new reset handling in pad_cell and its interaction with multiline expansion and existing terminal styling.
  • Regression coverage — Reviewed the added terminal tests for large totals, 80/120-column layouts, compact dates, wide characters, and ANSI cells.

Pullfrog  | ⚠️ this action is pinned to a commit SHA, which freezes the cleanup step — switch to @v0 or keep the SHA fresh with Dependabot | Fix all ➔ | Fix 👍s ➔ | View workflow run | Using GPT Luna (free via Pullfrog for OSS) | 𝕏

Comment thread rust/crates/ccusage-terminal/src/table.rs

fn pad_cell(cell: &str, width: usize, align: Align) -> String {
let visible = visible_width(cell);
let cell = ensure_ansi_reset(cell);

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.

ensure_ansi_reset runs after multiline expansion, so it resets the first physical fragment even when the original ANSI style intentionally continues across the newline. For example, color(style, "red continued", Color::Red) becomes a red first line and an uncolored second line, changing multiline ANSI rendering.

@pkg-pr-new

pkg-pr-new Bot commented Aug 31, 2026 •

Copy link
Copy Markdown

Open in StackBlitz

ccusage

npx https://pkg.pr.new/ccusage@1671

@ccusage/ccusage-darwin-arm64

npx https://pkg.pr.new/@ccusage/ccusage-darwin-arm64@1671

@ccusage/ccusage-darwin-x64

npx https://pkg.pr.new/@ccusage/ccusage-darwin-x64@1671

@ccusage/ccusage-linux-arm64

npx https://pkg.pr.new/@ccusage/ccusage-linux-arm64@1671

@ccusage/ccusage-linux-x64

npx https://pkg.pr.new/@ccusage/ccusage-linux-x64@1671

@ccusage/ccusage-win32-x64

npx https://pkg.pr.new/@ccusage/ccusage-win32-x64@1671

commit: 1d0d237

@github-actions

Copy link
Copy Markdown
Contributor

ccusage performance comparison

PR SHA: e73c9b97afef
Base SHA: 34c697b214f0

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

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, 2597 files), Codex /home/runner/_work/_temp/ccusage-large-codex-fixture (1.01 GiB, 2597 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 512.5ms 1.96 GiB/s 1
claude --offline --json Installed native binary 1.01 GiB 489.7ms 2.06 GiB/s 1
codex --offline --json Package wrapper 1.01 GiB 238.8ms 4.22 GiB/s 1
codex --offline --json Installed native binary 1.01 GiB 151.0ms 6.67 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 native ccusage binary from pkg.pr.new, installed before measurement. Both run --offline --json, measured by hyperfine with 2 warmups and 7 runs.
Peak RSS is measured separately with /usr/bin/time using 1 runs. Lower RSS ratios are better.

Command Input Base median PR median PR vs base Base peak RSS PR peak RSS PR/base RSS Base throughput PR throughput
claude daily --offline --json 0.00 MiB 40.9ms 15.0ms 2.72x 55.00 MiB 24.71 MiB 0.45x 0.04 MiB/s 0.10 MiB/s
claude session --offline --json 0.00 MiB 31.2ms 7.8ms 3.99x 55.00 MiB 24.71 MiB 0.45x 0.05 MiB/s 0.20 MiB/s
codex daily --offline --json 0.00 MiB 30.6ms 8.1ms 3.80x 55.00 MiB 24.71 MiB 0.45x 0.03 MiB/s 0.11 MiB/s
codex session --offline --json 0.00 MiB 31.5ms 7.6ms 4.13x 55.00 MiB 24.71 MiB 0.45x 0.03 MiB/s 0.11 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, 2597 files), Codex /home/runner/_work/_temp/ccusage-large-codex-fixture (1.01 GiB, 2597 files)
Base runs the published ccusage package from pkg.pr.new, installed before measurement; PR runs the published native ccusage binary from pkg.pr.new, installed before measurement. Both run --offline --json, measured by hyperfine with 0 warmups and 1 runs.
Peak RSS is measured separately with /usr/bin/time using 1 runs. Lower RSS ratios are better.

Command Input Base median PR median PR vs base Base peak RSS PR peak RSS PR/base RSS Base throughput PR throughput
claude --offline --json 1.01 GiB 456.4ms 432.1ms 1.06x 958.86 MiB 920.84 MiB 0.96x 2.21 GiB/s 2.33 GiB/s
codex --offline --json 1.01 GiB 183.2ms 153.1ms 1.20x 497.18 MiB 511.18 MiB 1.03x 5.50 GiB/s 6.57 GiB/s

Artifact size

Artifact Base PR Delta Ratio
packed ccusage-*.tgz 19.69 KiB 19.69 KiB -0.00 KiB 1.00x
installed native package binary 4363.28 KiB 4365.66 KiB +2.38 KiB 1.00x

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: e73c9b97afef
Base SHA: 34c697b214f0

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

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, 2597 files), Codex /home/runner/_work/_temp/ccusage-large-codex-fixture (1.01 GiB, 2597 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 325.2ms 3.10 GiB/s 1
claude --offline --json Installed native binary 1.01 GiB 312.0ms 3.23 GiB/s 1
codex --offline --json Package wrapper 1.01 GiB 141.0ms 7.14 GiB/s 1
codex --offline --json Installed native binary 1.01 GiB 122.9ms 8.19 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.
Peak RSS is measured separately with /usr/bin/time using 1 runs. Lower RSS ratios are better.

Command Input Base median PR median PR vs base Base peak RSS PR peak RSS PR/base RSS Base throughput PR throughput
claude daily --offline --json 0.00 MiB 69.5ms 63.6ms 1.09x 55.25 MiB 55.25 MiB 1.00x 0.02 MiB/s 0.02 MiB/s
claude session --offline --json 0.00 MiB 65.4ms 33.4ms 1.96x 55.25 MiB 55.50 MiB 1.00x 0.02 MiB/s 0.05 MiB/s
codex daily --offline --json 0.00 MiB 37.4ms 37.0ms 1.01x 55.50 MiB 55.25 MiB 1.00x 0.02 MiB/s 0.02 MiB/s
codex session --offline --json 0.00 MiB 37.6ms 32.3ms 1.16x 55.00 MiB 55.50 MiB 1.01x 0.02 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, 2597 files), Codex /home/runner/_work/_temp/ccusage-large-codex-fixture (1.01 GiB, 2597 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.
Peak RSS is measured separately with /usr/bin/time using 1 runs. Lower RSS ratios are better.

Command Input Base median PR median PR vs base Base peak RSS PR peak RSS PR/base RSS Base throughput PR throughput
claude --offline --json 1.01 GiB 367.6ms 321.8ms 1.14x 980.86 MiB 936.85 MiB 0.96x 2.74 GiB/s 3.13 GiB/s
codex --offline --json 1.01 GiB 162.1ms 156.2ms 1.04x 509.18 MiB 495.17 MiB 0.97x 6.21 GiB/s 6.44 GiB/s

Artifact size

Artifact Base PR Delta Ratio
packed ccusage-*.tgz 19.69 KiB 19.69 KiB -0.00 KiB 1.00x
installed native package binary 4363.28 KiB 4365.66 KiB +2.38 KiB 1.00x

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

@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.

1 issue found across 2 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="rust/crates/ccusage-terminal/src/width.rs">

<violation number="1" location="rust/crates/ccusage-terminal/src/width.rs:51">
P3: For the common case where a cell has no ANSI codes, this always allocates a fresh String copy via `value.to_string()` even though the value is returned unchanged. This runs once per cell per rendered table row, so color-less renders allocate a needless copy per cell. Return `Cow<'_, str>` (Borrowed when no reset is needed) to avoid the allocation; the caller would need `.into_owned()` in the paths that own the result.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic


pub(crate) fn ensure_ansi_reset(value: &str) -> String {
if !contains_ansi(value) || value.ends_with("\x1b[0m") {
return value.to_string();

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.

P3: For the common case where a cell has no ANSI codes, this always allocates a fresh String copy via value.to_string() even though the value is returned unchanged. This runs once per cell per rendered table row, so color-less renders allocate a needless copy per cell. Return Cow<'_, str> (Borrowed when no reset is needed) to avoid the allocation; the caller would need .into_owned() in the paths that own the result.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At rust/crates/ccusage-terminal/src/width.rs, line 51:

<comment>For the common case where a cell has no ANSI codes, this always allocates a fresh String copy via `value.to_string()` even though the value is returned unchanged. This runs once per cell per rendered table row, so color-less renders allocate a needless copy per cell. Return `Cow<'_, str>` (Borrowed when no reset is needed) to avoid the allocation; the caller would need `.into_owned()` in the paths that own the result.</comment>

<file context>
@@ -46,6 +46,13 @@ pub(crate) fn visible_width_max_line(value: &str) -> usize {
 
+pub(crate) fn ensure_ansi_reset(value: &str) -> String {
+    if !contains_ansi(value) || value.ends_with("\x1b[0m") {
+        return value.to_string();
+    }
+    format!("{value}\x1b[0m")
</file context>

ryoppippi and others added 3 commits August 31, 2026 03:27
Derive fallback widths for non-numeric columns from their rendered row content so status markers remain intact when Models is not the second column. Reclaim width from the Models column before shrinking other wrap-capable text while retaining measured numeric minima.\n\nCarry active SGR sequences onto later physical fragments of multiline cells, while keeping the per-fragment reset at cell borders to prevent style leaks into adjacent cells.
Keep dash list markers attached to provider-prefixed model names when a wrapped cell must truncate them.

Replay active SGR sequences across automatic word-wrapped fragments so styled model output remains consistent.

Retain explicit-newline continuation and per-cell border resets, and update the affected rendered snapshot and regressions.

Co-authored-by: Cristos L-C <[email protected]>
Derive automatic-wrap continuation from the source fragment before truncation adds a display reset, preserving active SGR state in later model fragments.

Treat authored newlines as logical boundaries while retaining state across automatic wrapping, and cover the complete 56-column five-column render.

Co-authored-by: Cristos L-C <[email protected]>

@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.

1 issue found across 4 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="rust/crates/ccusage-terminal/src/width.rs">

<violation number="1" location="rust/crates/ccusage-terminal/src/width.rs:64">
P2: When a wrapped cell uses an SGR reset other than exact `ESC[0m`, `ansi_continuation` retains every prior style command and prepends it to later fragments. Track the current SGR state, or canonicalize attribute resets, so long ANSI cells do not produce unbounded repeated escape sequences.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

let end = skip_ansi_escape(bytes, index);
let escape = &value[index..end];
if escape.ends_with('m') {
if escape == "\x1b[0m" {

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.

P2: When a wrapped cell uses an SGR reset other than exact ESC[0m, ansi_continuation retains every prior style command and prepends it to later fragments. Track the current SGR state, or canonicalize attribute resets, so long ANSI cells do not produce unbounded repeated escape sequences.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At rust/crates/ccusage-terminal/src/width.rs, line 64:

<comment>When a wrapped cell uses an SGR reset other than exact `ESC[0m`, `ansi_continuation` retains every prior style command and prepends it to later fragments. Track the current SGR state, or canonicalize attribute resets, so long ANSI cells do not produce unbounded repeated escape sequences.</comment>

<file context>
@@ -46,6 +46,32 @@ pub(crate) fn visible_width_max_line(value: &str) -> usize {
+        let end = skip_ansi_escape(bytes, index);
+        let escape = &value[index..end];
+        if escape.ends_with('m') {
+            if escape == "\x1b[0m" {
+                continuation.clear();
+            } else {
</file context>

@pullfrog pullfrog 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 new correctness issues found in the incremental changes. The remaining explicit-newline ANSI behavior is unchanged and is not re-raised here.

Reviewed changes

  • Preserved non-model text markers — Derived fallback minima from text content and prioritized the actual Models column while shrinking narrow tables.
  • Maintained wrapped formatting — Grouped list markers with their following model token and replayed active ANSI state across word-wrapped fragments.
  • Added regression coverage — Added tests and snapshots for status markers, ANSI continuation, truncation, compact dates, and narrow numeric layouts.

Pullfrog  | ⚠️ this action is pinned to a commit SHA, which freezes the cleanup step — switch to @v0 or keep the SHA fresh with Dependabot | Fix it ➔ | View workflow run | Using GPT Luna (free via Pullfrog for OSS) | 𝕏

@github-actions

Copy link
Copy Markdown
Contributor

ccusage performance comparison

PR SHA: 1d0d2370e9e3
Base SHA: 34c697b214f0

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

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, 2597 files), Codex /home/runner/_work/_temp/ccusage-large-codex-fixture (1.01 GiB, 2597 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 395.2ms 2.55 GiB/s 1
claude --offline --json Installed native binary 1.01 GiB 329.3ms 3.06 GiB/s 1
codex --offline --json Package wrapper 1.01 GiB 128.2ms 7.85 GiB/s 1
codex --offline --json Installed native binary 1.01 GiB 107.6ms 9.36 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 native ccusage binary from pkg.pr.new, installed before measurement. Both run --offline --json, measured by hyperfine with 2 warmups and 7 runs.
Peak RSS is measured separately with /usr/bin/time using 1 runs. Lower RSS ratios are better.

Command Input Base median PR median PR vs base Base peak RSS PR peak RSS PR/base RSS Base throughput PR throughput
claude daily --offline --json 0.00 MiB 37.4ms 15.1ms 2.49x 55.00 MiB 24.71 MiB 0.45x 0.04 MiB/s 0.10 MiB/s
claude session --offline --json 0.00 MiB 39.8ms 7.9ms 5.03x 55.00 MiB 24.71 MiB 0.45x 0.04 MiB/s 0.20 MiB/s
codex daily --offline --json 0.00 MiB 28.8ms 7.7ms 3.72x 55.00 MiB 24.95 MiB 0.45x 0.03 MiB/s 0.11 MiB/s
codex session --offline --json 0.00 MiB 27.9ms 7.6ms 3.68x 55.50 MiB 24.96 MiB 0.45x 0.03 MiB/s 0.11 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, 2597 files), Codex /home/runner/_work/_temp/ccusage-large-codex-fixture (1.01 GiB, 2597 files)
Base runs the published ccusage package from pkg.pr.new, installed before measurement; PR runs the published native ccusage binary from pkg.pr.new, installed before measurement. Both run --offline --json, measured by hyperfine with 0 warmups and 1 runs.
Peak RSS is measured separately with /usr/bin/time using 1 runs. Lower RSS ratios are better.

Command Input Base median PR median PR vs base Base peak RSS PR peak RSS PR/base RSS Base throughput PR throughput
claude --offline --json 1.01 GiB 380.0ms 329.7ms 1.15x 956.85 MiB 958.84 MiB 1.00x 2.65 GiB/s 3.05 GiB/s
codex --offline --json 1.01 GiB 144.3ms 125.9ms 1.15x 527.19 MiB 525.18 MiB 1.00x 6.98 GiB/s 8.00 GiB/s

Artifact size

Artifact Base PR Delta Ratio
packed ccusage-*.tgz 19.69 KiB 19.69 KiB -0.00 KiB 1.00x
installed native package binary 4363.28 KiB 4368.47 KiB +5.19 KiB 1.00x

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: 1d0d2370e9e3
Base SHA: 34c697b214f0

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

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, 2597 files), Codex /home/runner/_work/_temp/ccusage-large-codex-fixture (1.01 GiB, 2597 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 379.4ms 2.65 GiB/s 1
claude --offline --json Installed native binary 1.01 GiB 352.9ms 2.85 GiB/s 1
codex --offline --json Package wrapper 1.01 GiB 133.2ms 7.56 GiB/s 1
codex --offline --json Installed native binary 1.01 GiB 109.7ms 9.18 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.
Peak RSS is measured separately with /usr/bin/time using 1 runs. Lower RSS ratios are better.

Command Input Base median PR median PR vs base Base peak RSS PR peak RSS PR/base RSS Base throughput PR throughput
claude daily --offline --json 0.00 MiB 39.8ms 32.5ms 1.22x 55.00 MiB 55.00 MiB 1.00x 0.04 MiB/s 0.05 MiB/s
claude session --offline --json 0.00 MiB 32.4ms 29.0ms 1.12x 55.25 MiB 55.00 MiB 1.00x 0.05 MiB/s 0.05 MiB/s
codex daily --offline --json 0.00 MiB 31.4ms 28.9ms 1.09x 54.75 MiB 55.00 MiB 1.00x 0.03 MiB/s 0.03 MiB/s
codex session --offline --json 0.00 MiB 29.2ms 27.9ms 1.05x 55.00 MiB 55.25 MiB 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, 2597 files), Codex /home/runner/_work/_temp/ccusage-large-codex-fixture (1.01 GiB, 2597 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.
Peak RSS is measured separately with /usr/bin/time using 1 runs. Lower RSS ratios are better.

Command Input Base median PR median PR vs base Base peak RSS PR peak RSS PR/base RSS Base throughput PR throughput
claude --offline --json 1.01 GiB 383.4ms 394.0ms 0.97x 976.86 MiB 968.84 MiB 0.99x 2.63 GiB/s 2.56 GiB/s
codex --offline --json 1.01 GiB 134.7ms 135.7ms 0.99x 507.18 MiB 507.18 MiB 1.00x 7.47 GiB/s 7.42 GiB/s

Artifact size

Artifact Base PR Delta Ratio
packed ccusage-*.tgz 19.69 KiB 19.69 KiB -0.00 KiB 1.00x
installed native package binary 4363.28 KiB 4368.47 KiB +5.19 KiB 1.00x

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

@ryoppippi
ryoppippi merged commit 2715f79 into main Aug 31, 2026
64 of 66 checks passed
@ryoppippi
ryoppippi deleted the codex/fix/issue-946-clean branch August 31, 2026 04:44
azidancorp added a commit to azidancorp/ccusage that referenced this pull request Sep 7, 2026
Upstream through 8841f92: official Antigravity SQLite adapter (ccusage#1677),
ZCode (ccusage#1675) and Grok Build CLI sources, Copilot session-state usage
(ccusage#1676), Codex originator breakdowns and cache-write token accounting
(ccusage#1663, ccusage#1674), date-window file skipping (ccusage#1665), session totals scoped
to the date window (ccusage#1664), OpenCode v2 session usage (ccusage#1668),
timestamp-aware DeepSeek V4 pricing (ccusage#1679), ETag-validated pricing cache
refreshes (ccusage#1672), and numeric-column preservation in narrow tables
(ccusage#1671).

Conflict resolutions per the personal divergence ledger:

- Antigravity: adopt the upstream native adapter wholesale; remove the
  personal heuristic adapter and the antigravity-analysis/ provenance
  directory.
- Codex: keep counting copied parent history (replay.rs stays deleted),
  keep tier changes applying at the following turn_context, keep the
  pre-v0.144.0 fast windows and the 2x fast-multiplier fallback, and keep
  the append-aware grouped cache with serde'd parser state. Integrate
  upstream cache-write tokens, originator sources, session_meta line
  detection, and filter_codex_usage_files date-window skipping. Bump the
  group, per-file event, and all-agent row cache discriminators.
- Claude: rewire the cached daily/session summary wrappers onto
  upstream's date-scoped loaders (ccusage#1664).
- OpenCode: keep WAL-signature cache signatures, the summary cache
  wrapper, and --no-cost -> Display mapping; take upstream's v2 session
  usage loading and split directory loader.
- Pricing: keep the explicit GLM-5.2 rates and 1,000,000-token context
  limit (now via put_builtin_entry for both GLM-5.1 and GLM-5.2); take
  upstream's DeepSeek V4 scheduled rates and catalog rules.
- Terminal: keep full dates whenever the minimum full-date layout fits
  and attached breakdown rows; take upstream's content-aware fallback
  minimums and numeric-column floors, adapting the 80-column regression
  test to the personal full-date policy.
- Presentation: keep the hidden-by-default Models column and the
  all-agent --with-models opt-in; regenerate zcode/copilot session
  snapshots under the wider first-column floor.
- Ledger: audit baseline updated to 8841f92; heuristic Antigravity and
  replay suppression recorded as retired divergences.
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.

fix(terminal): table truncates numeric columns when Models column is too wide

1 participant