Skip to content

refactor(nix): derive package metadata from the npm manifest - #1506

Merged
ryoppippi merged 1 commit into
mainfrom
codex/nix-meta-from-package-json
Jul 27, 2026
Merged

ryoppippi merged 1 commit into
mainfrom
codex/nix-meta-from-package-json

Conversation

@ryoppippi

@ryoppippi ryoppippi commented Jul 27, 2026 •

Copy link
Copy Markdown
Member

package.nix restated the name, description, homepage, license, and mainProgram that apps/ccusage/package.json already declares. The two had already drifted — the manifest says "Analyze coding (agent) CLI token usage and costs from local data" while Nix dropped the parentheses — and nothing tied the Nix mainProgram to the manifest's bin entry.

What Changed

  • Import apps/ccusage/package.json and derive pname, meta.description, meta.homepage, meta.license (via lib.getLicenseFromSpdxId), and meta.mainProgram (the sole bin key) from it, following the pattern in yusukebe/ax.
  • Switch the root manifest read from builtins.fromJSON (builtins.readFile ...) to lib.importJSON.

ccusage-static and ccusage-darwin-x64 already build their meta from config.packages.ccusage.meta, so they inherit this with no change.

Why version stays on the root manifest

rust/crates/ccusage/build.rs falls back to reading the root package.json when CCUSAGE_VERSION is unset, and compiled_version_matches_release_package asserts the compiled version matches it. Moving the Nix source would split the version's origin between the Nix build and a plain cargo build. tagpr bumps both manifests together.

Behaviour change

meta.homepage gains the #readme fragment the manifest carries (https://github.com/ccusage/ccusage#readme). Same page; happy to strip it or drop it from package.json if preferred.

Testing

nix eval on the resulting derivations:

  • .#ccusage: pname = ccusage, version = 20.0.19, license.spdxId = MIT, mainProgram = ccusage — all unchanged.
  • .#ccusage-darwin-x64: still inherits the license and mainProgram.
  • nixfmt --check package.nix passes.

View with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is enabled.


Summary by cubic

Derive ccusage Nix package metadata from apps/ccusage/package.json to keep name, description, homepage, license, and mainProgram in sync. Version still comes from the root package.json to match the Rust build.

  • Refactors
    • Import apps/ccusage/package.json via lib.importJSON and set pname, meta.description, meta.homepage, meta.license (with lib.getLicenseFromSpdxId), and meta.mainProgram (from the sole bin key).
    • Read the root package.json with lib.importJSON instead of builtins.fromJSON.
    • ccusage-static and ccusage-darwin-x64 inherit the updated meta without changes.
    • Minor: meta.homepage now includes the #readme fragment from the manifest.

Written for commit acf86b7. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • Chores
    • Updated package metadata to stay synchronized with the published application manifest.
    • Improved version, name, description, homepage, license, and executable metadata handling for package consumers.

`package.nix` restated the name, description, homepage, license, and
`mainProgram` that `apps/ccusage/package.json` already declares, so the
two drifted: the manifest describes the CLI as "Analyze coding (agent)
CLI token usage and costs from local data" while Nix dropped the
parentheses, and nothing tied the Nix `mainProgram` to the manifest's
`bin` entry.

Import the published manifest and derive all of it, following the
pattern in yusukebe/ax: `lib.getLicenseFromSpdxId` turns the SPDX string
into a nixpkgs license, and `mainProgram` comes from the sole `bin` key.
`ccusage-static` and `ccusage-darwin-x64` already build their `meta`
from `config.packages.ccusage.meta`, so they inherit this too.

`version` still comes from the root manifest. `rust/crates/ccusage/
build.rs` falls back to reading it when `CCUSAGE_VERSION` is unset, and
`compiled_version_matches_release_package` asserts the compiled version
matches it, so moving the Nix source would split the version's origin
between the Nix and plain-cargo builds. tagpr bumps both manifests
together.

`meta.homepage` gains the `#readme` fragment the manifest carries. The
URL resolves to the same page.

Verified with `nix eval`: `pname`, `version`, `license.spdxId`, and
`mainProgram` are unchanged, and `ccusage-darwin-x64` still inherits the
license and `mainProgram`.
Copilot AI review requested due to automatic review settings July 27, 2026 23:22
@pullfrog

pullfrog Bot commented Jul 27, 2026 •

Copy link
Copy Markdown
Contributor

This run was cancelled 🛑

The workflow was cancelled before completion. Please check the link below for details.

Pullfrog  | View workflow run | via Pullfrog | 𝕏

@cloudflare-workers-and-pages

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 acf86b7 Commit Preview URL

Branch Preview URL
Jul 27 2026, 11:18 PM

Copilot AI 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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@coderabbitai

coderabbitai Bot commented Jul 27, 2026 •

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

No new commits to review since the last review.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: f0678346-c44b-45de-8bbe-9e67d129dd64

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

package.nix now imports package manifests to derive the version, package name, description, homepage, license, and main program metadata for the Nix derivation.

Changes

Nix package metadata

Layer / File(s) Summary
Manifest imports and version source
package.nix
The Nix expression uses lib.importJSON for the root version and imports the published CLI manifest.
Derivation identity and metadata
package.nix
The derivation pname and meta fields are sourced from the CLI manifest, including SPDX license conversion and binary selection.

Estimated code review effort: 2 (Simple) | ~10 minutes

Suggested reviewers: copilot

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 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 change: sourcing Nix package metadata from the npm manifest.
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.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/nix-meta-from-package-json

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.

@ryoppippi

Copy link
Copy Markdown
Member Author

@coderabbitai review
@cubic-dev-ai review

Please pay particular attention to whether version should also move to apps/ccusage/package.json, and whether the #readme fragment now present in meta.homepage is acceptable for the Nix package metadata.

@ryoppippi
ryoppippi merged commit 1dab5c2 into main Jul 27, 2026
14 of 16 checks passed
@ryoppippi
ryoppippi deleted the codex/nix-meta-from-package-json branch July 27, 2026 23:23
@cubic-dev-ai

cubic-dev-ai Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

@coderabbitai review
@cubic-dev-ai review

Please pay particular attention to whether version should also move to apps/ccusage/package.json, and whether the #readme fragment now present in meta.homepage is acceptable for the Nix package metadata.

@ryoppippi I have started the AI code review. It will take a few minutes to complete.

@coderabbitai

coderabbitai Bot commented Jul 27, 2026 •

Copy link
Copy Markdown
🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '=== Changed files and diff ==='
git diff --stat HEAD^ HEAD
git diff -- package.nix package.json apps/ccusage/package.json rust/crates/ccusage/build.rs

echo '=== Locate relevant version assertions and manifest reads ==='
rg -n -C 4 --glob '!node_modules/**' \
  'CCUSAGE_VERSION|compiled_version_matches_release_package|readFile.*package\.json|importJSON|package\.json' \
  package.nix package.json apps/ccusage/package.json rust 2>/dev/null || true

echo '=== package.nix structure ==='
ast-grep outline package.nix --items all || true
echo '=== package.nix relevant content ==='
cat -n package.nix

echo '=== Root and app manifests: selected metadata ==='
jq '{name, version, description, homepage, license, bin}' package.json
jq '{name, version, description, homepage, license, bin}' apps/ccusage/package.json

echo '=== Rust build script and matching test context ==='
build_rs=$(fd -a '^build\.rs$' rust/crates/ccusage | head -n 1 || true)
if [ -n "$build_rs" ]; then
  cat -n "$build_rs"
fi
rg -n -C 8 --glob '!node_modules/**' 'compiled_version_matches_release_package' rust . 2>/dev/null || true

Length of output: 17156


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '=== Commit patch for package.nix ==='
git show --format=fuller --find-renames --find-copies HEAD -- package.nix

echo '=== Version synchronization configuration and manifest version references ==='
rg -n -C 4 --hidden \
  -g '!node_modules/**' -g '!dist/**' -g '!build/**' \
  'tagpr|apps/ccusage/package\.json|ccusage-monorepo|20\.0\.19|"version"' \
  .github .release-please-manifest.json .release-please-config.json package.json apps/ccusage/package.json 2>/dev/null || true

echo '=== Nix metadata validations or consumers in repository ==='
rg -n -C 3 --hidden \
  -g '!node_modules/**' -g '!dist/**' -g '!build/**' \
  'meta\.homepage|homepage\s*=|mainProgram|lib\.getLicenseFromSpdxId' \
  . 2>/dev/null || true

echo '=== Working tree / commit identity ==='
git status --short
git show -s --format='commit=%H%nparents=%P%nsubject=%s' HEAD

Length of output: 17757


@ryoppippi Reviewed — no findings.

  • Version: It should remain sourced from the root package.json. rust/crates/ccusage/build.rs falls back to that manifest for non-Nix Cargo builds, and compiled_version_matches_release_package asserts against the same file. Switching only package.nix to apps/ccusage/package.json would introduce divergent authorities, even though tagpr currently keeps the versions equal.
  • Homepage: https://github.com/ccusage/ccusage#readme is a valid homepage URL and resolves to the project’s canonical README section. Preserving it from the published npm manifest is appropriate for meta.homepage; no normalization is needed.

The metadata derivation, SPDX license conversion, and mainProgram derivation are consistent with the stated intent.

✅ Action performed

Review finished.

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

🧹 Nitpick comments (1)
package.nix (1)

143-143: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Validate the single bin entry before using head.

builtins.attrNames sorts attribute names, while builtins.head does not enforce that exactly one binary exists. A future second entry would silently select the lexicographically first binary and publish incorrect mainProgram metadata; an empty entry would fail less clearly. Assert the manifest’s stated single-bin contract before selecting the key.

Proposed fix
-      mainProgram = builtins.head (builtins.attrNames cliPackageJson.bin);
+      mainProgram =
+        let
+          binNames = builtins.attrNames cliPackageJson.bin;
+        in
+          assert lib.assertMsg (builtins.length binNames == 1)
+            "apps/ccusage/package.json must declare exactly one bin entry";
+          builtins.head binNames;
🤖 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 `@package.nix` at line 143, Update the mainProgram assignment to validate that
cliPackageJson.bin contains exactly one entry before selecting its name with
builtins.head; preserve the existing single-entry behavior and fail clearly for
empty or multiple binary entries.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@package.nix`:
- Line 143: Update the mainProgram assignment to validate that
cliPackageJson.bin contains exactly one entry before selecting its name with
builtins.head; preserve the existing single-entry behavior and fail clearly for
empty or multiple binary entries.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 3ad80597-339b-4e3d-839d-af981dd4a7a4

📥 Commits

Reviewing files that changed from the base of the PR and between caf89e8 and acf86b7.

📒 Files selected for processing (1)
  • package.nix

@github-actions

Copy link
Copy Markdown
Contributor

ccusage performance comparison

PR SHA: acf86b774e1d
Base SHA: caf89e8c0291

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 350.9ms 2.87 GiB/s 1
claude --offline --json Installed native binary 1.01 GiB 311.5ms 3.23 GiB/s 1
codex --offline --json Package wrapper 1.01 GiB 155.1ms 6.49 GiB/s 1
codex --offline --json Installed native binary 1.01 GiB 102.1ms 9.86 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 27.8ms 5.2ms 5.36x 55.00 MiB 12.45 MiB 0.23x 0.06 MiB/s 0.30 MiB/s
claude session --offline --json 0.00 MiB 28.8ms 3.4ms 8.51x 55.00 MiB 12.45 MiB 0.23x 0.05 MiB/s 0.46 MiB/s
codex daily --offline --json 0.00 MiB 24.4ms 2.5ms 9.71x 55.00 MiB 10.44 MiB 0.19x 0.04 MiB/s 0.34 MiB/s
codex session --offline --json 0.00 MiB 24.5ms 2.4ms 10.33x 55.00 MiB 10.45 MiB 0.19x 0.03 MiB/s 0.36 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 371.6ms 325.4ms 1.14x 974.58 MiB 952.58 MiB 0.98x 2.71 GiB/s 3.09 GiB/s
codex --offline --json 1.01 GiB 120.6ms 98.6ms 1.22x 406.66 MiB 430.64 MiB 1.06x 8.35 GiB/s 10.21 GiB/s

Artifact size

Artifact Base PR Delta Ratio
packed ccusage-*.tgz 18.78 KiB 18.78 KiB +0.00 KiB 1.00x
installed native package binary 4156.78 KiB 4156.78 KiB +0.00 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: acf86b774e1d
Base SHA: caf89e8c0291

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 333.6ms 3.02 GiB/s 1
claude --offline --json Installed native binary 1.01 GiB 301.2ms 3.34 GiB/s 1
codex --offline --json Package wrapper 1.01 GiB 113.6ms 8.86 GiB/s 1
codex --offline --json Installed native binary 1.01 GiB 116.5ms 8.64 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 29.8ms 29.3ms 1.02x 55.00 MiB 55.25 MiB 1.00x 0.05 MiB/s 0.05 MiB/s
claude session --offline --json 0.00 MiB 26.3ms 25.8ms 1.02x 55.00 MiB 55.00 MiB 1.00x 0.06 MiB/s 0.06 MiB/s
codex daily --offline --json 0.00 MiB 25.6ms 22.4ms 1.14x 55.25 MiB 55.00 MiB 1.00x 0.03 MiB/s 0.04 MiB/s
codex session --offline --json 0.00 MiB 22.8ms 23.1ms 0.99x 55.00 MiB 55.00 MiB 1.00x 0.04 MiB/s 0.04 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 369.8ms 325.8ms 1.13x 962.58 MiB 954.58 MiB 0.99x 2.72 GiB/s 3.09 GiB/s
codex --offline --json 1.01 GiB 114.3ms 118.5ms 0.97x 410.65 MiB 408.65 MiB 1.00x 8.80 GiB/s 8.50 GiB/s

Artifact size

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

No issues found across 1 file

Re-trigger cubic

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.

2 participants