Skip to content

perf(release): publish without the Nix dev shell - #1257

Merged
ryoppippi merged 4 commits into
mainfrom
perf-publish-without-nix-devshell
Jun 10, 2026
Merged

ryoppippi merged 4 commits into
mainfrom
perf-publish-without-nix-devshell

Conversation

@ryoppippi

@ryoppippi ryoppippi commented Jun 10, 2026 •

Copy link
Copy Markdown
Member

Summary

The npm publish release job took ~7m, of which ~5m was nix develop re-downloading the entire dev shell (Rust toolchain, litellm, typescript-go, …) from cache.nixos.org just to run pnpm publish. That job runs on a GitHub-hosted runner — required for npm provenance, which rejects self-hosted/Blacksmith runners — so it can never get the Blacksmith sticky-disk Nix cache and pays the full download every release. This PR removes the dev shell from the publish path and fixes a sticky-disk key collision that caused the same cold re-downloads (and large variance) on the Blacksmith pkg-pr-new job.

What changed

  • Drop schema regeneration from the publish build (apps/ccusage/package.json). build no longer runs generate:schema, which compiled and ran the Rust generate-config-schema binary on every publish / pkg-pr-new pack. The committed config-schema.json is already kept in sync with the Rust source by the nix flake check schema-drift check, so regenerating it during packaging is redundant — and it was the only Rust dependency left in the publish path. build now runs only tsdown and ensure:native-binary; the generate:schema script stays for local use (just schema).
  • Publish without the dev shell (.github/workflows/release.yaml). Instead of nix develop --command pnpm … publish (full dev shell), keep the lightweight setup-nix (Nix install only) and provision just pnpm with nix profile install --inputs-from . nixpkgs#pnpm — pinned to the flake's locked nixpkgs (11.1.1, same as the dev shell). setup-node stays only for the npm publish configuration (registry + OIDC provenance .npmrc wiring): the locked nixpkgs node is below the engines floor, so node is sourced from setup-node. bun is not installed explicitly — pnpm install downloads it via engines.runtime into node_modules/.bin, where the prepack ensure:native-binary script resolves it.
  • Scope the Blacksmith sticky-disk key per job (.github/actions/setup-linux-blacksmith-sticky-disk/action.yaml). The key was shared across every Linux job of the same arch; a sticky disk clones the last committed snapshot and re-commits on completion, so jobs with different Nix closures overwrote each other's store, forcing cold re-downloads. This was the source of the pkg-pr-new run-to-run variance (149s vs 388s). Keying by github.job keeps each closure warm independently. pkg-pr-new keeps its Nix dev shell but no longer recompiles Rust during prepack (first change) and gets a stable warm cache.

Why

pnpm publish only needs node, pnpm and bun. Pulling a full Rust dev shell — or recompiling the config schema — on the publish path was pure overhead, and no caching backend helps because the cost is the size of the closure on a cold miss, not where it's cached. A minimal nix profile install nixpkgs#pnpm keeps the version pinned to the same nixpkgs as the dev shell while making the job consistently fast.

Testing / validation

  • actionlint and zizmor clean on release.yaml (only the 2 pre-existing excessive-permissions warnings remain); treefmt clean; pre-commit hooks pass.
  • Verified locally that nix profile install-style provisioning resolves against the locked nixpkgs: nixpkgs#pnpm → 11.1.1 (== pnpm_11), nixpkgs#bun → 1.3.13, nixpkgs#nodejs_24 → 24.14.1 (below engines ^24.15.0 — hence node stays on setup-node).
  • Confirmed via the actual release run logs that ensure:native-binary exits before its cargo fallback when the native artifacts are restored (linux-arm64 binary present, correct version, static) — so the publish path needs no cargo.

Note

release.yaml only runs on tag push, so this path is not exercised by PR CI — it will be validated on the next release. The sticky-disk key change makes all Blacksmith jobs cold once (one-time re-warm).

Summary by CodeRabbit

  • Chores
    • Improved CI stability by scoping job-level cache/keying to avoid cross-job store conflicts and redundant downloads.
    • Streamlined publishing workflow by installing the package manager in the runtime environment and running publish commands directly.
    • Simplified the build script to remove an earlier generation step, reducing build steps and improving efficiency.

The publish build ran `generate:schema`, which compiles and runs the Rust
`generate-config-schema` binary on every `pnpm publish` and pkg-pr-new pack.
The committed apps/ccusage/config-schema.json is already kept in sync with the
Rust source by the `nix flake check` schema-drift check, so regenerating it
during packaging is redundant: it adds cargo build time and a hard Rust
toolchain dependency to the publish path.

`build` now runs only `tsdown` and `ensure:native-binary`. The `generate:schema`
script stays for local regeneration (`pnpm --filter ccusage run generate:schema`
and `just schema`).
The npm publish job runs on a GitHub-hosted runner (required for npm
provenance, which rejects self-hosted/Blacksmith runners), so it never gets the
Blacksmith sticky-disk Nix cache and re-downloaded the full dev shell (Rust
toolchain, litellm, etc.) from cache.nixos.org on every release — ~5 minutes of
the ~7-minute job for a task that only needs node, pnpm and bun.

Now that the publish build no longer invokes cargo, drop `nix develop` and set
up the toolchain directly: pnpm/action-setup (reads packageManager), setup-node,
then `pnpm install --frozen-lockfile`, which downloads the bun runtime declared
in engines.runtime so the `ensure:native-binary` script resolves it from
node_modules/.bin during packaging.
The sticky-disk key was shared across every Linux job of the same arch. A
sticky disk clones the last committed snapshot and re-commits on completion, so
jobs that realize different Nix closures (a full dev shell vs. a single
`nix build`) overwrote each other's store on the shared key, forcing cold
re-downloads from cache.nixos.org — the source of the large run-to-run variance
in pkg-pr-new (149s vs 388s).

Key the disk by `github.job` so each closure stays warm independently.
@coderabbitai

coderabbitai Bot commented Jun 10, 2026 •

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The PR updates CI/build infra: per-job Blacksmith sticky disk cache keying, the npm release job now installs pnpm via Nix and publishes directly with pnpm, and the ccusage build script removes schema generation.

Changes

CI/CD and build infrastructure updates

Layer / File(s) Summary
Sticky disk cache scoping per job
.github/actions/setup-linux-blacksmith-sticky-disk/action.yaml
The sticky disk cache key is updated to include github.job, ensuring each job maintains an isolated cache mount instead of sharing across jobs. This prevents different Nix closure realizations from overwriting each other's store.
npm release job: pnpm install and direct publishing
.github/workflows/release.yaml
The npm job installs the pnpm binary using Nix (nix profile install ... nixpkgs#pnpm) and runs pnpm install --frozen-lockfile; publishing now runs pnpm ... publish directly instead of via nix develop --command.
Build script optimization
apps/ccusage/package.json
The build script removes the generate:schema step, now running tsdown followed by pnpm run ensure:native-binary.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

  • ccusage/ccusage#1254: Also modifies the sticky-disk cache key behavior in the setup-linux-blacksmith-sticky-disk action.
  • ccusage/ccusage#1249: Introduced Blacksmith sticky-disk mounting and caching logic that this PR refines.

Poem

🐰 I hopped through CI with a careful paw,
Per-job caches now keep each store in law,
pnpm arrives, the publish runs clean,
Schema generation trimmed from the scene,
A small tidy hop — rejoice and gnaw!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title 'perf(release): publish without the Nix dev shell' clearly and concisely summarizes the main change: optimizing the release workflow by removing the Nix dev shell dependency from the publish process.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ 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 perf-publish-without-nix-devshell

Comment @coderabbitai help to get the list of available commands and usage tips.

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jun 10, 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 e4b2d57 Commit Preview URL

Branch Preview URL
Jun 10 2026, 10:40 PM

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 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 @.github/workflows/release.yaml:
- Line 104: The workflow step using actions/setup-node is configured with
registry-url which causes an .npmrc to be written with
//_authToken=${NODE_AUTH_TOKEN}, breaking OIDC Trusted Publishing when
NODE_AUTH_TOKEN is unset; to fix, stop writing that token by removing the
registry-url input (or otherwise avoid creating an authToken entry) from the
actions/setup-node step so the publish run (pnpm ... publish --provenance) can
use OIDC id-token authentication; update the setup-node configuration (the
actions/setup-node invocation) and ensure the publish run command (the pnpm
--filter='./apps/ccusage' --filter='./packages/ccusage-*' publish --provenance
--no-git-checks --access public line) remains unchanged.
🪄 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 Plus

Run ID: 5edd1fa4-82a8-4cc9-830c-dd8c937d19c9

📥 Commits

Reviewing files that changed from the base of the PR and between b7948ab and c918263.

📒 Files selected for processing (3)
  • .github/actions/setup-linux-blacksmith-sticky-disk/action.yaml
  • .github/workflows/release.yaml
  • apps/ccusage/package.json

tar -xf "$archive"
done
- run: nix develop --command pnpm --filter='./apps/ccusage' --filter='./packages/ccusage-*' publish --provenance --no-git-checks --access public
- run: pnpm --filter='./apps/ccusage' --filter='./packages/ccusage-*' publish --provenance --no-git-checks --access public

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Show relevant parts of release workflow around the publish step
ls -la .github/workflows || true
sed -n '1,220p' .github/workflows/release.yaml | nl -ba | sed -n '60,180p'

# Check for other publish/auth wiring in the repo (other workflows)
rg -n --hidden --glob '!.git/*' "setup-node|registry-url|NODE_AUTH_TOKEN|NPM_TOKEN|NPM_AUTH_TOKEN|npmrc|auth" .github/workflows

# Show pnpm config if present (may affect auth)
ls -la . || true
ls -la .npmrc pnpm-workspace.yaml package.json . || true
test -f .npmrc && nl -ba .npmrc || true
test -f pnpm-workspace.yaml && nl -ba pnpm-workspace.yaml || true

Repository: ccusage/ccusage

Length of output: 826


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== release.yaml (relevant sections) =="
# Show workflow with line numbers using cat -n (preferred over nl)
cat -n .github/workflows/release.yaml | sed -n '1,220p'

echo
echo "== Search for npm auth wiring in workflows =="
rg -n --hidden --glob '!.git/*' \
  "setup-node|registry-url|NODE_AUTH_TOKEN|NPM_TOKEN|NPM_AUTH_TOKEN|npmrc|auth" \
  .github/workflows

echo
echo "== Show any .npmrc in repo root =="
ls -la .npmrc || true
test -f .npmrc && cat -n .npmrc || true

echo
echo "== Check pnpm publish config/package.json for npm auth hints =="
ls -la package.json || true
test -f package.json && rg -n "publish|access|provenance|npm|registry" package.json || true

Repository: ccusage/ccusage

Length of output: 5783


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Search release.yaml for NODE_AUTH_TOKEN / NPM_TOKEN =="
rg -n "NODE_AUTH_TOKEN|NPM_TOKEN|NPM_AUTH_TOKEN|provenance|trusted" .github/workflows/release.yaml

echo "== Inspect actions/ setup-nix (in case it sets npm auth) =="
rg -n "npm|pnpm.*config|NODE_AUTH_TOKEN|NPM_TOKEN|registry.npmjs.org" .github/actions -S || true

# Show the setup-nix action entrypoint files
fd -td f "setup-nix" .github/actions || true
ls -la .github/actions || true
find .github/actions -maxdepth 2 -type f -print | head -n 80

Repository: ccusage/ccusage

Length of output: 1652


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== package.json publishConfig (if any) =="
cat package.json | sed -n '1,120p'
rg -n "\"publishConfig\"|registry|access|provenance|token|auth" package.json

echo
echo "== release.yaml npm job full permissions/steps (around pnpm publish) =="
# print the npm job only, roughly lines 70-120
cat -n .github/workflows/release.yaml | sed -n '70,140p'

echo
echo "== Inspect .github/actions/setup-nix/action.yaml =="
cat .github/actions/setup-nix/action.yaml

echo
echo "== Search for npm auth usage in actions (NODE_AUTH_TOKEN/NPM_TOKEN/token usage) =="
rg -n "NODE_AUTH_TOKEN|NPM_TOKEN|NPM_AUTH_TOKEN|npmrc|authToken|provenance|id-token|registry.npmjs.org|setup-node" .github/actions -S

Repository: ccusage/ccusage

Length of output: 722


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== release.yaml npm job excerpt (lines ~70-130) =="
cat -n .github/workflows/release.yaml | sed -n '70,130p' || true

echo
echo "== release.yaml npm job permissions/steps detail (search for env) =="
cat -n .github/workflows/release.yaml | sed -n '70,120p' | rg -n "env:|secrets\.|NPM|NODE|token|registry-url|provenance|id-token" || true

echo
echo "== Inspect .github/actions/setup-nix/action.yaml =="
cat .github/actions/setup-nix/action.yaml

echo
echo "== Search for npm/pnpm auth related strings in actions/setup-nix =="
rg -n "NODE_AUTH_TOKEN|NPM_TOKEN|NPM_AUTH_TOKEN|authToken|registry.npmjs.org|npmrc|provenance|id-token|pnpm config set" .github/actions/setup-nix/action.yaml || true

Repository: ccusage/ccusage

Length of output: 3538


🌐 Web query:

actions/setup-node registry-url trusted publishing OIDC NODE_AUTH_TOKEN required

💡 Result:

When using Trusted Publishing (OIDC) with actions/setup-node to publish to npm, you do not need to provide a NODE_AUTH_TOKEN [1][2]. In fact, configuring a NODE_AUTH_TOKEN is specifically intended for classic token-based authentication and is not required for OIDC flows [1][2]. Key implementation details: 1. Requirements: You must use Node.js 24 or newer (which includes npm ≥ 11.5.1), as older versions may lack native support for the OIDC flow [1][2]. 2. OIDC Permissions: Your workflow must explicitly grant the id-token: write permission [1]. 3. Interaction with registry-url: When you use the registry-url input in actions/setup-node, the action automatically writes a line to the local.npmrc file that uses the ${NODE_AUTH_TOKEN} environment variable [3][4]. 4. Troubleshooting: Because this.npmrc configuration exists, some users report that if NODE_AUTH_TOKEN is unset, the npm CLI may incorrectly attempt classic authentication with empty credentials instead of triggering the OIDC flow, leading to ENEEDAUTH or 404 errors [3][4]. If you encounter these errors despite correct OIDC configuration, the recommended workaround is to explicitly unset or clear the NODE_AUTH_TOKEN environment variable for the specific step where you run npm publish [5][2]. You can do this by running: - run: NODE_AUTH_TOKEN="" npm publish [5] This ensures that the npm CLI does not mistakenly detect an empty token and instead proceeds to use the OIDC flow [5][2].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Search for publishConfig/authToken/NODE_AUTH_TOKEN usage in repo =="
rg -n --hidden --glob '!.git/*' \
  "publishConfig|authToken|NODE_AUTH_TOKEN|NPM_TOKEN|NPM_AUTH_TOKEN|registry\.npmjs\.org|_authToken" \
  apps packages .github || true

echo
echo "== Search for provenance usage in pnpm/yaml/package files =="
rg -n --hidden --glob '!.git/*' \
  "provenance" \
  apps packages .github || true

echo
echo "== List package.json files under packages/ccusage-* (top-level excerpt only) =="
fd -e package.json "packages/ccusage-" -a || true
# fallback: just search by filename
fd -td f "package.json" packages | head -n 50

Repository: ccusage/ccusage

Length of output: 1430


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== apps/ccusage/package.json (publishConfig excerpt) =="
cat apps/ccusage/package.json | sed -n '1,120p' | rg -n "publishConfig|registry|access|provenance|authToken|token" -n || true
cat apps/ccusage/package.json | sed -n '1,80p'

echo
echo "== packages/ccusage-linux-x64/package.json (publishConfig excerpt) =="
cat packages/ccusage-linux-x64/package.json | sed -n '1,120p' | rg -n "publishConfig|registry|access|provenance|authToken|token" -n || true
cat packages/ccusage-linux-x64/package.json | sed -n '1,80p'

echo
echo "== packages/ccusage-win32-x64/package.json (publishConfig excerpt) =="
cat packages/ccusage-win32-x64/package.json | sed -n '1,120p' | rg -n "publishConfig|registry|access|provenance|authToken|token" -n || true
cat packages/ccusage-win32-x64/package.json | sed -n '1,80p'

Repository: ccusage/ccusage

Length of output: 4447


🌐 Web query:

actions/setup-node trusted publishing provenance NODE_AUTH_TOKEN unset .npmrc ${NODE_AUTH_TOKEN} behavior

💡 Result:

When using actions/setup-node with the registry-url input, the action automatically generates an .npmrc file containing a placeholder for authentication: //registry.npmjs.org/:_authToken=${NODE_AUTH_TOKEN} [1][2][3]. This behavior is designed to support classic token-based authentication [1]. However, this can interfere with npm Trusted Publishing (OIDC) workflows [1][2]. When NODE_AUTH_TOKEN is not explicitly set (which is the intended state for Trusted Publishing), the ${NODE_AUTH_TOKEN} placeholder expands to an empty string [2]. Some versions of the npm CLI interpret the presence of the _authToken= line in .npmrc as evidence that auth is already configured, causing the CLI to attempt a classic publish with empty credentials rather than initiating the OIDC token exchange, often resulting in ENEEDAUTH or E404 errors [1][2]. To address this, the following approaches are recommended: 1. Unset or clear the token: You can explicitly unset the NODE_AUTH_TOKEN environment variable before running npm publish to ensure the npm CLI does not see it as configured [4]. run: NODE_AUTH_TOKEN="" npm publish 2. Use a modern npm version: npm versions 11.5.1 and higher (typically bundled with Node.js 24+) have improved support for the OIDC flow, which may mitigate or resolve the conflict depending on the exact environment and CLI version [4][5]. 3. Avoid registry-url if not required: If you do not need the action to configure your registry and auth settings for other steps, omitting the registry-url input prevents the automatic creation of the .npmrc file [6]. For ongoing updates, the actions/setup-node maintainers have discussed refining this behavior to avoid setting dummy tokens by default, aiming to better support OIDC workflows [7]. Always ensure you have the id-token: write permission configured in your workflow for Trusted Publishing to function [8][5].

Citations:


Fix possible npm Trusted Publishing (OIDC) breakage in release.yaml publish step

The workflow grants id-token: write and publishes with --provenance, so it’s set up for npm Trusted Publishing (no token should be required). However, actions/setup-node is configured with registry-url, which creates an .npmrc containing //registry.npmjs.org/:_authToken=${NODE_AUTH_TOKEN}; since NODE_AUTH_TOKEN isn’t set, npm can fall back to classic auth with empty credentials and the publish may fail.

🔧 Proposed fix
-      - run: pnpm --filter='./apps/ccusage' --filter='./packages/ccusage-*' publish --provenance --no-git-checks --access public
+      - run: pnpm --filter='./apps/ccusage' --filter='./packages/ccusage-*' publish --provenance --no-git-checks --access public
+        env:
+          NODE_AUTH_TOKEN: ""
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- run: pnpm --filter='./apps/ccusage' --filter='./packages/ccusage-*' publish --provenance --no-git-checks --access public
- run: pnpm --filter='./apps/ccusage' --filter='./packages/ccusage-*' publish --provenance --no-git-checks --access public
env:
NODE_AUTH_TOKEN: ""
🤖 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 @.github/workflows/release.yaml at line 104, The workflow step using
actions/setup-node is configured with registry-url which causes an .npmrc to be
written with //_authToken=${NODE_AUTH_TOKEN}, breaking OIDC Trusted Publishing
when NODE_AUTH_TOKEN is unset; to fix, stop writing that token by removing the
registry-url input (or otherwise avoid creating an authToken entry) from the
actions/setup-node step so the publish run (pnpm ... publish --provenance) can
use OIDC id-token authentication; update the setup-node configuration (the
actions/setup-node invocation) and ensure the publish run command (the pnpm
--filter='./apps/ccusage' --filter='./packages/ccusage-*' publish --provenance
--no-git-checks --access public line) remains unchanged.

@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 3 files

Re-trigger cubic

@pkg-pr-new

pkg-pr-new Bot commented Jun 10, 2026 •

Copy link
Copy Markdown

Open in StackBlitz

ccusage

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

@ccusage/ccusage-darwin-arm64

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

@ccusage/ccusage-linux-arm64

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

@ccusage/ccusage-linux-x64

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

@ccusage/ccusage-win32-x64

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

commit: e4b2d57

@github-actions

Copy link
Copy Markdown
Contributor

ccusage performance comparison

PR SHA: c91826390381
Base SHA: b7948ab86529

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 b7948ab86529 1.221s 738.9ms 47.0ms 3
PR pkg.pr.new c918263 825.5ms 792.7ms 47.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: b7948ab86529; PR package: c918263. 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.
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
bunx -p <pkg> ccusage claude --offline --json 1.01 GiB 727.7ms 798.7ms 0.91x 724.00 MiB 740.25 MiB 1.02x 1.38 GiB/s 1.26 GiB/s
bunx -p <pkg> ccusage codex --offline --json 1.01 GiB 168.1ms 170.2ms 0.99x 89.00 MiB 92.50 MiB 1.04x 5.99 GiB/s 5.92 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 828.8ms 1.21 GiB/s 1
claude --offline --json Installed native binary 1.01 GiB 682.3ms 1.48 GiB/s 1
codex --offline --json Package wrapper 1.01 GiB 162.0ms 6.22 GiB/s 1
codex --offline --json Installed native binary 1.01 GiB 123.7ms 8.14 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.
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 41.8ms 5.7ms 7.39x 45.75 MiB 2.50 MiB 0.05x 0.04 MiB/s 0.27 MiB/s
claude session --offline --json 0.00 MiB 41.3ms 5.8ms 7.14x 43.00 MiB 2.50 MiB 0.06x 0.04 MiB/s 0.27 MiB/s
codex daily --offline --json 0.00 MiB 42.4ms 5.3ms 7.95x 45.75 MiB 2.50 MiB 0.05x 0.02 MiB/s 0.16 MiB/s
codex session --offline --json 0.00 MiB 43.1ms 5.5ms 7.87x 45.75 MiB 2.50 MiB 0.05x 0.02 MiB/s 0.16 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.
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 797.6ms 703.7ms 1.13x 737.75 MiB 725.00 MiB 0.98x 1.26 GiB/s 1.43 GiB/s
codex --offline --json 1.01 GiB 158.9ms 126.9ms 1.25x 92.00 MiB 91.25 MiB 0.99x 6.34 GiB/s 7.94 GiB/s

Artifact size

Artifact Base PR Delta Ratio
packed ccusage-*.tgz 17.32 KiB 17.33 KiB +0.00 KiB 1.00x
installed native package binary 3353.74 KiB 3417.74 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: c91826390381
Base SHA: b7948ab86529

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 b7948ab86529 751.9ms 1.012s 51.4ms 3
PR pkg.pr.new c918263 819.1ms 757.4ms 51.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: b7948ab86529; PR package: c918263. 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.
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
bunx -p <pkg> ccusage claude --offline --json 1.01 GiB 944.0ms 980.5ms 0.96x 733.25 MiB 756.75 MiB 1.03x 1.07 GiB/s 1.03 GiB/s
bunx -p <pkg> ccusage codex --offline --json 1.01 GiB 190.2ms 190.9ms 1.00x 93.25 MiB 89.25 MiB 0.96x 5.29 GiB/s 5.27 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 866.5ms 1.16 GiB/s 1
claude --offline --json Installed native binary 1.01 GiB 866.5ms 1.16 GiB/s 1
codex --offline --json Package wrapper 1.01 GiB 184.5ms 5.46 GiB/s 1
codex --offline --json Installed native binary 1.01 GiB 141.1ms 7.13 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 42.9ms 41.7ms 1.03x 45.75 MiB 45.50 MiB 0.99x 0.04 MiB/s 0.04 MiB/s
claude session --offline --json 0.00 MiB 42.7ms 43.8ms 0.98x 45.75 MiB 43.50 MiB 0.95x 0.04 MiB/s 0.04 MiB/s
codex daily --offline --json 0.00 MiB 42.6ms 42.6ms 1.00x 45.75 MiB 45.75 MiB 1.00x 0.02 MiB/s 0.02 MiB/s
codex session --offline --json 0.00 MiB 42.8ms 42.8ms 1.00x 46.00 MiB 46.00 MiB 1.00x 0.02 MiB/s 0.02 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.
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 967.3ms 853.0ms 1.13x 729.25 MiB 738.00 MiB 1.01x 1.04 GiB/s 1.18 GiB/s
codex --offline --json 1.01 GiB 182.5ms 185.8ms 0.98x 90.50 MiB 88.00 MiB 0.97x 5.52 GiB/s 5.42 GiB/s

Artifact size

Artifact Base PR Delta Ratio
packed ccusage-*.tgz 17.32 KiB 17.33 KiB +0.00 KiB 1.00x
installed native package binary 3353.74 KiB 3417.74 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.

Replace pnpm/action-setup with `nix profile install --inputs-from . nixpkgs#pnpm`
so the publish toolchain is pinned to the flake's locked nixpkgs (pnpm 11.1.1,
identical to the dev shell) instead of a separate action's resolution, while
still avoiding the full `nix develop` dev shell that made the job slow.

setup-node stays solely for the npm publish configuration (registry + OIDC
provenance .npmrc wiring); the locked nixpkgs node is below the engines floor,
so node is sourced from setup-node. bun is not installed here — `pnpm install`
downloads it via engines.runtime into node_modules/.bin, where the prepack
`ensure:native-binary` script resolves it.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
.github/workflows/release.yaml (1)

105-105: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Fix possible npm Trusted Publishing (OIDC) breakage in release.yaml publish step

The workflow grants id-token: write and publishes with --provenance, indicating npm Trusted Publishing (OIDC) is intended. However, actions/setup-node is configured with registry-url (line 90), which creates an .npmrc containing //registry.npmjs.org/:_authToken=${NODE_AUTH_TOKEN}. Since NODE_AUTH_TOKEN is not set, npm may fall back to classic authentication with empty credentials, causing the publish to fail with ENEEDAUTH or E404 errors instead of using the OIDC flow.

🔧 Proposed fix
-      - run: pnpm --filter='./apps/ccusage' --filter='./packages/ccusage-*' publish --provenance --no-git-checks --access public
+      - run: pnpm --filter='./apps/ccusage' --filter='./packages/ccusage-*' publish --provenance --no-git-checks --access public
+        env:
+          NODE_AUTH_TOKEN: ""
🤖 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 @.github/workflows/release.yaml at line 105, The publish step is set to use
OIDC (--provenance + id-token: write) but actions/setup-node is configured with
registry-url which causes an .npmrc to be written with
//registry.npmjs.org/:_authToken=${NODE_AUTH_TOKEN}, breaking OIDC; update the
workflow to stop creating an authToken entry by removing or not setting the
registry-url input on actions/setup-node (or set its npmAlwaysAuth / always-auth
equivalent to false) so the OIDC flow is used, and keep the publish command (the
pnpm --filter='./apps/ccusage' --filter='./packages/ccusage-*' publish
--provenance --no-git-checks --access public) unchanged.
🤖 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 @.github/workflows/release.yaml:
- Line 91: The release workflow uses node-version: lts/* which can drift and may
not satisfy the project's engines.runtime[].node.version (^24.15.0) in
package.json; update the release workflow's node-version setting (the
node-version key in the release workflow) to a pinned 24 series (e.g., '24' or
'24.x') so the CI runs on Node 24 and aligns with
engines.runtime[].node.version.

---

Duplicate comments:
In @.github/workflows/release.yaml:
- Line 105: The publish step is set to use OIDC (--provenance + id-token: write)
but actions/setup-node is configured with registry-url which causes an .npmrc to
be written with //registry.npmjs.org/:_authToken=${NODE_AUTH_TOKEN}, breaking
OIDC; update the workflow to stop creating an authToken entry by removing or not
setting the registry-url input on actions/setup-node (or set its npmAlwaysAuth /
always-auth equivalent to false) so the OIDC flow is used, and keep the publish
command (the pnpm --filter='./apps/ccusage' --filter='./packages/ccusage-*'
publish --provenance --no-git-checks --access public) unchanged.
🪄 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 Plus

Run ID: 55a1baf3-d6a4-4f15-b881-fae7fa42fcc6

📥 Commits

Reviewing files that changed from the base of the PR and between c918263 and e4b2d57.

📒 Files selected for processing (1)
  • .github/workflows/release.yaml

@@ -90,6 +90,8 @@ jobs:
registry-url: 'https://registry.npmjs.org'
node-version: lts/*

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Check package.json engines field and verify Node LTS compatibility

echo "== Project Node version requirements =="
rg -n "\"engines\":" -A 5 package.json apps/ccusage/package.json

echo ""
echo "== Current Node LTS version (for reference) =="
echo "As of June 2026, Node LTS is 22.x; Node 24 is recommended for OIDC provenance"

Repository: ccusage/ccusage

Length of output: 427


Align Node version in release workflow with engines.node (^24.15.0)

  • .github/workflows/release.yaml uses node-version: lts/* (line 91), but package.json declares engines.runtime[].node.version: ^24.15.0; LTS may not satisfy it.
  • Pin the workflow to node-version: '24' (or 24.x) instead of lts/* to match the project requirement.
🤖 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 @.github/workflows/release.yaml at line 91, The release workflow uses
node-version: lts/* which can drift and may not satisfy the project's
engines.runtime[].node.version (^24.15.0) in package.json; update the release
workflow's node-version setting (the node-version key in the release workflow)
to a pinned 24 series (e.g., '24' or '24.x') so the CI runs on Node 24 and
aligns with engines.runtime[].node.version.

@github-code-quality

Copy link
Copy Markdown

Code Coverage Overview

Languages: Rust

Rust / code-coverage/cargo-llvm-cov

The overall coverage in the perf-publish-without... branch is 77%. Coverage data for the main branch is not yet available.

Show a code coverage summary of the most covered files.
File main perf-publish-without... e4b2d57 +/-
crates/ccusage/...codex/loader.rs — 99% —
crates/ccusage/src/summary.rs — 99% —
crates/ccusage/src/pricing.rs — 97% —
crates/ccusage/...onfig_schema.rs — 96% —
crates/ccusage/...r/claude/mod.rs — 94% —
crates/ccusage/src/main.rs — 93% —
crates/ccusage/...ex/aggregate.rs — 93% —
crates/ccusage-...i/src/parser.rs — 91% —
crates/ccusage/...codex/parser.rs — 85% —
crates/ccusage/src/config.rs — 67% —

Code Coverage is in Public Preview. Learn more and provide us with your feedback.

@github-actions

Copy link
Copy Markdown
Contributor

ccusage performance comparison

PR SHA: e4b2d5799cb6
Base SHA: b7948ab86529

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 b7948ab86529 827.3ms 942.4ms 52.3ms 3
PR pkg.pr.new e4b2d57 850.1ms 1.148s 51.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: b7948ab86529; PR package: e4b2d57. 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.
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
bunx -p <pkg> ccusage claude --offline --json 1.01 GiB 929.7ms 950.8ms 0.98x 720.00 MiB 726.25 MiB 1.01x 1.08 GiB/s 1.06 GiB/s
bunx -p <pkg> ccusage codex --offline --json 1.01 GiB 198.8ms 185.8ms 1.07x 88.75 MiB 91.00 MiB 1.03x 5.07 GiB/s 5.42 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 906.9ms 1.11 GiB/s 1
claude --offline --json Installed native binary 1.01 GiB 985.3ms 1.02 GiB/s 1
codex --offline --json Package wrapper 1.01 GiB 174.9ms 5.75 GiB/s 1
codex --offline --json Installed native binary 1.01 GiB 133.7ms 7.53 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.
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.7ms 6.9ms 5.86x 45.75 MiB 2.75 MiB 0.06x 0.04 MiB/s 0.22 MiB/s
claude session --offline --json 0.00 MiB 40.4ms 6.9ms 5.89x 46.00 MiB 2.50 MiB 0.05x 0.04 MiB/s 0.23 MiB/s
codex daily --offline --json 0.00 MiB 41.5ms 6.4ms 6.48x 45.75 MiB 2.50 MiB 0.05x 0.02 MiB/s 0.13 MiB/s
codex session --offline --json 0.00 MiB 41.1ms 6.5ms 6.36x 45.75 MiB 2.50 MiB 0.05x 0.02 MiB/s 0.13 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.
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 915.2ms 898.6ms 1.02x 731.75 MiB 733.50 MiB 1.00x 1.10 GiB/s 1.12 GiB/s
codex --offline --json 1.01 GiB 175.8ms 140.3ms 1.25x 91.25 MiB 88.25 MiB 0.97x 5.73 GiB/s 7.18 GiB/s

Artifact size

Artifact Base PR Delta Ratio
packed ccusage-*.tgz 17.32 KiB 17.32 KiB +0.00 KiB 1.00x
installed native package binary 3353.74 KiB 3417.74 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: e4b2d5799cb6
Base SHA: b7948ab86529

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 b7948ab86529 602.1ms 1.225s 57.3ms 3
PR pkg.pr.new e4b2d57 1.094s 1.041s 58.5ms 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: b7948ab86529; PR package: e4b2d57. 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.
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
bunx -p <pkg> ccusage claude --offline --json 1.01 GiB 938.5ms 882.7ms 1.06x 739.75 MiB 733.75 MiB 0.99x 1.07 GiB/s 1.14 GiB/s
bunx -p <pkg> ccusage codex --offline --json 1.01 GiB 200.5ms 209.3ms 0.96x 91.25 MiB 88.50 MiB 0.97x 5.02 GiB/s 4.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 916.4ms 1.10 GiB/s 1
claude --offline --json Installed native binary 1.01 GiB 769.3ms 1.31 GiB/s 1
codex --offline --json Package wrapper 1.01 GiB 173.6ms 5.80 GiB/s 1
codex --offline --json Installed native binary 1.01 GiB 126.7ms 7.95 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 52.8ms 51.3ms 1.03x - 45.75 MiB - 0.03 MiB/s 0.03 MiB/s
claude session --offline --json 0.00 MiB 49.8ms 48.8ms 1.02x 45.75 MiB 46.00 MiB 1.01x 0.03 MiB/s 0.03 MiB/s
codex daily --offline --json 0.00 MiB 50.4ms 51.7ms 0.97x 45.75 MiB 45.75 MiB 1.00x 0.02 MiB/s 0.02 MiB/s
codex session --offline --json 0.00 MiB 55.3ms 53.7ms 1.03x 45.75 MiB - - 0.02 MiB/s 0.02 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.
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 895.0ms 918.4ms 0.97x 719.50 MiB 751.50 MiB 1.04x 1.12 GiB/s 1.10 GiB/s
codex --offline --json 1.01 GiB 195.4ms 188.9ms 1.03x 88.25 MiB 91.50 MiB 1.04x 5.15 GiB/s 5.33 GiB/s

Artifact size

Artifact Base PR Delta Ratio
packed ccusage-*.tgz 17.32 KiB 17.32 KiB +0.00 KiB 1.00x
installed native package binary 3353.74 KiB 3417.74 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